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.Nullable;
     20 import android.annotation.RequiresPermission;
     21 import android.annotation.SdkConstant;
     22 import android.annotation.SuppressLint;
     23 import android.annotation.SdkConstant.SdkConstantType;
     24 import android.annotation.SystemApi;
     25 import android.annotation.SystemService;
     26 import android.content.Context;
     27 import android.content.pm.ParceledListSlice;
     28 import android.net.ConnectivityManager;
     29 import android.net.DhcpInfo;
     30 import android.net.Network;
     31 import android.net.NetworkCapabilities;
     32 import android.net.NetworkRequest;
     33 import android.net.wifi.hotspot2.PasspointConfiguration;
     34 import android.os.Binder;
     35 import android.os.Build;
     36 import android.os.Handler;
     37 import android.os.IBinder;
     38 import android.os.Looper;
     39 import android.os.Message;
     40 import android.os.Messenger;
     41 import android.os.RemoteException;
     42 import android.os.WorkSource;
     43 import android.util.Log;
     44 import android.util.SparseArray;
     45 
     46 import com.android.internal.annotations.GuardedBy;
     47 import com.android.internal.annotations.VisibleForTesting;
     48 import com.android.internal.util.AsyncChannel;
     49 import com.android.internal.util.Protocol;
     50 import com.android.server.net.NetworkPinner;
     51 
     52 import dalvik.system.CloseGuard;
     53 
     54 import java.lang.ref.WeakReference;
     55 import java.net.InetAddress;
     56 import java.util.Collections;
     57 import java.util.List;
     58 import java.util.concurrent.CountDownLatch;
     59 
     60 /**
     61  * This class provides the primary API for managing all aspects of Wi-Fi
     62  * connectivity.
     63  * <p>
     64  * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
     65  * should only be obtained from an {@linkplain Context#getApplicationContext()
     66  * application context}, and not from any other derived context to avoid memory
     67  * leaks within the calling process.
     68  * <p>
     69  * It deals with several categories of items:
     70  * <ul>
     71  * <li>The list of configured networks. The list can be viewed and updated, and
     72  * attributes of individual entries can be modified.</li>
     73  * <li>The currently active Wi-Fi network, if any. Connectivity can be
     74  * established or torn down, and dynamic information about the state of the
     75  * network can be queried.</li>
     76  * <li>Results of access point scans, containing enough information to make
     77  * decisions about what access point to connect to.</li>
     78  * <li>It defines the names of various Intent actions that are broadcast upon
     79  * any sort of change in Wi-Fi state.
     80  * </ul>
     81  * This is the API to use when performing Wi-Fi specific operations. To perform
     82  * operations that pertain to network connectivity at an abstract level, use
     83  * {@link android.net.ConnectivityManager}.
     84  */
     85 @SystemService(Context.WIFI_SERVICE)
     86 public class WifiManager {
     87 
     88     private static final String TAG = "WifiManager";
     89     // Supplicant error codes:
     90     /**
     91      * The error code if there was a problem authenticating.
     92      */
     93     public static final int ERROR_AUTHENTICATING = 1;
     94 
     95     /**
     96      * The reason code if there is no error during authentication.
     97      * It could also imply that there no authentication in progress,
     98      * this reason code also serves as a reset value.
     99      * @hide
    100      */
    101     public static final int ERROR_AUTH_FAILURE_NONE = 0;
    102 
    103     /**
    104      * The reason code if there was a timeout authenticating.
    105      * @hide
    106      */
    107     public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
    108 
    109     /**
    110      * The reason code if there was a wrong password while
    111      * authenticating.
    112      * @hide
    113      */
    114     public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
    115 
    116     /**
    117      * The reason code if there was EAP failure while
    118      * authenticating.
    119      * @hide
    120      */
    121     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
    122 
    123     /**
    124      * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently
    125      * @hide
    126      */
    127     public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available";
    128 
    129     /**
    130      * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED
    131      * @hide
    132      */
    133     public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
    134 
    135     /**
    136      * Broadcast intent action indicating that the credential of a Wi-Fi network
    137      * has been changed. One extra provides the ssid of the network. Another
    138      * extra provides the event type, whether the credential is saved or forgot.
    139      * @hide
    140      */
    141     @SystemApi
    142     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
    143             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
    144     /** @hide */
    145     @SystemApi
    146     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
    147     /** @hide */
    148     @SystemApi
    149     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
    150     /** @hide */
    151     @SystemApi
    152     public static final int WIFI_CREDENTIAL_SAVED = 0;
    153     /** @hide */
    154     @SystemApi
    155     public static final int WIFI_CREDENTIAL_FORGOT = 1;
    156 
    157     /**
    158      * Broadcast intent action indicating that a Passpoint provider icon has been received.
    159      *
    160      * Included extras:
    161      * {@link #EXTRA_BSSID_LONG}
    162      * {@link #EXTRA_FILENAME}
    163      * {@link #EXTRA_ICON}
    164      *
    165      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
    166      *
    167      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
    168      * components will be launched.
    169      *
    170      * @hide
    171      */
    172     public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
    173     /**
    174      * BSSID of an AP in long representation.  The {@link #EXTRA_BSSID} contains BSSID in
    175      * String representation.
    176      *
    177      * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}.
    178      *
    179      * @hide
    180      */
    181     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
    182     /**
    183      * Icon data.
    184      *
    185      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
    186      * {@link android.graphics.drawable.Icon}.
    187      *
    188      * @hide
    189      */
    190     public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
    191     /**
    192      * Name of a file.
    193      *
    194      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
    195      *
    196      * @hide
    197      */
    198     public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
    199 
    200     /**
    201      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
    202      *
    203      * Included extras:
    204      * {@link #EXTRA_BSSID_LONG}
    205      * {@link #EXTRA_ANQP_ELEMENT_DATA}
    206      *
    207      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
    208      *
    209      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
    210      * components will be launched.
    211      *
    212      * @hide
    213      */
    214     public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
    215             "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
    216     /**
    217      * Raw binary data of an ANQP (Access Network Query Protocol) element.
    218      *
    219      * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}.
    220      *
    221      * @hide
    222      */
    223     public static final String EXTRA_ANQP_ELEMENT_DATA =
    224             "android.net.wifi.extra.ANQP_ELEMENT_DATA";
    225 
    226     /**
    227      * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
    228      *
    229      * Included extras:
    230      * {@link #EXTRA_BSSID_LONG}
    231      * {@link #EXTRA_ESS}
    232      * {@link #EXTRA_DELAY}
    233      * {@link #EXTRA_URL}
    234      *
    235      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
    236      *
    237      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
    238      * components will be launched.
    239      *
    240      * @hide
    241      */
    242     public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
    243             "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
    244     /**
    245      * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to
    246      * {@code true} for ESS.
    247      *
    248      * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}.
    249      *
    250      * @hide
    251      */
    252     public static final String EXTRA_ESS = "android.net.wifi.extra.ESS";
    253     /**
    254      * Delay in seconds.
    255      *
    256      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
    257      *
    258      * @hide
    259      */
    260     public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
    261     /**
    262      * String representation of an URL.
    263      *
    264      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
    265      *
    266      * @hide
    267      */
    268     public static final String EXTRA_URL = "android.net.wifi.extra.URL";
    269 
    270     /**
    271      * Broadcast intent action indicating a Passpoint subscription remediation frame has been
    272      * received.
    273      *
    274      * Included extras:
    275      * {@link #EXTRA_BSSID_LONG}
    276      * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD}
    277      * {@link #EXTRA_URL}
    278      *
    279      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
    280      *
    281      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
    282      * components will be launched.
    283      *
    284      * @hide
    285      */
    286     public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
    287             "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
    288     /**
    289      * The protocol supported by the subscription remediation server. The possible values are:
    290      * 0 - OMA DM
    291      * 1 - SOAP XML SPP
    292      *
    293      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
    294      *
    295      * @hide
    296      */
    297     public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD =
    298             "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
    299 
    300     /**
    301      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
    302      * enabling, disabling, or unknown. One extra provides this state as an int.
    303      * Another extra provides the previous state, if available.
    304      *
    305      * @see #EXTRA_WIFI_STATE
    306      * @see #EXTRA_PREVIOUS_WIFI_STATE
    307      */
    308     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    309     public static final String WIFI_STATE_CHANGED_ACTION =
    310         "android.net.wifi.WIFI_STATE_CHANGED";
    311     /**
    312      * The lookup key for an int that indicates whether Wi-Fi is enabled,
    313      * disabled, enabling, disabling, or unknown.  Retrieve it with
    314      * {@link android.content.Intent#getIntExtra(String,int)}.
    315      *
    316      * @see #WIFI_STATE_DISABLED
    317      * @see #WIFI_STATE_DISABLING
    318      * @see #WIFI_STATE_ENABLED
    319      * @see #WIFI_STATE_ENABLING
    320      * @see #WIFI_STATE_UNKNOWN
    321      */
    322     public static final String EXTRA_WIFI_STATE = "wifi_state";
    323     /**
    324      * The previous Wi-Fi state.
    325      *
    326      * @see #EXTRA_WIFI_STATE
    327      */
    328     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
    329 
    330     /**
    331      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
    332      * it finishes successfully.
    333      *
    334      * @see #WIFI_STATE_CHANGED_ACTION
    335      * @see #getWifiState()
    336      */
    337     public static final int WIFI_STATE_DISABLING = 0;
    338     /**
    339      * Wi-Fi is disabled.
    340      *
    341      * @see #WIFI_STATE_CHANGED_ACTION
    342      * @see #getWifiState()
    343      */
    344     public static final int WIFI_STATE_DISABLED = 1;
    345     /**
    346      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
    347      * it finishes successfully.
    348      *
    349      * @see #WIFI_STATE_CHANGED_ACTION
    350      * @see #getWifiState()
    351      */
    352     public static final int WIFI_STATE_ENABLING = 2;
    353     /**
    354      * Wi-Fi is enabled.
    355      *
    356      * @see #WIFI_STATE_CHANGED_ACTION
    357      * @see #getWifiState()
    358      */
    359     public static final int WIFI_STATE_ENABLED = 3;
    360     /**
    361      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
    362      * or disabling.
    363      *
    364      * @see #WIFI_STATE_CHANGED_ACTION
    365      * @see #getWifiState()
    366      */
    367     public static final int WIFI_STATE_UNKNOWN = 4;
    368 
    369     /**
    370      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
    371      * enabling, disabling, or failed.
    372      *
    373      * @hide
    374      */
    375     @SystemApi
    376     public static final String WIFI_AP_STATE_CHANGED_ACTION =
    377         "android.net.wifi.WIFI_AP_STATE_CHANGED";
    378 
    379     /**
    380      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
    381      * disabled, enabling, disabling, or failed.  Retrieve it with
    382      * {@link android.content.Intent#getIntExtra(String,int)}.
    383      *
    384      * @see #WIFI_AP_STATE_DISABLED
    385      * @see #WIFI_AP_STATE_DISABLING
    386      * @see #WIFI_AP_STATE_ENABLED
    387      * @see #WIFI_AP_STATE_ENABLING
    388      * @see #WIFI_AP_STATE_FAILED
    389      *
    390      * @hide
    391      */
    392     @SystemApi
    393     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
    394 
    395     /**
    396      * The look up key for an int that indicates why softAP started failed
    397      * currently support general and no_channel
    398      * @see #SAP_START_FAILURE_GENERIC
    399      * @see #SAP_START_FAILURE_NO_CHANNEL
    400      *
    401      * @hide
    402      */
    403     public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
    404     /**
    405      * The previous Wi-Fi state.
    406      *
    407      * @see #EXTRA_WIFI_AP_STATE
    408      *
    409      * @hide
    410      */
    411     @SystemApi
    412     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
    413     /**
    414      * The interface used for the softap.
    415      *
    416      * @hide
    417      */
    418     public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "wifi_ap_interface_name";
    419     /**
    420      * The intended ip mode for this softap.
    421      * @see #IFACE_IP_MODE_TETHERED
    422      * @see #IFACE_IP_MODE_LOCAL_ONLY
    423      *
    424      * @hide
    425      */
    426     public static final String EXTRA_WIFI_AP_MODE = "wifi_ap_mode";
    427 
    428     /**
    429      * Wi-Fi AP is currently being disabled. The state will change to
    430      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
    431      *
    432      * @see #WIFI_AP_STATE_CHANGED_ACTION
    433      * @see #getWifiApState()
    434      *
    435      * @hide
    436      */
    437     @SystemApi
    438     public static final int WIFI_AP_STATE_DISABLING = 10;
    439     /**
    440      * Wi-Fi AP is disabled.
    441      *
    442      * @see #WIFI_AP_STATE_CHANGED_ACTION
    443      * @see #getWifiState()
    444      *
    445      * @hide
    446      */
    447     @SystemApi
    448     public static final int WIFI_AP_STATE_DISABLED = 11;
    449     /**
    450      * Wi-Fi AP is currently being enabled. The state will change to
    451      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
    452      *
    453      * @see #WIFI_AP_STATE_CHANGED_ACTION
    454      * @see #getWifiApState()
    455      *
    456      * @hide
    457      */
    458     @SystemApi
    459     public static final int WIFI_AP_STATE_ENABLING = 12;
    460     /**
    461      * Wi-Fi AP is enabled.
    462      *
    463      * @see #WIFI_AP_STATE_CHANGED_ACTION
    464      * @see #getWifiApState()
    465      *
    466      * @hide
    467      */
    468     @SystemApi
    469     public static final int WIFI_AP_STATE_ENABLED = 13;
    470     /**
    471      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
    472      * enabling or disabling
    473      *
    474      * @see #WIFI_AP_STATE_CHANGED_ACTION
    475      * @see #getWifiApState()
    476      *
    477      * @hide
    478      */
    479     @SystemApi
    480     public static final int WIFI_AP_STATE_FAILED = 14;
    481 
    482     /**
    483      *  If WIFI AP start failed, this reason code means there is no legal channel exists on
    484      *  user selected band by regulatory
    485      *
    486      *  @hide
    487      */
    488     public static final int SAP_START_FAILURE_GENERAL= 0;
    489 
    490     /**
    491      *  All other reason for AP start failed besides SAP_START_FAILURE_GENERAL
    492      *
    493      *  @hide
    494      */
    495     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
    496 
    497     /**
    498      * Interface IP mode unspecified.
    499      *
    500      * @see updateInterfaceIpState(String, int)
    501      *
    502      * @hide
    503      */
    504     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
    505 
    506     /**
    507      * Interface IP mode for configuration error.
    508      *
    509      * @see updateInterfaceIpState(String, int)
    510      *
    511      * @hide
    512      */
    513     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
    514 
    515     /**
    516      * Interface IP mode for tethering.
    517      *
    518      * @see updateInterfaceIpState(String, int)
    519      *
    520      * @hide
    521      */
    522     public static final int IFACE_IP_MODE_TETHERED = 1;
    523 
    524     /**
    525      * Interface IP mode for Local Only Hotspot.
    526      *
    527      * @see updateInterfaceIpState(String, int)
    528      *
    529      * @hide
    530      */
    531     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
    532 
    533     /**
    534      * Broadcast intent action indicating that a connection to the supplicant has
    535      * been established (and it is now possible
    536      * to perform Wi-Fi operations) or the connection to the supplicant has been
    537      * lost. One extra provides the connection state as a boolean, where {@code true}
    538      * means CONNECTED.
    539      * @see #EXTRA_SUPPLICANT_CONNECTED
    540      */
    541     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    542     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
    543         "android.net.wifi.supplicant.CONNECTION_CHANGE";
    544     /**
    545      * The lookup key for a boolean that indicates whether a connection to
    546      * the supplicant daemon has been gained or lost. {@code true} means
    547      * a connection now exists.
    548      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
    549      */
    550     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
    551     /**
    552      * Broadcast intent action indicating that the state of Wi-Fi connectivity
    553      * has changed. One extra provides the new state
    554      * in the form of a {@link android.net.NetworkInfo} object. If the new
    555      * state is CONNECTED, additional extras may provide the BSSID and WifiInfo of
    556      * the access point.
    557      * as a {@code String}.
    558      * @see #EXTRA_NETWORK_INFO
    559      * @see #EXTRA_BSSID
    560      * @see #EXTRA_WIFI_INFO
    561      */
    562     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    563     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
    564     /**
    565      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
    566      * Wi-Fi network. Retrieve with
    567      * {@link android.content.Intent#getParcelableExtra(String)}.
    568      */
    569     public static final String EXTRA_NETWORK_INFO = "networkInfo";
    570     /**
    571      * The lookup key for a String giving the BSSID of the access point to which
    572      * we are connected. Only present when the new state is CONNECTED.
    573      * Retrieve with
    574      * {@link android.content.Intent#getStringExtra(String)}.
    575      */
    576     public static final String EXTRA_BSSID = "bssid";
    577     /**
    578      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
    579      * information about the access point to which we are connected. Only present
    580      * when the new state is CONNECTED.  Retrieve with
    581      * {@link android.content.Intent#getParcelableExtra(String)}.
    582      */
    583     public static final String EXTRA_WIFI_INFO = "wifiInfo";
    584     /**
    585      * Broadcast intent action indicating that the state of establishing a connection to
    586      * an access point has changed.One extra provides the new
    587      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
    588      * is not generally the most useful thing to look at if you are just interested in
    589      * the overall state of connectivity.
    590      * @see #EXTRA_NEW_STATE
    591      * @see #EXTRA_SUPPLICANT_ERROR
    592      */
    593     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    594     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
    595         "android.net.wifi.supplicant.STATE_CHANGE";
    596     /**
    597      * The lookup key for a {@link SupplicantState} describing the new state
    598      * Retrieve with
    599      * {@link android.content.Intent#getParcelableExtra(String)}.
    600      */
    601     public static final String EXTRA_NEW_STATE = "newState";
    602 
    603     /**
    604      * The lookup key for a {@link SupplicantState} describing the supplicant
    605      * error code if any
    606      * Retrieve with
    607      * {@link android.content.Intent#getIntExtra(String, int)}.
    608      * @see #ERROR_AUTHENTICATING
    609      */
    610     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
    611 
    612     /**
    613      * The lookup key for a {@link SupplicantState} describing the supplicant
    614      * error reason if any
    615      * Retrieve with
    616      * {@link android.content.Intent#getIntExtra(String, int)}.
    617      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
    618      * @hide
    619      */
    620     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
    621 
    622     /**
    623      * Broadcast intent action indicating that the configured networks changed.
    624      * This can be as a result of adding/updating/deleting a network. If
    625      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration
    626      * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple
    627      * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present.
    628      * @hide
    629      */
    630     @SystemApi
    631     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
    632         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
    633     /**
    634      * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing
    635      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
    636      * broadcast is sent.
    637      * @hide
    638      */
    639     @SystemApi
    640     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
    641     /**
    642      * Multiple network configurations have changed.
    643      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
    644      *
    645      * @hide
    646      */
    647     @SystemApi
    648     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
    649     /**
    650      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
    651      * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false}
    652      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
    653      * @hide
    654      */
    655     @SystemApi
    656     public static final String EXTRA_CHANGE_REASON = "changeReason";
    657     /**
    658      * The configuration is new and was added.
    659      * @hide
    660      */
    661     @SystemApi
    662     public static final int CHANGE_REASON_ADDED = 0;
    663     /**
    664      * The configuration was removed and is no longer present in the system's list of
    665      * configured networks.
    666      * @hide
    667      */
    668     @SystemApi
    669     public static final int CHANGE_REASON_REMOVED = 1;
    670     /**
    671      * The configuration has changed as a result of explicit action or because the system
    672      * took an automated action such as disabling a malfunctioning configuration.
    673      * @hide
    674      */
    675     @SystemApi
    676     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
    677     /**
    678      * An access point scan has completed, and results are available from the supplicant.
    679      * Call {@link #getScanResults()} to obtain the results. {@link #EXTRA_RESULTS_UPDATED}
    680      * indicates if the scan was completed successfully.
    681      */
    682     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    683     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
    684 
    685     /**
    686      * Lookup key for a {@code boolean} representing the result of previous {@link #startScan}
    687      * operation, reported with {@link #SCAN_RESULTS_AVAILABLE_ACTION}.
    688      * @return true scan was successful, results are updated
    689      * @return false scan was not successful, results haven't been updated since previous scan
    690      */
    691     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
    692 
    693     /**
    694      * A batch of access point scans has been completed and the results areavailable.
    695      * Call {@link #getBatchedScanResults()} to obtain the results.
    696      * @deprecated This API is nolonger supported.
    697      * Use {@link android.net.wifi.WifiScanner} API
    698      * @hide
    699      */
    700     @Deprecated
    701     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    702     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
    703             "android.net.wifi.BATCHED_RESULTS";
    704     /**
    705      * The RSSI (signal strength) has changed.
    706      * @see #EXTRA_NEW_RSSI
    707      */
    708     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    709     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
    710     /**
    711      * The lookup key for an {@code int} giving the new RSSI in dBm.
    712      */
    713     public static final String EXTRA_NEW_RSSI = "newRssi";
    714 
    715     /**
    716      * Broadcast intent action indicating that the link configuration
    717      * changed on wifi.
    718      * @hide
    719      */
    720     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
    721         "android.net.wifi.LINK_CONFIGURATION_CHANGED";
    722 
    723     /**
    724      * The lookup key for a {@link android.net.LinkProperties} object associated with the
    725      * Wi-Fi network. Retrieve with
    726      * {@link android.content.Intent#getParcelableExtra(String)}.
    727      * @hide
    728      */
    729     public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
    730 
    731     /**
    732      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
    733      * Wi-Fi network. Retrieve with
    734      * {@link android.content.Intent#getParcelableExtra(String)}.
    735      * @hide
    736      */
    737     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
    738 
    739     /**
    740      * The network IDs of the configured networks could have changed.
    741      */
    742     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    743     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
    744 
    745     /**
    746      * Activity Action: Show a system activity that allows the user to enable
    747      * scans to be available even with Wi-Fi turned off.
    748      *
    749      * <p>Notification of the result of this activity is posted using the
    750      * {@link android.app.Activity#onActivityResult} callback. The
    751      * <code>resultCode</code>
    752      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
    753      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
    754      * has rejected the request or an error has occurred.
    755      */
    756     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    757     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
    758             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
    759 
    760     /**
    761      * Activity Action: Pick a Wi-Fi network to connect to.
    762      * <p>Input: Nothing.
    763      * <p>Output: Nothing.
    764      */
    765     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    766     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
    767 
    768     /**
    769      * Activity Action: Show UI to get user approval to enable WiFi.
    770      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
    771      *           the name of the app requesting the action.
    772      * <p>Output: Nothing.
    773      *
    774      * @hide
    775      */
    776     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    777     public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
    778 
    779     /**
    780      * Activity Action: Show UI to get user approval to disable WiFi.
    781      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
    782      *           the name of the app requesting the action.
    783      * <p>Output: Nothing.
    784      *
    785      * @hide
    786      */
    787     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    788     public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
    789 
    790     /**
    791      * Internally used Wi-Fi lock mode representing the case were no locks are held.
    792      * @hide
    793      */
    794     public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
    795 
    796     /**
    797      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
    798      * and will behave normally, i.e., it will attempt to automatically
    799      * establish a connection to a remembered access point that is
    800      * within range, and will do periodic scans if there are remembered
    801      * access points but none are in range.
    802      */
    803     public static final int WIFI_MODE_FULL = 1;
    804     /**
    805      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
    806      * but the only operation that will be supported is initiation of
    807      * scans, and the subsequent reporting of scan results. No attempts
    808      * will be made to automatically connect to remembered access points,
    809      * nor will periodic scans be automatically performed looking for
    810      * remembered access points. Scans must be explicitly requested by
    811      * an application in this mode.
    812      */
    813     public static final int WIFI_MODE_SCAN_ONLY = 2;
    814     /**
    815      * In this Wi-Fi lock mode, Wi-Fi will be kept active as in mode
    816      * {@link #WIFI_MODE_FULL} but it operates at high performance
    817      * with minimum packet loss and low packet latency even when
    818      * the device screen is off. This mode will consume more power
    819      * and hence should be used only when there is a need for such
    820      * an active connection.
    821      * <p>
    822      * An example use case is when a voice connection needs to be
    823      * kept active even after the device screen goes off. Holding the
    824      * regular {@link #WIFI_MODE_FULL} lock will keep the wifi
    825      * connection active, but the connection can be lossy.
    826      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
    827      * duration of the voice call will improve the call quality.
    828      * <p>
    829      * When there is no support from the hardware, this lock mode
    830      * will have the same behavior as {@link #WIFI_MODE_FULL}
    831      */
    832     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
    833 
    834     /** Anything worse than or equal to this will show 0 bars. */
    835     private static final int MIN_RSSI = -100;
    836 
    837     /** Anything better than or equal to this will show the max bars. */
    838     private static final int MAX_RSSI = -55;
    839 
    840     /**
    841      * Number of RSSI levels used in the framework to initiate
    842      * {@link #RSSI_CHANGED_ACTION} broadcast
    843      * @hide
    844      */
    845     public static final int RSSI_LEVELS = 5;
    846 
    847     /**
    848      * Auto settings in the driver. The driver could choose to operate on both
    849      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
    850      * @hide
    851      */
    852     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
    853 
    854     /**
    855      * Operation on 5 GHz alone
    856      * @hide
    857      */
    858     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
    859 
    860     /**
    861      * Operation on 2.4 GHz alone
    862      * @hide
    863      */
    864     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
    865 
    866     /** List of asyncronous notifications
    867      * @hide
    868      */
    869     public static final int DATA_ACTIVITY_NOTIFICATION = 1;
    870 
    871     //Lowest bit indicates data reception and the second lowest
    872     //bit indicates data transmitted
    873     /** @hide */
    874     public static final int DATA_ACTIVITY_NONE         = 0x00;
    875     /** @hide */
    876     public static final int DATA_ACTIVITY_IN           = 0x01;
    877     /** @hide */
    878     public static final int DATA_ACTIVITY_OUT          = 0x02;
    879     /** @hide */
    880     public static final int DATA_ACTIVITY_INOUT        = 0x03;
    881 
    882     /** @hide */
    883     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
    884 
    885     /* Maximum number of active locks we allow.
    886      * This limit was added to prevent apps from creating a ridiculous number
    887      * of locks and crashing the system by overflowing the global ref table.
    888      */
    889     private static final int MAX_ACTIVE_LOCKS = 50;
    890 
    891     /* Number of currently active WifiLocks and MulticastLocks */
    892     private int mActiveLockCount;
    893 
    894     private Context mContext;
    895     IWifiManager mService;
    896     private final int mTargetSdkVersion;
    897 
    898     private static final int INVALID_KEY = 0;
    899     private int mListenerKey = 1;
    900     private final SparseArray mListenerMap = new SparseArray();
    901     private final Object mListenerMapLock = new Object();
    902 
    903     private AsyncChannel mAsyncChannel;
    904     private CountDownLatch mConnected;
    905     private Looper mLooper;
    906 
    907     /* LocalOnlyHotspot callback message types */
    908     /** @hide */
    909     public static final int HOTSPOT_STARTED = 0;
    910     /** @hide */
    911     public static final int HOTSPOT_STOPPED = 1;
    912     /** @hide */
    913     public static final int HOTSPOT_FAILED = 2;
    914     /** @hide */
    915     public static final int HOTSPOT_OBSERVER_REGISTERED = 3;
    916 
    917     private final Object mLock = new Object(); // lock guarding access to the following vars
    918     @GuardedBy("mLock")
    919     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
    920     @GuardedBy("mLock")
    921     private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
    922 
    923     /**
    924      * Create a new WifiManager instance.
    925      * Applications will almost always want to use
    926      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
    927      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
    928      * @param context the application context
    929      * @param service the Binder interface
    930      * @hide - hide this because it takes in a parameter of type IWifiManager, which
    931      * is a system private class.
    932      */
    933     public WifiManager(Context context, IWifiManager service, Looper looper) {
    934         mContext = context;
    935         mService = service;
    936         mLooper = looper;
    937         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    938     }
    939 
    940     /**
    941      * Return a list of all the networks configured for the current foreground
    942      * user.
    943      * Not all fields of WifiConfiguration are returned. Only the following
    944      * fields are filled in:
    945      * <ul>
    946      * <li>networkId</li>
    947      * <li>SSID</li>
    948      * <li>BSSID</li>
    949      * <li>priority</li>
    950      * <li>allowedProtocols</li>
    951      * <li>allowedKeyManagement</li>
    952      * <li>allowedAuthAlgorithms</li>
    953      * <li>allowedPairwiseCiphers</li>
    954      * <li>allowedGroupCiphers</li>
    955      * </ul>
    956      * @return a list of network configurations in the form of a list
    957      * of {@link WifiConfiguration} objects. Upon failure to fetch or
    958      * when Wi-Fi is turned off, it can be null.
    959      */
    960     public List<WifiConfiguration> getConfiguredNetworks() {
    961         try {
    962             ParceledListSlice<WifiConfiguration> parceledList =
    963                 mService.getConfiguredNetworks();
    964             if (parceledList == null) {
    965                 return Collections.emptyList();
    966             }
    967             return parceledList.getList();
    968         } catch (RemoteException e) {
    969             throw e.rethrowFromSystemServer();
    970         }
    971     }
    972 
    973     /** @hide */
    974     @SystemApi
    975     @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL)
    976     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
    977         try {
    978             ParceledListSlice<WifiConfiguration> parceledList =
    979                 mService.getPrivilegedConfiguredNetworks();
    980             if (parceledList == null) {
    981                 return Collections.emptyList();
    982             }
    983             return parceledList.getList();
    984         } catch (RemoteException e) {
    985             throw e.rethrowFromSystemServer();
    986         }
    987     }
    988 
    989     /** @hide */
    990     @SystemApi
    991     @RequiresPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL)
    992     public WifiConnectionStatistics getConnectionStatistics() {
    993         try {
    994             return mService.getConnectionStatistics();
    995         } catch (RemoteException e) {
    996             throw e.rethrowFromSystemServer();
    997         }
    998     }
    999 
   1000     /**
   1001      * Returns a WifiConfiguration matching this ScanResult
   1002      *
   1003      * An {@link UnsupportedOperationException} will be thrown if Passpoint is not enabled
   1004      * on the device.
   1005      *
   1006      * @param scanResult scanResult that represents the BSSID
   1007      * @return {@link WifiConfiguration} that matches this BSSID or null
   1008      * @hide
   1009      */
   1010     public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
   1011         try {
   1012             return mService.getMatchingWifiConfig(scanResult);
   1013         } catch (RemoteException e) {
   1014             throw e.rethrowFromSystemServer();
   1015         }
   1016     }
   1017 
   1018     /**
   1019      * Add a new network description to the set of configured networks.
   1020      * The {@code networkId} field of the supplied configuration object
   1021      * is ignored.
   1022      * <p/>
   1023      * The new network will be marked DISABLED by default. To enable it,
   1024      * called {@link #enableNetwork}.
   1025      *
   1026      * @param config the set of variables that describe the configuration,
   1027      *            contained in a {@link WifiConfiguration} object.
   1028      *            If the {@link WifiConfiguration} has an Http Proxy set
   1029      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
   1030      * @return the ID of the newly created network description. This is used in
   1031      *         other operations to specified the network to be acted upon.
   1032      *         Returns {@code -1} on failure.
   1033      */
   1034     public int addNetwork(WifiConfiguration config) {
   1035         if (config == null) {
   1036             return -1;
   1037         }
   1038         config.networkId = -1;
   1039         return addOrUpdateNetwork(config);
   1040     }
   1041 
   1042     /**
   1043      * Update the network description of an existing configured network.
   1044      *
   1045      * @param config the set of variables that describe the configuration,
   1046      *            contained in a {@link WifiConfiguration} object. It may
   1047      *            be sparse, so that only the items that are being changed
   1048      *            are non-<code>null</code>. The {@code networkId} field
   1049      *            must be set to the ID of the existing network being updated.
   1050      *            If the {@link WifiConfiguration} has an Http Proxy set
   1051      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
   1052      * @return Returns the {@code networkId} of the supplied
   1053      *         {@code WifiConfiguration} on success.
   1054      *         <br/>
   1055      *         Returns {@code -1} on failure, including when the {@code networkId}
   1056      *         field of the {@code WifiConfiguration} does not refer to an
   1057      *         existing network.
   1058      */
   1059     public int updateNetwork(WifiConfiguration config) {
   1060         if (config == null || config.networkId < 0) {
   1061             return -1;
   1062         }
   1063         return addOrUpdateNetwork(config);
   1064     }
   1065 
   1066     /**
   1067      * Internal method for doing the RPC that creates a new network description
   1068      * or updates an existing one.
   1069      *
   1070      * @param config The possibly sparse object containing the variables that
   1071      *         are to set or updated in the network description.
   1072      * @return the ID of the network on success, {@code -1} on failure.
   1073      */
   1074     private int addOrUpdateNetwork(WifiConfiguration config) {
   1075         try {
   1076             return mService.addOrUpdateNetwork(config);
   1077         } catch (RemoteException e) {
   1078             throw e.rethrowFromSystemServer();
   1079         }
   1080     }
   1081 
   1082     /**
   1083      * Add or update a Passpoint configuration.  The configuration provides a credential
   1084      * for connecting to Passpoint networks that are operated by the Passpoint
   1085      * service provider specified in the configuration.
   1086      *
   1087      * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
   1088      * Name).  In the case when there is an existing configuration with the same
   1089      * FQDN, the new configuration will replace the existing configuration.
   1090      *
   1091      * @param config The Passpoint configuration to be added
   1092      * @throws IllegalArgumentException if configuration is invalid
   1093      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
   1094      */
   1095     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
   1096         try {
   1097             if (!mService.addOrUpdatePasspointConfiguration(config)) {
   1098                 throw new IllegalArgumentException();
   1099             }
   1100         } catch (RemoteException e) {
   1101             throw e.rethrowFromSystemServer();
   1102         }
   1103     }
   1104 
   1105     /**
   1106      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
   1107      *
   1108      * @param fqdn The FQDN of the Passpoint configuration to be removed
   1109      * @throws IllegalArgumentException if no configuration is associated with the given FQDN.
   1110      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
   1111      */
   1112     public void removePasspointConfiguration(String fqdn) {
   1113         try {
   1114             if (!mService.removePasspointConfiguration(fqdn)) {
   1115                 throw new IllegalArgumentException();
   1116             }
   1117         } catch (RemoteException e) {
   1118             throw e.rethrowFromSystemServer();
   1119         }
   1120     }
   1121 
   1122     /**
   1123      * Return the list of installed Passpoint configurations.
   1124      *
   1125      * An empty list will be returned when no configurations are installed.
   1126      *
   1127      * @return A list of {@link PasspointConfiguration}
   1128      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
   1129      */
   1130     public List<PasspointConfiguration> getPasspointConfigurations() {
   1131         try {
   1132             return mService.getPasspointConfigurations();
   1133         } catch (RemoteException e) {
   1134             throw e.rethrowFromSystemServer();
   1135         }
   1136     }
   1137 
   1138     /**
   1139      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
   1140      * will be broadcasted once the request is completed.  The presence of the intent extra
   1141      * {@link #EXTRA_ICON} will indicate the result of the request.
   1142      * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
   1143      *
   1144      * @param bssid The BSSID of the AP
   1145      * @param fileName Name of the icon file (remote file) to query from the AP
   1146      *
   1147      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
   1148      * @hide
   1149      */
   1150     public void queryPasspointIcon(long bssid, String fileName) {
   1151         try {
   1152             mService.queryPasspointIcon(bssid, fileName);
   1153         } catch (RemoteException e) {
   1154             throw e.rethrowFromSystemServer();
   1155         }
   1156     }
   1157 
   1158     /**
   1159      * Match the currently associated network against the SP matching the given FQDN
   1160      * @param fqdn FQDN of the SP
   1161      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
   1162      * @hide
   1163      */
   1164     public int matchProviderWithCurrentNetwork(String fqdn) {
   1165         try {
   1166             return mService.matchProviderWithCurrentNetwork(fqdn);
   1167         } catch (RemoteException e) {
   1168             throw e.rethrowFromSystemServer();
   1169         }
   1170     }
   1171 
   1172     /**
   1173      * Deauthenticate and set the re-authentication hold off time for the current network
   1174      * @param holdoff hold off time in milliseconds
   1175      * @param ess set if the hold off pertains to an ESS rather than a BSS
   1176      * @hide
   1177      */
   1178     public void deauthenticateNetwork(long holdoff, boolean ess) {
   1179         try {
   1180             mService.deauthenticateNetwork(holdoff, ess);
   1181         } catch (RemoteException e) {
   1182             throw e.rethrowFromSystemServer();
   1183         }
   1184     }
   1185 
   1186     /**
   1187      * Remove the specified network from the list of configured networks.
   1188      * This may result in the asynchronous delivery of state change
   1189      * events.
   1190      *
   1191      * Applications are not allowed to remove networks created by other
   1192      * applications.
   1193      *
   1194      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
   1195      *        #getConfiguredNetworks}.
   1196      * @return {@code true} if the operation succeeded
   1197      */
   1198     public boolean removeNetwork(int netId) {
   1199         try {
   1200             return mService.removeNetwork(netId);
   1201         } catch (RemoteException e) {
   1202             throw e.rethrowFromSystemServer();
   1203         }
   1204     }
   1205 
   1206     /**
   1207      * Allow a previously configured network to be associated with. If
   1208      * <code>attemptConnect</code> is true, an attempt to connect to the selected
   1209      * network is initiated. This may result in the asynchronous delivery
   1210      * of state change events.
   1211      * <p>
   1212      * <b>Note:</b> If an application's target SDK version is
   1213      * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
   1214      * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
   1215      * instead be sent through another network, such as cellular data,
   1216      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
   1217      * Wi-Fi network that does not provide Internet access (e.g. a wireless
   1218      * printer), if another network that does offer Internet access (e.g.
   1219      * cellular data) is available. Applications that need to ensure that their
   1220      * network traffic uses Wi-Fi should use APIs such as
   1221      * {@link Network#bindSocket(java.net.Socket)},
   1222      * {@link Network#openConnection(java.net.URL)}, or
   1223      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
   1224      *
   1225      * Applications are not allowed to enable networks created by other
   1226      * applications.
   1227      *
   1228      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
   1229      *        #getConfiguredNetworks}.
   1230      * @param attemptConnect The way to select a particular network to connect to is specify
   1231      *        {@code true} for this parameter.
   1232      * @return {@code true} if the operation succeeded
   1233      */
   1234     public boolean enableNetwork(int netId, boolean attemptConnect) {
   1235         final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
   1236         if (pin) {
   1237             NetworkRequest request = new NetworkRequest.Builder()
   1238                     .clearCapabilities()
   1239                     .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
   1240                     .build();
   1241             NetworkPinner.pin(mContext, request);
   1242         }
   1243 
   1244         boolean success;
   1245         try {
   1246             success = mService.enableNetwork(netId, attemptConnect);
   1247         } catch (RemoteException e) {
   1248             throw e.rethrowFromSystemServer();
   1249         }
   1250 
   1251         if (pin && !success) {
   1252             NetworkPinner.unpin();
   1253         }
   1254 
   1255         return success;
   1256     }
   1257 
   1258     /**
   1259      * Disable a configured network. The specified network will not be
   1260      * a candidate for associating. This may result in the asynchronous
   1261      * delivery of state change events.
   1262      *
   1263      * Applications are not allowed to disable networks created by other
   1264      * applications.
   1265      *
   1266      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
   1267      *        #getConfiguredNetworks}.
   1268      * @return {@code true} if the operation succeeded
   1269      */
   1270     public boolean disableNetwork(int netId) {
   1271         try {
   1272             return mService.disableNetwork(netId);
   1273         } catch (RemoteException e) {
   1274             throw e.rethrowFromSystemServer();
   1275         }
   1276     }
   1277 
   1278     /**
   1279      * Disassociate from the currently active access point. This may result
   1280      * in the asynchronous delivery of state change events.
   1281      * @return {@code true} if the operation succeeded
   1282      */
   1283     public boolean disconnect() {
   1284         try {
   1285             mService.disconnect();
   1286             return true;
   1287         } catch (RemoteException e) {
   1288             throw e.rethrowFromSystemServer();
   1289         }
   1290     }
   1291 
   1292     /**
   1293      * Reconnect to the currently active access point, if we are currently
   1294      * disconnected. This may result in the asynchronous delivery of state
   1295      * change events.
   1296      * @return {@code true} if the operation succeeded
   1297      */
   1298     public boolean reconnect() {
   1299         try {
   1300             mService.reconnect();
   1301             return true;
   1302         } catch (RemoteException e) {
   1303             throw e.rethrowFromSystemServer();
   1304         }
   1305     }
   1306 
   1307     /**
   1308      * Reconnect to the currently active access point, even if we are already
   1309      * connected. This may result in the asynchronous delivery of state
   1310      * change events.
   1311      * @return {@code true} if the operation succeeded
   1312      */
   1313     public boolean reassociate() {
   1314         try {
   1315             mService.reassociate();
   1316             return true;
   1317         } catch (RemoteException e) {
   1318             throw e.rethrowFromSystemServer();
   1319         }
   1320     }
   1321 
   1322     /**
   1323      * Check that the supplicant daemon is responding to requests.
   1324      * @return {@code true} if we were able to communicate with the supplicant and
   1325      * it returned the expected response to the PING message.
   1326      * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
   1327      */
   1328     @Deprecated
   1329     public boolean pingSupplicant() {
   1330         return isWifiEnabled();
   1331     }
   1332 
   1333     /** @hide */
   1334     public static final int WIFI_FEATURE_INFRA            = 0x0001;  // Basic infrastructure mode
   1335     /** @hide */
   1336     public static final int WIFI_FEATURE_INFRA_5G         = 0x0002;  // Support for 5 GHz Band
   1337     /** @hide */
   1338     public static final int WIFI_FEATURE_PASSPOINT        = 0x0004;  // Support for GAS/ANQP
   1339     /** @hide */
   1340     public static final int WIFI_FEATURE_P2P              = 0x0008;  // Wifi-Direct
   1341     /** @hide */
   1342     public static final int WIFI_FEATURE_MOBILE_HOTSPOT   = 0x0010;  // Soft AP
   1343     /** @hide */
   1344     public static final int WIFI_FEATURE_SCANNER          = 0x0020;  // WifiScanner APIs
   1345     /** @hide */
   1346     public static final int WIFI_FEATURE_AWARE            = 0x0040;  // Wi-Fi AWare networking
   1347     /** @hide */
   1348     public static final int WIFI_FEATURE_D2D_RTT          = 0x0080;  // Device-to-device RTT
   1349     /** @hide */
   1350     public static final int WIFI_FEATURE_D2AP_RTT         = 0x0100;  // Device-to-AP RTT
   1351     /** @hide */
   1352     public static final int WIFI_FEATURE_BATCH_SCAN       = 0x0200;  // Batched Scan (deprecated)
   1353     /** @hide */
   1354     public static final int WIFI_FEATURE_PNO              = 0x0400;  // Preferred network offload
   1355     /** @hide */
   1356     public static final int WIFI_FEATURE_ADDITIONAL_STA   = 0x0800;  // Support for two STAs
   1357     /** @hide */
   1358     public static final int WIFI_FEATURE_TDLS             = 0x1000;  // Tunnel directed link setup
   1359     /** @hide */
   1360     public static final int WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000;  // Support for TDLS off channel
   1361     /** @hide */
   1362     public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
   1363     /** @hide */
   1364     public static final int WIFI_FEATURE_AP_STA           = 0x8000;  // AP STA Concurrency
   1365     /** @hide */
   1366     public static final int WIFI_FEATURE_LINK_LAYER_STATS = 0x10000; // Link layer stats collection
   1367     /** @hide */
   1368     public static final int WIFI_FEATURE_LOGGER           = 0x20000; // WiFi Logger
   1369     /** @hide */
   1370     public static final int WIFI_FEATURE_HAL_EPNO         = 0x40000; // Enhanced PNO
   1371     /** @hide */
   1372     public static final int WIFI_FEATURE_RSSI_MONITOR     = 0x80000; // RSSI Monitor
   1373     /** @hide */
   1374     public static final int WIFI_FEATURE_MKEEP_ALIVE      = 0x100000; // mkeep_alive
   1375     /** @hide */
   1376     public static final int WIFI_FEATURE_CONFIG_NDO       = 0x200000; // ND offload
   1377     /** @hide */
   1378     public static final int WIFI_FEATURE_TRANSMIT_POWER   = 0x400000; // Capture transmit power
   1379     /** @hide */
   1380     public static final int WIFI_FEATURE_CONTROL_ROAMING  = 0x800000; // Control firmware roaming
   1381     /** @hide */
   1382     public static final int WIFI_FEATURE_IE_WHITELIST     = 0x1000000; // Probe IE white listing
   1383     /** @hide */
   1384     public static final int WIFI_FEATURE_SCAN_RAND        = 0x2000000; // Random MAC & Probe seq
   1385 
   1386 
   1387     private int getSupportedFeatures() {
   1388         try {
   1389             return mService.getSupportedFeatures();
   1390         } catch (RemoteException e) {
   1391             throw e.rethrowFromSystemServer();
   1392         }
   1393     }
   1394 
   1395     private boolean isFeatureSupported(int feature) {
   1396         return (getSupportedFeatures() & feature) == feature;
   1397     }
   1398     /**
   1399      * @return true if this adapter supports 5 GHz band
   1400      */
   1401     public boolean is5GHzBandSupported() {
   1402         return isFeatureSupported(WIFI_FEATURE_INFRA_5G);
   1403     }
   1404 
   1405     /**
   1406      * @return true if this adapter supports Passpoint
   1407      * @hide
   1408      */
   1409     public boolean isPasspointSupported() {
   1410         return isFeatureSupported(WIFI_FEATURE_PASSPOINT);
   1411     }
   1412 
   1413     /**
   1414      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
   1415      */
   1416     public boolean isP2pSupported() {
   1417         return isFeatureSupported(WIFI_FEATURE_P2P);
   1418     }
   1419 
   1420     /**
   1421      * @return true if this adapter supports portable Wi-Fi hotspot
   1422      * @hide
   1423      */
   1424     @SystemApi
   1425     public boolean isPortableHotspotSupported() {
   1426         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
   1427     }
   1428 
   1429     /**
   1430      * @return true if this adapter supports WifiScanner APIs
   1431      * @hide
   1432      */
   1433     @SystemApi
   1434     public boolean isWifiScannerSupported() {
   1435         return isFeatureSupported(WIFI_FEATURE_SCANNER);
   1436     }
   1437 
   1438     /**
   1439      * @return true if this adapter supports Neighbour Awareness Network APIs
   1440      * @hide
   1441      */
   1442     public boolean isWifiAwareSupported() {
   1443         return isFeatureSupported(WIFI_FEATURE_AWARE);
   1444     }
   1445 
   1446     /**
   1447      * @return true if this adapter supports Device-to-device RTT
   1448      * @hide
   1449      */
   1450     @SystemApi
   1451     public boolean isDeviceToDeviceRttSupported() {
   1452         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
   1453     }
   1454 
   1455     /**
   1456      * @return true if this adapter supports Device-to-AP RTT
   1457      */
   1458     @SystemApi
   1459     public boolean isDeviceToApRttSupported() {
   1460         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
   1461     }
   1462 
   1463     /**
   1464      * @return true if this adapter supports offloaded connectivity scan
   1465      */
   1466     public boolean isPreferredNetworkOffloadSupported() {
   1467         return isFeatureSupported(WIFI_FEATURE_PNO);
   1468     }
   1469 
   1470     /**
   1471      * @return true if this adapter supports multiple simultaneous connections
   1472      * @hide
   1473      */
   1474     public boolean isAdditionalStaSupported() {
   1475         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
   1476     }
   1477 
   1478     /**
   1479      * @return true if this adapter supports Tunnel Directed Link Setup
   1480      */
   1481     public boolean isTdlsSupported() {
   1482         return isFeatureSupported(WIFI_FEATURE_TDLS);
   1483     }
   1484 
   1485     /**
   1486      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
   1487      * @hide
   1488      */
   1489     public boolean isOffChannelTdlsSupported() {
   1490         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
   1491     }
   1492 
   1493     /**
   1494      * @return true if this adapter supports advanced power/performance counters
   1495      */
   1496     public boolean isEnhancedPowerReportingSupported() {
   1497         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
   1498     }
   1499 
   1500     /**
   1501      * Return the record of {@link WifiActivityEnergyInfo} object that
   1502      * has the activity and energy info. This can be used to ascertain what
   1503      * the controller has been up to, since the last sample.
   1504      * @param updateType Type of info, cached vs refreshed.
   1505      *
   1506      * @return a record with {@link WifiActivityEnergyInfo} or null if
   1507      * report is unavailable or unsupported
   1508      * @hide
   1509      */
   1510     public WifiActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
   1511         if (mService == null) return null;
   1512         try {
   1513             synchronized(this) {
   1514                 return mService.reportActivityInfo();
   1515             }
   1516         } catch (RemoteException e) {
   1517             throw e.rethrowFromSystemServer();
   1518         }
   1519     }
   1520 
   1521     /**
   1522      * Request a scan for access points. Returns immediately. The availability
   1523      * of the results is made known later by means of an asynchronous event sent
   1524      * on completion of the scan.
   1525      * @return {@code true} if the operation succeeded, i.e., the scan was initiated
   1526      */
   1527     public boolean startScan() {
   1528         return startScan(null);
   1529     }
   1530 
   1531     /** @hide */
   1532     @SystemApi
   1533     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
   1534     public boolean startScan(WorkSource workSource) {
   1535         try {
   1536             String packageName = mContext.getOpPackageName();
   1537             mService.startScan(null, workSource, packageName);
   1538             return true;
   1539         } catch (RemoteException e) {
   1540             throw e.rethrowFromSystemServer();
   1541         }
   1542     }
   1543 
   1544     /**
   1545      * startLocationRestrictedScan()
   1546      * Trigger a scan which will not make use of DFS channels and is thus not suitable for
   1547      * establishing wifi connection.
   1548      * @deprecated This API is nolonger supported.
   1549      * Use {@link android.net.wifi.WifiScanner} API
   1550      * @hide
   1551      */
   1552     @Deprecated
   1553     @SystemApi
   1554     @SuppressLint("Doclava125")
   1555     public boolean startLocationRestrictedScan(WorkSource workSource) {
   1556         return false;
   1557     }
   1558 
   1559     /**
   1560      * Check if the Batched Scan feature is supported.
   1561      *
   1562      * @return false if not supported.
   1563      * @deprecated This API is nolonger supported.
   1564      * Use {@link android.net.wifi.WifiScanner} API
   1565      * @hide
   1566      */
   1567     @Deprecated
   1568     @SystemApi
   1569     @SuppressLint("Doclava125")
   1570     public boolean isBatchedScanSupported() {
   1571         return false;
   1572     }
   1573 
   1574     /**
   1575      * Retrieve the latest batched scan result.  This should be called immediately after
   1576      * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received.
   1577      * @deprecated This API is nolonger supported.
   1578      * Use {@link android.net.wifi.WifiScanner} API
   1579      * @hide
   1580      */
   1581     @Deprecated
   1582     @SystemApi
   1583     @SuppressLint("Doclava125")
   1584     public List<BatchedScanResult> getBatchedScanResults() {
   1585         return null;
   1586     }
   1587 
   1588     /**
   1589      * Creates a configuration token describing the current network of MIME type
   1590      * application/vnd.wfa.wsc. Can be used to configure WiFi networks via NFC.
   1591      *
   1592      * @return hex-string encoded configuration token or null if there is no current network
   1593      * @hide
   1594      */
   1595     public String getCurrentNetworkWpsNfcConfigurationToken() {
   1596         try {
   1597             return mService.getCurrentNetworkWpsNfcConfigurationToken();
   1598         } catch (RemoteException e) {
   1599             throw e.rethrowFromSystemServer();
   1600         }
   1601     }
   1602 
   1603     /**
   1604      * Return dynamic information about the current Wi-Fi connection, if any is active.
   1605      * @return the Wi-Fi information, contained in {@link WifiInfo}.
   1606      */
   1607     public WifiInfo getConnectionInfo() {
   1608         try {
   1609             return mService.getConnectionInfo();
   1610         } catch (RemoteException e) {
   1611             throw e.rethrowFromSystemServer();
   1612         }
   1613     }
   1614 
   1615     /**
   1616      * Return the results of the latest access point scan.
   1617      * @return the list of access points found in the most recent scan. An app must hold
   1618      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
   1619      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
   1620      * in order to get valid results.  If there is a remote exception (e.g., either a communication
   1621      * problem with the system service or an exception within the framework) an empty list will be
   1622      * returned.
   1623      */
   1624     public List<ScanResult> getScanResults() {
   1625         try {
   1626             return mService.getScanResults(mContext.getOpPackageName());
   1627         } catch (RemoteException e) {
   1628             throw e.rethrowFromSystemServer();
   1629         }
   1630     }
   1631 
   1632     /**
   1633      * Check if scanning is always available.
   1634      *
   1635      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
   1636      * even when Wi-Fi is turned off.
   1637      *
   1638      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
   1639      */
   1640     public boolean isScanAlwaysAvailable() {
   1641         try {
   1642             return mService.isScanAlwaysAvailable();
   1643         } catch (RemoteException e) {
   1644             throw e.rethrowFromSystemServer();
   1645         }
   1646     }
   1647 
   1648     /**
   1649      * Tell the device to persist the current list of configured networks.
   1650      * <p>
   1651      * Note: It is possible for this method to change the network IDs of
   1652      * existing networks. You should assume the network IDs can be different
   1653      * after calling this method.
   1654      *
   1655      * @return {@code true} if the operation succeeded
   1656      * @deprecated There is no need to call this method -
   1657      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
   1658      * and {@link #removeNetwork(int)} already persist the configurations automatically.
   1659      */
   1660     @Deprecated
   1661     public boolean saveConfiguration() {
   1662         try {
   1663             return mService.saveConfiguration();
   1664         } catch (RemoteException e) {
   1665             throw e.rethrowFromSystemServer();
   1666         }
   1667     }
   1668 
   1669     /**
   1670      * Set the country code.
   1671      * @param countryCode country code in ISO 3166 format.
   1672      * @param persist {@code true} if this needs to be remembered
   1673      *
   1674      * @hide
   1675      */
   1676     public void setCountryCode(String country, boolean persist) {
   1677         try {
   1678             mService.setCountryCode(country, persist);
   1679         } catch (RemoteException e) {
   1680             throw e.rethrowFromSystemServer();
   1681         }
   1682     }
   1683 
   1684     /**
   1685     * get the country code.
   1686     * @return the country code in ISO 3166 format.
   1687     *
   1688     * @hide
   1689     */
   1690     public String getCountryCode() {
   1691        try {
   1692            String country = mService.getCountryCode();
   1693            return country;
   1694        } catch (RemoteException e) {
   1695            throw e.rethrowFromSystemServer();
   1696        }
   1697     }
   1698 
   1699     /**
   1700      * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
   1701      * @return {@code true} if supported, {@code false} otherwise.
   1702      * @hide
   1703      */
   1704     public boolean isDualBandSupported() {
   1705         try {
   1706             return mService.isDualBandSupported();
   1707         } catch (RemoteException e) {
   1708             throw e.rethrowFromSystemServer();
   1709         }
   1710     }
   1711 
   1712     /**
   1713      * Return the DHCP-assigned addresses from the last successful DHCP request,
   1714      * if any.
   1715      * @return the DHCP information
   1716      */
   1717     public DhcpInfo getDhcpInfo() {
   1718         try {
   1719             return mService.getDhcpInfo();
   1720         } catch (RemoteException e) {
   1721             throw e.rethrowFromSystemServer();
   1722         }
   1723     }
   1724 
   1725     /**
   1726      * Enable or disable Wi-Fi.
   1727      * @param enabled {@code true} to enable, {@code false} to disable.
   1728      * @return {@code true} if the operation succeeds (or if the existing state
   1729      *         is the same as the requested state).
   1730      */
   1731     public boolean setWifiEnabled(boolean enabled) {
   1732         try {
   1733             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
   1734         } catch (RemoteException e) {
   1735             throw e.rethrowFromSystemServer();
   1736         }
   1737     }
   1738 
   1739     /**
   1740      * Gets the Wi-Fi enabled state.
   1741      * @return One of {@link #WIFI_STATE_DISABLED},
   1742      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
   1743      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
   1744      * @see #isWifiEnabled()
   1745      */
   1746     public int getWifiState() {
   1747         try {
   1748             return mService.getWifiEnabledState();
   1749         } catch (RemoteException e) {
   1750             throw e.rethrowFromSystemServer();
   1751         }
   1752     }
   1753 
   1754     /**
   1755      * Return whether Wi-Fi is enabled or disabled.
   1756      * @return {@code true} if Wi-Fi is enabled
   1757      * @see #getWifiState()
   1758      */
   1759     public boolean isWifiEnabled() {
   1760         return getWifiState() == WIFI_STATE_ENABLED;
   1761     }
   1762 
   1763     /**
   1764      * Return TX packet counter, for CTS test of WiFi watchdog.
   1765      * @param listener is the interface to receive result
   1766      *
   1767      * @hide for CTS test only
   1768      */
   1769     public void getTxPacketCount(TxPacketCountListener listener) {
   1770         getChannel().sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
   1771     }
   1772 
   1773     /**
   1774      * Calculates the level of the signal. This should be used any time a signal
   1775      * is being shown.
   1776      *
   1777      * @param rssi The power of the signal measured in RSSI.
   1778      * @param numLevels The number of levels to consider in the calculated
   1779      *            level.
   1780      * @return A level of the signal, given in the range of 0 to numLevels-1
   1781      *         (both inclusive).
   1782      */
   1783     public static int calculateSignalLevel(int rssi, int numLevels) {
   1784         if (rssi <= MIN_RSSI) {
   1785             return 0;
   1786         } else if (rssi >= MAX_RSSI) {
   1787             return numLevels - 1;
   1788         } else {
   1789             float inputRange = (MAX_RSSI - MIN_RSSI);
   1790             float outputRange = (numLevels - 1);
   1791             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
   1792         }
   1793     }
   1794 
   1795     /**
   1796      * Compares two signal strengths.
   1797      *
   1798      * @param rssiA The power of the first signal measured in RSSI.
   1799      * @param rssiB The power of the second signal measured in RSSI.
   1800      * @return Returns <0 if the first signal is weaker than the second signal,
   1801      *         0 if the two signals have the same strength, and >0 if the first
   1802      *         signal is stronger than the second signal.
   1803      */
   1804     public static int compareSignalLevel(int rssiA, int rssiB) {
   1805         return rssiA - rssiB;
   1806     }
   1807 
   1808     /**
   1809      * This call will be deprecated and removed in an upcoming release.  It is no longer used to
   1810      * start WiFi Tethering.  Please use {@link ConnectivityManager#startTethering(int, boolean,
   1811      * ConnectivityManager#OnStartTetheringCallback)} if
   1812      * the caller has proper permissions.  Callers can also use the LocalOnlyHotspot feature for a
   1813      * hotspot capable of communicating with co-located devices {@link
   1814      * WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}.
   1815      *
   1816      * @param wifiConfig SSID, security and channel details as
   1817      *        part of WifiConfiguration
   1818      * @return {@code false}
   1819      *
   1820      * @hide
   1821      */
   1822     @SystemApi
   1823     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
   1824     public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
   1825         String packageName = mContext.getOpPackageName();
   1826 
   1827         Log.w(TAG, packageName + " attempted call to setWifiApEnabled: enabled = " + enabled);
   1828         return false;
   1829     }
   1830 
   1831     /**
   1832      * Call allowing ConnectivityService to update WifiService with interface mode changes.
   1833      *
   1834      * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
   1835      *                             {@link IFACE_IP_MODE_LOCAL_ONLY},
   1836      *                             {@link IFACE_IP_MODE_CONFIGURATION_ERROR}
   1837      *
   1838      * @param ifaceName String name of the updated interface
   1839      * @param mode int representing the new mode
   1840      *
   1841      * @hide
   1842      */
   1843     public void updateInterfaceIpState(String ifaceName, int mode) {
   1844         try {
   1845             mService.updateInterfaceIpState(ifaceName, mode);
   1846         } catch (RemoteException e) {
   1847             throw e.rethrowFromSystemServer();
   1848         }
   1849     }
   1850 
   1851     /**
   1852      * Start SoftAp mode with the specified configuration.
   1853      * Note that starting in access point mode disables station
   1854      * mode operation
   1855      * @param wifiConfig SSID, security and channel details as
   1856      *        part of WifiConfiguration
   1857      * @return {@code true} if the operation succeeds, {@code false} otherwise
   1858      *
   1859      * @hide
   1860      */
   1861     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
   1862         try {
   1863             return mService.startSoftAp(wifiConfig);
   1864         } catch (RemoteException e) {
   1865             throw e.rethrowFromSystemServer();
   1866         }
   1867     }
   1868 
   1869     /**
   1870      * Stop SoftAp mode.
   1871      * Note that stopping softap mode will restore the previous wifi mode.
   1872      * @return {@code true} if the operation succeeds, {@code false} otherwise
   1873      *
   1874      * @hide
   1875      */
   1876     public boolean stopSoftAp() {
   1877         try {
   1878             return mService.stopSoftAp();
   1879         } catch (RemoteException e) {
   1880             throw e.rethrowFromSystemServer();
   1881         }
   1882     }
   1883 
   1884     /**
   1885      * Request a local only hotspot that an application can use to communicate between co-located
   1886      * devices connected to the created WiFi hotspot.  The network created by this method will not
   1887      * have Internet access.  Each application can make a single request for the hotspot, but
   1888      * multiple applications could be requesting the hotspot at the same time.  When multiple
   1889      * applications have successfully registered concurrently, they will be sharing the underlying
   1890      * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called
   1891      * when the hotspot is ready for use by the application.
   1892      * <p>
   1893      * Each application can make a single active call to this method. The {@link
   1894      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
   1895      * requestor with a {@link LocalOnlyHotspotReservation} that contains a
   1896      * {@link WifiConfiguration} with the SSID, security type and credentials needed to connect
   1897      * to the hotspot.  Communicating this information is up to the application.
   1898      * <p>
   1899      * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
   1900      * method will be called. Example failures include errors bringing up the network or if
   1901      * there is an incompatible operating mode.  For example, if the user is currently using Wifi
   1902      * Tethering to provide an upstream to another device, LocalOnlyHotspot will not start due to
   1903      * an incompatible mode. The possible error codes include:
   1904      * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL},
   1905      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC},
   1906      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and
   1907      * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}.
   1908      * <p>
   1909      * Internally, requests will be tracked to prevent the hotspot from being torn down while apps
   1910      * are still using it.  The {@link LocalOnlyHotspotReservation} object passed in the  {@link
   1911      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when
   1912      * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}.
   1913      * Since the hotspot may be shared among multiple applications, removing the final registered
   1914      * application request will trigger the hotspot teardown.  This means that applications should
   1915      * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after
   1916      * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is
   1917      * called, applications will not receive callbacks of any kind.
   1918      * <p>
   1919      * Applications should be aware that the user may also stop the LocalOnlyHotspot through the
   1920      * Settings UI; it is not guaranteed to stay up as long as there is a requesting application.
   1921      * The requestors will be notified of this case via
   1922      * {@link LocalOnlyHotspotCallback#onStopped()}.  Other cases may arise where the hotspot is
   1923      * torn down (Emergency mode, etc).  Application developers should be aware that it can stop
   1924      * unexpectedly, but they will receive a notification if they have properly registered.
   1925      * <p>
   1926      * Applications should also be aware that this network will be shared with other applications.
   1927      * Applications are responsible for protecting their data on this network (e.g., TLS).
   1928      * <p>
   1929      * Applications need to have the following permissions to start LocalOnlyHotspot: {@link
   1930      * android.Manifest.permission#CHANGE_WIFI_STATE} and {@link
   1931      * android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}.  Callers without
   1932      * the permissions will trigger a {@link java.lang.SecurityException}.
   1933      * <p>
   1934      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
   1935      * operating status.
   1936      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
   1937      * main thread will be used.
   1938      */
   1939     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
   1940             @Nullable Handler handler) {
   1941         synchronized (mLock) {
   1942             Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
   1943             LocalOnlyHotspotCallbackProxy proxy =
   1944                     new LocalOnlyHotspotCallbackProxy(this, looper, callback);
   1945             try {
   1946                 String packageName = mContext.getOpPackageName();
   1947                 int returnCode = mService.startLocalOnlyHotspot(
   1948                         proxy.getMessenger(), new Binder(), packageName);
   1949                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
   1950                     // Send message to the proxy to make sure we call back on the correct thread
   1951                     proxy.notifyFailed(returnCode);
   1952                     return;
   1953                 }
   1954                 mLOHSCallbackProxy = proxy;
   1955             } catch (RemoteException e) {
   1956                 throw e.rethrowFromSystemServer();
   1957             }
   1958         }
   1959     }
   1960 
   1961     /**
   1962      * Cancels a pending local only hotspot request.  This can be used by the calling application to
   1963      * cancel the existing request if the provided callback has not been triggered.  Calling this
   1964      * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not
   1965      * explicitly required.
   1966      * <p>
   1967      * When cancelling this request, application developers should be aware that there may still be
   1968      * outstanding local only hotspot requests and the hotspot may still start, or continue running.
   1969      * Additionally, if a callback was registered, it will no longer be triggered after calling
   1970      * cancel.
   1971      *
   1972      * @hide
   1973      */
   1974     public void cancelLocalOnlyHotspotRequest() {
   1975         synchronized (mLock) {
   1976             stopLocalOnlyHotspot();
   1977         }
   1978     }
   1979 
   1980     /**
   1981      *  Method used to inform WifiService that the LocalOnlyHotspot is no longer needed.  This
   1982      *  method is used by WifiManager to release LocalOnlyHotspotReservations held by calling
   1983      *  applications and removes the internal tracking for the hotspot request.  When all requesting
   1984      *  applications are finished using the hotspot, it will be stopped and WiFi will return to the
   1985      *  previous operational mode.
   1986      *
   1987      *  This method should not be called by applications.  Instead, they should call the close()
   1988      *  method on their LocalOnlyHotspotReservation.
   1989      */
   1990     private void stopLocalOnlyHotspot() {
   1991         synchronized (mLock) {
   1992             if (mLOHSCallbackProxy == null) {
   1993                 // nothing to do, the callback was already cleaned up.
   1994                 return;
   1995             }
   1996             mLOHSCallbackProxy = null;
   1997             try {
   1998                 mService.stopLocalOnlyHotspot();
   1999             } catch (RemoteException e) {
   2000                 throw e.rethrowFromSystemServer();
   2001             }
   2002         }
   2003     }
   2004 
   2005     /**
   2006      * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes.  Callers will
   2007      * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
   2008      * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
   2009      * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(WifiConfiguration)} and
   2010      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
   2011      * <p>
   2012      * Applications should have the
   2013      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}
   2014      * permission.  Callers without the permission will trigger a
   2015      * {@link java.lang.SecurityException}.
   2016      * <p>
   2017      * @param observer LocalOnlyHotspotObserver callback.
   2018      * @param handler Handler to use for callbacks
   2019      *
   2020      * @hide
   2021      */
   2022     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
   2023             @Nullable Handler handler) {
   2024         synchronized (mLock) {
   2025             Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
   2026             mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer);
   2027             try {
   2028                 mService.startWatchLocalOnlyHotspot(
   2029                         mLOHSObserverProxy.getMessenger(), new Binder());
   2030                 mLOHSObserverProxy.registered();
   2031             } catch (RemoteException e) {
   2032                 mLOHSObserverProxy = null;
   2033                 throw e.rethrowFromSystemServer();
   2034             }
   2035         }
   2036     }
   2037 
   2038     /**
   2039      * Allow callers to stop watching LocalOnlyHotspot state changes.  After calling this method,
   2040      * applications will no longer receive callbacks.
   2041      *
   2042      * @hide
   2043      */
   2044     public void unregisterLocalOnlyHotspotObserver() {
   2045         synchronized (mLock) {
   2046             if (mLOHSObserverProxy == null) {
   2047                 // nothing to do, the callback was already cleaned up
   2048                 return;
   2049             }
   2050             mLOHSObserverProxy = null;
   2051             try {
   2052                 mService.stopWatchLocalOnlyHotspot();
   2053             } catch (RemoteException e) {
   2054                 throw e.rethrowFromSystemServer();
   2055             }
   2056         }
   2057     }
   2058 
   2059     /**
   2060      * Gets the Wi-Fi enabled state.
   2061      * @return One of {@link #WIFI_AP_STATE_DISABLED},
   2062      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
   2063      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
   2064      * @see #isWifiApEnabled()
   2065      *
   2066      * @hide
   2067      */
   2068     @SystemApi
   2069     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
   2070     public int getWifiApState() {
   2071         try {
   2072             return mService.getWifiApEnabledState();
   2073         } catch (RemoteException e) {
   2074             throw e.rethrowFromSystemServer();
   2075         }
   2076     }
   2077 
   2078     /**
   2079      * Return whether Wi-Fi AP is enabled or disabled.
   2080      * @return {@code true} if Wi-Fi AP is enabled
   2081      * @see #getWifiApState()
   2082      *
   2083      * @hide
   2084      */
   2085     @SystemApi
   2086     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
   2087     public boolean isWifiApEnabled() {
   2088         return getWifiApState() == WIFI_AP_STATE_ENABLED;
   2089     }
   2090 
   2091     /**
   2092      * Gets the Wi-Fi AP Configuration.
   2093      * @return AP details in WifiConfiguration
   2094      *
   2095      * @hide
   2096      */
   2097     @SystemApi
   2098     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
   2099     public WifiConfiguration getWifiApConfiguration() {
   2100         try {
   2101             return mService.getWifiApConfiguration();
   2102         } catch (RemoteException e) {
   2103             throw e.rethrowFromSystemServer();
   2104         }
   2105     }
   2106 
   2107     /**
   2108      * Sets the Wi-Fi AP Configuration.
   2109      * @return {@code true} if the operation succeeded, {@code false} otherwise
   2110      *
   2111      * @hide
   2112      */
   2113     @SystemApi
   2114     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
   2115     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
   2116         try {
   2117             mService.setWifiApConfiguration(wifiConfig);
   2118             return true;
   2119         } catch (RemoteException e) {
   2120             throw e.rethrowFromSystemServer();
   2121         }
   2122     }
   2123 
   2124     /**
   2125      * Enable/Disable TDLS on a specific local route.
   2126      *
   2127      * <p>
   2128      * TDLS enables two wireless endpoints to talk to each other directly
   2129      * without going through the access point that is managing the local
   2130      * network. It saves bandwidth and improves quality of the link.
   2131      * </p>
   2132      * <p>
   2133      * This API enables/disables the option of using TDLS. If enabled, the
   2134      * underlying hardware is free to use TDLS or a hop through the access
   2135      * point. If disabled, existing TDLS session is torn down and
   2136      * hardware is restricted to use access point for transferring wireless
   2137      * packets. Default value for all routes is 'disabled', meaning restricted
   2138      * to use access point for transferring packets.
   2139      * </p>
   2140      *
   2141      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
   2142      * @param enable true = setup and false = tear down TDLS
   2143      */
   2144     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
   2145         try {
   2146             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
   2147         } catch (RemoteException e) {
   2148             throw e.rethrowFromSystemServer();
   2149         }
   2150     }
   2151 
   2152     /**
   2153      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
   2154      * this version allows you to specify remote endpoint with a MAC address.
   2155      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
   2156      * @param enable true = setup and false = tear down TDLS
   2157      */
   2158     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
   2159         try {
   2160             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
   2161         } catch (RemoteException e) {
   2162             throw e.rethrowFromSystemServer();
   2163         }
   2164     }
   2165 
   2166     /* TODO: deprecate synchronous API and open up the following API */
   2167 
   2168     private static final int BASE = Protocol.BASE_WIFI_MANAGER;
   2169 
   2170     /* Commands to WifiService */
   2171     /** @hide */
   2172     public static final int CONNECT_NETWORK                 = BASE + 1;
   2173     /** @hide */
   2174     public static final int CONNECT_NETWORK_FAILED          = BASE + 2;
   2175     /** @hide */
   2176     public static final int CONNECT_NETWORK_SUCCEEDED       = BASE + 3;
   2177 
   2178     /** @hide */
   2179     public static final int FORGET_NETWORK                  = BASE + 4;
   2180     /** @hide */
   2181     public static final int FORGET_NETWORK_FAILED           = BASE + 5;
   2182     /** @hide */
   2183     public static final int FORGET_NETWORK_SUCCEEDED        = BASE + 6;
   2184 
   2185     /** @hide */
   2186     public static final int SAVE_NETWORK                    = BASE + 7;
   2187     /** @hide */
   2188     public static final int SAVE_NETWORK_FAILED             = BASE + 8;
   2189     /** @hide */
   2190     public static final int SAVE_NETWORK_SUCCEEDED          = BASE + 9;
   2191 
   2192     /** @hide */
   2193     public static final int START_WPS                       = BASE + 10;
   2194     /** @hide */
   2195     public static final int START_WPS_SUCCEEDED             = BASE + 11;
   2196     /** @hide */
   2197     public static final int WPS_FAILED                      = BASE + 12;
   2198     /** @hide */
   2199     public static final int WPS_COMPLETED                   = BASE + 13;
   2200 
   2201     /** @hide */
   2202     public static final int CANCEL_WPS                      = BASE + 14;
   2203     /** @hide */
   2204     public static final int CANCEL_WPS_FAILED               = BASE + 15;
   2205     /** @hide */
   2206     public static final int CANCEL_WPS_SUCCEDED             = BASE + 16;
   2207 
   2208     /** @hide */
   2209     public static final int DISABLE_NETWORK                 = BASE + 17;
   2210     /** @hide */
   2211     public static final int DISABLE_NETWORK_FAILED          = BASE + 18;
   2212     /** @hide */
   2213     public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 19;
   2214 
   2215     /** @hide */
   2216     public static final int RSSI_PKTCNT_FETCH               = BASE + 20;
   2217     /** @hide */
   2218     public static final int RSSI_PKTCNT_FETCH_SUCCEEDED     = BASE + 21;
   2219     /** @hide */
   2220     public static final int RSSI_PKTCNT_FETCH_FAILED        = BASE + 22;
   2221 
   2222     /**
   2223      * Passed with {@link ActionListener#onFailure}.
   2224      * Indicates that the operation failed due to an internal error.
   2225      * @hide
   2226      */
   2227     public static final int ERROR                       = 0;
   2228 
   2229     /**
   2230      * Passed with {@link ActionListener#onFailure}.
   2231      * Indicates that the operation is already in progress
   2232      * @hide
   2233      */
   2234     public static final int IN_PROGRESS                 = 1;
   2235 
   2236     /**
   2237      * Passed with {@link ActionListener#onFailure}.
   2238      * Indicates that the operation failed because the framework is busy and
   2239      * unable to service the request
   2240      * @hide
   2241      */
   2242     public static final int BUSY                        = 2;
   2243 
   2244     /* WPS specific errors */
   2245     /** WPS overlap detected */
   2246     public static final int WPS_OVERLAP_ERROR           = 3;
   2247     /** WEP on WPS is prohibited */
   2248     public static final int WPS_WEP_PROHIBITED          = 4;
   2249     /** TKIP only prohibited */
   2250     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
   2251     /** Authentication failure on WPS */
   2252     public static final int WPS_AUTH_FAILURE            = 6;
   2253     /** WPS timed out */
   2254     public static final int WPS_TIMED_OUT               = 7;
   2255 
   2256     /**
   2257      * Passed with {@link ActionListener#onFailure}.
   2258      * Indicates that the operation failed due to invalid inputs
   2259      * @hide
   2260      */
   2261     public static final int INVALID_ARGS                = 8;
   2262 
   2263     /**
   2264      * Passed with {@link ActionListener#onFailure}.
   2265      * Indicates that the operation failed due to user permissions.
   2266      * @hide
   2267      */
   2268     public static final int NOT_AUTHORIZED              = 9;
   2269 
   2270     /**
   2271      * Interface for callback invocation on an application action
   2272      * @hide
   2273      */
   2274     @SystemApi
   2275     public interface ActionListener {
   2276         /** The operation succeeded */
   2277         public void onSuccess();
   2278         /**
   2279          * The operation failed
   2280          * @param reason The reason for failure could be one of
   2281          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
   2282          */
   2283         public void onFailure(int reason);
   2284     }
   2285 
   2286     /** Interface for callback invocation on a start WPS action */
   2287     public static abstract class WpsCallback {
   2288         /** WPS start succeeded */
   2289         public abstract void onStarted(String pin);
   2290 
   2291         /** WPS operation completed succesfully */
   2292         public abstract void onSucceeded();
   2293 
   2294         /**
   2295          * WPS operation failed
   2296          * @param reason The reason for failure could be one of
   2297          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
   2298          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
   2299          * and some generic errors.
   2300          */
   2301         public abstract void onFailed(int reason);
   2302     }
   2303 
   2304     /** Interface for callback invocation on a TX packet count poll action {@hide} */
   2305     public interface TxPacketCountListener {
   2306         /**
   2307          * The operation succeeded
   2308          * @param count TX packet counter
   2309          */
   2310         public void onSuccess(int count);
   2311         /**
   2312          * The operation failed
   2313          * @param reason The reason for failure could be one of
   2314          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
   2315          */
   2316         public void onFailure(int reason);
   2317     }
   2318 
   2319     /**
   2320      * LocalOnlyHotspotReservation that contains the {@link WifiConfiguration} for the active
   2321      * LocalOnlyHotspot request.
   2322      * <p>
   2323      * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
   2324      * LocalOnlyHotspotReservation in the
   2325      * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call.  This
   2326      * reservation contains the relevant {@link WifiConfiguration}.
   2327      * When an application is done with the LocalOnlyHotspot, they should call {@link
   2328      * LocalOnlyHotspotReservation#close()}.  Once this happens, the application will not receive
   2329      * any further callbacks. If the LocalOnlyHotspot is stopped due to a
   2330      * user triggered mode change, applications will be notified via the {@link
   2331      * LocalOnlyHotspotCallback#onStopped()} callback.
   2332      */
   2333     public class LocalOnlyHotspotReservation implements AutoCloseable {
   2334 
   2335         private final CloseGuard mCloseGuard = CloseGuard.get();
   2336         private final WifiConfiguration mConfig;
   2337 
   2338         /** @hide */
   2339         @VisibleForTesting
   2340         public LocalOnlyHotspotReservation(WifiConfiguration config) {
   2341             mConfig = config;
   2342             mCloseGuard.open("close");
   2343         }
   2344 
   2345         public WifiConfiguration getWifiConfiguration() {
   2346             return mConfig;
   2347         }
   2348 
   2349         @Override
   2350         public void close() {
   2351             try {
   2352                 stopLocalOnlyHotspot();
   2353                 mCloseGuard.close();
   2354             } catch (Exception e) {
   2355                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
   2356             }
   2357         }
   2358 
   2359         @Override
   2360         protected void finalize() throws Throwable {
   2361             try {
   2362                 if (mCloseGuard != null) {
   2363                     mCloseGuard.warnIfOpen();
   2364                 }
   2365                 close();
   2366             } finally {
   2367                 super.finalize();
   2368             }
   2369         }
   2370     }
   2371 
   2372     /**
   2373      * Callback class for applications to receive updates about the LocalOnlyHotspot status.
   2374      */
   2375     public static class LocalOnlyHotspotCallback {
   2376         /** @hide */
   2377         public static final int REQUEST_REGISTERED = 0;
   2378 
   2379         public static final int ERROR_NO_CHANNEL = 1;
   2380         public static final int ERROR_GENERIC = 2;
   2381         public static final int ERROR_INCOMPATIBLE_MODE = 3;
   2382         public static final int ERROR_TETHERING_DISALLOWED = 4;
   2383 
   2384         /** LocalOnlyHotspot start succeeded. */
   2385         public void onStarted(LocalOnlyHotspotReservation reservation) {};
   2386 
   2387         /**
   2388          * LocalOnlyHotspot stopped.
   2389          * <p>
   2390          * The LocalOnlyHotspot can be disabled at any time by the user.  When this happens,
   2391          * applications will be notified that it was stopped. This will not be invoked when an
   2392          * application calls {@link LocalOnlyHotspotReservation#close()}.
   2393          */
   2394         public void onStopped() {};
   2395 
   2396         /**
   2397          * LocalOnlyHotspot failed to start.
   2398          * <p>
   2399          * Applications can attempt to call
   2400          * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at
   2401          * a later time.
   2402          * <p>
   2403          * @param reason The reason for failure could be one of: {@link
   2404          * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE},
   2405          * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}.
   2406          */
   2407         public void onFailed(int reason) { };
   2408     }
   2409 
   2410     /**
   2411      * Callback proxy for LocalOnlyHotspotCallback objects.
   2412      */
   2413     private static class LocalOnlyHotspotCallbackProxy {
   2414         private final Handler mHandler;
   2415         private final WeakReference<WifiManager> mWifiManager;
   2416         private final Looper mLooper;
   2417         private final Messenger mMessenger;
   2418 
   2419         /**
   2420          * Constructs a {@link LocalOnlyHotspotCallback} using the specified looper.  All callbacks
   2421          * will be delivered on the thread of the specified looper.
   2422          *
   2423          * @param manager WifiManager
   2424          * @param looper Looper for delivering callbacks
   2425          * @param callback LocalOnlyHotspotCallback to notify the calling application.
   2426          */
   2427         LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper,
   2428                 final LocalOnlyHotspotCallback callback) {
   2429             mWifiManager = new WeakReference<>(manager);
   2430             mLooper = looper;
   2431 
   2432             mHandler = new Handler(looper) {
   2433                 @Override
   2434                 public void handleMessage(Message msg) {
   2435                     Log.d(TAG, "LocalOnlyHotspotCallbackProxy: handle message what: "
   2436                             + msg.what + " msg: " + msg);
   2437 
   2438                     WifiManager manager = mWifiManager.get();
   2439                     if (manager == null) {
   2440                         Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC");
   2441                         return;
   2442                     }
   2443 
   2444                     switch (msg.what) {
   2445                         case HOTSPOT_STARTED:
   2446                             WifiConfiguration config = (WifiConfiguration) msg.obj;
   2447                             if (config == null) {
   2448                                 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
   2449                                 callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
   2450                                 return;
   2451                             }
   2452                             callback.onStarted(manager.new LocalOnlyHotspotReservation(config));
   2453                             break;
   2454                         case HOTSPOT_STOPPED:
   2455                             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
   2456                             callback.onStopped();
   2457                             break;
   2458                         case HOTSPOT_FAILED:
   2459                             int reasonCode = msg.arg1;
   2460                             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
   2461                                     + reasonCode);
   2462                             callback.onFailed(reasonCode);
   2463                             Log.w(TAG, "done with the callback...");
   2464                             break;
   2465                         default:
   2466                             Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message.  type: "
   2467                                     + msg.what);
   2468                     }
   2469                 }
   2470             };
   2471             mMessenger = new Messenger(mHandler);
   2472         }
   2473 
   2474         public Messenger getMessenger() {
   2475             return mMessenger;
   2476         }
   2477 
   2478         /**
   2479          * Helper method allowing the the incoming application call to move the onFailed callback
   2480          * over to the desired callback thread.
   2481          *
   2482          * @param reason int representing the error type
   2483          */
   2484         public void notifyFailed(int reason) throws RemoteException {
   2485             Message msg = Message.obtain();
   2486             msg.what = HOTSPOT_FAILED;
   2487             msg.arg1 = reason;
   2488             mMessenger.send(msg);
   2489         }
   2490     }
   2491 
   2492     /**
   2493      * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications
   2494      * watching for LocalOnlyHotspot changes.
   2495      *
   2496      * @hide
   2497      */
   2498     public class LocalOnlyHotspotSubscription implements AutoCloseable {
   2499         private final CloseGuard mCloseGuard = CloseGuard.get();
   2500 
   2501         /** @hide */
   2502         @VisibleForTesting
   2503         public LocalOnlyHotspotSubscription() {
   2504             mCloseGuard.open("close");
   2505         }
   2506 
   2507         @Override
   2508         public void close() {
   2509             try {
   2510                 unregisterLocalOnlyHotspotObserver();
   2511                 mCloseGuard.close();
   2512             } catch (Exception e) {
   2513                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
   2514             }
   2515         }
   2516 
   2517         @Override
   2518         protected void finalize() throws Throwable {
   2519             try {
   2520                 if (mCloseGuard != null) {
   2521                     mCloseGuard.warnIfOpen();
   2522                 }
   2523                 close();
   2524             } finally {
   2525                 super.finalize();
   2526             }
   2527         }
   2528     }
   2529 
   2530     /**
   2531      * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates.
   2532      *
   2533      * @hide
   2534      */
   2535     public static class LocalOnlyHotspotObserver {
   2536         /**
   2537          * Confirm registration for LocalOnlyHotspotChanges by returning a
   2538          * LocalOnlyHotspotSubscription.
   2539          */
   2540         public void onRegistered(LocalOnlyHotspotSubscription subscription) {};
   2541 
   2542         /**
   2543          * LocalOnlyHotspot started with the supplied config.
   2544          */
   2545         public void onStarted(WifiConfiguration config) {};
   2546 
   2547         /**
   2548          * LocalOnlyHotspot stopped.
   2549          */
   2550         public void onStopped() {};
   2551     }
   2552 
   2553     /**
   2554      * Callback proxy for LocalOnlyHotspotObserver objects.
   2555      */
   2556     private static class LocalOnlyHotspotObserverProxy {
   2557         private final Handler mHandler;
   2558         private final WeakReference<WifiManager> mWifiManager;
   2559         private final Looper mLooper;
   2560         private final Messenger mMessenger;
   2561 
   2562         /**
   2563          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
   2564          * All callbacks will be delivered on the thread of the specified looper.
   2565          *
   2566          * @param manager WifiManager
   2567          * @param looper Looper for delivering callbacks
   2568          * @param observer LocalOnlyHotspotObserver to notify the calling application.
   2569          */
   2570         LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper,
   2571                 final LocalOnlyHotspotObserver observer) {
   2572             mWifiManager = new WeakReference<>(manager);
   2573             mLooper = looper;
   2574 
   2575             mHandler = new Handler(looper) {
   2576                 @Override
   2577                 public void handleMessage(Message msg) {
   2578                     Log.d(TAG, "LocalOnlyHotspotObserverProxy: handle message what: "
   2579                             + msg.what + " msg: " + msg);
   2580 
   2581                     WifiManager manager = mWifiManager.get();
   2582                     if (manager == null) {
   2583                         Log.w(TAG, "LocalOnlyHotspotObserverProxy: handle message post GC");
   2584                         return;
   2585                     }
   2586 
   2587                     switch (msg.what) {
   2588                         case HOTSPOT_OBSERVER_REGISTERED:
   2589                             observer.onRegistered(manager.new LocalOnlyHotspotSubscription());
   2590                             break;
   2591                         case HOTSPOT_STARTED:
   2592                             WifiConfiguration config = (WifiConfiguration) msg.obj;
   2593                             if (config == null) {
   2594                                 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
   2595                                 return;
   2596                             }
   2597                             observer.onStarted(config);
   2598                             break;
   2599                         case HOTSPOT_STOPPED:
   2600                             observer.onStopped();
   2601                             break;
   2602                         default:
   2603                             Log.e(TAG, "LocalOnlyHotspotObserverProxy unhandled message.  type: "
   2604                                     + msg.what);
   2605                     }
   2606                 }
   2607             };
   2608             mMessenger = new Messenger(mHandler);
   2609         }
   2610 
   2611         public Messenger getMessenger() {
   2612             return mMessenger;
   2613         }
   2614 
   2615         public void registered() throws RemoteException {
   2616             Message msg = Message.obtain();
   2617             msg.what = HOTSPOT_OBSERVER_REGISTERED;
   2618             mMessenger.send(msg);
   2619         }
   2620     }
   2621 
   2622     // Ensure that multiple ServiceHandler threads do not interleave message dispatch.
   2623     private static final Object sServiceHandlerDispatchLock = new Object();
   2624 
   2625     private class ServiceHandler extends Handler {
   2626         ServiceHandler(Looper looper) {
   2627             super(looper);
   2628         }
   2629 
   2630         @Override
   2631         public void handleMessage(Message message) {
   2632             synchronized (sServiceHandlerDispatchLock) {
   2633                 dispatchMessageToListeners(message);
   2634             }
   2635         }
   2636 
   2637         private void dispatchMessageToListeners(Message message) {
   2638             Object listener = removeListener(message.arg2);
   2639             switch (message.what) {
   2640                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
   2641                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
   2642                         mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
   2643                     } else {
   2644                         Log.e(TAG, "Failed to set up channel connection");
   2645                         // This will cause all further async API calls on the WifiManager
   2646                         // to fail and throw an exception
   2647                         mAsyncChannel = null;
   2648                     }
   2649                     mConnected.countDown();
   2650                     break;
   2651                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
   2652                     // Ignore
   2653                     break;
   2654                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
   2655                     Log.e(TAG, "Channel connection lost");
   2656                     // This will cause all further async API calls on the WifiManager
   2657                     // to fail and throw an exception
   2658                     mAsyncChannel = null;
   2659                     getLooper().quit();
   2660                     break;
   2661                     /* ActionListeners grouped together */
   2662                 case WifiManager.CONNECT_NETWORK_FAILED:
   2663                 case WifiManager.FORGET_NETWORK_FAILED:
   2664                 case WifiManager.SAVE_NETWORK_FAILED:
   2665                 case WifiManager.DISABLE_NETWORK_FAILED:
   2666                     if (listener != null) {
   2667                         ((ActionListener) listener).onFailure(message.arg1);
   2668                     }
   2669                     break;
   2670                     /* ActionListeners grouped together */
   2671                 case WifiManager.CONNECT_NETWORK_SUCCEEDED:
   2672                 case WifiManager.FORGET_NETWORK_SUCCEEDED:
   2673                 case WifiManager.SAVE_NETWORK_SUCCEEDED:
   2674                 case WifiManager.DISABLE_NETWORK_SUCCEEDED:
   2675                     if (listener != null) {
   2676                         ((ActionListener) listener).onSuccess();
   2677                     }
   2678                     break;
   2679                 case WifiManager.START_WPS_SUCCEEDED:
   2680                     if (listener != null) {
   2681                         WpsResult result = (WpsResult) message.obj;
   2682                         ((WpsCallback) listener).onStarted(result.pin);
   2683                         //Listener needs to stay until completion or failure
   2684                         synchronized (mListenerMapLock) {
   2685                             mListenerMap.put(message.arg2, listener);
   2686                         }
   2687                     }
   2688                     break;
   2689                 case WifiManager.WPS_COMPLETED:
   2690                     if (listener != null) {
   2691                         ((WpsCallback) listener).onSucceeded();
   2692                     }
   2693                     break;
   2694                 case WifiManager.WPS_FAILED:
   2695                     if (listener != null) {
   2696                         ((WpsCallback) listener).onFailed(message.arg1);
   2697                     }
   2698                     break;
   2699                 case WifiManager.CANCEL_WPS_SUCCEDED:
   2700                     if (listener != null) {
   2701                         ((WpsCallback) listener).onSucceeded();
   2702                     }
   2703                     break;
   2704                 case WifiManager.CANCEL_WPS_FAILED:
   2705                     if (listener != null) {
   2706                         ((WpsCallback) listener).onFailed(message.arg1);
   2707                     }
   2708                     break;
   2709                 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
   2710                     if (listener != null) {
   2711                         RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
   2712                         if (info != null)
   2713                             ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
   2714                         else
   2715                             ((TxPacketCountListener) listener).onFailure(ERROR);
   2716                     }
   2717                     break;
   2718                 case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
   2719                     if (listener != null) {
   2720                         ((TxPacketCountListener) listener).onFailure(message.arg1);
   2721                     }
   2722                     break;
   2723                 default:
   2724                     //ignore
   2725                     break;
   2726             }
   2727         }
   2728     }
   2729 
   2730     private int putListener(Object listener) {
   2731         if (listener == null) return INVALID_KEY;
   2732         int key;
   2733         synchronized (mListenerMapLock) {
   2734             do {
   2735                 key = mListenerKey++;
   2736             } while (key == INVALID_KEY);
   2737             mListenerMap.put(key, listener);
   2738         }
   2739         return key;
   2740     }
   2741 
   2742     private Object removeListener(int key) {
   2743         if (key == INVALID_KEY) return null;
   2744         synchronized (mListenerMapLock) {
   2745             Object listener = mListenerMap.get(key);
   2746             mListenerMap.remove(key);
   2747             return listener;
   2748         }
   2749     }
   2750 
   2751     private synchronized AsyncChannel getChannel() {
   2752         if (mAsyncChannel == null) {
   2753             Messenger messenger = getWifiServiceMessenger();
   2754             if (messenger == null) {
   2755                 throw new IllegalStateException(
   2756                         "getWifiServiceMessenger() returned null!  This is invalid.");
   2757             }
   2758 
   2759             mAsyncChannel = new AsyncChannel();
   2760             mConnected = new CountDownLatch(1);
   2761 
   2762             Handler handler = new ServiceHandler(mLooper);
   2763             mAsyncChannel.connect(mContext, handler, messenger);
   2764             try {
   2765                 mConnected.await();
   2766             } catch (InterruptedException e) {
   2767                 Log.e(TAG, "interrupted wait at init");
   2768             }
   2769         }
   2770         return mAsyncChannel;
   2771     }
   2772 
   2773     /**
   2774      * Connect to a network with the given configuration. The network also
   2775      * gets added to the list of configured networks for the foreground user.
   2776      *
   2777      * For a new network, this function is used instead of a
   2778      * sequence of addNetwork(), enableNetwork(), saveConfiguration() and
   2779      * reconnect()
   2780      *
   2781      * @param config the set of variables that describe the configuration,
   2782      *            contained in a {@link WifiConfiguration} object.
   2783      * @param listener for callbacks on success or failure. Can be null.
   2784      * @throws IllegalStateException if the WifiManager instance needs to be
   2785      * initialized again
   2786      *
   2787      * @hide
   2788      */
   2789     @SystemApi
   2790     public void connect(WifiConfiguration config, ActionListener listener) {
   2791         if (config == null) throw new IllegalArgumentException("config cannot be null");
   2792         // Use INVALID_NETWORK_ID for arg1 when passing a config object
   2793         // arg1 is used to pass network id when the network already exists
   2794         getChannel().sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
   2795                 putListener(listener), config);
   2796     }
   2797 
   2798     /**
   2799      * Connect to a network with the given networkId.
   2800      *
   2801      * This function is used instead of a enableNetwork(), saveConfiguration() and
   2802      * reconnect()
   2803      *
   2804      * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
   2805      *        getConfiguredNetworks}.
   2806      * @param listener for callbacks on success or failure. Can be null.
   2807      * @throws IllegalStateException if the WifiManager instance needs to be
   2808      * initialized again
   2809      * @hide
   2810      */
   2811     public void connect(int networkId, ActionListener listener) {
   2812         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   2813         getChannel().sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
   2814     }
   2815 
   2816     /**
   2817      * Save the given network to the list of configured networks for the
   2818      * foreground user. If the network already exists, the configuration
   2819      * is updated. Any new network is enabled by default.
   2820      *
   2821      * For a new network, this function is used instead of a
   2822      * sequence of addNetwork(), enableNetwork() and saveConfiguration().
   2823      *
   2824      * For an existing network, it accomplishes the task of updateNetwork()
   2825      * and saveConfiguration()
   2826      *
   2827      * @param config the set of variables that describe the configuration,
   2828      *            contained in a {@link WifiConfiguration} object.
   2829      * @param listener for callbacks on success or failure. Can be null.
   2830      * @throws IllegalStateException if the WifiManager instance needs to be
   2831      * initialized again
   2832      * @hide
   2833      */
   2834     public void save(WifiConfiguration config, ActionListener listener) {
   2835         if (config == null) throw new IllegalArgumentException("config cannot be null");
   2836         getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
   2837     }
   2838 
   2839     /**
   2840      * Delete the network from the list of configured networks for the
   2841      * foreground user.
   2842      *
   2843      * This function is used instead of a sequence of removeNetwork()
   2844      * and saveConfiguration().
   2845      *
   2846      * @param config the set of variables that describe the configuration,
   2847      *            contained in a {@link WifiConfiguration} object.
   2848      * @param listener for callbacks on success or failure. Can be null.
   2849      * @throws IllegalStateException if the WifiManager instance needs to be
   2850      * initialized again
   2851      * @hide
   2852      */
   2853     public void forget(int netId, ActionListener listener) {
   2854         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   2855         getChannel().sendMessage(FORGET_NETWORK, netId, putListener(listener));
   2856     }
   2857 
   2858     /**
   2859      * Disable network
   2860      *
   2861      * @param netId is the network Id
   2862      * @param listener for callbacks on success or failure. Can be null.
   2863      * @throws IllegalStateException if the WifiManager instance needs to be
   2864      * initialized again
   2865      * @hide
   2866      */
   2867     public void disable(int netId, ActionListener listener) {
   2868         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
   2869         getChannel().sendMessage(DISABLE_NETWORK, netId, putListener(listener));
   2870     }
   2871 
   2872     /**
   2873      * Disable ephemeral Network
   2874      *
   2875      * @param SSID, in the format of WifiConfiguration's SSID.
   2876      * @hide
   2877      */
   2878     public void disableEphemeralNetwork(String SSID) {
   2879         if (SSID == null) throw new IllegalArgumentException("SSID cannot be null");
   2880         try {
   2881             mService.disableEphemeralNetwork(SSID);
   2882         } catch (RemoteException e) {
   2883             throw e.rethrowFromSystemServer();
   2884         }
   2885     }
   2886 
   2887     /**
   2888      * Start Wi-fi Protected Setup
   2889      *
   2890      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
   2891      * @param listener for callbacks on success or failure. Can be null.
   2892      * @throws IllegalStateException if the WifiManager instance needs to be
   2893      * initialized again
   2894      */
   2895     public void startWps(WpsInfo config, WpsCallback listener) {
   2896         if (config == null) throw new IllegalArgumentException("config cannot be null");
   2897         getChannel().sendMessage(START_WPS, 0, putListener(listener), config);
   2898     }
   2899 
   2900     /**
   2901      * Cancel any ongoing Wi-fi Protected Setup
   2902      *
   2903      * @param listener for callbacks on success or failure. Can be null.
   2904      * @throws IllegalStateException if the WifiManager instance needs to be
   2905      * initialized again
   2906      */
   2907     public void cancelWps(WpsCallback listener) {
   2908         getChannel().sendMessage(CANCEL_WPS, 0, putListener(listener));
   2909     }
   2910 
   2911     /**
   2912      * Get a reference to WifiService handler. This is used by a client to establish
   2913      * an AsyncChannel communication with WifiService
   2914      *
   2915      * @return Messenger pointing to the WifiService handler
   2916      * @hide
   2917      */
   2918     public Messenger getWifiServiceMessenger() {
   2919         try {
   2920             return mService.getWifiServiceMessenger();
   2921         } catch (RemoteException e) {
   2922             throw e.rethrowFromSystemServer();
   2923         }
   2924     }
   2925 
   2926 
   2927     /**
   2928      * Allows an application to keep the Wi-Fi radio awake.
   2929      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
   2930      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
   2931      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
   2932      * WifiLocks are held in any application.
   2933      * <p>
   2934      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
   2935      * could function over a mobile network, if available.  A program that needs to download large
   2936      * files should hold a WifiLock to ensure that the download will complete, but a program whose
   2937      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
   2938      * affecting battery life.
   2939      * <p>
   2940      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
   2941      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
   2942      * is idle.
   2943      * <p>
   2944      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
   2945      * permission in an {@code <uses-permission>} element of the application's manifest.
   2946      */
   2947     public class WifiLock {
   2948         private String mTag;
   2949         private final IBinder mBinder;
   2950         private int mRefCount;
   2951         int mLockType;
   2952         private boolean mRefCounted;
   2953         private boolean mHeld;
   2954         private WorkSource mWorkSource;
   2955 
   2956         private WifiLock(int lockType, String tag) {
   2957             mTag = tag;
   2958             mLockType = lockType;
   2959             mBinder = new Binder();
   2960             mRefCount = 0;
   2961             mRefCounted = true;
   2962             mHeld = false;
   2963         }
   2964 
   2965         /**
   2966          * Locks the Wi-Fi radio on until {@link #release} is called.
   2967          *
   2968          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
   2969          * reference count, and the radio will remain locked as long as the reference count is
   2970          * above zero.
   2971          *
   2972          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
   2973          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
   2974          * will be required, regardless of the number of times that {@code acquire} is called.
   2975          */
   2976         public void acquire() {
   2977             synchronized (mBinder) {
   2978                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
   2979                     try {
   2980                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
   2981                         synchronized (WifiManager.this) {
   2982                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
   2983                                 mService.releaseWifiLock(mBinder);
   2984                                 throw new UnsupportedOperationException(
   2985                                             "Exceeded maximum number of wifi locks");
   2986                             }
   2987                             mActiveLockCount++;
   2988                         }
   2989                     } catch (RemoteException e) {
   2990                         throw e.rethrowFromSystemServer();
   2991                     }
   2992                     mHeld = true;
   2993                 }
   2994             }
   2995         }
   2996 
   2997         /**
   2998          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
   2999          *
   3000          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
   3001          * reference count, and the radio will be unlocked only when the reference count reaches
   3002          * zero.  If the reference count goes below zero (that is, if {@code release} is called
   3003          * a greater number of times than {@link #acquire}), an exception is thrown.
   3004          *
   3005          * If this WifiLock is not reference-counted, the first call to {@code release} (after
   3006          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
   3007          * calls will be ignored.
   3008          */
   3009         public void release() {
   3010             synchronized (mBinder) {
   3011                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
   3012                     try {
   3013                         mService.releaseWifiLock(mBinder);
   3014                         synchronized (WifiManager.this) {
   3015                             mActiveLockCount--;
   3016                         }
   3017                     } catch (RemoteException e) {
   3018                         throw e.rethrowFromSystemServer();
   3019                     }
   3020                     mHeld = false;
   3021                 }
   3022                 if (mRefCount < 0) {
   3023                     throw new RuntimeException("WifiLock under-locked " + mTag);
   3024                 }
   3025             }
   3026         }
   3027 
   3028         /**
   3029          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
   3030          *
   3031          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
   3032          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
   3033          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
   3034          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
   3035          * radio whenever {@link #release} is called and it is locked.
   3036          *
   3037          * @param refCounted true if this WifiLock should keep a reference count
   3038          */
   3039         public void setReferenceCounted(boolean refCounted) {
   3040             mRefCounted = refCounted;
   3041         }
   3042 
   3043         /**
   3044          * Checks whether this WifiLock is currently held.
   3045          *
   3046          * @return true if this WifiLock is held, false otherwise
   3047          */
   3048         public boolean isHeld() {
   3049             synchronized (mBinder) {
   3050                 return mHeld;
   3051             }
   3052         }
   3053 
   3054         public void setWorkSource(WorkSource ws) {
   3055             synchronized (mBinder) {
   3056                 if (ws != null && ws.size() == 0) {
   3057                     ws = null;
   3058                 }
   3059                 boolean changed = true;
   3060                 if (ws == null) {
   3061                     mWorkSource = null;
   3062                 } else {
   3063                     ws.clearNames();
   3064                     if (mWorkSource == null) {
   3065                         changed = mWorkSource != null;
   3066                         mWorkSource = new WorkSource(ws);
   3067                     } else {
   3068                         changed = mWorkSource.diff(ws);
   3069                         if (changed) {
   3070                             mWorkSource.set(ws);
   3071                         }
   3072                     }
   3073                 }
   3074                 if (changed && mHeld) {
   3075                     try {
   3076                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
   3077                     } catch (RemoteException e) {
   3078                         throw e.rethrowFromSystemServer();
   3079                     }
   3080                 }
   3081             }
   3082         }
   3083 
   3084         public String toString() {
   3085             String s1, s2, s3;
   3086             synchronized (mBinder) {
   3087                 s1 = Integer.toHexString(System.identityHashCode(this));
   3088                 s2 = mHeld ? "held; " : "";
   3089                 if (mRefCounted) {
   3090                     s3 = "refcounted: refcount = " + mRefCount;
   3091                 } else {
   3092                     s3 = "not refcounted";
   3093                 }
   3094                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
   3095             }
   3096         }
   3097 
   3098         @Override
   3099         protected void finalize() throws Throwable {
   3100             super.finalize();
   3101             synchronized (mBinder) {
   3102                 if (mHeld) {
   3103                     try {
   3104                         mService.releaseWifiLock(mBinder);
   3105                         synchronized (WifiManager.this) {
   3106                             mActiveLockCount--;
   3107                         }
   3108                     } catch (RemoteException e) {
   3109                         throw e.rethrowFromSystemServer();
   3110                     }
   3111                 }
   3112             }
   3113         }
   3114     }
   3115 
   3116     /**
   3117      * Creates a new WifiLock.
   3118      *
   3119      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL},
   3120      * {@link #WIFI_MODE_FULL_HIGH_PERF} and {@link #WIFI_MODE_SCAN_ONLY} for
   3121      * descriptions of the types of Wi-Fi locks.
   3122      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   3123      *            never shown to the user under normal conditions, but should be descriptive
   3124      *            enough to identify your application and the specific WifiLock within it, if it
   3125      *            holds multiple WifiLocks.
   3126      *
   3127      * @return a new, unacquired WifiLock with the given tag.
   3128      *
   3129      * @see WifiLock
   3130      */
   3131     public WifiLock createWifiLock(int lockType, String tag) {
   3132         return new WifiLock(lockType, tag);
   3133     }
   3134 
   3135     /**
   3136      * Creates a new WifiLock.
   3137      *
   3138      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
   3139      *            never shown to the user under normal conditions, but should be descriptive
   3140      *            enough to identify your application and the specific WifiLock within it, if it
   3141      *            holds multiple WifiLocks.
   3142      *
   3143      * @return a new, unacquired WifiLock with the given tag.
   3144      *
   3145      * @see WifiLock
   3146      */
   3147     public WifiLock createWifiLock(String tag) {
   3148         return new WifiLock(WIFI_MODE_FULL, tag);
   3149     }
   3150 
   3151 
   3152     /**
   3153      * Create a new MulticastLock
   3154      *
   3155      * @param tag a tag for the MulticastLock to identify it in debugging
   3156      *            messages.  This string is never shown to the user under
   3157      *            normal conditions, but should be descriptive enough to
   3158      *            identify your application and the specific MulticastLock
   3159      *            within it, if it holds multiple MulticastLocks.
   3160      *
   3161      * @return a new, unacquired MulticastLock with the given tag.
   3162      *
   3163      * @see MulticastLock
   3164      */
   3165     public MulticastLock createMulticastLock(String tag) {
   3166         return new MulticastLock(tag);
   3167     }
   3168 
   3169     /**
   3170      * Allows an application to receive Wifi Multicast packets.
   3171      * Normally the Wifi stack filters out packets not explicitly
   3172      * addressed to this device.  Acquring a MulticastLock will
   3173      * cause the stack to receive packets addressed to multicast
   3174      * addresses.  Processing these extra packets can cause a noticable
   3175      * battery drain and should be disabled when not needed.
   3176      */
   3177     public class MulticastLock {
   3178         private String mTag;
   3179         private final IBinder mBinder;
   3180         private int mRefCount;
   3181         private boolean mRefCounted;
   3182         private boolean mHeld;
   3183 
   3184         private MulticastLock(String tag) {
   3185             mTag = tag;
   3186             mBinder = new Binder();
   3187             mRefCount = 0;
   3188             mRefCounted = true;
   3189             mHeld = false;
   3190         }
   3191 
   3192         /**
   3193          * Locks Wifi Multicast on until {@link #release} is called.
   3194          *
   3195          * If this MulticastLock is reference-counted each call to
   3196          * {@code acquire} will increment the reference count, and the
   3197          * wifi interface will receive multicast packets as long as the
   3198          * reference count is above zero.
   3199          *
   3200          * If this MulticastLock is not reference-counted, the first call to
   3201          * {@code acquire} will turn on the multicast packets, but subsequent
   3202          * calls will be ignored.  Only one call to {@link #release} will
   3203          * be required, regardless of the number of times that {@code acquire}
   3204          * is called.
   3205          *
   3206          * Note that other applications may also lock Wifi Multicast on.
   3207          * Only they can relinquish their lock.
   3208          *
   3209          * Also note that applications cannot leave Multicast locked on.
   3210          * When an app exits or crashes, any Multicast locks will be released.
   3211          */
   3212         public void acquire() {
   3213             synchronized (mBinder) {
   3214                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
   3215                     try {
   3216                         mService.acquireMulticastLock(mBinder, mTag);
   3217                         synchronized (WifiManager.this) {
   3218                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
   3219                                 mService.releaseMulticastLock();
   3220                                 throw new UnsupportedOperationException(
   3221                                         "Exceeded maximum number of wifi locks");
   3222                             }
   3223                             mActiveLockCount++;
   3224                         }
   3225                     } catch (RemoteException e) {
   3226                         throw e.rethrowFromSystemServer();
   3227                     }
   3228                     mHeld = true;
   3229                 }
   3230             }
   3231         }
   3232 
   3233         /**
   3234          * Unlocks Wifi Multicast, restoring the filter of packets
   3235          * not addressed specifically to this device and saving power.
   3236          *
   3237          * If this MulticastLock is reference-counted, each call to
   3238          * {@code release} will decrement the reference count, and the
   3239          * multicast packets will only stop being received when the reference
   3240          * count reaches zero.  If the reference count goes below zero (that
   3241          * is, if {@code release} is called a greater number of times than
   3242          * {@link #acquire}), an exception is thrown.
   3243          *
   3244          * If this MulticastLock is not reference-counted, the first call to
   3245          * {@code release} (after the radio was multicast locked using
   3246          * {@link #acquire}) will unlock the multicast, and subsequent calls
   3247          * will be ignored.
   3248          *
   3249          * Note that if any other Wifi Multicast Locks are still outstanding
   3250          * this {@code release} call will not have an immediate effect.  Only
   3251          * when all applications have released all their Multicast Locks will
   3252          * the Multicast filter be turned back on.
   3253          *
   3254          * Also note that when an app exits or crashes all of its Multicast
   3255          * Locks will be automatically released.
   3256          */
   3257         public void release() {
   3258             synchronized (mBinder) {
   3259                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
   3260                     try {
   3261                         mService.releaseMulticastLock();
   3262                         synchronized (WifiManager.this) {
   3263                             mActiveLockCount--;
   3264                         }
   3265                     } catch (RemoteException e) {
   3266                         throw e.rethrowFromSystemServer();
   3267                     }
   3268                     mHeld = false;
   3269                 }
   3270                 if (mRefCount < 0) {
   3271                     throw new RuntimeException("MulticastLock under-locked "
   3272                             + mTag);
   3273                 }
   3274             }
   3275         }
   3276 
   3277         /**
   3278          * Controls whether this is a reference-counted or non-reference-
   3279          * counted MulticastLock.
   3280          *
   3281          * Reference-counted MulticastLocks keep track of the number of calls
   3282          * to {@link #acquire} and {@link #release}, and only stop the
   3283          * reception of multicast packets when every call to {@link #acquire}
   3284          * has been balanced with a call to {@link #release}.  Non-reference-
   3285          * counted MulticastLocks allow the reception of multicast packets
   3286          * whenever {@link #acquire} is called and stop accepting multicast
   3287          * packets whenever {@link #release} is called.
   3288          *
   3289          * @param refCounted true if this MulticastLock should keep a reference
   3290          * count
   3291          */
   3292         public void setReferenceCounted(boolean refCounted) {
   3293             mRefCounted = refCounted;
   3294         }
   3295 
   3296         /**
   3297          * Checks whether this MulticastLock is currently held.
   3298          *
   3299          * @return true if this MulticastLock is held, false otherwise
   3300          */
   3301         public boolean isHeld() {
   3302             synchronized (mBinder) {
   3303                 return mHeld;
   3304             }
   3305         }
   3306 
   3307         public String toString() {
   3308             String s1, s2, s3;
   3309             synchronized (mBinder) {
   3310                 s1 = Integer.toHexString(System.identityHashCode(this));
   3311                 s2 = mHeld ? "held; " : "";
   3312                 if (mRefCounted) {
   3313                     s3 = "refcounted: refcount = " + mRefCount;
   3314                 } else {
   3315                     s3 = "not refcounted";
   3316                 }
   3317                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
   3318             }
   3319         }
   3320 
   3321         @Override
   3322         protected void finalize() throws Throwable {
   3323             super.finalize();
   3324             setReferenceCounted(false);
   3325             release();
   3326         }
   3327     }
   3328 
   3329     /**
   3330      * Check multicast filter status.
   3331      *
   3332      * @return true if multicast packets are allowed.
   3333      *
   3334      * @hide pending API council approval
   3335      */
   3336     public boolean isMulticastEnabled() {
   3337         try {
   3338             return mService.isMulticastEnabled();
   3339         } catch (RemoteException e) {
   3340             throw e.rethrowFromSystemServer();
   3341         }
   3342     }
   3343 
   3344     /**
   3345      * Initialize the multicast filtering to 'on'
   3346      * @hide no intent to publish
   3347      */
   3348     public boolean initializeMulticastFiltering() {
   3349         try {
   3350             mService.initializeMulticastFiltering();
   3351             return true;
   3352         } catch (RemoteException e) {
   3353             throw e.rethrowFromSystemServer();
   3354         }
   3355     }
   3356 
   3357     protected void finalize() throws Throwable {
   3358         try {
   3359             if (mAsyncChannel != null) {
   3360                 mAsyncChannel.disconnect();
   3361             }
   3362         } finally {
   3363             super.finalize();
   3364         }
   3365     }
   3366 
   3367     /**
   3368      * Set wifi verbose log. Called from developer settings.
   3369      * @hide
   3370      */
   3371     public void enableVerboseLogging (int verbose) {
   3372         try {
   3373             mService.enableVerboseLogging(verbose);
   3374         } catch (Exception e) {
   3375             //ignore any failure here
   3376             Log.e(TAG, "enableVerboseLogging " + e.toString());
   3377         }
   3378     }
   3379 
   3380     /**
   3381      * Get the WiFi verbose logging level.This is used by settings
   3382      * to decide what to show within the picker.
   3383      * @hide
   3384      */
   3385     public int getVerboseLoggingLevel() {
   3386         try {
   3387             return mService.getVerboseLoggingLevel();
   3388         } catch (RemoteException e) {
   3389             throw e.rethrowFromSystemServer();
   3390         }
   3391     }
   3392 
   3393     /**
   3394      * Set wifi Aggressive Handover. Called from developer settings.
   3395      * @hide
   3396      */
   3397     public void enableAggressiveHandover(int enabled) {
   3398         try {
   3399             mService.enableAggressiveHandover(enabled);
   3400         } catch (RemoteException e) {
   3401             throw e.rethrowFromSystemServer();
   3402         }
   3403     }
   3404 
   3405     /**
   3406      * Get the WiFi Handover aggressiveness.This is used by settings
   3407      * to decide what to show within the picker.
   3408      * @hide
   3409      */
   3410     public int getAggressiveHandover() {
   3411         try {
   3412             return mService.getAggressiveHandover();
   3413         } catch (RemoteException e) {
   3414             throw e.rethrowFromSystemServer();
   3415         }
   3416     }
   3417 
   3418     /**
   3419      * Set setting for allowing Scans when traffic is ongoing.
   3420      * @hide
   3421      */
   3422     public void setAllowScansWithTraffic(int enabled) {
   3423         try {
   3424             mService.setAllowScansWithTraffic(enabled);
   3425         } catch (RemoteException e) {
   3426             throw e.rethrowFromSystemServer();
   3427         }
   3428     }
   3429 
   3430     /**
   3431      * Get setting for allowing Scans when traffic is ongoing.
   3432      * @hide
   3433      */
   3434     public int getAllowScansWithTraffic() {
   3435         try {
   3436             return mService.getAllowScansWithTraffic();
   3437         } catch (RemoteException e) {
   3438             throw e.rethrowFromSystemServer();
   3439         }
   3440     }
   3441 
   3442     /**
   3443      * Resets all wifi manager settings back to factory defaults.
   3444      *
   3445      * @hide
   3446      */
   3447     public void factoryReset() {
   3448         try {
   3449             mService.factoryReset();
   3450         } catch (RemoteException e) {
   3451             throw e.rethrowFromSystemServer();
   3452         }
   3453     }
   3454 
   3455     /**
   3456      * Get Network object of current wifi network
   3457      * @return Get Network object of current wifi network
   3458      * @hide
   3459      */
   3460     public Network getCurrentNetwork() {
   3461         try {
   3462             return mService.getCurrentNetwork();
   3463         } catch (RemoteException e) {
   3464             throw e.rethrowFromSystemServer();
   3465         }
   3466     }
   3467 
   3468     /**
   3469      * Framework layer autojoin enable/disable when device is associated
   3470      * this will enable/disable autojoin scan and switch network when connected
   3471      * @return true -- if set successful false -- if set failed
   3472      * @hide
   3473      */
   3474     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
   3475         try {
   3476             return mService.setEnableAutoJoinWhenAssociated(enabled);
   3477         } catch (RemoteException e) {
   3478             throw e.rethrowFromSystemServer();
   3479         }
   3480     }
   3481 
   3482     /**
   3483      * Get setting for Framework layer autojoin enable status
   3484      * @hide
   3485      */
   3486     public boolean getEnableAutoJoinWhenAssociated() {
   3487         try {
   3488             return mService.getEnableAutoJoinWhenAssociated();
   3489         } catch (RemoteException e) {
   3490             throw e.rethrowFromSystemServer();
   3491         }
   3492     }
   3493 
   3494     /**
   3495      * Enable/disable WifiConnectivityManager
   3496      * @hide
   3497      */
   3498     public void enableWifiConnectivityManager(boolean enabled) {
   3499         try {
   3500             mService.enableWifiConnectivityManager(enabled);
   3501         } catch (RemoteException e) {
   3502             throw e.rethrowFromSystemServer();
   3503         }
   3504     }
   3505 
   3506     /**
   3507      * Retrieve the data to be backed to save the current state.
   3508      * @hide
   3509      */
   3510     public byte[] retrieveBackupData() {
   3511         try {
   3512             return mService.retrieveBackupData();
   3513         } catch (RemoteException e) {
   3514             throw e.rethrowFromSystemServer();
   3515         }
   3516     }
   3517 
   3518     /**
   3519      * Restore state from the backed up data.
   3520      * @hide
   3521      */
   3522     public void restoreBackupData(byte[] data) {
   3523         try {
   3524             mService.restoreBackupData(data);
   3525         } catch (RemoteException e) {
   3526             throw e.rethrowFromSystemServer();
   3527         }
   3528     }
   3529 
   3530     /**
   3531      * Restore state from the older version of back up data.
   3532      * The old backup data was essentially a backup of wpa_supplicant.conf
   3533      * and ipconfig.txt file.
   3534      * @hide
   3535      */
   3536     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
   3537         try {
   3538             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
   3539         } catch (RemoteException e) {
   3540             throw e.rethrowFromSystemServer();
   3541         }
   3542     }
   3543 }
   3544