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