• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.Manifest.permission.ACCESS_FINE_LOCATION;
20 import static android.Manifest.permission.ACCESS_WIFI_STATE;
21 import static android.Manifest.permission.READ_WIFI_CREDENTIAL;
22 
23 import android.annotation.CallbackExecutor;
24 import android.annotation.IntDef;
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.annotation.RequiresPermission;
28 import android.annotation.SdkConstant;
29 import android.annotation.SdkConstant.SdkConstantType;
30 import android.annotation.SystemApi;
31 import android.annotation.SystemService;
32 import android.annotation.UnsupportedAppUsage;
33 import android.app.ActivityManager;
34 import android.content.Context;
35 import android.content.pm.ParceledListSlice;
36 import android.net.ConnectivityManager;
37 import android.net.DhcpInfo;
38 import android.net.Network;
39 import android.net.NetworkCapabilities;
40 import android.net.NetworkRequest;
41 import android.net.wifi.hotspot2.IProvisioningCallback;
42 import android.net.wifi.hotspot2.OsuProvider;
43 import android.net.wifi.hotspot2.PasspointConfiguration;
44 import android.net.wifi.hotspot2.ProvisioningCallback;
45 import android.os.Binder;
46 import android.os.Build;
47 import android.os.Handler;
48 import android.os.IBinder;
49 import android.os.Looper;
50 import android.os.Message;
51 import android.os.Messenger;
52 import android.os.RemoteException;
53 import android.os.WorkSource;
54 import android.util.Log;
55 import android.util.Pair;
56 import android.util.SparseArray;
57 
58 import com.android.internal.annotations.GuardedBy;
59 import com.android.internal.annotations.VisibleForTesting;
60 import com.android.internal.util.AsyncChannel;
61 import com.android.internal.util.Protocol;
62 import com.android.server.net.NetworkPinner;
63 
64 import dalvik.system.CloseGuard;
65 
66 import java.lang.annotation.Retention;
67 import java.lang.annotation.RetentionPolicy;
68 import java.lang.ref.WeakReference;
69 import java.net.InetAddress;
70 import java.util.ArrayList;
71 import java.util.Collections;
72 import java.util.HashMap;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Set;
76 import java.util.concurrent.CountDownLatch;
77 import java.util.concurrent.Executor;
78 
79 /**
80  * This class provides the primary API for managing all aspects of Wi-Fi
81  * connectivity.
82  * <p>
83  * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
84  * should only be obtained from an {@linkplain Context#getApplicationContext()
85  * application context}, and not from any other derived context to avoid memory
86  * leaks within the calling process.
87  * <p>
88  * It deals with several categories of items:
89  * </p>
90  * <ul>
91  * <li>The list of configured networks. The list can be viewed and updated, and
92  * attributes of individual entries can be modified.</li>
93  * <li>The currently active Wi-Fi network, if any. Connectivity can be
94  * established or torn down, and dynamic information about the state of the
95  * network can be queried.</li>
96  * <li>Results of access point scans, containing enough information to make
97  * decisions about what access point to connect to.</li>
98  * <li>It defines the names of various Intent actions that are broadcast upon
99  * any sort of change in Wi-Fi state.
100  * </ul>
101  * <p>
102  * This is the API to use when performing Wi-Fi specific operations. To perform
103  * operations that pertain to network connectivity at an abstract level, use
104  * {@link android.net.ConnectivityManager}.
105  * </p>
106  */
107 @SystemService(Context.WIFI_SERVICE)
108 public class WifiManager {
109 
110     private static final String TAG = "WifiManager";
111     // Supplicant error codes:
112     /**
113      * The error code if there was a problem authenticating.
114      * @deprecated This is no longer supported.
115      */
116     @Deprecated
117     public static final int ERROR_AUTHENTICATING = 1;
118 
119     /**
120      * The reason code if there is no error during authentication.
121      * It could also imply that there no authentication in progress,
122      * this reason code also serves as a reset value.
123      * @deprecated This is no longer supported.
124      * @hide
125      */
126     @Deprecated
127     public static final int ERROR_AUTH_FAILURE_NONE = 0;
128 
129     /**
130      * The reason code if there was a timeout authenticating.
131      * @deprecated This is no longer supported.
132      * @hide
133      */
134     @Deprecated
135     public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
136 
137     /**
138      * The reason code if there was a wrong password while
139      * authenticating.
140      * @deprecated This is no longer supported.
141      * @hide
142      */
143     @Deprecated
144     public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
145 
146     /**
147      * The reason code if there was EAP failure while
148      * authenticating.
149      * @deprecated This is no longer supported.
150      * @hide
151      */
152     @Deprecated
153     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
154 
155     /**
156      * Maximum number of active network suggestions allowed per app.
157      * @hide
158      */
159     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP =
160             ActivityManager.isLowRamDeviceStatic() ? 256 : 1024;
161 
162     /**
163      * Reason code if all of the network suggestions were successfully added or removed.
164      */
165     public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0;
166 
167     /**
168      * Reason code if there was an internal error in the platform while processing the addition or
169      * removal of suggestions.
170      */
171     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1;
172 
173     /**
174      * Reason code if the user has disallowed "android:change_wifi_state" app-ops from the app.
175      * @see android.app.AppOpsManager#unsafeCheckOp(String, int, String).
176      */
177     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2;
178 
179     /**
180      * Reason code if one or more of the network suggestions added already exists in platform's
181      * database.
182      * @see WifiNetworkSuggestion#equals(Object)
183      */
184     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
185 
186     /**
187      * Reason code if the number of network suggestions provided by the app crosses the max
188      * threshold set per app.
189      * @see #getMaxNumberOfNetworkSuggestionsPerApp()
190      */
191     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
192 
193     /**
194      * Reason code if one or more of the network suggestions removed does not exist in platform's
195      * database.
196      */
197     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
198 
199     /** @hide */
200     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
201             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
202             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
203             STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED,
204             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
205             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
206             STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
207     })
208     @Retention(RetentionPolicy.SOURCE)
209     public @interface NetworkSuggestionsStatusCode {}
210 
211     /**
212      * Broadcast intent action indicating whether Wi-Fi scanning is allowed currently
213      * @hide
214      */
215     public static final String WIFI_SCAN_AVAILABLE = "wifi_scan_available";
216 
217     /**
218      * Extra int indicating scan availability, WIFI_STATE_ENABLED and WIFI_STATE_DISABLED
219      * @hide
220      */
221     public static final String EXTRA_SCAN_AVAILABLE = "scan_enabled";
222 
223     /**
224      * Broadcast intent action indicating that the credential of a Wi-Fi network
225      * has been changed. One extra provides the ssid of the network. Another
226      * extra provides the event type, whether the credential is saved or forgot.
227      * @hide
228      */
229     @SystemApi
230     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
231             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
232     /** @hide */
233     @SystemApi
234     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
235     /** @hide */
236     @SystemApi
237     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
238     /** @hide */
239     @SystemApi
240     public static final int WIFI_CREDENTIAL_SAVED = 0;
241     /** @hide */
242     @SystemApi
243     public static final int WIFI_CREDENTIAL_FORGOT = 1;
244 
245     /** @hide */
246     @SystemApi
247     public static final int PASSPOINT_HOME_NETWORK = 0;
248 
249     /** @hide */
250     @SystemApi
251     public static final int PASSPOINT_ROAMING_NETWORK = 1;
252 
253     /**
254      * Broadcast intent action indicating that a Passpoint provider icon has been received.
255      *
256      * Included extras:
257      * {@link #EXTRA_BSSID_LONG}
258      * {@link #EXTRA_FILENAME}
259      * {@link #EXTRA_ICON}
260      *
261      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
262      *
263      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
264      * components will be launched.
265      *
266      * @hide
267      */
268     public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
269     /**
270      * BSSID of an AP in long representation.  The {@link #EXTRA_BSSID} contains BSSID in
271      * String representation.
272      *
273      * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}.
274      *
275      * @hide
276      */
277     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
278     /**
279      * Icon data.
280      *
281      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
282      * {@link android.graphics.drawable.Icon}.
283      *
284      * @hide
285      */
286     public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
287     /**
288      * Name of a file.
289      *
290      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
291      *
292      * @hide
293      */
294     public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
295 
296     /**
297      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
298      *
299      * Included extras:
300      * {@link #EXTRA_BSSID_LONG}
301      * {@link #EXTRA_ANQP_ELEMENT_DATA}
302      *
303      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
304      *
305      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
306      * components will be launched.
307      *
308      * @hide
309      */
310     public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
311             "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
312     /**
313      * Raw binary data of an ANQP (Access Network Query Protocol) element.
314      *
315      * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}.
316      *
317      * @hide
318      */
319     public static final String EXTRA_ANQP_ELEMENT_DATA =
320             "android.net.wifi.extra.ANQP_ELEMENT_DATA";
321 
322     /**
323      * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
324      *
325      * Included extras:
326      * {@link #EXTRA_BSSID_LONG}
327      * {@link #EXTRA_ESS}
328      * {@link #EXTRA_DELAY}
329      * {@link #EXTRA_URL}
330      *
331      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
332      *
333      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
334      * components will be launched.
335      *
336      * @hide
337      */
338     public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
339             "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
340     /**
341      * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to
342      * {@code true} for ESS.
343      *
344      * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}.
345      *
346      * @hide
347      */
348     public static final String EXTRA_ESS = "android.net.wifi.extra.ESS";
349     /**
350      * Delay in seconds.
351      *
352      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
353      *
354      * @hide
355      */
356     public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
357     /**
358      * String representation of an URL.
359      *
360      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
361      *
362      * @hide
363      */
364     public static final String EXTRA_URL = "android.net.wifi.extra.URL";
365 
366     /**
367      * Broadcast intent action indicating a Passpoint subscription remediation frame has been
368      * received.
369      *
370      * Included extras:
371      * {@link #EXTRA_BSSID_LONG}
372      * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD}
373      * {@link #EXTRA_URL}
374      *
375      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
376      *
377      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
378      * components will be launched.
379      *
380      * @hide
381      */
382     public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
383             "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
384     /**
385      * The protocol supported by the subscription remediation server. The possible values are:
386      * 0 - OMA DM
387      * 1 - SOAP XML SPP
388      *
389      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
390      *
391      * @hide
392      */
393     public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD =
394             "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
395 
396     /**
397      * Activity Action: lunch OSU (Online Sign Up) view.
398      * Included extras:
399      *
400      * {@link #EXTRA_OSU_NETWORK}: {@link Network} instance associated with OSU AP.
401      * {@link #EXTRA_URL}: String representation of a server URL used for OSU process.
402      *
403      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
404      * components will be launched.
405      *
406      * @hide
407      */
408     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
409     public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW =
410             "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
411 
412     /**
413      * The lookup key for a {@link android.net.Network} associated with OSU server.
414      *
415      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
416      *
417      * @hide
418      */
419     public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
420 
421     /**
422      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
423      * enabling, disabling, or unknown. One extra provides this state as an int.
424      * Another extra provides the previous state, if available.
425      *
426      * @see #EXTRA_WIFI_STATE
427      * @see #EXTRA_PREVIOUS_WIFI_STATE
428      */
429     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
430     public static final String WIFI_STATE_CHANGED_ACTION =
431         "android.net.wifi.WIFI_STATE_CHANGED";
432     /**
433      * The lookup key for an int that indicates whether Wi-Fi is enabled,
434      * disabled, enabling, disabling, or unknown.  Retrieve it with
435      * {@link android.content.Intent#getIntExtra(String,int)}.
436      *
437      * @see #WIFI_STATE_DISABLED
438      * @see #WIFI_STATE_DISABLING
439      * @see #WIFI_STATE_ENABLED
440      * @see #WIFI_STATE_ENABLING
441      * @see #WIFI_STATE_UNKNOWN
442      */
443     public static final String EXTRA_WIFI_STATE = "wifi_state";
444     /**
445      * The previous Wi-Fi state.
446      *
447      * @see #EXTRA_WIFI_STATE
448      */
449     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
450 
451     /**
452      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
453      * it finishes successfully.
454      *
455      * @see #WIFI_STATE_CHANGED_ACTION
456      * @see #getWifiState()
457      */
458     public static final int WIFI_STATE_DISABLING = 0;
459     /**
460      * Wi-Fi is disabled.
461      *
462      * @see #WIFI_STATE_CHANGED_ACTION
463      * @see #getWifiState()
464      */
465     public static final int WIFI_STATE_DISABLED = 1;
466     /**
467      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
468      * it finishes successfully.
469      *
470      * @see #WIFI_STATE_CHANGED_ACTION
471      * @see #getWifiState()
472      */
473     public static final int WIFI_STATE_ENABLING = 2;
474     /**
475      * Wi-Fi is enabled.
476      *
477      * @see #WIFI_STATE_CHANGED_ACTION
478      * @see #getWifiState()
479      */
480     public static final int WIFI_STATE_ENABLED = 3;
481     /**
482      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
483      * or disabling.
484      *
485      * @see #WIFI_STATE_CHANGED_ACTION
486      * @see #getWifiState()
487      */
488     public static final int WIFI_STATE_UNKNOWN = 4;
489 
490     /**
491      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
492      * enabling, disabling, or failed.
493      *
494      * @hide
495      */
496     @SystemApi
497     public static final String WIFI_AP_STATE_CHANGED_ACTION =
498         "android.net.wifi.WIFI_AP_STATE_CHANGED";
499 
500     /**
501      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
502      * disabled, enabling, disabling, or failed.  Retrieve it with
503      * {@link android.content.Intent#getIntExtra(String,int)}.
504      *
505      * @see #WIFI_AP_STATE_DISABLED
506      * @see #WIFI_AP_STATE_DISABLING
507      * @see #WIFI_AP_STATE_ENABLED
508      * @see #WIFI_AP_STATE_ENABLING
509      * @see #WIFI_AP_STATE_FAILED
510      *
511      * @hide
512      */
513     @SystemApi
514     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
515 
516     /**
517      * The look up key for an int that indicates why softAP started failed
518      * currently support general and no_channel
519      * @see #SAP_START_FAILURE_GENERAL
520      * @see #SAP_START_FAILURE_NO_CHANNEL
521      *
522      * @hide
523      */
524     public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
525     /**
526      * The previous Wi-Fi state.
527      *
528      * @see #EXTRA_WIFI_AP_STATE
529      *
530      * @hide
531      */
532     @SystemApi
533     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
534     /**
535      * The interface used for the softap.
536      *
537      * @hide
538      */
539     public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "wifi_ap_interface_name";
540     /**
541      * The intended ip mode for this softap.
542      * @see #IFACE_IP_MODE_TETHERED
543      * @see #IFACE_IP_MODE_LOCAL_ONLY
544      *
545      * @hide
546      */
547     public static final String EXTRA_WIFI_AP_MODE = "wifi_ap_mode";
548 
549     /** @hide */
550     @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
551         WIFI_AP_STATE_DISABLING,
552         WIFI_AP_STATE_DISABLED,
553         WIFI_AP_STATE_ENABLING,
554         WIFI_AP_STATE_ENABLED,
555         WIFI_AP_STATE_FAILED,
556     })
557     @Retention(RetentionPolicy.SOURCE)
558     public @interface WifiApState {}
559 
560     /**
561      * Wi-Fi AP is currently being disabled. The state will change to
562      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
563      *
564      * @see #WIFI_AP_STATE_CHANGED_ACTION
565      * @see #getWifiApState()
566      *
567      * @hide
568      */
569     @SystemApi
570     public static final int WIFI_AP_STATE_DISABLING = 10;
571     /**
572      * Wi-Fi AP is disabled.
573      *
574      * @see #WIFI_AP_STATE_CHANGED_ACTION
575      * @see #getWifiState()
576      *
577      * @hide
578      */
579     @SystemApi
580     public static final int WIFI_AP_STATE_DISABLED = 11;
581     /**
582      * Wi-Fi AP is currently being enabled. The state will change to
583      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
584      *
585      * @see #WIFI_AP_STATE_CHANGED_ACTION
586      * @see #getWifiApState()
587      *
588      * @hide
589      */
590     @SystemApi
591     public static final int WIFI_AP_STATE_ENABLING = 12;
592     /**
593      * Wi-Fi AP is enabled.
594      *
595      * @see #WIFI_AP_STATE_CHANGED_ACTION
596      * @see #getWifiApState()
597      *
598      * @hide
599      */
600     @SystemApi
601     public static final int WIFI_AP_STATE_ENABLED = 13;
602     /**
603      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
604      * enabling or disabling
605      *
606      * @see #WIFI_AP_STATE_CHANGED_ACTION
607      * @see #getWifiApState()
608      *
609      * @hide
610      */
611     @SystemApi
612     public static final int WIFI_AP_STATE_FAILED = 14;
613 
614     /** @hide */
615     @IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = {
616         SAP_START_FAILURE_GENERAL,
617         SAP_START_FAILURE_NO_CHANNEL,
618     })
619     @Retention(RetentionPolicy.SOURCE)
620     public @interface SapStartFailure {}
621 
622     /**
623      *  All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL}.
624      *
625      *  @hide
626      */
627     public static final int SAP_START_FAILURE_GENERAL= 0;
628 
629     /**
630      *  If Wi-Fi AP start failed, this reason code means that no legal channel exists on user
631      *  selected band due to regulatory constraints.
632      *
633      *  @hide
634      */
635     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
636 
637     /**
638      * Interface IP mode unspecified.
639      *
640      * @see updateInterfaceIpState(String, int)
641      *
642      * @hide
643      */
644     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
645 
646     /**
647      * Interface IP mode for configuration error.
648      *
649      * @see updateInterfaceIpState(String, int)
650      *
651      * @hide
652      */
653     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
654 
655     /**
656      * Interface IP mode for tethering.
657      *
658      * @see updateInterfaceIpState(String, int)
659      *
660      * @hide
661      */
662     public static final int IFACE_IP_MODE_TETHERED = 1;
663 
664     /**
665      * Interface IP mode for Local Only Hotspot.
666      *
667      * @see updateInterfaceIpState(String, int)
668      *
669      * @hide
670      */
671     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
672 
673     /**
674      * Broadcast intent action indicating that a connection to the supplicant has
675      * been established (and it is now possible
676      * to perform Wi-Fi operations) or the connection to the supplicant has been
677      * lost. One extra provides the connection state as a boolean, where {@code true}
678      * means CONNECTED.
679      * @deprecated This is no longer supported.
680      * @see #EXTRA_SUPPLICANT_CONNECTED
681      */
682     @Deprecated
683     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
684     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
685         "android.net.wifi.supplicant.CONNECTION_CHANGE";
686     /**
687      * The lookup key for a boolean that indicates whether a connection to
688      * the supplicant daemon has been gained or lost. {@code true} means
689      * a connection now exists.
690      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
691      * @deprecated This is no longer supported.
692      */
693     @Deprecated
694     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
695     /**
696      * Broadcast intent action indicating that the state of Wi-Fi connectivity
697      * has changed. An extra provides the new state
698      * in the form of a {@link android.net.NetworkInfo} object.
699      * @see #EXTRA_NETWORK_INFO
700      */
701     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
702     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
703     /**
704      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
705      * Wi-Fi network. Retrieve with
706      * {@link android.content.Intent#getParcelableExtra(String)}.
707      */
708     public static final String EXTRA_NETWORK_INFO = "networkInfo";
709     /**
710      * The lookup key for a String giving the BSSID of the access point to which
711      * we are connected. No longer used.
712      */
713     @Deprecated
714     public static final String EXTRA_BSSID = "bssid";
715     /**
716      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
717      * information about the access point to which we are connected.
718      * No longer used.
719      */
720     @Deprecated
721     public static final String EXTRA_WIFI_INFO = "wifiInfo";
722     /**
723      * Broadcast intent action indicating that the state of establishing a connection to
724      * an access point has changed.One extra provides the new
725      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
726      * is not generally the most useful thing to look at if you are just interested in
727      * the overall state of connectivity.
728      * @see #EXTRA_NEW_STATE
729      * @see #EXTRA_SUPPLICANT_ERROR
730      * @deprecated This is no longer supported.
731      */
732     @Deprecated
733     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
734     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
735         "android.net.wifi.supplicant.STATE_CHANGE";
736     /**
737      * The lookup key for a {@link SupplicantState} describing the new state
738      * Retrieve with
739      * {@link android.content.Intent#getParcelableExtra(String)}.
740      * @deprecated This is no longer supported.
741      */
742     @Deprecated
743     public static final String EXTRA_NEW_STATE = "newState";
744 
745     /**
746      * The lookup key for a {@link SupplicantState} describing the supplicant
747      * error code if any
748      * Retrieve with
749      * {@link android.content.Intent#getIntExtra(String, int)}.
750      * @see #ERROR_AUTHENTICATING
751      * @deprecated This is no longer supported.
752      */
753     @Deprecated
754     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
755 
756     /**
757      * The lookup key for a {@link SupplicantState} describing the supplicant
758      * error reason if any
759      * Retrieve with
760      * {@link android.content.Intent#getIntExtra(String, int)}.
761      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
762      * @deprecated This is no longer supported.
763      * @hide
764      */
765     @Deprecated
766     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
767 
768     /**
769      * Broadcast intent action indicating that the configured networks changed.
770      * This can be as a result of adding/updating/deleting a network. If
771      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set to true the new configuration
772      * can be retreived with the {@link #EXTRA_WIFI_CONFIGURATION} extra. If multiple
773      * Wi-Fi configurations changed, {@link #EXTRA_WIFI_CONFIGURATION} will not be present.
774      * @hide
775      */
776     @SystemApi
777     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
778         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
779     /**
780      * The lookup key for a (@link android.net.wifi.WifiConfiguration} object representing
781      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
782      * broadcast is sent.
783      * @hide
784      */
785     @SystemApi
786     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
787     /**
788      * Multiple network configurations have changed.
789      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
790      *
791      * @hide
792      */
793     @SystemApi
794     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
795     /**
796      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
797      * has changed. Only present if {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is {@code false}
798      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
799      * @hide
800      */
801     @SystemApi
802     public static final String EXTRA_CHANGE_REASON = "changeReason";
803     /**
804      * The configuration is new and was added.
805      * @hide
806      */
807     @SystemApi
808     public static final int CHANGE_REASON_ADDED = 0;
809     /**
810      * The configuration was removed and is no longer present in the system's list of
811      * configured networks.
812      * @hide
813      */
814     @SystemApi
815     public static final int CHANGE_REASON_REMOVED = 1;
816     /**
817      * The configuration has changed as a result of explicit action or because the system
818      * took an automated action such as disabling a malfunctioning configuration.
819      * @hide
820      */
821     @SystemApi
822     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
823     /**
824      * An access point scan has completed, and results are available.
825      * Call {@link #getScanResults()} to obtain the results.
826      * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
827      * and a {@code boolean} value indicating if the scan was successful.
828      */
829     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
830     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
831 
832     /**
833      * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
834      * representing if the scan was successful or not.
835      * Scans may fail for multiple reasons, these may include:
836      * <ol>
837      * <li>An app requested too many scans in a certain period of time.
838      * This may lead to additional scan request rejections via "scan throttling" for both
839      * foreground and background apps.
840      * Note: Apps holding android.Manifest.permission.NETWORK_SETTINGS permission are
841      * exempted from scan throttling.
842      * </li>
843      * <li>The device is idle and scanning is disabled.</li>
844      * <li>Wifi hardware reported a scan failure.</li>
845      * </ol>
846      * @return true scan was successful, results are updated
847      * @return false scan was not successful, results haven't been updated since previous scan
848      */
849     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
850 
851     /**
852      * A batch of access point scans has been completed and the results areavailable.
853      * Call {@link #getBatchedScanResults()} to obtain the results.
854      * @deprecated This API is nolonger supported.
855      * Use {@link android.net.wifi.WifiScanner} API
856      * @hide
857      */
858     @Deprecated
859     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
860     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
861             "android.net.wifi.BATCHED_RESULTS";
862 
863     /**
864      * The RSSI (signal strength) has changed.
865      *
866      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
867      * @see {@link #EXTRA_NEW_RSSI}
868      */
869     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
870     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
871     /**
872      * The lookup key for an {@code int} giving the new RSSI in dBm.
873      */
874     public static final String EXTRA_NEW_RSSI = "newRssi";
875 
876     /**
877      * Broadcast intent action indicating that the link configuration
878      * changed on wifi.
879      * @hide
880      */
881     @UnsupportedAppUsage
882     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
883         "android.net.wifi.LINK_CONFIGURATION_CHANGED";
884 
885     /**
886      * The lookup key for a {@link android.net.LinkProperties} object associated with the
887      * Wi-Fi network. Retrieve with
888      * {@link android.content.Intent#getParcelableExtra(String)}.
889      * @hide
890      */
891     public static final String EXTRA_LINK_PROPERTIES = "linkProperties";
892 
893     /**
894      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
895      * Wi-Fi network. Retrieve with
896      * {@link android.content.Intent#getParcelableExtra(String)}.
897      * @hide
898      */
899     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
900 
901     /**
902      * The network IDs of the configured networks could have changed.
903      */
904     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
905     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
906 
907     /**
908      * Activity Action: Show a system activity that allows the user to enable
909      * scans to be available even with Wi-Fi turned off.
910      *
911      * <p>Notification of the result of this activity is posted using the
912      * {@link android.app.Activity#onActivityResult} callback. The
913      * <code>resultCode</code>
914      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
915      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
916      * has rejected the request or an error has occurred.
917      */
918     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
919     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
920             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
921 
922     /**
923      * Activity Action: Pick a Wi-Fi network to connect to.
924      * <p>Input: Nothing.
925      * <p>Output: Nothing.
926      */
927     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
928     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
929 
930     /**
931      * Activity Action: Show UI to get user approval to enable WiFi.
932      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
933      *           the name of the app requesting the action.
934      * <p>Output: Nothing.
935      *
936      * @hide
937      */
938     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
939     public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
940 
941     /**
942      * Activity Action: Show UI to get user approval to disable WiFi.
943      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
944      *           the name of the app requesting the action.
945      * <p>Output: Nothing.
946      *
947      * @hide
948      */
949     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
950     public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
951 
952     /**
953      * Directed broadcast intent action indicating that the device has connected to one of the
954      * network suggestions provided by the app. This will be sent post connection to a network
955      * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
956      * boolean)}
957      * flag set.
958      * <p>
959      * Note: The broadcast is sent to the app only if it holds
960      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
961      *
962      * @see #EXTRA_NETWORK_SUGGESTION
963      */
964     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
965     public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION =
966             "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
967     /**
968      * Sent as as a part of {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} that holds
969      * an instance of {@link WifiNetworkSuggestion} corresponding to the connected network.
970      */
971     public static final String EXTRA_NETWORK_SUGGESTION =
972             "android.net.wifi.extra.NETWORK_SUGGESTION";
973 
974     /**
975      * Internally used Wi-Fi lock mode representing the case were no locks are held.
976      * @hide
977      */
978     public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
979 
980     /**
981      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
982      * and will behave normally, i.e., it will attempt to automatically
983      * establish a connection to a remembered access point that is
984      * within range, and will do periodic scans if there are remembered
985      * access points but none are in range.
986      *
987      * @deprecated This API is non-functional and will have no impact.
988      */
989     @Deprecated
990     public static final int WIFI_MODE_FULL = WifiProtoEnums.WIFI_MODE_FULL; // 1
991 
992     /**
993      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
994      * but the only operation that will be supported is initiation of
995      * scans, and the subsequent reporting of scan results. No attempts
996      * will be made to automatically connect to remembered access points,
997      * nor will periodic scans be automatically performed looking for
998      * remembered access points. Scans must be explicitly requested by
999      * an application in this mode.
1000      *
1001      * @deprecated This API is non-functional and will have no impact.
1002      */
1003     @Deprecated
1004     public static final int WIFI_MODE_SCAN_ONLY = WifiProtoEnums.WIFI_MODE_SCAN_ONLY; // 2
1005 
1006     /**
1007      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
1008      * This results in operating with low packet latency.
1009      * The lock is only active when the device is connected to an access point.
1010      * The lock is active even when the device screen is off or the acquiring application is
1011      * running in the background.
1012      * This mode will consume more power and hence should be used only
1013      * when there is a need for this tradeoff.
1014      * <p>
1015      * An example use case is when a voice connection needs to be
1016      * kept active even after the device screen goes off.
1017      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
1018      * duration of the voice call may improve the call quality.
1019      * <p>
1020      * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
1021      * lock will have no impact.
1022      */
1023     public static final int WIFI_MODE_FULL_HIGH_PERF = WifiProtoEnums.WIFI_MODE_FULL_HIGH_PERF; // 3
1024 
1025     /**
1026      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
1027      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock has the following limitations:
1028      * <ol>
1029      * <li>The lock is only active when the device is connected to an access point.</li>
1030      * <li>The lock is only active when the screen is on.</li>
1031      * <li>The lock is only active when the acquiring app is running in the foreground.</li>
1032      * </ol>
1033      * Low latency mode optimizes for reduced packet latency,
1034      * and as a result other performance measures may suffer when there are trade-offs to make:
1035      * <ol>
1036      * <li>Battery life may be reduced.</li>
1037      * <li>Throughput may be reduced.</li>
1038      * <li>Frequency of Wi-Fi scanning may be reduced. This may result in: </li>
1039      * <ul>
1040      * <li>The device may not roam or switch to the AP with highest signal quality.</li>
1041      * <li>Location accuracy may be reduced.</li>
1042      * </ul>
1043      * </ol>
1044      * <p>
1045      * Example use cases are real time gaming or virtual reality applications where
1046      * low latency is a key factor for user experience.
1047      * <p>
1048      * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and
1049      * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY}
1050      * lock will be effective when app is running in foreground and screen is on,
1051      * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
1052      */
1053     public static final int WIFI_MODE_FULL_LOW_LATENCY =
1054             WifiProtoEnums.WIFI_MODE_FULL_LOW_LATENCY; // 4
1055 
1056     /** Anything worse than or equal to this will show 0 bars. */
1057     @UnsupportedAppUsage
1058     private static final int MIN_RSSI = -100;
1059 
1060     /** Anything better than or equal to this will show the max bars. */
1061     @UnsupportedAppUsage
1062     private static final int MAX_RSSI = -55;
1063 
1064     /**
1065      * Number of RSSI levels used in the framework to initiate
1066      * {@link #RSSI_CHANGED_ACTION} broadcast
1067      * @hide
1068      */
1069     @UnsupportedAppUsage
1070     public static final int RSSI_LEVELS = 5;
1071 
1072     /**
1073      * Auto settings in the driver. The driver could choose to operate on both
1074      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
1075      * @hide
1076      */
1077     @UnsupportedAppUsage
1078     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
1079 
1080     /**
1081      * Operation on 5 GHz alone
1082      * @hide
1083      */
1084     @UnsupportedAppUsage
1085     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
1086 
1087     /**
1088      * Operation on 2.4 GHz alone
1089      * @hide
1090      */
1091     @UnsupportedAppUsage
1092     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
1093 
1094     /** @hide */
1095     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
1096 
1097     /* Maximum number of active locks we allow.
1098      * This limit was added to prevent apps from creating a ridiculous number
1099      * of locks and crashing the system by overflowing the global ref table.
1100      */
1101     private static final int MAX_ACTIVE_LOCKS = 50;
1102 
1103     /* Number of currently active WifiLocks and MulticastLocks */
1104     @UnsupportedAppUsage
1105     private int mActiveLockCount;
1106 
1107     private Context mContext;
1108     @UnsupportedAppUsage
1109     IWifiManager mService;
1110     private final int mTargetSdkVersion;
1111 
1112     private static final int INVALID_KEY = 0;
1113     private int mListenerKey = 1;
1114     private final SparseArray mListenerMap = new SparseArray();
1115     private final Object mListenerMapLock = new Object();
1116 
1117     private AsyncChannel mAsyncChannel;
1118     private CountDownLatch mConnected;
1119     private Looper mLooper;
1120     private boolean mVerboseLoggingEnabled = false;
1121 
1122     /* LocalOnlyHotspot callback message types */
1123     /** @hide */
1124     public static final int HOTSPOT_STARTED = 0;
1125     /** @hide */
1126     public static final int HOTSPOT_STOPPED = 1;
1127     /** @hide */
1128     public static final int HOTSPOT_FAILED = 2;
1129     /** @hide */
1130     public static final int HOTSPOT_OBSERVER_REGISTERED = 3;
1131 
1132     private final Object mLock = new Object(); // lock guarding access to the following vars
1133     @GuardedBy("mLock")
1134     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
1135     @GuardedBy("mLock")
1136     private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
1137 
1138     /**
1139      * Create a new WifiManager instance.
1140      * Applications will almost always want to use
1141      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
1142      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
1143      * @param context the application context
1144      * @param service the Binder interface
1145      * @hide - hide this because it takes in a parameter of type IWifiManager, which
1146      * is a system private class.
1147      */
WifiManager(Context context, IWifiManager service, Looper looper)1148     public WifiManager(Context context, IWifiManager service, Looper looper) {
1149         mContext = context;
1150         mService = service;
1151         mLooper = looper;
1152         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
1153         updateVerboseLoggingEnabledFromService();
1154     }
1155 
1156     /**
1157      * Return a list of all the networks configured for the current foreground
1158      * user.
1159      *
1160      * Not all fields of WifiConfiguration are returned. Only the following
1161      * fields are filled in:
1162      * <ul>
1163      * <li>networkId</li>
1164      * <li>SSID</li>
1165      * <li>BSSID</li>
1166      * <li>priority</li>
1167      * <li>allowedProtocols</li>
1168      * <li>allowedKeyManagement</li>
1169      * <li>allowedAuthAlgorithms</li>
1170      * <li>allowedPairwiseCiphers</li>
1171      * <li>allowedGroupCiphers</li>
1172      * </ul>
1173      * @return a list of network configurations in the form of a list
1174      * of {@link WifiConfiguration} objects.
1175      *
1176      * @deprecated
1177      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1178      * mechanism to trigger connection to a Wi-Fi network.
1179      * b) See {@link #addNetworkSuggestions(List)},
1180      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1181      * when auto-connecting to wifi.
1182      * <b>Compatibility Note:</b> For applications targeting
1183      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will return an empty list,
1184      * except for:
1185      * <ul>
1186      * <li>Device Owner (DO) & Profile Owner (PO) apps will have access to the full list.
1187      * <li>Callers with Carrier privilege will receive a restricted list only containing
1188      * configurations which they created.
1189      * </ul>
1190      */
1191     @Deprecated
1192     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
getConfiguredNetworks()1193     public List<WifiConfiguration> getConfiguredNetworks() {
1194         try {
1195             ParceledListSlice<WifiConfiguration> parceledList =
1196                     mService.getConfiguredNetworks(mContext.getOpPackageName());
1197             if (parceledList == null) {
1198                 return Collections.emptyList();
1199             }
1200             return parceledList.getList();
1201         } catch (RemoteException e) {
1202             throw e.rethrowFromSystemServer();
1203         }
1204     }
1205 
1206     /** @hide */
1207     @SystemApi
1208     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL})
getPrivilegedConfiguredNetworks()1209     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
1210         try {
1211             ParceledListSlice<WifiConfiguration> parceledList =
1212                     mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName());
1213             if (parceledList == null) {
1214                 return Collections.emptyList();
1215             }
1216             return parceledList.getList();
1217         } catch (RemoteException e) {
1218             throw e.rethrowFromSystemServer();
1219         }
1220     }
1221 
1222     /**
1223      * Returns a list of all matching WifiConfigurations for a given list of ScanResult.
1224      *
1225      * An empty list will be returned when no configurations are installed or if no configurations
1226      * match the ScanResult.
1227      *
1228      * @param scanResults a list of scanResult that represents the BSSID
1229      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
1230      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
1231      * @hide
1232      */
1233     @SystemApi
1234     @RequiresPermission(anyOf = {
1235             android.Manifest.permission.NETWORK_SETTINGS,
1236             android.Manifest.permission.NETWORK_SETUP_WIZARD
1237     })
1238     @NonNull
getAllMatchingWifiConfigs( @onNull List<ScanResult> scanResults)1239     public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
1240             @NonNull List<ScanResult> scanResults) {
1241         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
1242         try {
1243             Map<String, Map<Integer, List<ScanResult>>> results =
1244                     mService.getAllMatchingFqdnsForScanResults(
1245                             scanResults);
1246             if (results.isEmpty()) {
1247                 return configs;
1248             }
1249             List<WifiConfiguration> wifiConfigurations =
1250                     mService.getWifiConfigsForPasspointProfiles(
1251                             new ArrayList<>(results.keySet()));
1252             for (WifiConfiguration configuration : wifiConfigurations) {
1253                 Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
1254                         configuration.FQDN);
1255                 if (scanResultsPerNetworkType != null) {
1256                     configs.add(Pair.create(configuration, scanResultsPerNetworkType));
1257                 }
1258             }
1259         } catch (RemoteException e) {
1260             throw e.rethrowFromSystemServer();
1261         }
1262 
1263         return configs;
1264     }
1265 
1266     /**
1267      * Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
1268      * list of ScanResult.
1269      *
1270      * An empty list will be returned if no match is found.
1271      *
1272      * @param scanResults a list of ScanResult
1273      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
1274      * @hide
1275      */
1276     @SystemApi
1277     @RequiresPermission(anyOf = {
1278             android.Manifest.permission.NETWORK_SETTINGS,
1279             android.Manifest.permission.NETWORK_SETUP_WIZARD
1280     })
1281     @NonNull
getMatchingOsuProviders( @ullable List<ScanResult> scanResults)1282     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
1283             @Nullable List<ScanResult> scanResults) {
1284         if (scanResults == null) {
1285             return new HashMap<>();
1286         }
1287         try {
1288             return mService.getMatchingOsuProviders(scanResults);
1289         } catch (RemoteException e) {
1290             throw e.rethrowFromSystemServer();
1291         }
1292     }
1293 
1294     /**
1295      * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers.
1296      *
1297      * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2
1298      * configurations in the device.
1299      * An empty map will be returned when there is no matching Passpoint R2 configuration for the
1300      * given OsuProviders.
1301      *
1302      * @param osuProviders a set of {@link OsuProvider}
1303      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
1304      * @hide
1305      */
1306     @SystemApi
1307     @RequiresPermission(anyOf = {
1308             android.Manifest.permission.NETWORK_SETTINGS,
1309             android.Manifest.permission.NETWORK_SETUP_WIZARD
1310     })
1311     @NonNull
getMatchingPasspointConfigsForOsuProviders( @onNull Set<OsuProvider> osuProviders)1312     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
1313             @NonNull Set<OsuProvider> osuProviders) {
1314         try {
1315             return mService.getMatchingPasspointConfigsForOsuProviders(
1316                     new ArrayList<>(osuProviders));
1317         } catch (RemoteException e) {
1318             throw e.rethrowFromSystemServer();
1319         }
1320     }
1321 
1322     /**
1323      * Add a new network description to the set of configured networks.
1324      * The {@code networkId} field of the supplied configuration object
1325      * is ignored.
1326      * <p/>
1327      * The new network will be marked DISABLED by default. To enable it,
1328      * called {@link #enableNetwork}.
1329      *
1330      * @param config the set of variables that describe the configuration,
1331      *            contained in a {@link WifiConfiguration} object.
1332      *            If the {@link WifiConfiguration} has an Http Proxy set
1333      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
1334      * @return the ID of the newly created network description. This is used in
1335      *         other operations to specified the network to be acted upon.
1336      *         Returns {@code -1} on failure.
1337      *
1338      * @deprecated
1339      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1340      * mechanism to trigger connection to a Wi-Fi network.
1341      * b) See {@link #addNetworkSuggestions(List)},
1342      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1343      * when auto-connecting to wifi.
1344      * <b>Compatibility Note:</b> For applications targeting
1345      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
1346      */
1347     @Deprecated
addNetwork(WifiConfiguration config)1348     public int addNetwork(WifiConfiguration config) {
1349         if (config == null) {
1350             return -1;
1351         }
1352         config.networkId = -1;
1353         return addOrUpdateNetwork(config);
1354     }
1355 
1356     /**
1357      * Update the network description of an existing configured network.
1358      *
1359      * @param config the set of variables that describe the configuration,
1360      *            contained in a {@link WifiConfiguration} object. It may
1361      *            be sparse, so that only the items that are being changed
1362      *            are non-<code>null</code>. The {@code networkId} field
1363      *            must be set to the ID of the existing network being updated.
1364      *            If the {@link WifiConfiguration} has an Http Proxy set
1365      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
1366      * @return Returns the {@code networkId} of the supplied
1367      *         {@code WifiConfiguration} on success.
1368      *         <br/>
1369      *         Returns {@code -1} on failure, including when the {@code networkId}
1370      *         field of the {@code WifiConfiguration} does not refer to an
1371      *         existing network.
1372      *
1373      * @deprecated
1374      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1375      * mechanism to trigger connection to a Wi-Fi network.
1376      * b) See {@link #addNetworkSuggestions(List)},
1377      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1378      * when auto-connecting to wifi.
1379      * <b>Compatibility Note:</b> For applications targeting
1380      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
1381      */
1382     @Deprecated
updateNetwork(WifiConfiguration config)1383     public int updateNetwork(WifiConfiguration config) {
1384         if (config == null || config.networkId < 0) {
1385             return -1;
1386         }
1387         return addOrUpdateNetwork(config);
1388     }
1389 
1390     /**
1391      * Internal method for doing the RPC that creates a new network description
1392      * or updates an existing one.
1393      *
1394      * @param config The possibly sparse object containing the variables that
1395      *         are to set or updated in the network description.
1396      * @return the ID of the network on success, {@code -1} on failure.
1397      */
addOrUpdateNetwork(WifiConfiguration config)1398     private int addOrUpdateNetwork(WifiConfiguration config) {
1399         try {
1400             return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
1401         } catch (RemoteException e) {
1402             throw e.rethrowFromSystemServer();
1403         }
1404     }
1405 
1406     /**
1407      * Interface for indicating user selection from the list of networks presented in the
1408      * {@link NetworkRequestMatchCallback#onMatch(List)}.
1409      *
1410      * The platform will implement this callback and pass it along with the
1411      * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
1412      * NetworkRequestUserSelectionCallback)}. The UI component handling
1413      * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
1414      * {@link #reject()} to return the user's selection back to the platform via this callback.
1415      * @hide
1416      */
1417     public interface NetworkRequestUserSelectionCallback {
1418         /**
1419          * User selected this network to connect to.
1420          * @param wifiConfiguration WifiConfiguration object corresponding to the network
1421          *                          user selected.
1422          */
select(@onNull WifiConfiguration wifiConfiguration)1423         void select(@NonNull WifiConfiguration wifiConfiguration);
1424 
1425         /**
1426          * User rejected the app's request.
1427          */
reject()1428         void reject();
1429     }
1430 
1431     /**
1432      * Interface for network request callback. Should be implemented by applications and passed when
1433      * calling {@link #registerNetworkRequestMatchCallback(NetworkRequestMatchCallback, Handler)}.
1434      *
1435      * This is meant to be implemented by a UI component to present the user with a list of networks
1436      * matching the app's request. The user is allowed to pick one of these networks to connect to
1437      * or reject the request by the app.
1438      * @hide
1439      */
1440     public interface NetworkRequestMatchCallback {
1441         /**
1442          * Invoked to register a callback to be invoked to convey user selection. The callback
1443          * object paased in this method is to be invoked by the UI component after the service sends
1444          * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
1445          * from that list.
1446          *
1447          * @param userSelectionCallback Callback object to send back the user selection.
1448          */
onUserSelectionCallbackRegistration( @onNull NetworkRequestUserSelectionCallback userSelectionCallback)1449         void onUserSelectionCallbackRegistration(
1450                 @NonNull NetworkRequestUserSelectionCallback userSelectionCallback);
1451 
1452         /**
1453          * Invoked when the active network request is aborted, either because
1454          * <li> The app released the request, OR</li>
1455          * <li> Request was overridden by a new request</li>
1456          * This signals the end of processing for the current request and should stop the UI
1457          * component. No subsequent calls from the UI component will be handled by the platform.
1458          */
onAbort()1459         void onAbort();
1460 
1461         /**
1462          * Invoked when a network request initiated by an app matches some networks in scan results.
1463          * This may be invoked multiple times for a single network request as the platform finds new
1464          * matching networks in scan results.
1465          *
1466          * @param scanResults List of {@link ScanResult} objects corresponding to the networks
1467          *                    matching the request.
1468          */
onMatch(@onNull List<ScanResult> scanResults)1469         void onMatch(@NonNull List<ScanResult> scanResults);
1470 
1471         /**
1472          * Invoked on a successful connection with the network that the user selected
1473          * via {@link NetworkRequestUserSelectionCallback}.
1474          *
1475          * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
1476          *                          user selected.
1477          */
onUserSelectionConnectSuccess(@onNull WifiConfiguration wifiConfiguration)1478         void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration);
1479 
1480         /**
1481          * Invoked on failure to establish connection with the network that the user selected
1482          * via {@link NetworkRequestUserSelectionCallback}.
1483          *
1484          * @param wifiConfiguration WifiConfiguration object corresponding to the network
1485          *                          user selected.
1486          */
onUserSelectionConnectFailure(@onNull WifiConfiguration wifiConfiguration)1487         void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration);
1488     }
1489 
1490     /**
1491      * Callback proxy for NetworkRequestUserSelectionCallback objects.
1492      * @hide
1493      */
1494     private class NetworkRequestUserSelectionCallbackProxy implements
1495             NetworkRequestUserSelectionCallback {
1496         private final INetworkRequestUserSelectionCallback mCallback;
1497 
NetworkRequestUserSelectionCallbackProxy( INetworkRequestUserSelectionCallback callback)1498         NetworkRequestUserSelectionCallbackProxy(
1499                 INetworkRequestUserSelectionCallback callback) {
1500             mCallback = callback;
1501         }
1502 
1503         @Override
select(@onNull WifiConfiguration wifiConfiguration)1504         public void select(@NonNull WifiConfiguration wifiConfiguration) {
1505             if (mVerboseLoggingEnabled) {
1506                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
1507                         + "wificonfiguration: " + wifiConfiguration);
1508             }
1509             try {
1510                 mCallback.select(wifiConfiguration);
1511             } catch (RemoteException e) {
1512                 Log.e(TAG, "Failed to invoke onSelected", e);
1513                 throw e.rethrowFromSystemServer();
1514             }
1515         }
1516 
1517         @Override
reject()1518         public void reject() {
1519             if (mVerboseLoggingEnabled) {
1520                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
1521             }
1522             try {
1523                 mCallback.reject();
1524             } catch (RemoteException e) {
1525                 Log.e(TAG, "Failed to invoke onRejected", e);
1526                 throw e.rethrowFromSystemServer();
1527             }
1528         }
1529     }
1530 
1531     /**
1532      * Callback proxy for NetworkRequestMatchCallback objects.
1533      * @hide
1534      */
1535     private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
1536         private final Handler mHandler;
1537         private final NetworkRequestMatchCallback mCallback;
1538 
NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback)1539         NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback) {
1540             mHandler = new Handler(looper);
1541             mCallback = callback;
1542         }
1543 
1544         @Override
onUserSelectionCallbackRegistration( INetworkRequestUserSelectionCallback userSelectionCallback)1545         public void onUserSelectionCallbackRegistration(
1546                 INetworkRequestUserSelectionCallback userSelectionCallback) {
1547             if (mVerboseLoggingEnabled) {
1548                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
1549                         + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
1550             }
1551             mHandler.post(() -> {
1552                 mCallback.onUserSelectionCallbackRegistration(
1553                         new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
1554             });
1555         }
1556 
1557         @Override
onAbort()1558         public void onAbort() {
1559             if (mVerboseLoggingEnabled) {
1560                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onAbort");
1561             }
1562             mHandler.post(() -> {
1563                 mCallback.onAbort();
1564             });
1565         }
1566 
1567         @Override
onMatch(List<ScanResult> scanResults)1568         public void onMatch(List<ScanResult> scanResults) {
1569             if (mVerboseLoggingEnabled) {
1570                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch scanResults: "
1571                         + scanResults);
1572             }
1573             mHandler.post(() -> {
1574                 mCallback.onMatch(scanResults);
1575             });
1576         }
1577 
1578         @Override
onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration)1579         public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
1580             if (mVerboseLoggingEnabled) {
1581                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
1582                         + " wificonfiguration: " + wifiConfiguration);
1583             }
1584             mHandler.post(() -> {
1585                 mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
1586             });
1587         }
1588 
1589         @Override
onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration)1590         public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
1591             if (mVerboseLoggingEnabled) {
1592                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
1593                         + " wificonfiguration: " + wifiConfiguration);
1594             }
1595             mHandler.post(() -> {
1596                 mCallback.onUserSelectionConnectFailure(wifiConfiguration);
1597             });
1598         }
1599     }
1600 
1601     /**
1602      * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
1603      * Caller can unregister a previously registered callback using
1604      * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
1605      * <p>
1606      * Applications should have the
1607      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
1608      * without the permission will trigger a {@link java.lang.SecurityException}.
1609      * <p>
1610      *
1611      * @param callback Callback for network match events
1612      * @param handler  The Handler on whose thread to execute the callbacks of the {@code callback}
1613      *                 object. If null, then the application's main thread will be used.
1614      * @hide
1615      */
1616     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerNetworkRequestMatchCallback(@onNull NetworkRequestMatchCallback callback, @Nullable Handler handler)1617     public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback,
1618                                                     @Nullable Handler handler) {
1619         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
1620         Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
1621                 + ", handler=" + handler);
1622 
1623         Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
1624         Binder binder = new Binder();
1625         try {
1626             mService.registerNetworkRequestMatchCallback(
1627                     binder, new NetworkRequestMatchCallbackProxy(looper, callback),
1628                     callback.hashCode());
1629         } catch (RemoteException e) {
1630             throw e.rethrowFromSystemServer();
1631         }
1632     }
1633 
1634     /**
1635      * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
1636      * <p>
1637      * Applications should have the
1638      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
1639      * without the permission will trigger a {@link java.lang.SecurityException}.
1640      * <p>
1641      *
1642      * @param callback Callback for network match events
1643      * @hide
1644      */
1645     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterNetworkRequestMatchCallback( @onNull NetworkRequestMatchCallback callback)1646     public void unregisterNetworkRequestMatchCallback(
1647             @NonNull NetworkRequestMatchCallback callback) {
1648         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
1649         Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
1650 
1651         try {
1652             mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
1653         } catch (RemoteException e) {
1654             throw e.rethrowFromSystemServer();
1655         }
1656     }
1657 
1658     /**
1659      * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
1660      * for a detailed explanation of the parameters.
1661      * When the device decides to connect to one of the provided network suggestions, platform sends
1662      * a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
1663      * the network was created with {@link WifiNetworkSuggestion.Builder
1664      * #setIsAppInteractionRequired()} flag set and the app holds
1665      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
1666      *<p>
1667      * NOTE:
1668      * <li> These networks are just a suggestion to the platform. The platform will ultimately
1669      * decide on which network the device connects to. </li>
1670      * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is
1671      * currently connected to a suggested network which is being removed then the device will
1672      * disconnect from that network.</li>
1673      * <li> No in-place modification of existing suggestions are allowed. Apps are expected to
1674      * remove suggestions using {@link #removeNetworkSuggestions(List)} and then add the modified
1675      * suggestion back using this API.</li>
1676      *
1677      * @param networkSuggestions List of network suggestions provided by the app.
1678      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
1679      * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
1680      * @throws {@link SecurityException} if the caller is missing required permissions.
1681      */
1682     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
addNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)1683     public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
1684             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
1685         try {
1686             return mService.addNetworkSuggestions(networkSuggestions, mContext.getOpPackageName());
1687         } catch (RemoteException e) {
1688             throw e.rethrowFromSystemServer();
1689         }
1690     }
1691 
1692     /**
1693      * Remove some or all of the network suggestions that were previously provided by the app.
1694      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
1695      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
1696      *
1697      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
1698      *                           to remove all the previous suggestions provided by the app.
1699      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
1700      * Any matching suggestions are removed from the device and will not be considered for any
1701      * further connection attempts.
1702      */
1703     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)1704     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
1705             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
1706         try {
1707             return mService.removeNetworkSuggestions(
1708                     networkSuggestions, mContext.getOpPackageName());
1709         } catch (RemoteException e) {
1710             throw e.rethrowFromSystemServer();
1711         }
1712     }
1713 
1714     /**
1715      * Returns the max number of network suggestions that are allowed per app on the device.
1716      * @see #addNetworkSuggestions(List)
1717      * @see #removeNetworkSuggestions(List)
1718      */
getMaxNumberOfNetworkSuggestionsPerApp()1719     public int getMaxNumberOfNetworkSuggestionsPerApp() {
1720         return NETWORK_SUGGESTIONS_MAX_PER_APP;
1721     }
1722 
1723     /**
1724      * Add or update a Passpoint configuration.  The configuration provides a credential
1725      * for connecting to Passpoint networks that are operated by the Passpoint
1726      * service provider specified in the configuration.
1727      *
1728      * Each configuration is uniquely identified by its FQDN (Fully Qualified Domain
1729      * Name).  In the case when there is an existing configuration with the same
1730      * FQDN, the new configuration will replace the existing configuration.
1731      *
1732      * @param config The Passpoint configuration to be added
1733      * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
1734      *                                  the device.
1735      */
addOrUpdatePasspointConfiguration(PasspointConfiguration config)1736     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
1737         try {
1738             if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
1739                 throw new IllegalArgumentException();
1740             }
1741         } catch (RemoteException e) {
1742             throw e.rethrowFromSystemServer();
1743         }
1744     }
1745 
1746     /**
1747      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
1748      *
1749      * @param fqdn The FQDN of the Passpoint configuration to be removed
1750      * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
1751      *                                  Passpoint is not enabled on the device.
1752      * @deprecated This is no longer supported.
1753      */
1754     @Deprecated
1755     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
removePasspointConfiguration(String fqdn)1756     public void removePasspointConfiguration(String fqdn) {
1757         try {
1758             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
1759                 throw new IllegalArgumentException();
1760             }
1761         } catch (RemoteException e) {
1762             throw e.rethrowFromSystemServer();
1763         }
1764     }
1765 
1766     /**
1767      * Return the list of installed Passpoint configurations.
1768      *
1769      * An empty list will be returned when no configurations are installed.
1770      *
1771      * @return A list of {@link PasspointConfiguration}
1772      * @deprecated This is no longer supported.
1773      */
1774     @Deprecated
1775     @RequiresPermission(anyOf = {
1776             android.Manifest.permission.NETWORK_SETTINGS,
1777             android.Manifest.permission.NETWORK_SETUP_WIZARD
1778     })
getPasspointConfigurations()1779     public List<PasspointConfiguration> getPasspointConfigurations() {
1780         try {
1781             return mService.getPasspointConfigurations(mContext.getOpPackageName());
1782         } catch (RemoteException e) {
1783             throw e.rethrowFromSystemServer();
1784         }
1785     }
1786 
1787     /**
1788      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
1789      * will be broadcasted once the request is completed.  The presence of the intent extra
1790      * {@link #EXTRA_ICON} will indicate the result of the request.
1791      * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
1792      *
1793      * @param bssid The BSSID of the AP
1794      * @param fileName Name of the icon file (remote file) to query from the AP
1795      *
1796      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
1797      * @hide
1798      */
queryPasspointIcon(long bssid, String fileName)1799     public void queryPasspointIcon(long bssid, String fileName) {
1800         try {
1801             mService.queryPasspointIcon(bssid, fileName);
1802         } catch (RemoteException e) {
1803             throw e.rethrowFromSystemServer();
1804         }
1805     }
1806 
1807     /**
1808      * Match the currently associated network against the SP matching the given FQDN
1809      * @param fqdn FQDN of the SP
1810      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
1811      * @hide
1812      */
matchProviderWithCurrentNetwork(String fqdn)1813     public int matchProviderWithCurrentNetwork(String fqdn) {
1814         try {
1815             return mService.matchProviderWithCurrentNetwork(fqdn);
1816         } catch (RemoteException e) {
1817             throw e.rethrowFromSystemServer();
1818         }
1819     }
1820 
1821     /**
1822      * Deauthenticate and set the re-authentication hold off time for the current network
1823      * @param holdoff hold off time in milliseconds
1824      * @param ess set if the hold off pertains to an ESS rather than a BSS
1825      * @hide
1826      */
deauthenticateNetwork(long holdoff, boolean ess)1827     public void deauthenticateNetwork(long holdoff, boolean ess) {
1828         try {
1829             mService.deauthenticateNetwork(holdoff, ess);
1830         } catch (RemoteException e) {
1831             throw e.rethrowFromSystemServer();
1832         }
1833     }
1834 
1835     /**
1836      * Remove the specified network from the list of configured networks.
1837      * This may result in the asynchronous delivery of state change
1838      * events.
1839      *
1840      * Applications are not allowed to remove networks created by other
1841      * applications.
1842      *
1843      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
1844      *        #getConfiguredNetworks}.
1845      * @return {@code true} if the operation succeeded
1846      *
1847      * @deprecated
1848      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1849      * mechanism to trigger connection to a Wi-Fi network.
1850      * b) See {@link #addNetworkSuggestions(List)},
1851      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1852      * when auto-connecting to wifi.
1853      * <b>Compatibility Note:</b> For applications targeting
1854      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
1855      */
1856     @Deprecated
removeNetwork(int netId)1857     public boolean removeNetwork(int netId) {
1858         try {
1859             return mService.removeNetwork(netId, mContext.getOpPackageName());
1860         } catch (RemoteException e) {
1861             throw e.rethrowFromSystemServer();
1862         }
1863     }
1864 
1865     /**
1866      * Allow a previously configured network to be associated with. If
1867      * <code>attemptConnect</code> is true, an attempt to connect to the selected
1868      * network is initiated. This may result in the asynchronous delivery
1869      * of state change events.
1870      * <p>
1871      * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
1872      * traffic may instead be sent through another network, such as cellular data,
1873      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
1874      * Wi-Fi network that does not provide Internet access (e.g. a wireless
1875      * printer), if another network that does offer Internet access (e.g.
1876      * cellular data) is available. Applications that need to ensure that their
1877      * network traffic uses Wi-Fi should use APIs such as
1878      * {@link Network#bindSocket(java.net.Socket)},
1879      * {@link Network#openConnection(java.net.URL)}, or
1880      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
1881      *
1882      * Applications are not allowed to enable networks created by other
1883      * applications.
1884      *
1885      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
1886      *        #getConfiguredNetworks}.
1887      * @param attemptConnect The way to select a particular network to connect to is specify
1888      *        {@code true} for this parameter.
1889      * @return {@code true} if the operation succeeded
1890      *
1891      * @deprecated
1892      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1893      * mechanism to trigger connection to a Wi-Fi network.
1894      * b) See {@link #addNetworkSuggestions(List)},
1895      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1896      * when auto-connecting to wifi.
1897      * <b>Compatibility Note:</b> For applications targeting
1898      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
1899      */
1900     @Deprecated
enableNetwork(int netId, boolean attemptConnect)1901     public boolean enableNetwork(int netId, boolean attemptConnect) {
1902         final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
1903         if (pin) {
1904             NetworkRequest request = new NetworkRequest.Builder()
1905                     .clearCapabilities()
1906                     .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
1907                     .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
1908                     .build();
1909             NetworkPinner.pin(mContext, request);
1910         }
1911 
1912         boolean success;
1913         try {
1914             success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
1915         } catch (RemoteException e) {
1916             throw e.rethrowFromSystemServer();
1917         }
1918 
1919         if (pin && !success) {
1920             NetworkPinner.unpin();
1921         }
1922 
1923         return success;
1924     }
1925 
1926     /**
1927      * Disable a configured network. The specified network will not be
1928      * a candidate for associating. This may result in the asynchronous
1929      * delivery of state change events.
1930      *
1931      * Applications are not allowed to disable networks created by other
1932      * applications.
1933      *
1934      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
1935      *        #getConfiguredNetworks}.
1936      * @return {@code true} if the operation succeeded
1937      *
1938      * @deprecated
1939      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1940      * mechanism to trigger connection to a Wi-Fi network.
1941      * b) See {@link #addNetworkSuggestions(List)},
1942      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1943      * when auto-connecting to wifi.
1944      * <b>Compatibility Note:</b> For applications targeting
1945      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
1946      */
1947     @Deprecated
1948     public boolean disableNetwork(int netId) {
1949         try {
1950             return mService.disableNetwork(netId, mContext.getOpPackageName());
1951         } catch (RemoteException e) {
1952             throw e.rethrowFromSystemServer();
1953         }
1954     }
1955 
1956     /**
1957      * Disassociate from the currently active access point. This may result
1958      * in the asynchronous delivery of state change events.
1959      * @return {@code true} if the operation succeeded
1960      *
1961      * @deprecated
1962      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1963      * mechanism to trigger connection to a Wi-Fi network.
1964      * b) See {@link #addNetworkSuggestions(List)},
1965      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1966      * when auto-connecting to wifi.
1967      * <b>Compatibility Note:</b> For applications targeting
1968      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
1969      */
1970     @Deprecated
1971     public boolean disconnect() {
1972         try {
1973             return mService.disconnect(mContext.getOpPackageName());
1974         } catch (RemoteException e) {
1975             throw e.rethrowFromSystemServer();
1976         }
1977     }
1978 
1979     /**
1980      * Reconnect to the currently active access point, if we are currently
1981      * disconnected. This may result in the asynchronous delivery of state
1982      * change events.
1983      * @return {@code true} if the operation succeeded
1984      *
1985      * @deprecated
1986      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1987      * mechanism to trigger connection to a Wi-Fi network.
1988      * b) See {@link #addNetworkSuggestions(List)},
1989      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1990      * when auto-connecting to wifi.
1991      * <b>Compatibility Note:</b> For applications targeting
1992      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
1993      */
1994     @Deprecated
1995     public boolean reconnect() {
1996         try {
1997             return mService.reconnect(mContext.getOpPackageName());
1998         } catch (RemoteException e) {
1999             throw e.rethrowFromSystemServer();
2000         }
2001     }
2002 
2003     /**
2004      * Reconnect to the currently active access point, even if we are already
2005      * connected. This may result in the asynchronous delivery of state
2006      * change events.
2007      * @return {@code true} if the operation succeeded
2008      *
2009      * @deprecated
2010      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2011      * mechanism to trigger connection to a Wi-Fi network.
2012      * b) See {@link #addNetworkSuggestions(List)},
2013      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2014      * when auto-connecting to wifi.
2015      * <b>Compatibility Note:</b> For applications targeting
2016      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
2017      */
2018     @Deprecated
2019     public boolean reassociate() {
2020         try {
2021             return mService.reassociate(mContext.getOpPackageName());
2022         } catch (RemoteException e) {
2023             throw e.rethrowFromSystemServer();
2024         }
2025     }
2026 
2027     /**
2028      * Check that the supplicant daemon is responding to requests.
2029      * @return {@code true} if we were able to communicate with the supplicant and
2030      * it returned the expected response to the PING message.
2031      * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
2032      */
2033     @Deprecated
2034     public boolean pingSupplicant() {
2035         return isWifiEnabled();
2036     }
2037 
2038     /** @hide */
2039     public static final int WIFI_FEATURE_INFRA            = 0x0001;  // Basic infrastructure mode
2040     /** @hide */
2041     public static final int WIFI_FEATURE_INFRA_5G         = 0x0002;  // Support for 5 GHz Band
2042     /** @hide */
2043     public static final int WIFI_FEATURE_PASSPOINT        = 0x0004;  // Support for GAS/ANQP
2044     /** @hide */
2045     public static final int WIFI_FEATURE_P2P              = 0x0008;  // Wifi-Direct
2046     /** @hide */
2047     public static final int WIFI_FEATURE_MOBILE_HOTSPOT   = 0x0010;  // Soft AP
2048     /** @hide */
2049     public static final int WIFI_FEATURE_SCANNER          = 0x0020;  // WifiScanner APIs
2050     /** @hide */
2051     public static final int WIFI_FEATURE_AWARE            = 0x0040;  // Wi-Fi AWare networking
2052     /** @hide */
2053     public static final int WIFI_FEATURE_D2D_RTT          = 0x0080;  // Device-to-device RTT
2054     /** @hide */
2055     public static final int WIFI_FEATURE_D2AP_RTT         = 0x0100;  // Device-to-AP RTT
2056     /** @hide */
2057     public static final int WIFI_FEATURE_BATCH_SCAN       = 0x0200;  // Batched Scan (deprecated)
2058     /** @hide */
2059     public static final int WIFI_FEATURE_PNO              = 0x0400;  // Preferred network offload
2060     /** @hide */
2061     public static final int WIFI_FEATURE_ADDITIONAL_STA   = 0x0800;  // Support for two STAs
2062     /** @hide */
2063     public static final int WIFI_FEATURE_TDLS             = 0x1000;  // Tunnel directed link setup
2064     /** @hide */
2065     public static final int WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000;  // Support for TDLS off channel
2066     /** @hide */
2067     public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
2068     /** @hide */
2069     public static final int WIFI_FEATURE_AP_STA           = 0x8000;  // AP STA Concurrency
2070     /** @hide */
2071     public static final int WIFI_FEATURE_LINK_LAYER_STATS = 0x10000; // Link layer stats collection
2072     /** @hide */
2073     public static final int WIFI_FEATURE_LOGGER           = 0x20000; // WiFi Logger
2074     /** @hide */
2075     public static final int WIFI_FEATURE_HAL_EPNO         = 0x40000; // Enhanced PNO
2076     /** @hide */
2077     public static final int WIFI_FEATURE_RSSI_MONITOR     = 0x80000; // RSSI Monitor
2078     /** @hide */
2079     public static final int WIFI_FEATURE_MKEEP_ALIVE      = 0x100000; // mkeep_alive
2080     /** @hide */
2081     public static final int WIFI_FEATURE_CONFIG_NDO       = 0x200000; // ND offload
2082     /** @hide */
2083     public static final int WIFI_FEATURE_TRANSMIT_POWER   = 0x400000; // Capture transmit power
2084     /** @hide */
2085     public static final int WIFI_FEATURE_CONTROL_ROAMING  = 0x800000; // Control firmware roaming
2086     /** @hide */
2087     public static final int WIFI_FEATURE_IE_WHITELIST     = 0x1000000; // Probe IE white listing
2088     /** @hide */
2089     public static final int WIFI_FEATURE_SCAN_RAND        = 0x2000000; // Random MAC & Probe seq
2090     /** @hide */
2091     public static final int WIFI_FEATURE_TX_POWER_LIMIT   = 0x4000000; // Set Tx power limit
2092     /** @hide */
2093     public static final int WIFI_FEATURE_WPA3_SAE         = 0x8000000; // WPA3-Personal SAE
2094     /** @hide */
2095     public static final int WIFI_FEATURE_WPA3_SUITE_B     = 0x10000000; // WPA3-Enterprise Suite-B
2096     /** @hide */
2097     public static final int WIFI_FEATURE_OWE              = 0x20000000; // Enhanced Open
2098     /** @hide */
2099     public static final int WIFI_FEATURE_LOW_LATENCY      = 0x40000000; // Low Latency modes
2100     /** @hide */
2101     public static final int WIFI_FEATURE_DPP              = 0x80000000; // DPP (Easy-Connect)
2102     /** @hide */
2103     public static final long WIFI_FEATURE_P2P_RAND_MAC    = 0x100000000L; // Random P2P MAC
2104 
2105     private long getSupportedFeatures() {
2106         try {
2107             return mService.getSupportedFeatures();
2108         } catch (RemoteException e) {
2109             throw e.rethrowFromSystemServer();
2110         }
2111     }
2112 
2113     private boolean isFeatureSupported(long feature) {
2114         return (getSupportedFeatures() & feature) == feature;
2115     }
2116     /**
2117      * @return true if this adapter supports 5 GHz band
2118      */
2119     public boolean is5GHzBandSupported() {
2120         return isFeatureSupported(WIFI_FEATURE_INFRA_5G);
2121     }
2122 
2123     /**
2124      * @return true if this adapter supports Passpoint
2125      * @hide
2126      */
2127     public boolean isPasspointSupported() {
2128         return isFeatureSupported(WIFI_FEATURE_PASSPOINT);
2129     }
2130 
2131     /**
2132      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
2133      */
2134     public boolean isP2pSupported() {
2135         return isFeatureSupported(WIFI_FEATURE_P2P);
2136     }
2137 
2138     /**
2139      * @return true if this adapter supports portable Wi-Fi hotspot
2140      * @hide
2141      */
2142     @SystemApi
2143     public boolean isPortableHotspotSupported() {
2144         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
2145     }
2146 
2147     /**
2148      * @return true if this adapter supports WifiScanner APIs
2149      * @hide
2150      */
2151     @SystemApi
2152     public boolean isWifiScannerSupported() {
2153         return isFeatureSupported(WIFI_FEATURE_SCANNER);
2154     }
2155 
2156     /**
2157      * @return true if this adapter supports Neighbour Awareness Network APIs
2158      * @hide
2159      */
2160     public boolean isWifiAwareSupported() {
2161         return isFeatureSupported(WIFI_FEATURE_AWARE);
2162     }
2163 
2164     /**
2165      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
2166      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
2167      * {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
2168      *
2169      * @return true if this adapter supports Device-to-device RTT
2170      * @hide
2171      */
2172     @Deprecated
2173     @SystemApi
2174     public boolean isDeviceToDeviceRttSupported() {
2175         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
2176     }
2177 
2178     /**
2179      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
2180      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT}.
2181      *
2182      * @return true if this adapter supports Device-to-AP RTT
2183      */
2184     @Deprecated
2185     public boolean isDeviceToApRttSupported() {
2186         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
2187     }
2188 
2189     /**
2190      * @return true if this adapter supports offloaded connectivity scan
2191      */
2192     public boolean isPreferredNetworkOffloadSupported() {
2193         return isFeatureSupported(WIFI_FEATURE_PNO);
2194     }
2195 
2196     /**
2197      * @return true if this adapter supports multiple simultaneous connections
2198      * @hide
2199      */
2200     public boolean isAdditionalStaSupported() {
2201         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
2202     }
2203 
2204     /**
2205      * @return true if this adapter supports Tunnel Directed Link Setup
2206      */
2207     public boolean isTdlsSupported() {
2208         return isFeatureSupported(WIFI_FEATURE_TDLS);
2209     }
2210 
2211     /**
2212      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
2213      * @hide
2214      */
2215     public boolean isOffChannelTdlsSupported() {
2216         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
2217     }
2218 
2219     /**
2220      * @return true if this adapter supports advanced power/performance counters
2221      */
2222     public boolean isEnhancedPowerReportingSupported() {
2223         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
2224     }
2225 
2226     /**
2227      * Return the record of {@link WifiActivityEnergyInfo} object that
2228      * has the activity and energy info. This can be used to ascertain what
2229      * the controller has been up to, since the last sample.
2230      *
2231      * @return a record with {@link WifiActivityEnergyInfo} or null if
2232      * report is unavailable or unsupported
2233      * @hide
2234      */
2235     public WifiActivityEnergyInfo getControllerActivityEnergyInfo() {
2236         if (mService == null) return null;
2237         try {
2238             synchronized(this) {
2239                 return mService.reportActivityInfo();
2240             }
2241         } catch (RemoteException e) {
2242             throw e.rethrowFromSystemServer();
2243         }
2244     }
2245 
2246     /**
2247      * Request a scan for access points. Returns immediately. The availability
2248      * of the results is made known later by means of an asynchronous event sent
2249      * on completion of the scan.
2250      * <p>
2251      * To initiate a Wi-Fi scan, declare the
2252      * {@link android.Manifest.permission#CHANGE_WIFI_STATE}
2253      * permission in the manifest, and perform these steps:
2254      * </p>
2255      * <ol style="1">
2256      * <li>Invoke the following method:
2257      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>
2258      * <li>
2259      * Register a BroadcastReceiver to listen to
2260      * {@code SCAN_RESULTS_AVAILABLE_ACTION}.</li>
2261      * <li>When a broadcast is received, call:
2262      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>
2263      * </ol>
2264      * @return {@code true} if the operation succeeded, i.e., the scan was initiated.
2265      * @deprecated The ability for apps to trigger scan requests will be removed in a future
2266      * release.
2267      */
2268     @Deprecated
2269     public boolean startScan() {
2270         return startScan(null);
2271     }
2272 
2273     /** @hide */
2274     @SystemApi
2275     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
2276     public boolean startScan(WorkSource workSource) {
2277         try {
2278             String packageName = mContext.getOpPackageName();
2279             return mService.startScan(packageName);
2280         } catch (RemoteException e) {
2281             throw e.rethrowFromSystemServer();
2282         }
2283     }
2284 
2285     /**
2286      * WPS has been deprecated from Client mode operation.
2287      *
2288      * @return null
2289      * @hide
2290      * @deprecated This API is deprecated
2291      */
2292     public String getCurrentNetworkWpsNfcConfigurationToken() {
2293         return null;
2294     }
2295 
2296     /**
2297      * Return dynamic information about the current Wi-Fi connection, if any is active.
2298      * <p>
2299      * In the connected state, access to the SSID and BSSID requires
2300      * the same permissions as {@link #getScanResults}. If such access is not allowed,
2301      * {@link WifiInfo#getSSID} will return {@code "<unknown ssid>"} and
2302      * {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
2303      *
2304      * @return the Wi-Fi information, contained in {@link WifiInfo}.
2305      */
2306     public WifiInfo getConnectionInfo() {
2307         try {
2308             return mService.getConnectionInfo(mContext.getOpPackageName());
2309         } catch (RemoteException e) {
2310             throw e.rethrowFromSystemServer();
2311         }
2312     }
2313 
2314     /**
2315      * Return the results of the latest access point scan.
2316      * @return the list of access points found in the most recent scan. An app must hold
2317      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
2318      * in order to get valid results.
2319      */
2320     public List<ScanResult> getScanResults() {
2321         try {
2322             return mService.getScanResults(mContext.getOpPackageName());
2323         } catch (RemoteException e) {
2324             throw e.rethrowFromSystemServer();
2325         }
2326     }
2327 
2328     /**
2329      * Check if scanning is always available.
2330      *
2331      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
2332      * even when Wi-Fi is turned off.
2333      *
2334      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
2335      * @deprecated The ability for apps to trigger scan requests will be removed in a future
2336      * release.
2337      */
2338     @Deprecated
2339     public boolean isScanAlwaysAvailable() {
2340         try {
2341             return mService.isScanAlwaysAvailable();
2342         } catch (RemoteException e) {
2343             throw e.rethrowFromSystemServer();
2344         }
2345     }
2346 
2347     /**
2348      * Tell the device to persist the current list of configured networks.
2349      * <p>
2350      * Note: It is possible for this method to change the network IDs of
2351      * existing networks. You should assume the network IDs can be different
2352      * after calling this method.
2353      *
2354      * @return {@code false}.
2355      * @deprecated There is no need to call this method -
2356      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
2357      * and {@link #removeNetwork(int)} already persist the configurations automatically.
2358      */
2359     @Deprecated
2360     public boolean saveConfiguration() {
2361         return false;
2362     }
2363 
2364     /**
2365      * Set the country code.
2366      * @param countryCode country code in ISO 3166 format.
2367      *
2368      * @hide
2369      */
2370     public void setCountryCode(@NonNull String country) {
2371         try {
2372             mService.setCountryCode(country);
2373         } catch (RemoteException e) {
2374             throw e.rethrowFromSystemServer();
2375         }
2376     }
2377 
2378     /**
2379     * get the country code.
2380     * @return the country code in ISO 3166 format.
2381     *
2382     * @hide
2383     */
2384     @UnsupportedAppUsage
2385     public String getCountryCode() {
2386        try {
2387            String country = mService.getCountryCode();
2388            return country;
2389        } catch (RemoteException e) {
2390            throw e.rethrowFromSystemServer();
2391        }
2392     }
2393 
2394     /**
2395      * Check if the chipset supports dual frequency band (2.4 GHz and 5 GHz)
2396      * @return {@code true} if supported, {@code false} otherwise.
2397      * @hide
2398      */
2399     @UnsupportedAppUsage
2400     public boolean isDualBandSupported() {
2401         try {
2402             return mService.isDualBandSupported();
2403         } catch (RemoteException e) {
2404             throw e.rethrowFromSystemServer();
2405         }
2406     }
2407 
2408     /**
2409      * Check if the chipset requires conversion of 5GHz Only apBand to ANY.
2410      * @return {@code true} if required, {@code false} otherwise.
2411      * @hide
2412      */
2413     public boolean isDualModeSupported() {
2414         try {
2415             return mService.needs5GHzToAnyApBandConversion();
2416         } catch (RemoteException e) {
2417             throw e.rethrowFromSystemServer();
2418         }
2419     }
2420 
2421     /**
2422      * Return the DHCP-assigned addresses from the last successful DHCP request,
2423      * if any.
2424      * @return the DHCP information
2425      */
2426     public DhcpInfo getDhcpInfo() {
2427         try {
2428             return mService.getDhcpInfo();
2429         } catch (RemoteException e) {
2430             throw e.rethrowFromSystemServer();
2431         }
2432     }
2433 
2434     /**
2435      * Enable or disable Wi-Fi.
2436      * <p>
2437      * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
2438      * permission to toggle wifi.
2439      *
2440      * @param enabled {@code true} to enable, {@code false} to disable.
2441      * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
2442      *         either already in the requested state, or in progress toward the requested state.
2443      * @throws  {@link java.lang.SecurityException} if the caller is missing required permissions.
2444      *
2445      * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
2446      * enable/disable Wi-Fi.
2447      * <b>Compatibility Note:</b> For applications targeting
2448      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code false}
2449      * and will have no effect. If apps are targeting an older SDK (
2450      * {@link android.os.Build.VERSION_CODES#P} or below), they can continue to use this API.
2451      */
2452     @Deprecated
2453     public boolean setWifiEnabled(boolean enabled) {
2454         try {
2455             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
2456         } catch (RemoteException e) {
2457             throw e.rethrowFromSystemServer();
2458         }
2459     }
2460 
2461     /**
2462      * Gets the Wi-Fi enabled state.
2463      * @return One of {@link #WIFI_STATE_DISABLED},
2464      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
2465      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
2466      * @see #isWifiEnabled()
2467      */
2468     public int getWifiState() {
2469         try {
2470             return mService.getWifiEnabledState();
2471         } catch (RemoteException e) {
2472             throw e.rethrowFromSystemServer();
2473         }
2474     }
2475 
2476     /**
2477      * Return whether Wi-Fi is enabled or disabled.
2478      * @return {@code true} if Wi-Fi is enabled
2479      * @see #getWifiState()
2480      */
2481     public boolean isWifiEnabled() {
2482         return getWifiState() == WIFI_STATE_ENABLED;
2483     }
2484 
2485     /**
2486      * Return TX packet counter, for CTS test of WiFi watchdog.
2487      * @param listener is the interface to receive result
2488      *
2489      * @hide for CTS test only
2490      */
2491     public void getTxPacketCount(TxPacketCountListener listener) {
2492         getChannel().sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
2493     }
2494 
2495     /**
2496      * Calculates the level of the signal. This should be used any time a signal
2497      * is being shown.
2498      *
2499      * @param rssi The power of the signal measured in RSSI.
2500      * @param numLevels The number of levels to consider in the calculated
2501      *            level.
2502      * @return A level of the signal, given in the range of 0 to numLevels-1
2503      *         (both inclusive).
2504      */
2505     public static int calculateSignalLevel(int rssi, int numLevels) {
2506         if (rssi <= MIN_RSSI) {
2507             return 0;
2508         } else if (rssi >= MAX_RSSI) {
2509             return numLevels - 1;
2510         } else {
2511             float inputRange = (MAX_RSSI - MIN_RSSI);
2512             float outputRange = (numLevels - 1);
2513             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
2514         }
2515     }
2516 
2517     /**
2518      * Compares two signal strengths.
2519      *
2520      * @param rssiA The power of the first signal measured in RSSI.
2521      * @param rssiB The power of the second signal measured in RSSI.
2522      * @return Returns <0 if the first signal is weaker than the second signal,
2523      *         0 if the two signals have the same strength, and >0 if the first
2524      *         signal is stronger than the second signal.
2525      */
2526     public static int compareSignalLevel(int rssiA, int rssiB) {
2527         return rssiA - rssiB;
2528     }
2529 
2530     /**
2531      * Call allowing ConnectivityService to update WifiService with interface mode changes.
2532      *
2533      * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
2534      *                             {@link IFACE_IP_MODE_LOCAL_ONLY},
2535      *                             {@link IFACE_IP_MODE_CONFIGURATION_ERROR}
2536      *
2537      * @param ifaceName String name of the updated interface
2538      * @param mode int representing the new mode
2539      *
2540      * @hide
2541      */
2542     public void updateInterfaceIpState(String ifaceName, int mode) {
2543         try {
2544             mService.updateInterfaceIpState(ifaceName, mode);
2545         } catch (RemoteException e) {
2546             throw e.rethrowFromSystemServer();
2547         }
2548     }
2549 
2550     /**
2551      * Start SoftAp mode with the specified configuration.
2552      * Note that starting in access point mode disables station
2553      * mode operation
2554      * @param wifiConfig SSID, security and channel details as
2555      *        part of WifiConfiguration
2556      * @return {@code true} if the operation succeeds, {@code false} otherwise
2557      *
2558      * @hide
2559      */
2560     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
2561         try {
2562             return mService.startSoftAp(wifiConfig);
2563         } catch (RemoteException e) {
2564             throw e.rethrowFromSystemServer();
2565         }
2566     }
2567 
2568     /**
2569      * Stop SoftAp mode.
2570      * Note that stopping softap mode will restore the previous wifi mode.
2571      * @return {@code true} if the operation succeeds, {@code false} otherwise
2572      *
2573      * @hide
2574      */
2575     public boolean stopSoftAp() {
2576         try {
2577             return mService.stopSoftAp();
2578         } catch (RemoteException e) {
2579             throw e.rethrowFromSystemServer();
2580         }
2581     }
2582 
2583     /**
2584      * Request a local only hotspot that an application can use to communicate between co-located
2585      * devices connected to the created WiFi hotspot.  The network created by this method will not
2586      * have Internet access.  Each application can make a single request for the hotspot, but
2587      * multiple applications could be requesting the hotspot at the same time.  When multiple
2588      * applications have successfully registered concurrently, they will be sharing the underlying
2589      * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called
2590      * when the hotspot is ready for use by the application.
2591      * <p>
2592      * Each application can make a single active call to this method. The {@link
2593      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
2594      * requestor with a {@link LocalOnlyHotspotReservation} that contains a
2595      * {@link WifiConfiguration} with the SSID, security type and credentials needed to connect
2596      * to the hotspot.  Communicating this information is up to the application.
2597      * <p>
2598      * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
2599      * method will be called. Example failures include errors bringing up the network or if
2600      * there is an incompatible operating mode.  For example, if the user is currently using Wifi
2601      * Tethering to provide an upstream to another device, LocalOnlyHotspot will not start due to
2602      * an incompatible mode. The possible error codes include:
2603      * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL},
2604      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC},
2605      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and
2606      * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}.
2607      * <p>
2608      * Internally, requests will be tracked to prevent the hotspot from being torn down while apps
2609      * are still using it.  The {@link LocalOnlyHotspotReservation} object passed in the  {@link
2610      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when
2611      * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}.
2612      * Since the hotspot may be shared among multiple applications, removing the final registered
2613      * application request will trigger the hotspot teardown.  This means that applications should
2614      * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after
2615      * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is
2616      * called, applications will not receive callbacks of any kind.
2617      * <p>
2618      * Applications should be aware that the user may also stop the LocalOnlyHotspot through the
2619      * Settings UI; it is not guaranteed to stay up as long as there is a requesting application.
2620      * The requestors will be notified of this case via
2621      * {@link LocalOnlyHotspotCallback#onStopped()}.  Other cases may arise where the hotspot is
2622      * torn down (Emergency mode, etc).  Application developers should be aware that it can stop
2623      * unexpectedly, but they will receive a notification if they have properly registered.
2624      * <p>
2625      * Applications should also be aware that this network will be shared with other applications.
2626      * Applications are responsible for protecting their data on this network (e.g., TLS).
2627      * <p>
2628      * Applications need to have the following permissions to start LocalOnlyHotspot: {@link
2629      * android.Manifest.permission#CHANGE_WIFI_STATE} and {@link
2630      * android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}.  Callers without
2631      * the permissions will trigger a {@link java.lang.SecurityException}.
2632      * <p>
2633      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
2634      * operating status.
2635      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
2636      * main thread will be used.
2637      */
2638     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
2639             @Nullable Handler handler) {
2640         synchronized (mLock) {
2641             Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
2642             LocalOnlyHotspotCallbackProxy proxy =
2643                     new LocalOnlyHotspotCallbackProxy(this, looper, callback);
2644             try {
2645                 String packageName = mContext.getOpPackageName();
2646                 int returnCode = mService.startLocalOnlyHotspot(
2647                         proxy.getMessenger(), new Binder(), packageName);
2648                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
2649                     // Send message to the proxy to make sure we call back on the correct thread
2650                     proxy.notifyFailed(returnCode);
2651                     return;
2652                 }
2653                 mLOHSCallbackProxy = proxy;
2654             } catch (RemoteException e) {
2655                 throw e.rethrowFromSystemServer();
2656             }
2657         }
2658     }
2659 
2660     /**
2661      * Cancels a pending local only hotspot request.  This can be used by the calling application to
2662      * cancel the existing request if the provided callback has not been triggered.  Calling this
2663      * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not
2664      * explicitly required.
2665      * <p>
2666      * When cancelling this request, application developers should be aware that there may still be
2667      * outstanding local only hotspot requests and the hotspot may still start, or continue running.
2668      * Additionally, if a callback was registered, it will no longer be triggered after calling
2669      * cancel.
2670      *
2671      * @hide
2672      */
2673     @UnsupportedAppUsage
2674     public void cancelLocalOnlyHotspotRequest() {
2675         synchronized (mLock) {
2676             stopLocalOnlyHotspot();
2677         }
2678     }
2679 
2680     /**
2681      *  Method used to inform WifiService that the LocalOnlyHotspot is no longer needed.  This
2682      *  method is used by WifiManager to release LocalOnlyHotspotReservations held by calling
2683      *  applications and removes the internal tracking for the hotspot request.  When all requesting
2684      *  applications are finished using the hotspot, it will be stopped and WiFi will return to the
2685      *  previous operational mode.
2686      *
2687      *  This method should not be called by applications.  Instead, they should call the close()
2688      *  method on their LocalOnlyHotspotReservation.
2689      */
2690     private void stopLocalOnlyHotspot() {
2691         synchronized (mLock) {
2692             if (mLOHSCallbackProxy == null) {
2693                 // nothing to do, the callback was already cleaned up.
2694                 return;
2695             }
2696             mLOHSCallbackProxy = null;
2697             try {
2698                 mService.stopLocalOnlyHotspot();
2699             } catch (RemoteException e) {
2700                 throw e.rethrowFromSystemServer();
2701             }
2702         }
2703     }
2704 
2705     /**
2706      * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes.  Callers will
2707      * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
2708      * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
2709      * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(WifiConfiguration)} and
2710      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
2711      * <p>
2712      * Applications should have the
2713      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
2714      * permission.  Callers without the permission will trigger a
2715      * {@link java.lang.SecurityException}.
2716      * <p>
2717      * @param observer LocalOnlyHotspotObserver callback.
2718      * @param handler Handler to use for callbacks
2719      *
2720      * @hide
2721      */
2722     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
2723             @Nullable Handler handler) {
2724         synchronized (mLock) {
2725             Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
2726             mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer);
2727             try {
2728                 mService.startWatchLocalOnlyHotspot(
2729                         mLOHSObserverProxy.getMessenger(), new Binder());
2730                 mLOHSObserverProxy.registered();
2731             } catch (RemoteException e) {
2732                 mLOHSObserverProxy = null;
2733                 throw e.rethrowFromSystemServer();
2734             }
2735         }
2736     }
2737 
2738     /**
2739      * Allow callers to stop watching LocalOnlyHotspot state changes.  After calling this method,
2740      * applications will no longer receive callbacks.
2741      *
2742      * @hide
2743      */
2744     public void unregisterLocalOnlyHotspotObserver() {
2745         synchronized (mLock) {
2746             if (mLOHSObserverProxy == null) {
2747                 // nothing to do, the callback was already cleaned up
2748                 return;
2749             }
2750             mLOHSObserverProxy = null;
2751             try {
2752                 mService.stopWatchLocalOnlyHotspot();
2753             } catch (RemoteException e) {
2754                 throw e.rethrowFromSystemServer();
2755             }
2756         }
2757     }
2758 
2759     /**
2760      * Gets the Wi-Fi enabled state.
2761      * @return One of {@link #WIFI_AP_STATE_DISABLED},
2762      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
2763      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
2764      * @see #isWifiApEnabled()
2765      *
2766      * @hide
2767      */
2768     @SystemApi
2769     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
2770     public int getWifiApState() {
2771         try {
2772             return mService.getWifiApEnabledState();
2773         } catch (RemoteException e) {
2774             throw e.rethrowFromSystemServer();
2775         }
2776     }
2777 
2778     /**
2779      * Return whether Wi-Fi AP is enabled or disabled.
2780      * @return {@code true} if Wi-Fi AP is enabled
2781      * @see #getWifiApState()
2782      *
2783      * @hide
2784      */
2785     @SystemApi
2786     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
2787     public boolean isWifiApEnabled() {
2788         return getWifiApState() == WIFI_AP_STATE_ENABLED;
2789     }
2790 
2791     /**
2792      * Gets the Wi-Fi AP Configuration.
2793      * @return AP details in WifiConfiguration
2794      *
2795      * @hide
2796      */
2797     @SystemApi
2798     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
2799     public WifiConfiguration getWifiApConfiguration() {
2800         try {
2801             return mService.getWifiApConfiguration();
2802         } catch (RemoteException e) {
2803             throw e.rethrowFromSystemServer();
2804         }
2805     }
2806 
2807     /**
2808      * Sets the Wi-Fi AP Configuration.  The AP configuration must either be open or
2809      * WPA2 PSK networks.
2810      * @return {@code true} if the operation succeeded, {@code false} otherwise
2811      *
2812      * @hide
2813      */
2814     @SystemApi
2815     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
2816     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
2817         try {
2818             return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
2819         } catch (RemoteException e) {
2820             throw e.rethrowFromSystemServer();
2821         }
2822     }
2823 
2824     /**
2825      * Method that triggers a notification to the user about a conversion to their saved AP config.
2826      *
2827      * @hide
2828      */
2829     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
2830     public void notifyUserOfApBandConversion() {
2831         Log.d(TAG, "apBand was converted, notify the user");
2832         try {
2833             mService.notifyUserOfApBandConversion(mContext.getOpPackageName());
2834         } catch (RemoteException e) {
2835             throw e.rethrowFromSystemServer();
2836         }
2837     }
2838 
2839     /**
2840      * Enable/Disable TDLS on a specific local route.
2841      *
2842      * <p>
2843      * TDLS enables two wireless endpoints to talk to each other directly
2844      * without going through the access point that is managing the local
2845      * network. It saves bandwidth and improves quality of the link.
2846      * </p>
2847      * <p>
2848      * This API enables/disables the option of using TDLS. If enabled, the
2849      * underlying hardware is free to use TDLS or a hop through the access
2850      * point. If disabled, existing TDLS session is torn down and
2851      * hardware is restricted to use access point for transferring wireless
2852      * packets. Default value for all routes is 'disabled', meaning restricted
2853      * to use access point for transferring packets.
2854      * </p>
2855      *
2856      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
2857      * @param enable true = setup and false = tear down TDLS
2858      */
2859     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
2860         try {
2861             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
2862         } catch (RemoteException e) {
2863             throw e.rethrowFromSystemServer();
2864         }
2865     }
2866 
2867     /**
2868      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
2869      * this version allows you to specify remote endpoint with a MAC address.
2870      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
2871      * @param enable true = setup and false = tear down TDLS
2872      */
2873     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
2874         try {
2875             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
2876         } catch (RemoteException e) {
2877             throw e.rethrowFromSystemServer();
2878         }
2879     }
2880 
2881     /* TODO: deprecate synchronous API and open up the following API */
2882 
2883     private static final int BASE = Protocol.BASE_WIFI_MANAGER;
2884 
2885     /* Commands to WifiService */
2886     /** @hide */
2887     public static final int CONNECT_NETWORK                 = BASE + 1;
2888     /** @hide */
2889     public static final int CONNECT_NETWORK_FAILED          = BASE + 2;
2890     /** @hide */
2891     public static final int CONNECT_NETWORK_SUCCEEDED       = BASE + 3;
2892 
2893     /** @hide */
2894     public static final int FORGET_NETWORK                  = BASE + 4;
2895     /** @hide */
2896     public static final int FORGET_NETWORK_FAILED           = BASE + 5;
2897     /** @hide */
2898     public static final int FORGET_NETWORK_SUCCEEDED        = BASE + 6;
2899 
2900     /** @hide */
2901     public static final int SAVE_NETWORK                    = BASE + 7;
2902     /** @hide */
2903     public static final int SAVE_NETWORK_FAILED             = BASE + 8;
2904     /** @hide */
2905     public static final int SAVE_NETWORK_SUCCEEDED          = BASE + 9;
2906 
2907     /** @hide
2908      * @deprecated This is deprecated
2909      */
2910     public static final int START_WPS                       = BASE + 10;
2911     /** @hide
2912      * @deprecated This is deprecated
2913      */
2914     public static final int START_WPS_SUCCEEDED             = BASE + 11;
2915     /** @hide
2916      * @deprecated This is deprecated
2917      */
2918     public static final int WPS_FAILED                      = BASE + 12;
2919     /** @hide
2920      * @deprecated This is deprecated
2921      */
2922     public static final int WPS_COMPLETED                   = BASE + 13;
2923 
2924     /** @hide
2925      * @deprecated This is deprecated
2926      */
2927     public static final int CANCEL_WPS                      = BASE + 14;
2928     /** @hide
2929      * @deprecated This is deprecated
2930      */
2931     public static final int CANCEL_WPS_FAILED               = BASE + 15;
2932     /** @hide
2933      * @deprecated This is deprecated
2934      */
2935     public static final int CANCEL_WPS_SUCCEDED             = BASE + 16;
2936 
2937     /** @hide */
2938     public static final int DISABLE_NETWORK                 = BASE + 17;
2939     /** @hide */
2940     public static final int DISABLE_NETWORK_FAILED          = BASE + 18;
2941     /** @hide */
2942     public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 19;
2943 
2944     /** @hide */
2945     public static final int RSSI_PKTCNT_FETCH               = BASE + 20;
2946     /** @hide */
2947     public static final int RSSI_PKTCNT_FETCH_SUCCEEDED     = BASE + 21;
2948     /** @hide */
2949     public static final int RSSI_PKTCNT_FETCH_FAILED        = BASE + 22;
2950 
2951     /**
2952      * Passed with {@link ActionListener#onFailure}.
2953      * Indicates that the operation failed due to an internal error.
2954      * @hide
2955      */
2956     public static final int ERROR                       = 0;
2957 
2958     /**
2959      * Passed with {@link ActionListener#onFailure}.
2960      * Indicates that the operation is already in progress
2961      * @hide
2962      */
2963     public static final int IN_PROGRESS                 = 1;
2964 
2965     /**
2966      * Passed with {@link ActionListener#onFailure}.
2967      * Indicates that the operation failed because the framework is busy and
2968      * unable to service the request
2969      * @hide
2970      */
2971     public static final int BUSY                        = 2;
2972 
2973     /* WPS specific errors */
2974     /** WPS overlap detected
2975      * @deprecated This is deprecated
2976      */
2977     public static final int WPS_OVERLAP_ERROR           = 3;
2978     /** WEP on WPS is prohibited
2979      * @deprecated This is deprecated
2980      */
2981     public static final int WPS_WEP_PROHIBITED          = 4;
2982     /** TKIP only prohibited
2983      * @deprecated This is deprecated
2984      */
2985     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
2986     /** Authentication failure on WPS
2987      * @deprecated This is deprecated
2988      */
2989     public static final int WPS_AUTH_FAILURE            = 6;
2990     /** WPS timed out
2991      * @deprecated This is deprecated
2992      */
2993     public static final int WPS_TIMED_OUT               = 7;
2994 
2995     /**
2996      * Passed with {@link ActionListener#onFailure}.
2997      * Indicates that the operation failed due to invalid inputs
2998      * @hide
2999      */
3000     public static final int INVALID_ARGS                = 8;
3001 
3002     /**
3003      * Passed with {@link ActionListener#onFailure}.
3004      * Indicates that the operation failed due to user permissions.
3005      * @hide
3006      */
3007     public static final int NOT_AUTHORIZED              = 9;
3008 
3009     /**
3010      * Interface for callback invocation on an application action
3011      * @hide
3012      */
3013     @SystemApi
3014     public interface ActionListener {
3015         /**
3016          * The operation succeeded.
3017          * This is called when the scan request has been validated and ready
3018          * to sent to driver.
3019          */
3020         public void onSuccess();
3021         /**
3022          * The operation failed.
3023          * This is called when the scan request failed.
3024          * @param reason The reason for failure could be one of the following:
3025          * {@link #REASON_INVALID_REQUEST}} is specified when scan request parameters are invalid.
3026          * {@link #REASON_NOT_AUTHORIZED} is specified when requesting app doesn't have the required
3027          * permission to request a scan.
3028          * {@link #REASON_UNSPECIFIED} is specified when driver reports a scan failure.
3029          */
3030         public void onFailure(int reason);
3031     }
3032 
3033     /** Interface for callback invocation on a start WPS action
3034      * @deprecated This is deprecated
3035      */
3036     public static abstract class WpsCallback {
3037 
3038         /** WPS start succeeded
3039          * @deprecated This API is deprecated
3040          */
3041         public abstract void onStarted(String pin);
3042 
3043         /** WPS operation completed successfully
3044          * @deprecated This API is deprecated
3045          */
3046         public abstract void onSucceeded();
3047 
3048         /**
3049          * WPS operation failed
3050          * @param reason The reason for failure could be one of
3051          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
3052          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
3053          * and some generic errors.
3054          * @deprecated This API is deprecated
3055          */
3056         public abstract void onFailed(int reason);
3057     }
3058 
3059     /** Interface for callback invocation on a TX packet count poll action {@hide} */
3060     public interface TxPacketCountListener {
3061         /**
3062          * The operation succeeded
3063          * @param count TX packet counter
3064          */
3065         public void onSuccess(int count);
3066         /**
3067          * The operation failed
3068          * @param reason The reason for failure could be one of
3069          * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
3070          */
3071         public void onFailure(int reason);
3072     }
3073 
3074     /**
3075      * Base class for soft AP callback. Should be extended by applications and set when calling
3076      * {@link WifiManager#registerSoftApCallback(SoftApCallback, Handler)}.
3077      *
3078      * @hide
3079      */
3080     public interface SoftApCallback {
3081         /**
3082          * Called when soft AP state changes.
3083          *
3084          * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
3085          *        {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
3086          *        {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
3087          * @param failureReason reason when in failed state. One of
3088          *        {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL}
3089          */
3090         public abstract void onStateChanged(@WifiApState int state,
3091                 @SapStartFailure int failureReason);
3092 
3093         /**
3094          * Called when number of connected clients to soft AP changes.
3095          *
3096          * @param numClients number of connected clients
3097          */
3098         public abstract void onNumClientsChanged(int numClients);
3099     }
3100 
3101     /**
3102      * Callback proxy for SoftApCallback objects.
3103      *
3104      * @hide
3105      */
3106     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
3107         private final Handler mHandler;
3108         private final SoftApCallback mCallback;
3109 
3110         SoftApCallbackProxy(Looper looper, SoftApCallback callback) {
3111             mHandler = new Handler(looper);
3112             mCallback = callback;
3113         }
3114 
3115         @Override
3116         public void onStateChanged(int state, int failureReason) {
3117             if (mVerboseLoggingEnabled) {
3118                 Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state
3119                         + ", failureReason=" + failureReason);
3120             }
3121             mHandler.post(() -> {
3122                 mCallback.onStateChanged(state, failureReason);
3123             });
3124         }
3125 
3126         @Override
onNumClientsChanged(int numClients)3127         public void onNumClientsChanged(int numClients) {
3128             if (mVerboseLoggingEnabled) {
3129                 Log.v(TAG, "SoftApCallbackProxy: onNumClientsChanged: numClients=" + numClients);
3130             }
3131             mHandler.post(() -> {
3132                 mCallback.onNumClientsChanged(numClients);
3133             });
3134         }
3135     }
3136 
3137     /**
3138      * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the current
3139      * soft AP state and number of connected devices immediately after a successful call to this API
3140      * via callback. Note that receiving an immediate WIFI_AP_STATE_FAILED value for soft AP state
3141      * indicates that the latest attempt to start soft AP has failed. Caller can unregister a
3142      * previously registered callback using {@link unregisterSoftApCallback}
3143      * <p>
3144      * Applications should have the
3145      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
3146      * without the permission will trigger a {@link java.lang.SecurityException}.
3147      * <p>
3148      *
3149      * @param callback Callback for soft AP events
3150      * @param handler  The Handler on whose thread to execute the callbacks of the {@code callback}
3151      *                 object. If null, then the application's main thread will be used.
3152      *
3153      * @hide
3154      */
3155     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerSoftApCallback(@onNull SoftApCallback callback, @Nullable Handler handler)3156     public void registerSoftApCallback(@NonNull SoftApCallback callback,
3157                                        @Nullable Handler handler) {
3158         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3159         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", handler=" + handler);
3160 
3161         Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
3162         Binder binder = new Binder();
3163         try {
3164             mService.registerSoftApCallback(binder, new SoftApCallbackProxy(looper, callback),
3165                     callback.hashCode());
3166         } catch (RemoteException e) {
3167             throw e.rethrowFromSystemServer();
3168         }
3169     }
3170 
3171     /**
3172      * Allow callers to unregister a previously registered callback. After calling this method,
3173      * applications will no longer receive soft AP events.
3174      *
3175      * @param callback Callback to unregister for soft AP events
3176      *
3177      * @hide
3178      */
3179     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterSoftApCallback(@onNull SoftApCallback callback)3180     public void unregisterSoftApCallback(@NonNull SoftApCallback callback) {
3181         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3182         Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
3183 
3184         try {
3185             mService.unregisterSoftApCallback(callback.hashCode());
3186         } catch (RemoteException e) {
3187             throw e.rethrowFromSystemServer();
3188         }
3189     }
3190 
3191     /**
3192      * LocalOnlyHotspotReservation that contains the {@link WifiConfiguration} for the active
3193      * LocalOnlyHotspot request.
3194      * <p>
3195      * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
3196      * LocalOnlyHotspotReservation in the
3197      * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call.  This
3198      * reservation contains the relevant {@link WifiConfiguration}.
3199      * When an application is done with the LocalOnlyHotspot, they should call {@link
3200      * LocalOnlyHotspotReservation#close()}.  Once this happens, the application will not receive
3201      * any further callbacks. If the LocalOnlyHotspot is stopped due to a
3202      * user triggered mode change, applications will be notified via the {@link
3203      * LocalOnlyHotspotCallback#onStopped()} callback.
3204      */
3205     public class LocalOnlyHotspotReservation implements AutoCloseable {
3206 
3207         private final CloseGuard mCloseGuard = CloseGuard.get();
3208         private final WifiConfiguration mConfig;
3209 
3210         /** @hide */
3211         @VisibleForTesting
LocalOnlyHotspotReservation(WifiConfiguration config)3212         public LocalOnlyHotspotReservation(WifiConfiguration config) {
3213             mConfig = config;
3214             mCloseGuard.open("close");
3215         }
3216 
getWifiConfiguration()3217         public WifiConfiguration getWifiConfiguration() {
3218             return mConfig;
3219         }
3220 
3221         @Override
close()3222         public void close() {
3223             try {
3224                 stopLocalOnlyHotspot();
3225                 mCloseGuard.close();
3226             } catch (Exception e) {
3227                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
3228             }
3229         }
3230 
3231         @Override
finalize()3232         protected void finalize() throws Throwable {
3233             try {
3234                 if (mCloseGuard != null) {
3235                     mCloseGuard.warnIfOpen();
3236                 }
3237                 close();
3238             } finally {
3239                 super.finalize();
3240             }
3241         }
3242     }
3243 
3244     /**
3245      * Callback class for applications to receive updates about the LocalOnlyHotspot status.
3246      */
3247     public static class LocalOnlyHotspotCallback {
3248         /** @hide */
3249         public static final int REQUEST_REGISTERED = 0;
3250 
3251         public static final int ERROR_NO_CHANNEL = 1;
3252         public static final int ERROR_GENERIC = 2;
3253         public static final int ERROR_INCOMPATIBLE_MODE = 3;
3254         public static final int ERROR_TETHERING_DISALLOWED = 4;
3255 
3256         /** LocalOnlyHotspot start succeeded. */
onStarted(LocalOnlyHotspotReservation reservation)3257         public void onStarted(LocalOnlyHotspotReservation reservation) {};
3258 
3259         /**
3260          * LocalOnlyHotspot stopped.
3261          * <p>
3262          * The LocalOnlyHotspot can be disabled at any time by the user.  When this happens,
3263          * applications will be notified that it was stopped. This will not be invoked when an
3264          * application calls {@link LocalOnlyHotspotReservation#close()}.
3265          */
onStopped()3266         public void onStopped() {};
3267 
3268         /**
3269          * LocalOnlyHotspot failed to start.
3270          * <p>
3271          * Applications can attempt to call
3272          * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at
3273          * a later time.
3274          * <p>
3275          * @param reason The reason for failure could be one of: {@link
3276          * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE},
3277          * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}.
3278          */
onFailed(int reason)3279         public void onFailed(int reason) { };
3280     }
3281 
3282     /**
3283      * Callback proxy for LocalOnlyHotspotCallback objects.
3284      */
3285     private static class LocalOnlyHotspotCallbackProxy {
3286         private final Handler mHandler;
3287         private final WeakReference<WifiManager> mWifiManager;
3288         private final Looper mLooper;
3289         private final Messenger mMessenger;
3290 
3291         /**
3292          * Constructs a {@link LocalOnlyHotspotCallback} using the specified looper.  All callbacks
3293          * will be delivered on the thread of the specified looper.
3294          *
3295          * @param manager WifiManager
3296          * @param looper Looper for delivering callbacks
3297          * @param callback LocalOnlyHotspotCallback to notify the calling application.
3298          */
LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper, final LocalOnlyHotspotCallback callback)3299         LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper,
3300                 final LocalOnlyHotspotCallback callback) {
3301             mWifiManager = new WeakReference<>(manager);
3302             mLooper = looper;
3303 
3304             mHandler = new Handler(looper) {
3305                 @Override
3306                 public void handleMessage(Message msg) {
3307                     Log.d(TAG, "LocalOnlyHotspotCallbackProxy: handle message what: "
3308                             + msg.what + " msg: " + msg);
3309 
3310                     WifiManager manager = mWifiManager.get();
3311                     if (manager == null) {
3312                         Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC");
3313                         return;
3314                     }
3315 
3316                     switch (msg.what) {
3317                         case HOTSPOT_STARTED:
3318                             WifiConfiguration config = (WifiConfiguration) msg.obj;
3319                             if (config == null) {
3320                                 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
3321                                 callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
3322                                 return;
3323                             }
3324                             callback.onStarted(manager.new LocalOnlyHotspotReservation(config));
3325                             break;
3326                         case HOTSPOT_STOPPED:
3327                             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
3328                             callback.onStopped();
3329                             break;
3330                         case HOTSPOT_FAILED:
3331                             int reasonCode = msg.arg1;
3332                             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
3333                                     + reasonCode);
3334                             callback.onFailed(reasonCode);
3335                             Log.w(TAG, "done with the callback...");
3336                             break;
3337                         default:
3338                             Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message.  type: "
3339                                     + msg.what);
3340                     }
3341                 }
3342             };
3343             mMessenger = new Messenger(mHandler);
3344         }
3345 
getMessenger()3346         public Messenger getMessenger() {
3347             return mMessenger;
3348         }
3349 
3350         /**
3351          * Helper method allowing the the incoming application call to move the onFailed callback
3352          * over to the desired callback thread.
3353          *
3354          * @param reason int representing the error type
3355          */
notifyFailed(int reason)3356         public void notifyFailed(int reason) throws RemoteException {
3357             Message msg = Message.obtain();
3358             msg.what = HOTSPOT_FAILED;
3359             msg.arg1 = reason;
3360             mMessenger.send(msg);
3361         }
3362     }
3363 
3364     /**
3365      * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications
3366      * watching for LocalOnlyHotspot changes.
3367      *
3368      * @hide
3369      */
3370     public class LocalOnlyHotspotSubscription implements AutoCloseable {
3371         private final CloseGuard mCloseGuard = CloseGuard.get();
3372 
3373         /** @hide */
3374         @VisibleForTesting
LocalOnlyHotspotSubscription()3375         public LocalOnlyHotspotSubscription() {
3376             mCloseGuard.open("close");
3377         }
3378 
3379         @Override
close()3380         public void close() {
3381             try {
3382                 unregisterLocalOnlyHotspotObserver();
3383                 mCloseGuard.close();
3384             } catch (Exception e) {
3385                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
3386             }
3387         }
3388 
3389         @Override
finalize()3390         protected void finalize() throws Throwable {
3391             try {
3392                 if (mCloseGuard != null) {
3393                     mCloseGuard.warnIfOpen();
3394                 }
3395                 close();
3396             } finally {
3397                 super.finalize();
3398             }
3399         }
3400     }
3401 
3402     /**
3403      * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates.
3404      *
3405      * @hide
3406      */
3407     public static class LocalOnlyHotspotObserver {
3408         /**
3409          * Confirm registration for LocalOnlyHotspotChanges by returning a
3410          * LocalOnlyHotspotSubscription.
3411          */
onRegistered(LocalOnlyHotspotSubscription subscription)3412         public void onRegistered(LocalOnlyHotspotSubscription subscription) {};
3413 
3414         /**
3415          * LocalOnlyHotspot started with the supplied config.
3416          */
onStarted(WifiConfiguration config)3417         public void onStarted(WifiConfiguration config) {};
3418 
3419         /**
3420          * LocalOnlyHotspot stopped.
3421          */
onStopped()3422         public void onStopped() {};
3423     }
3424 
3425     /**
3426      * Callback proxy for LocalOnlyHotspotObserver objects.
3427      */
3428     private static class LocalOnlyHotspotObserverProxy {
3429         private final Handler mHandler;
3430         private final WeakReference<WifiManager> mWifiManager;
3431         private final Looper mLooper;
3432         private final Messenger mMessenger;
3433 
3434         /**
3435          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
3436          * All callbacks will be delivered on the thread of the specified looper.
3437          *
3438          * @param manager WifiManager
3439          * @param looper Looper for delivering callbacks
3440          * @param observer LocalOnlyHotspotObserver to notify the calling application.
3441          */
LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper, final LocalOnlyHotspotObserver observer)3442         LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper,
3443                 final LocalOnlyHotspotObserver observer) {
3444             mWifiManager = new WeakReference<>(manager);
3445             mLooper = looper;
3446 
3447             mHandler = new Handler(looper) {
3448                 @Override
3449                 public void handleMessage(Message msg) {
3450                     Log.d(TAG, "LocalOnlyHotspotObserverProxy: handle message what: "
3451                             + msg.what + " msg: " + msg);
3452 
3453                     WifiManager manager = mWifiManager.get();
3454                     if (manager == null) {
3455                         Log.w(TAG, "LocalOnlyHotspotObserverProxy: handle message post GC");
3456                         return;
3457                     }
3458 
3459                     switch (msg.what) {
3460                         case HOTSPOT_OBSERVER_REGISTERED:
3461                             observer.onRegistered(manager.new LocalOnlyHotspotSubscription());
3462                             break;
3463                         case HOTSPOT_STARTED:
3464                             WifiConfiguration config = (WifiConfiguration) msg.obj;
3465                             if (config == null) {
3466                                 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
3467                                 return;
3468                             }
3469                             observer.onStarted(config);
3470                             break;
3471                         case HOTSPOT_STOPPED:
3472                             observer.onStopped();
3473                             break;
3474                         default:
3475                             Log.e(TAG, "LocalOnlyHotspotObserverProxy unhandled message.  type: "
3476                                     + msg.what);
3477                     }
3478                 }
3479             };
3480             mMessenger = new Messenger(mHandler);
3481         }
3482 
getMessenger()3483         public Messenger getMessenger() {
3484             return mMessenger;
3485         }
3486 
registered()3487         public void registered() throws RemoteException {
3488             Message msg = Message.obtain();
3489             msg.what = HOTSPOT_OBSERVER_REGISTERED;
3490             mMessenger.send(msg);
3491         }
3492     }
3493 
3494     // Ensure that multiple ServiceHandler threads do not interleave message dispatch.
3495     private static final Object sServiceHandlerDispatchLock = new Object();
3496 
3497     private class ServiceHandler extends Handler {
ServiceHandler(Looper looper)3498         ServiceHandler(Looper looper) {
3499             super(looper);
3500         }
3501 
3502         @Override
handleMessage(Message message)3503         public void handleMessage(Message message) {
3504             synchronized (sServiceHandlerDispatchLock) {
3505                 dispatchMessageToListeners(message);
3506             }
3507         }
3508 
dispatchMessageToListeners(Message message)3509         private void dispatchMessageToListeners(Message message) {
3510             Object listener = removeListener(message.arg2);
3511             switch (message.what) {
3512                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
3513                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
3514                         mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
3515                     } else {
3516                         Log.e(TAG, "Failed to set up channel connection");
3517                         // This will cause all further async API calls on the WifiManager
3518                         // to fail and throw an exception
3519                         mAsyncChannel = null;
3520                     }
3521                     mConnected.countDown();
3522                     break;
3523                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
3524                     // Ignore
3525                     break;
3526                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
3527                     Log.e(TAG, "Channel connection lost");
3528                     // This will cause all further async API calls on the WifiManager
3529                     // to fail and throw an exception
3530                     mAsyncChannel = null;
3531                     getLooper().quit();
3532                     break;
3533                     /* ActionListeners grouped together */
3534                 case WifiManager.CONNECT_NETWORK_FAILED:
3535                 case WifiManager.FORGET_NETWORK_FAILED:
3536                 case WifiManager.SAVE_NETWORK_FAILED:
3537                 case WifiManager.DISABLE_NETWORK_FAILED:
3538                     if (listener != null) {
3539                         ((ActionListener) listener).onFailure(message.arg1);
3540                     }
3541                     break;
3542                     /* ActionListeners grouped together */
3543                 case WifiManager.CONNECT_NETWORK_SUCCEEDED:
3544                 case WifiManager.FORGET_NETWORK_SUCCEEDED:
3545                 case WifiManager.SAVE_NETWORK_SUCCEEDED:
3546                 case WifiManager.DISABLE_NETWORK_SUCCEEDED:
3547                     if (listener != null) {
3548                         ((ActionListener) listener).onSuccess();
3549                     }
3550                     break;
3551                 case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
3552                     if (listener != null) {
3553                         RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
3554                         if (info != null)
3555                             ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
3556                         else
3557                             ((TxPacketCountListener) listener).onFailure(ERROR);
3558                     }
3559                     break;
3560                 case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
3561                     if (listener != null) {
3562                         ((TxPacketCountListener) listener).onFailure(message.arg1);
3563                     }
3564                     break;
3565                 default:
3566                     //ignore
3567                     break;
3568             }
3569         }
3570     }
3571 
putListener(Object listener)3572     private int putListener(Object listener) {
3573         if (listener == null) return INVALID_KEY;
3574         int key;
3575         synchronized (mListenerMapLock) {
3576             do {
3577                 key = mListenerKey++;
3578             } while (key == INVALID_KEY);
3579             mListenerMap.put(key, listener);
3580         }
3581         return key;
3582     }
3583 
removeListener(int key)3584     private Object removeListener(int key) {
3585         if (key == INVALID_KEY) return null;
3586         synchronized (mListenerMapLock) {
3587             Object listener = mListenerMap.get(key);
3588             mListenerMap.remove(key);
3589             return listener;
3590         }
3591     }
3592 
getChannel()3593     private synchronized AsyncChannel getChannel() {
3594         if (mAsyncChannel == null) {
3595             Messenger messenger = getWifiServiceMessenger();
3596             if (messenger == null) {
3597                 throw new IllegalStateException(
3598                         "getWifiServiceMessenger() returned null!  This is invalid.");
3599             }
3600 
3601             mAsyncChannel = new AsyncChannel();
3602             mConnected = new CountDownLatch(1);
3603 
3604             Handler handler = new ServiceHandler(mLooper);
3605             mAsyncChannel.connect(mContext, handler, messenger);
3606             try {
3607                 mConnected.await();
3608             } catch (InterruptedException e) {
3609                 Log.e(TAG, "interrupted wait at init");
3610             }
3611         }
3612         return mAsyncChannel;
3613     }
3614 
3615     /**
3616      * Connect to a network with the given configuration. The network also
3617      * gets added to the list of configured networks for the foreground user.
3618      *
3619      * For a new network, this function is used instead of a
3620      * sequence of addNetwork(), enableNetwork(), and reconnect()
3621      *
3622      * @param config the set of variables that describe the configuration,
3623      *            contained in a {@link WifiConfiguration} object.
3624      * @param listener for callbacks on success or failure. Can be null.
3625      * @throws IllegalStateException if the WifiManager instance needs to be
3626      * initialized again
3627      *
3628      * @hide
3629      */
3630     @SystemApi
3631     @RequiresPermission(anyOf = {
3632             android.Manifest.permission.NETWORK_SETTINGS,
3633             android.Manifest.permission.NETWORK_SETUP_WIZARD,
3634             android.Manifest.permission.NETWORK_STACK
3635     })
connect(@onNull WifiConfiguration config, @Nullable ActionListener listener)3636     public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
3637         if (config == null) throw new IllegalArgumentException("config cannot be null");
3638         // Use INVALID_NETWORK_ID for arg1 when passing a config object
3639         // arg1 is used to pass network id when the network already exists
3640         getChannel().sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
3641                 putListener(listener), config);
3642     }
3643 
3644     /**
3645      * Connect to a network with the given networkId.
3646      *
3647      * This function is used instead of a enableNetwork() and reconnect()
3648      *
3649      * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
3650      *        getConfiguredNetworks}.
3651      * @param listener for callbacks on success or failure. Can be null.
3652      * @throws IllegalStateException if the WifiManager instance needs to be
3653      * initialized again
3654      * @hide
3655      */
3656     @SystemApi
3657     @RequiresPermission(anyOf = {
3658             android.Manifest.permission.NETWORK_SETTINGS,
3659             android.Manifest.permission.NETWORK_SETUP_WIZARD,
3660             android.Manifest.permission.NETWORK_STACK
3661     })
connect(int networkId, @Nullable ActionListener listener)3662     public void connect(int networkId, @Nullable ActionListener listener) {
3663         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
3664         getChannel().sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
3665     }
3666 
3667     /**
3668      * Save the given network to the list of configured networks for the
3669      * foreground user. If the network already exists, the configuration
3670      * is updated. Any new network is enabled by default.
3671      *
3672      * For a new network, this function is used instead of a
3673      * sequence of addNetwork() and enableNetwork().
3674      *
3675      * For an existing network, it accomplishes the task of updateNetwork()
3676      *
3677      * This API will cause reconnect if the crecdentials of the current active
3678      * connection has been changed.
3679      *
3680      * @param config the set of variables that describe the configuration,
3681      *            contained in a {@link WifiConfiguration} object.
3682      * @param listener for callbacks on success or failure. Can be null.
3683      * @throws IllegalStateException if the WifiManager instance needs to be
3684      * initialized again
3685      * @hide
3686      */
3687     @SystemApi
3688     @RequiresPermission(anyOf = {
3689             android.Manifest.permission.NETWORK_SETTINGS,
3690             android.Manifest.permission.NETWORK_SETUP_WIZARD,
3691             android.Manifest.permission.NETWORK_STACK
3692     })
save(@onNull WifiConfiguration config, @Nullable ActionListener listener)3693     public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
3694         if (config == null) throw new IllegalArgumentException("config cannot be null");
3695         getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
3696     }
3697 
3698     /**
3699      * Delete the network from the list of configured networks for the
3700      * foreground user.
3701      *
3702      * This function is used instead of a sequence of removeNetwork()
3703      *
3704      * @param config the set of variables that describe the configuration,
3705      *            contained in a {@link WifiConfiguration} object.
3706      * @param listener for callbacks on success or failure. Can be null.
3707      * @throws IllegalStateException if the WifiManager instance needs to be
3708      * initialized again
3709      * @hide
3710      */
3711     @SystemApi
3712     @RequiresPermission(anyOf = {
3713             android.Manifest.permission.NETWORK_SETTINGS,
3714             android.Manifest.permission.NETWORK_SETUP_WIZARD,
3715             android.Manifest.permission.NETWORK_STACK
3716     })
forget(int netId, @Nullable ActionListener listener)3717     public void forget(int netId, @Nullable ActionListener listener) {
3718         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
3719         getChannel().sendMessage(FORGET_NETWORK, netId, putListener(listener));
3720     }
3721 
3722     /**
3723      * Disable network
3724      *
3725      * @param netId is the network Id
3726      * @param listener for callbacks on success or failure. Can be null.
3727      * @throws IllegalStateException if the WifiManager instance needs to be
3728      * initialized again
3729      * @hide
3730      */
3731     @SystemApi
3732     @RequiresPermission(anyOf = {
3733             android.Manifest.permission.NETWORK_SETTINGS,
3734             android.Manifest.permission.NETWORK_SETUP_WIZARD,
3735             android.Manifest.permission.NETWORK_STACK
3736     })
disable(int netId, @Nullable ActionListener listener)3737     public void disable(int netId, @Nullable ActionListener listener) {
3738         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
3739         getChannel().sendMessage(DISABLE_NETWORK, netId, putListener(listener));
3740     }
3741 
3742     /**
3743      * Disable ephemeral Network
3744      *
3745      * @param SSID, in the format of WifiConfiguration's SSID.
3746      * @hide
3747      */
3748     @RequiresPermission(anyOf = {
3749             android.Manifest.permission.NETWORK_SETTINGS,
3750             android.Manifest.permission.NETWORK_STACK
3751     })
disableEphemeralNetwork(String SSID)3752     public void disableEphemeralNetwork(String SSID) {
3753         if (SSID == null) throw new IllegalArgumentException("SSID cannot be null");
3754         try {
3755             mService.disableEphemeralNetwork(SSID, mContext.getOpPackageName());
3756         } catch (RemoteException e) {
3757             throw e.rethrowFromSystemServer();
3758         }
3759     }
3760 
3761     /**
3762      * WPS suport has been deprecated from Client mode and this method will immediately trigger
3763      * {@link WpsCallback#onFailed(int)} with a generic error.
3764      *
3765      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
3766      * @param listener for callbacks on success or failure. Can be null.
3767      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
3768      * @deprecated This API is deprecated
3769      */
startWps(WpsInfo config, WpsCallback listener)3770     public void startWps(WpsInfo config, WpsCallback listener) {
3771         if (listener != null ) {
3772             listener.onFailed(ERROR);
3773         }
3774     }
3775 
3776     /**
3777      * WPS support has been deprecated from Client mode and this method will immediately trigger
3778      * {@link WpsCallback#onFailed(int)} with a generic error.
3779      *
3780      * @param listener for callbacks on success or failure. Can be null.
3781      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
3782      * @deprecated This API is deprecated
3783      */
cancelWps(WpsCallback listener)3784     public void cancelWps(WpsCallback listener) {
3785         if (listener != null) {
3786             listener.onFailed(ERROR);
3787         }
3788     }
3789 
3790     /**
3791      * Get a reference to WifiService handler. This is used by a client to establish
3792      * an AsyncChannel communication with WifiService
3793      *
3794      * @return Messenger pointing to the WifiService handler
3795      */
3796     @UnsupportedAppUsage
getWifiServiceMessenger()3797     private Messenger getWifiServiceMessenger() {
3798         try {
3799             return mService.getWifiServiceMessenger(mContext.getOpPackageName());
3800         } catch (RemoteException e) {
3801             throw e.rethrowFromSystemServer();
3802         }
3803     }
3804 
3805 
3806     /**
3807      * Allows an application to keep the Wi-Fi radio awake.
3808      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
3809      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
3810      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
3811      * WifiLocks are held in any application.
3812      * <p>
3813      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
3814      * could function over a mobile network, if available.  A program that needs to download large
3815      * files should hold a WifiLock to ensure that the download will complete, but a program whose
3816      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
3817      * affecting battery life.
3818      * <p>
3819      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
3820      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
3821      * is idle.
3822      * <p>
3823      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
3824      * permission in an {@code <uses-permission>} element of the application's manifest.
3825      */
3826     public class WifiLock {
3827         private String mTag;
3828         private final IBinder mBinder;
3829         private int mRefCount;
3830         int mLockType;
3831         private boolean mRefCounted;
3832         private boolean mHeld;
3833         private WorkSource mWorkSource;
3834 
WifiLock(int lockType, String tag)3835         private WifiLock(int lockType, String tag) {
3836             mTag = tag;
3837             mLockType = lockType;
3838             mBinder = new Binder();
3839             mRefCount = 0;
3840             mRefCounted = true;
3841             mHeld = false;
3842         }
3843 
3844         /**
3845          * Locks the Wi-Fi radio on until {@link #release} is called.
3846          *
3847          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
3848          * reference count, and the radio will remain locked as long as the reference count is
3849          * above zero.
3850          *
3851          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
3852          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
3853          * will be required, regardless of the number of times that {@code acquire} is called.
3854          */
acquire()3855         public void acquire() {
3856             synchronized (mBinder) {
3857                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
3858                     try {
3859                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
3860                         synchronized (WifiManager.this) {
3861                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
3862                                 mService.releaseWifiLock(mBinder);
3863                                 throw new UnsupportedOperationException(
3864                                             "Exceeded maximum number of wifi locks");
3865                             }
3866                             mActiveLockCount++;
3867                         }
3868                     } catch (RemoteException e) {
3869                         throw e.rethrowFromSystemServer();
3870                     }
3871                     mHeld = true;
3872                 }
3873             }
3874         }
3875 
3876         /**
3877          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
3878          *
3879          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
3880          * reference count, and the radio will be unlocked only when the reference count reaches
3881          * zero.  If the reference count goes below zero (that is, if {@code release} is called
3882          * a greater number of times than {@link #acquire}), an exception is thrown.
3883          *
3884          * If this WifiLock is not reference-counted, the first call to {@code release} (after
3885          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
3886          * calls will be ignored.
3887          */
release()3888         public void release() {
3889             synchronized (mBinder) {
3890                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
3891                     try {
3892                         mService.releaseWifiLock(mBinder);
3893                         synchronized (WifiManager.this) {
3894                             mActiveLockCount--;
3895                         }
3896                     } catch (RemoteException e) {
3897                         throw e.rethrowFromSystemServer();
3898                     }
3899                     mHeld = false;
3900                 }
3901                 if (mRefCount < 0) {
3902                     throw new RuntimeException("WifiLock under-locked " + mTag);
3903                 }
3904             }
3905         }
3906 
3907         /**
3908          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
3909          *
3910          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
3911          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
3912          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
3913          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
3914          * radio whenever {@link #release} is called and it is locked.
3915          *
3916          * @param refCounted true if this WifiLock should keep a reference count
3917          */
setReferenceCounted(boolean refCounted)3918         public void setReferenceCounted(boolean refCounted) {
3919             mRefCounted = refCounted;
3920         }
3921 
3922         /**
3923          * Checks whether this WifiLock is currently held.
3924          *
3925          * @return true if this WifiLock is held, false otherwise
3926          */
isHeld()3927         public boolean isHeld() {
3928             synchronized (mBinder) {
3929                 return mHeld;
3930             }
3931         }
3932 
setWorkSource(WorkSource ws)3933         public void setWorkSource(WorkSource ws) {
3934             synchronized (mBinder) {
3935                 if (ws != null && ws.isEmpty()) {
3936                     ws = null;
3937                 }
3938                 boolean changed = true;
3939                 if (ws == null) {
3940                     mWorkSource = null;
3941                 } else {
3942                     ws.clearNames();
3943                     if (mWorkSource == null) {
3944                         changed = mWorkSource != null;
3945                         mWorkSource = new WorkSource(ws);
3946                     } else {
3947                         changed = !mWorkSource.equals(ws);
3948                         if (changed) {
3949                             mWorkSource.set(ws);
3950                         }
3951                     }
3952                 }
3953                 if (changed && mHeld) {
3954                     try {
3955                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
3956                     } catch (RemoteException e) {
3957                         throw e.rethrowFromSystemServer();
3958                     }
3959                 }
3960             }
3961         }
3962 
toString()3963         public String toString() {
3964             String s1, s2, s3;
3965             synchronized (mBinder) {
3966                 s1 = Integer.toHexString(System.identityHashCode(this));
3967                 s2 = mHeld ? "held; " : "";
3968                 if (mRefCounted) {
3969                     s3 = "refcounted: refcount = " + mRefCount;
3970                 } else {
3971                     s3 = "not refcounted";
3972                 }
3973                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
3974             }
3975         }
3976 
3977         @Override
finalize()3978         protected void finalize() throws Throwable {
3979             super.finalize();
3980             synchronized (mBinder) {
3981                 if (mHeld) {
3982                     try {
3983                         mService.releaseWifiLock(mBinder);
3984                         synchronized (WifiManager.this) {
3985                             mActiveLockCount--;
3986                         }
3987                     } catch (RemoteException e) {
3988                         throw e.rethrowFromSystemServer();
3989                     }
3990                 }
3991             }
3992         }
3993     }
3994 
3995     /**
3996      * Creates a new WifiLock.
3997      *
3998      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL_HIGH_PERF}
3999      * and {@link #WIFI_MODE_FULL_LOW_LATENCY} for descriptions of the types of Wi-Fi locks.
4000      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
4001      *            never shown to the user under normal conditions, but should be descriptive
4002      *            enough to identify your application and the specific WifiLock within it, if it
4003      *            holds multiple WifiLocks.
4004      *
4005      * @return a new, unacquired WifiLock with the given tag.
4006      *
4007      * @see WifiLock
4008      */
createWifiLock(int lockType, String tag)4009     public WifiLock createWifiLock(int lockType, String tag) {
4010         return new WifiLock(lockType, tag);
4011     }
4012 
4013     /**
4014      * Creates a new WifiLock.
4015      *
4016      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
4017      *            never shown to the user under normal conditions, but should be descriptive
4018      *            enough to identify your application and the specific WifiLock within it, if it
4019      *            holds multiple WifiLocks.
4020      *
4021      * @return a new, unacquired WifiLock with the given tag.
4022      *
4023      * @see WifiLock
4024      *
4025      * @deprecated This API is non-functional.
4026      */
4027     @Deprecated
createWifiLock(String tag)4028     public WifiLock createWifiLock(String tag) {
4029         return new WifiLock(WIFI_MODE_FULL, tag);
4030     }
4031 
4032     /**
4033      * Create a new MulticastLock
4034      *
4035      * @param tag a tag for the MulticastLock to identify it in debugging
4036      *            messages.  This string is never shown to the user under
4037      *            normal conditions, but should be descriptive enough to
4038      *            identify your application and the specific MulticastLock
4039      *            within it, if it holds multiple MulticastLocks.
4040      *
4041      * @return a new, unacquired MulticastLock with the given tag.
4042      *
4043      * @see MulticastLock
4044      */
createMulticastLock(String tag)4045     public MulticastLock createMulticastLock(String tag) {
4046         return new MulticastLock(tag);
4047     }
4048 
4049     /**
4050      * Allows an application to receive Wifi Multicast packets.
4051      * Normally the Wifi stack filters out packets not explicitly
4052      * addressed to this device.  Acquring a MulticastLock will
4053      * cause the stack to receive packets addressed to multicast
4054      * addresses.  Processing these extra packets can cause a noticeable
4055      * battery drain and should be disabled when not needed.
4056      */
4057     public class MulticastLock {
4058         private String mTag;
4059         private final IBinder mBinder;
4060         private int mRefCount;
4061         private boolean mRefCounted;
4062         private boolean mHeld;
4063 
MulticastLock(String tag)4064         private MulticastLock(String tag) {
4065             mTag = tag;
4066             mBinder = new Binder();
4067             mRefCount = 0;
4068             mRefCounted = true;
4069             mHeld = false;
4070         }
4071 
4072         /**
4073          * Locks Wifi Multicast on until {@link #release} is called.
4074          *
4075          * If this MulticastLock is reference-counted each call to
4076          * {@code acquire} will increment the reference count, and the
4077          * wifi interface will receive multicast packets as long as the
4078          * reference count is above zero.
4079          *
4080          * If this MulticastLock is not reference-counted, the first call to
4081          * {@code acquire} will turn on the multicast packets, but subsequent
4082          * calls will be ignored.  Only one call to {@link #release} will
4083          * be required, regardless of the number of times that {@code acquire}
4084          * is called.
4085          *
4086          * Note that other applications may also lock Wifi Multicast on.
4087          * Only they can relinquish their lock.
4088          *
4089          * Also note that applications cannot leave Multicast locked on.
4090          * When an app exits or crashes, any Multicast locks will be released.
4091          */
acquire()4092         public void acquire() {
4093             synchronized (mBinder) {
4094                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
4095                     try {
4096                         mService.acquireMulticastLock(mBinder, mTag);
4097                         synchronized (WifiManager.this) {
4098                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
4099                                 mService.releaseMulticastLock(mTag);
4100                                 throw new UnsupportedOperationException(
4101                                         "Exceeded maximum number of wifi locks");
4102                             }
4103                             mActiveLockCount++;
4104                         }
4105                     } catch (RemoteException e) {
4106                         throw e.rethrowFromSystemServer();
4107                     }
4108                     mHeld = true;
4109                 }
4110             }
4111         }
4112 
4113         /**
4114          * Unlocks Wifi Multicast, restoring the filter of packets
4115          * not addressed specifically to this device and saving power.
4116          *
4117          * If this MulticastLock is reference-counted, each call to
4118          * {@code release} will decrement the reference count, and the
4119          * multicast packets will only stop being received when the reference
4120          * count reaches zero.  If the reference count goes below zero (that
4121          * is, if {@code release} is called a greater number of times than
4122          * {@link #acquire}), an exception is thrown.
4123          *
4124          * If this MulticastLock is not reference-counted, the first call to
4125          * {@code release} (after the radio was multicast locked using
4126          * {@link #acquire}) will unlock the multicast, and subsequent calls
4127          * will be ignored.
4128          *
4129          * Note that if any other Wifi Multicast Locks are still outstanding
4130          * this {@code release} call will not have an immediate effect.  Only
4131          * when all applications have released all their Multicast Locks will
4132          * the Multicast filter be turned back on.
4133          *
4134          * Also note that when an app exits or crashes all of its Multicast
4135          * Locks will be automatically released.
4136          */
release()4137         public void release() {
4138             synchronized (mBinder) {
4139                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
4140                     try {
4141                         mService.releaseMulticastLock(mTag);
4142                         synchronized (WifiManager.this) {
4143                             mActiveLockCount--;
4144                         }
4145                     } catch (RemoteException e) {
4146                         throw e.rethrowFromSystemServer();
4147                     }
4148                     mHeld = false;
4149                 }
4150                 if (mRefCount < 0) {
4151                     throw new RuntimeException("MulticastLock under-locked "
4152                             + mTag);
4153                 }
4154             }
4155         }
4156 
4157         /**
4158          * Controls whether this is a reference-counted or non-reference-
4159          * counted MulticastLock.
4160          *
4161          * Reference-counted MulticastLocks keep track of the number of calls
4162          * to {@link #acquire} and {@link #release}, and only stop the
4163          * reception of multicast packets when every call to {@link #acquire}
4164          * has been balanced with a call to {@link #release}.  Non-reference-
4165          * counted MulticastLocks allow the reception of multicast packets
4166          * whenever {@link #acquire} is called and stop accepting multicast
4167          * packets whenever {@link #release} is called.
4168          *
4169          * @param refCounted true if this MulticastLock should keep a reference
4170          * count
4171          */
setReferenceCounted(boolean refCounted)4172         public void setReferenceCounted(boolean refCounted) {
4173             mRefCounted = refCounted;
4174         }
4175 
4176         /**
4177          * Checks whether this MulticastLock is currently held.
4178          *
4179          * @return true if this MulticastLock is held, false otherwise
4180          */
isHeld()4181         public boolean isHeld() {
4182             synchronized (mBinder) {
4183                 return mHeld;
4184             }
4185         }
4186 
toString()4187         public String toString() {
4188             String s1, s2, s3;
4189             synchronized (mBinder) {
4190                 s1 = Integer.toHexString(System.identityHashCode(this));
4191                 s2 = mHeld ? "held; " : "";
4192                 if (mRefCounted) {
4193                     s3 = "refcounted: refcount = " + mRefCount;
4194                 } else {
4195                     s3 = "not refcounted";
4196                 }
4197                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
4198             }
4199         }
4200 
4201         @Override
finalize()4202         protected void finalize() throws Throwable {
4203             super.finalize();
4204             setReferenceCounted(false);
4205             release();
4206         }
4207     }
4208 
4209     /**
4210      * Check multicast filter status.
4211      *
4212      * @return true if multicast packets are allowed.
4213      *
4214      * @hide pending API council approval
4215      */
isMulticastEnabled()4216     public boolean isMulticastEnabled() {
4217         try {
4218             return mService.isMulticastEnabled();
4219         } catch (RemoteException e) {
4220             throw e.rethrowFromSystemServer();
4221         }
4222     }
4223 
4224     /**
4225      * Initialize the multicast filtering to 'on'
4226      * @hide no intent to publish
4227      */
4228     @UnsupportedAppUsage
initializeMulticastFiltering()4229     public boolean initializeMulticastFiltering() {
4230         try {
4231             mService.initializeMulticastFiltering();
4232             return true;
4233         } catch (RemoteException e) {
4234             throw e.rethrowFromSystemServer();
4235         }
4236     }
4237 
finalize()4238     protected void finalize() throws Throwable {
4239         try {
4240             if (mAsyncChannel != null) {
4241                 mAsyncChannel.disconnect();
4242             }
4243         } finally {
4244             super.finalize();
4245         }
4246     }
4247 
4248     /**
4249      * Set wifi verbose log. Called from developer settings.
4250      * @hide
4251      */
4252     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
4253     @UnsupportedAppUsage
enableVerboseLogging(int verbose)4254     public void enableVerboseLogging (int verbose) {
4255         try {
4256             mService.enableVerboseLogging(verbose);
4257         } catch (Exception e) {
4258             //ignore any failure here
4259             Log.e(TAG, "enableVerboseLogging " + e.toString());
4260         }
4261     }
4262 
4263     /**
4264      * Get the WiFi verbose logging level.This is used by settings
4265      * to decide what to show within the picker.
4266      * @hide
4267      */
4268     @UnsupportedAppUsage
getVerboseLoggingLevel()4269     public int getVerboseLoggingLevel() {
4270         try {
4271             return mService.getVerboseLoggingLevel();
4272         } catch (RemoteException e) {
4273             throw e.rethrowFromSystemServer();
4274         }
4275     }
4276 
4277     /**
4278      * Removes all saved wifi networks.
4279      *
4280      * @hide
4281      */
factoryReset()4282     public void factoryReset() {
4283         try {
4284             mService.factoryReset(mContext.getOpPackageName());
4285         } catch (RemoteException e) {
4286             throw e.rethrowFromSystemServer();
4287         }
4288     }
4289 
4290     /**
4291      * Get Network object of current wifi network
4292      * @return Get Network object of current wifi network
4293      * @hide
4294      */
4295     @UnsupportedAppUsage
getCurrentNetwork()4296     public Network getCurrentNetwork() {
4297         try {
4298             return mService.getCurrentNetwork();
4299         } catch (RemoteException e) {
4300             throw e.rethrowFromSystemServer();
4301         }
4302     }
4303 
4304     /**
4305      * Deprecated
4306      * returns false
4307      * @hide
4308      * @deprecated
4309      */
setEnableAutoJoinWhenAssociated(boolean enabled)4310     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
4311         return false;
4312     }
4313 
4314     /**
4315      * Deprecated
4316      * returns false
4317      * @hide
4318      * @deprecated
4319      */
getEnableAutoJoinWhenAssociated()4320     public boolean getEnableAutoJoinWhenAssociated() {
4321         return false;
4322     }
4323 
4324     /**
4325      * Enable/disable WifiConnectivityManager
4326      * @hide
4327      */
enableWifiConnectivityManager(boolean enabled)4328     public void enableWifiConnectivityManager(boolean enabled) {
4329         try {
4330             mService.enableWifiConnectivityManager(enabled);
4331         } catch (RemoteException e) {
4332             throw e.rethrowFromSystemServer();
4333         }
4334     }
4335 
4336     /**
4337      * Retrieve the data to be backed to save the current state.
4338      * @hide
4339      */
retrieveBackupData()4340     public byte[] retrieveBackupData() {
4341         try {
4342             return mService.retrieveBackupData();
4343         } catch (RemoteException e) {
4344             throw e.rethrowFromSystemServer();
4345         }
4346     }
4347 
4348     /**
4349      * Restore state from the backed up data.
4350      * @hide
4351      */
restoreBackupData(byte[] data)4352     public void restoreBackupData(byte[] data) {
4353         try {
4354             mService.restoreBackupData(data);
4355         } catch (RemoteException e) {
4356             throw e.rethrowFromSystemServer();
4357         }
4358     }
4359 
4360     /**
4361      * Restore state from the older version of back up data.
4362      * The old backup data was essentially a backup of wpa_supplicant.conf
4363      * and ipconfig.txt file.
4364      * @deprecated this is no longer supported.
4365      * @hide
4366      */
4367     @Deprecated
restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData)4368     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
4369         try {
4370             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
4371         } catch (RemoteException e) {
4372             throw e.rethrowFromSystemServer();
4373         }
4374     }
4375 
4376     /**
4377      * Start subscription provisioning flow
4378      *
4379      * @param provider {@link OsuProvider} to provision with
4380      * @param executor the Executor on which to run the callback.
4381      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
4382      * @hide
4383      */
4384     @SystemApi
4385     @RequiresPermission(anyOf = {
4386             android.Manifest.permission.NETWORK_SETTINGS,
4387             android.Manifest.permission.NETWORK_SETUP_WIZARD
4388     })
startSubscriptionProvisioning(@onNull OsuProvider provider, @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback)4389     public void startSubscriptionProvisioning(@NonNull OsuProvider provider,
4390             @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback) {
4391         // Verify arguments
4392         if (executor == null) {
4393             throw new IllegalArgumentException("executor must not be null");
4394         }
4395         if (callback == null) {
4396             throw new IllegalArgumentException("callback must not be null");
4397         }
4398         try {
4399             mService.startSubscriptionProvisioning(provider,
4400                     new ProvisioningCallbackProxy(executor, callback));
4401         } catch (RemoteException e) {
4402             throw e.rethrowFromSystemServer();
4403         }
4404     }
4405 
4406     /**
4407      * Helper class to support OSU Provisioning callbacks
4408      */
4409     private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
4410         private final Executor mExecutor;
4411         private final ProvisioningCallback mCallback;
4412 
ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback)4413         ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback) {
4414             mExecutor = executor;
4415             mCallback = callback;
4416         }
4417 
4418         @Override
onProvisioningStatus(int status)4419         public void onProvisioningStatus(int status) {
4420             mExecutor.execute(() -> mCallback.onProvisioningStatus(status));
4421         }
4422 
4423         @Override
onProvisioningFailure(int status)4424         public void onProvisioningFailure(int status) {
4425             mExecutor.execute(() -> mCallback.onProvisioningFailure(status));
4426         }
4427 
4428         @Override
onProvisioningComplete()4429         public void onProvisioningComplete() {
4430             mExecutor.execute(() -> mCallback.onProvisioningComplete());
4431         }
4432     }
4433 
4434     /**
4435      * Base class for Traffic state callback. Should be extended by applications and set when
4436      * calling {@link WifiManager#registerTrafficStateCallback(TrafficStateCallback, Handler)}.
4437      * @hide
4438      */
4439     public interface TrafficStateCallback {
4440         /**
4441          * Lowest bit indicates data reception and the second lowest
4442          * bit indicates data transmitted
4443          */
4444         /** @hide */
4445         int DATA_ACTIVITY_NONE         = 0x00;
4446         /** @hide */
4447         int DATA_ACTIVITY_IN           = 0x01;
4448         /** @hide */
4449         int DATA_ACTIVITY_OUT          = 0x02;
4450         /** @hide */
4451         int DATA_ACTIVITY_INOUT        = 0x03;
4452 
4453         /**
4454          * Callback invoked to inform clients about the current traffic state.
4455          *
4456          * @param state One of the values: {@link #DATA_ACTIVITY_NONE}, {@link #DATA_ACTIVITY_IN},
4457          * {@link #DATA_ACTIVITY_OUT} & {@link #DATA_ACTIVITY_INOUT}.
4458          * @hide
4459          */
onStateChanged(int state)4460         void onStateChanged(int state);
4461     }
4462 
4463     /**
4464      * Callback proxy for TrafficStateCallback objects.
4465      *
4466      * @hide
4467      */
4468     private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub {
4469         private final Handler mHandler;
4470         private final TrafficStateCallback mCallback;
4471 
TrafficStateCallbackProxy(Looper looper, TrafficStateCallback callback)4472         TrafficStateCallbackProxy(Looper looper, TrafficStateCallback callback) {
4473             mHandler = new Handler(looper);
4474             mCallback = callback;
4475         }
4476 
4477         @Override
onStateChanged(int state)4478         public void onStateChanged(int state) {
4479             if (mVerboseLoggingEnabled) {
4480                 Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state);
4481             }
4482             mHandler.post(() -> {
4483                 mCallback.onStateChanged(state);
4484             });
4485         }
4486     }
4487 
4488     /**
4489      * Registers a callback for monitoring traffic state. See {@link TrafficStateCallback}. These
4490      * callbacks will be invoked periodically by platform to inform clients about the current
4491      * traffic state. Caller can unregister a previously registered callback using
4492      * {@link #unregisterTrafficStateCallback(TrafficStateCallback)}
4493      * <p>
4494      * Applications should have the
4495      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
4496      * without the permission will trigger a {@link java.lang.SecurityException}.
4497      * <p>
4498      *
4499      * @param callback Callback for traffic state events
4500      * @param handler  The Handler on whose thread to execute the callbacks of the {@code callback}
4501      *                 object. If null, then the application's main thread will be used.
4502      * @hide
4503      */
4504     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerTrafficStateCallback(@onNull TrafficStateCallback callback, @Nullable Handler handler)4505     public void registerTrafficStateCallback(@NonNull TrafficStateCallback callback,
4506                                              @Nullable Handler handler) {
4507         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
4508         Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", handler=" + handler);
4509 
4510         Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
4511         Binder binder = new Binder();
4512         try {
4513             mService.registerTrafficStateCallback(
4514                     binder, new TrafficStateCallbackProxy(looper, callback), callback.hashCode());
4515         } catch (RemoteException e) {
4516             throw e.rethrowFromSystemServer();
4517         }
4518     }
4519 
4520     /**
4521      * Allow callers to unregister a previously registered callback. After calling this method,
4522      * applications will no longer receive traffic state notifications.
4523      *
4524      * @param callback Callback to unregister for traffic state events
4525      * @hide
4526      */
4527     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterTrafficStateCallback(@onNull TrafficStateCallback callback)4528     public void unregisterTrafficStateCallback(@NonNull TrafficStateCallback callback) {
4529         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
4530         Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
4531 
4532         try {
4533             mService.unregisterTrafficStateCallback(callback.hashCode());
4534         } catch (RemoteException e) {
4535             throw e.rethrowFromSystemServer();
4536         }
4537     }
4538 
4539     /**
4540      * Helper method to update the local verbose logging flag based on the verbose logging
4541      * level from wifi service.
4542      */
updateVerboseLoggingEnabledFromService()4543     private void updateVerboseLoggingEnabledFromService() {
4544         mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0;
4545     }
4546 
4547     /**
4548      * @return true if this device supports WPA3-Personal SAE
4549      */
isWpa3SaeSupported()4550     public boolean isWpa3SaeSupported() {
4551         return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
4552     }
4553 
4554     /**
4555      * @return true if this device supports WPA3-Enterprise Suite-B-192
4556      */
isWpa3SuiteBSupported()4557     public boolean isWpa3SuiteBSupported() {
4558         return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
4559     }
4560 
4561     /**
4562      * @return true if this device supports Wi-Fi Enhanced Open (OWE)
4563      */
isEnhancedOpenSupported()4564     public boolean isEnhancedOpenSupported() {
4565         return isFeatureSupported(WIFI_FEATURE_OWE);
4566     }
4567 
4568     /**
4569      * Wi-Fi Easy Connect (DPP) introduces standardized mechanisms to simplify the provisioning and
4570      * configuration of Wi-Fi devices.
4571      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
4572      * search for "Easy Connect" or "Device Provisioning Protocol specification".
4573      *
4574      * @return true if this device supports Wi-Fi Easy-connect (Device Provisioning Protocol)
4575      */
isEasyConnectSupported()4576     public boolean isEasyConnectSupported() {
4577         return isFeatureSupported(WIFI_FEATURE_DPP);
4578     }
4579 
4580     /**
4581      * Gets the factory Wi-Fi MAC addresses.
4582      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
4583      * if failed.
4584      * @hide
4585      */
4586     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getFactoryMacAddresses()4587     public String[] getFactoryMacAddresses() {
4588         try {
4589             return mService.getFactoryMacAddresses();
4590         } catch (RemoteException e) {
4591             throw e.rethrowFromSystemServer();
4592         }
4593     }
4594 
4595     /** @hide */
4596     @Retention(RetentionPolicy.SOURCE)
4597     @IntDef(prefix = {"DEVICE_MOBILITY_STATE_"}, value = {
4598             DEVICE_MOBILITY_STATE_UNKNOWN,
4599             DEVICE_MOBILITY_STATE_HIGH_MVMT,
4600             DEVICE_MOBILITY_STATE_LOW_MVMT,
4601             DEVICE_MOBILITY_STATE_STATIONARY})
4602     public @interface DeviceMobilityState {}
4603 
4604     /**
4605      * Unknown device mobility state
4606      *
4607      * @see #setDeviceMobilityState(int)
4608      *
4609      * @hide
4610      */
4611     @SystemApi
4612     public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0;
4613 
4614     /**
4615      * High movement device mobility state.
4616      * e.g. on a bike, in a motor vehicle
4617      *
4618      * @see #setDeviceMobilityState(int)
4619      *
4620      * @hide
4621      */
4622     @SystemApi
4623     public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1;
4624 
4625     /**
4626      * Low movement device mobility state.
4627      * e.g. walking, running
4628      *
4629      * @see #setDeviceMobilityState(int)
4630      *
4631      * @hide
4632      */
4633     @SystemApi
4634     public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2;
4635 
4636     /**
4637      * Stationary device mobility state
4638      *
4639      * @see #setDeviceMobilityState(int)
4640      *
4641      * @hide
4642      */
4643     @SystemApi
4644     public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3;
4645 
4646     /**
4647      * Updates the device mobility state. Wifi uses this information to adjust the interval between
4648      * Wifi scans in order to balance power consumption with scan accuracy.
4649      * The default mobility state when the device boots is {@link #DEVICE_MOBILITY_STATE_UNKNOWN}.
4650      * This API should be called whenever there is a change in the mobility state.
4651      * @param state the updated device mobility state
4652      * @hide
4653      */
4654     @SystemApi
4655     @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
setDeviceMobilityState(@eviceMobilityState int state)4656     public void setDeviceMobilityState(@DeviceMobilityState int state) {
4657         try {
4658             mService.setDeviceMobilityState(state);
4659         } catch (RemoteException e) {
4660             throw e.rethrowFromSystemServer();
4661         }
4662     }
4663 
4664     /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
4665 
4666     /**
4667      * Easy Connect Network role: Station.
4668      *
4669      * @hide
4670      */
4671     @SystemApi
4672     public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
4673 
4674     /**
4675      * Easy Connect Network role: Access Point.
4676      *
4677      * @hide
4678      */
4679     @SystemApi
4680     public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
4681 
4682     /** @hide */
4683     @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
4684             EASY_CONNECT_NETWORK_ROLE_STA,
4685             EASY_CONNECT_NETWORK_ROLE_AP,
4686     })
4687     @Retention(RetentionPolicy.SOURCE)
4688     public @interface EasyConnectNetworkRole {
4689     }
4690 
4691     /**
4692      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
4693      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
4694      * the specified network using the Easy Connect protocol on an encrypted link.
4695      *
4696      * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
4697      * @param selectedNetworkId   Selected network ID to be sent to the peer
4698      * @param enrolleeNetworkRole The network role of the enrollee
4699      * @param callback            Callback for status updates
4700      * @param executor            The Executor on which to run the callback.
4701      * @hide
4702      */
4703     @SystemApi
4704     @RequiresPermission(anyOf = {
4705             android.Manifest.permission.NETWORK_SETTINGS,
4706             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsConfiguratorInitiator(@onNull String enrolleeUri, int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)4707     public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
4708             int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
4709             @NonNull @CallbackExecutor Executor executor,
4710             @NonNull EasyConnectStatusCallback callback) {
4711         Binder binder = new Binder();
4712         try {
4713             mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
4714                     enrolleeNetworkRole, new EasyConnectCallbackProxy(executor, callback));
4715         } catch (RemoteException e) {
4716             throw e.rethrowFromSystemServer();
4717         }
4718     }
4719 
4720     /**
4721      * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
4722      * Connect bootstrapping with a peer, and receive the SSID and password from the peer
4723      * configurator.
4724      *
4725      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
4726      * @param callback        Callback for status updates
4727      * @param executor        The Executor on which to run the callback.
4728      * @hide
4729      */
4730     @SystemApi
4731     @RequiresPermission(anyOf = {
4732             android.Manifest.permission.NETWORK_SETTINGS,
4733             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsEnrolleeInitiator(@onNull String configuratorUri, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)4734     public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
4735             @NonNull @CallbackExecutor Executor executor,
4736             @NonNull EasyConnectStatusCallback callback) {
4737         Binder binder = new Binder();
4738         try {
4739             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
4740                     new EasyConnectCallbackProxy(executor, callback));
4741         } catch (RemoteException e) {
4742             throw e.rethrowFromSystemServer();
4743         }
4744     }
4745 
4746     /**
4747      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
4748      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
4749      * expect any callbacks once this call is made. However, due to the asynchronous nature of
4750      * this call, a callback may be fired if it was already pending in the queue.
4751      *
4752      * @hide
4753      */
4754     @SystemApi
4755     @RequiresPermission(anyOf = {
4756             android.Manifest.permission.NETWORK_SETTINGS,
4757             android.Manifest.permission.NETWORK_SETUP_WIZARD})
stopEasyConnectSession()4758     public void stopEasyConnectSession() {
4759         try {
4760             /* Request lower layers to stop/abort and clear resources */
4761             mService.stopDppSession();
4762         } catch (RemoteException e) {
4763             throw e.rethrowFromSystemServer();
4764         }
4765     }
4766 
4767     /**
4768      * Helper class to support Easy Connect (DPP) callbacks
4769      *
4770      * @hide
4771      */
4772     private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
4773         private final Executor mExecutor;
4774         private final EasyConnectStatusCallback mEasyConnectStatusCallback;
4775 
EasyConnectCallbackProxy(Executor executor, EasyConnectStatusCallback easyConnectStatusCallback)4776         EasyConnectCallbackProxy(Executor executor,
4777                 EasyConnectStatusCallback easyConnectStatusCallback) {
4778             mExecutor = executor;
4779             mEasyConnectStatusCallback = easyConnectStatusCallback;
4780         }
4781 
4782         @Override
onSuccessConfigReceived(int newNetworkId)4783         public void onSuccessConfigReceived(int newNetworkId) {
4784             Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
4785             mExecutor.execute(() -> {
4786                 mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
4787             });
4788         }
4789 
4790         @Override
onSuccess(int status)4791         public void onSuccess(int status) {
4792             Log.d(TAG, "Easy Connect onSuccess callback");
4793             mExecutor.execute(() -> {
4794                 mEasyConnectStatusCallback.onConfiguratorSuccess(status);
4795             });
4796         }
4797 
4798         @Override
onFailure(int status)4799         public void onFailure(int status) {
4800             Log.d(TAG, "Easy Connect onFailure callback");
4801             mExecutor.execute(() -> {
4802                 mEasyConnectStatusCallback.onFailure(status);
4803             });
4804         }
4805 
4806         @Override
onProgress(int status)4807         public void onProgress(int status) {
4808             Log.d(TAG, "Easy Connect onProgress callback");
4809             mExecutor.execute(() -> {
4810                 mEasyConnectStatusCallback.onProgress(status);
4811             });
4812         }
4813     }
4814 
4815     /**
4816      * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
4817      * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor,
4818      * OnWifiUsabilityStatsListener)}.
4819      *
4820      * @hide
4821      */
4822     @SystemApi
4823     public interface OnWifiUsabilityStatsListener {
4824         /**
4825          * Called when Wi-Fi usability statistics is updated.
4826          *
4827          * @param seqNum The sequence number of statistics, used to derive the timing of updated
4828          *               Wi-Fi usability statistics, set by framework and incremented by one after
4829          *               each update.
4830          * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
4831          *                           network stays the same or not relative to the last update of
4832          *                           Wi-Fi usability stats.
4833          * @param stats The updated Wi-Fi usability statistics.
4834          */
onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, @NonNull WifiUsabilityStatsEntry stats)4835         void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
4836                 @NonNull WifiUsabilityStatsEntry stats);
4837     }
4838 
4839     /**
4840      * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}.
4841      * Multiple listeners can be added. Callers will be invoked periodically by framework to
4842      * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
4843      * added listener using {@link removeOnWifiUsabilityStatsListener}.
4844      *
4845      * @param executor The executor on which callback will be invoked.
4846      * @param listener Listener for Wifi usability statistics.
4847      *
4848      * @hide
4849      */
4850     @SystemApi
4851     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
addOnWifiUsabilityStatsListener(@onNull @allbackExecutor Executor executor, @NonNull OnWifiUsabilityStatsListener listener)4852     public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
4853             @NonNull OnWifiUsabilityStatsListener listener) {
4854         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
4855         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
4856         if (mVerboseLoggingEnabled) {
4857             Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
4858         }
4859         try {
4860             mService.addOnWifiUsabilityStatsListener(new Binder(),
4861                     new IOnWifiUsabilityStatsListener.Stub() {
4862                         @Override
4863                         public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
4864                                 WifiUsabilityStatsEntry stats) {
4865                             if (mVerboseLoggingEnabled) {
4866                                 Log.v(TAG, "OnWifiUsabilityStatsListener: "
4867                                         + "onWifiUsabilityStats: seqNum=" + seqNum);
4868                             }
4869                             Binder.withCleanCallingIdentity(() ->
4870                                     executor.execute(() -> listener.onWifiUsabilityStats(seqNum,
4871                                             isSameBssidAndFreq, stats)));
4872                         }
4873                     },
4874                     listener.hashCode()
4875             );
4876         } catch (RemoteException e) {
4877             throw e.rethrowFromSystemServer();
4878         }
4879     }
4880 
4881     /**
4882      * Allow callers to remove a previously registered listener. After calling this method,
4883      * applications will no longer receive Wi-Fi usability statistics.
4884      *
4885      * @param listener Listener to remove the Wi-Fi usability statistics.
4886      *
4887      * @hide
4888      */
4889     @SystemApi
4890     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
removeOnWifiUsabilityStatsListener(@onNull OnWifiUsabilityStatsListener listener)4891     public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) {
4892         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
4893         if (mVerboseLoggingEnabled) {
4894             Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
4895         }
4896         try {
4897             mService.removeOnWifiUsabilityStatsListener(listener.hashCode());
4898         } catch (RemoteException e) {
4899             throw e.rethrowFromSystemServer();
4900         }
4901     }
4902 
4903     /**
4904      * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
4905      * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
4906      * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
4907      * is used to quantify whether Wi-Fi is usable in a future time.
4908      *
4909      * @param seqNum Sequence number of the Wi-Fi usability score.
4910      * @param score The Wi-Fi usability score, expected range: [0, 100].
4911      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
4912      *                             expected range: [0, 30].
4913      *
4914      * @hide
4915      */
4916     @SystemApi
4917     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)4918     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
4919         try {
4920             mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
4921         } catch (RemoteException e) {
4922             throw e.rethrowFromSystemServer();
4923         }
4924     }
4925 }
4926