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