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      */
WifiManager(Context context, IWifiManager service, Looper looper)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      */
getConfiguredNetworks()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)
getPrivilegedConfiguredNetworks()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)
getConnectionStatistics()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      */
getMatchingWifiConfig(ScanResult scanResult)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      */
addNetwork(WifiConfiguration config)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      */
updateNetwork(WifiConfiguration config)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      */
addOrUpdateNetwork(WifiConfiguration config)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      */
addOrUpdatePasspointConfiguration(PasspointConfiguration config)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      */
removePasspointConfiguration(String fqdn)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      */
getPasspointConfigurations()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      */
queryPasspointIcon(long bssid, String fileName)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      */
matchProviderWithCurrentNetwork(String fqdn)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      */
deauthenticateNetwork(long holdoff, boolean ess)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      */
removeNetwork(int netId)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      */
enableNetwork(int netId, boolean attemptConnect)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