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.IntRange;
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.RequiresPermission;
29 import android.annotation.SdkConstant;
30 import android.annotation.SdkConstant.SdkConstantType;
31 import android.annotation.SuppressLint;
32 import android.annotation.SystemApi;
33 import android.annotation.SystemService;
34 import android.app.ActivityManager;
35 import android.compat.annotation.UnsupportedAppUsage;
36 import android.content.Context;
37 import android.content.pm.ParceledListSlice;
38 import android.net.ConnectivityManager;
39 import android.net.DhcpInfo;
40 import android.net.MacAddress;
41 import android.net.Network;
42 import android.net.NetworkStack;
43 import android.net.wifi.hotspot2.IProvisioningCallback;
44 import android.net.wifi.hotspot2.OsuProvider;
45 import android.net.wifi.hotspot2.PasspointConfiguration;
46 import android.net.wifi.hotspot2.ProvisioningCallback;
47 import android.os.Binder;
48 import android.os.Build;
49 import android.os.Handler;
50 import android.os.HandlerExecutor;
51 import android.os.IBinder;
52 import android.os.Looper;
53 import android.os.RemoteException;
54 import android.os.WorkSource;
55 import android.os.connectivity.WifiActivityEnergyInfo;
56 import android.text.TextUtils;
57 import android.util.CloseGuard;
58 import android.util.Log;
59 import android.util.Pair;
60 import android.util.SparseArray;
61 
62 import com.android.internal.annotations.GuardedBy;
63 import com.android.internal.annotations.VisibleForTesting;
64 
65 import java.lang.annotation.Retention;
66 import java.lang.annotation.RetentionPolicy;
67 import java.lang.ref.Reference;
68 import java.lang.ref.WeakReference;
69 import java.net.InetAddress;
70 import java.util.ArrayList;
71 import java.util.Collections;
72 import java.util.HashMap;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Objects;
76 import java.util.Set;
77 import java.util.StringTokenizer;
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     /** @hide */
157     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM = 256;
158 
159     /** @hide */
160     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM = 1024;
161 
162     /**
163      * Reason code if all of the network suggestions were successfully added or removed.
164      */
165     public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0;
166 
167     /**
168      * Reason code if there was an internal error in the platform while processing the addition or
169      * removal of suggestions.
170      */
171     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1;
172 
173     /**
174      * Reason code if the user has disallowed "android:change_wifi_state" app-ops from the app.
175      * @see android.app.AppOpsManager#unsafeCheckOp(String, int, String).
176      */
177     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2;
178 
179     /**
180      * Reason code if one or more of the network suggestions added already exists in platform's
181      * database.
182      * Note: this code will not be returned with Android 11 as in-place modification is allowed,
183      * please check {@link #addNetworkSuggestions(List)}.
184      * @see WifiNetworkSuggestion#equals(Object)
185      */
186     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
187 
188     /**
189      * Reason code if the number of network suggestions provided by the app crosses the max
190      * threshold set per app.
191      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} if
192      * the total size exceeds the limit.
193      * @see #getMaxNumberOfNetworkSuggestionsPerApp()
194      */
195     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
196 
197     /**
198      * Reason code if one or more of the network suggestions removed does not exist in platform's
199      * database.
200      * The framework won't remove any suggestions if one or more of suggestions provided
201      * by {@link #removeNetworkSuggestions(List)} does not exist in database.
202      * @see WifiNetworkSuggestion#equals(Object)
203      */
204     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
205 
206     /**
207      * Reason code if one or more of the network suggestions added is not allowed.
208      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
209      * if one or more of them is not allowed.
210      * This error may be caused by suggestion is using SIM-based encryption method, but calling app
211      * is not carrier privileged.
212      */
213     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6;
214 
215     /**
216      * Reason code if one or more of the network suggestions added is invalid. Framework will reject
217      * all the suggestions in the list.
218      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
219      * if one or more of them is invalid.
220      * Please use {@link WifiNetworkSuggestion.Builder} to create network suggestions.
221      */
222     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7;
223 
224     /** @hide */
225     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
226             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
227             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
228             STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED,
229             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
230             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
231             STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
232             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED,
233             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
234     })
235     @Retention(RetentionPolicy.SOURCE)
236     public @interface NetworkSuggestionsStatusCode {}
237 
238     /**
239      * Reason code if suggested network connection attempt failed with an unknown failure.
240      */
241     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN = 0;
242     /**
243      * Reason code if suggested network connection attempt failed with association failure.
244      */
245     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1;
246     /**
247      * Reason code if suggested network connection attempt failed with an authentication failure.
248      */
249     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2;
250     /**
251      * Reason code if suggested network connection attempt failed with an IP provision failure.
252      */
253     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3;
254 
255     /** @hide */
256     @IntDef(prefix = {"STATUS_SUGGESTION_CONNECTION_FAILURE_"},
257             value = {STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN,
258                     STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION,
259                     STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION,
260                     STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING
261     })
262     @Retention(RetentionPolicy.SOURCE)
263     public @interface SuggestionConnectionStatusCode {}
264 
265     /**
266      * Broadcast intent action indicating whether Wi-Fi scanning is currently available.
267      * Available extras:
268      * - {@link #EXTRA_SCAN_AVAILABLE}
269      */
270     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
271     public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED =
272             "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
273 
274     /**
275      * A boolean extra indicating whether scanning is currently available.
276      * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABILITY_CHANGED}.
277      * Its value is true if scanning is currently available, false otherwise.
278      */
279     public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
280 
281     /**
282      * Broadcast intent action indicating that the credential of a Wi-Fi network
283      * has been changed. One extra provides the ssid of the network. Another
284      * extra provides the event type, whether the credential is saved or forgot.
285      * @hide
286      */
287     @SystemApi
288     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
289             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
290     /** @hide */
291     @SystemApi
292     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
293     /** @hide */
294     @SystemApi
295     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
296     /** @hide */
297     @SystemApi
298     public static final int WIFI_CREDENTIAL_SAVED = 0;
299     /** @hide */
300     @SystemApi
301     public static final int WIFI_CREDENTIAL_FORGOT = 1;
302 
303     /** @hide */
304     @SystemApi
305     public static final int PASSPOINT_HOME_NETWORK = 0;
306 
307     /** @hide */
308     @SystemApi
309     public static final int PASSPOINT_ROAMING_NETWORK = 1;
310 
311     /**
312      * Broadcast intent action indicating that a Passpoint provider icon has been received.
313      *
314      * Included extras:
315      * {@link #EXTRA_BSSID_LONG}
316      * {@link #EXTRA_FILENAME}
317      * {@link #EXTRA_ICON}
318      *
319      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
320      *
321      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
322      * components will be launched.
323      *
324      * @hide
325      */
326     public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
327     /**
328      * BSSID of an AP in long representation.  The {@link #EXTRA_BSSID} contains BSSID in
329      * String representation.
330      *
331      * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}.
332      *
333      * @hide
334      */
335     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
336     /**
337      * Icon data.
338      *
339      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
340      * {@link android.graphics.drawable.Icon}.
341      *
342      * @hide
343      */
344     public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
345     /**
346      * Name of a file.
347      *
348      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
349      *
350      * @hide
351      */
352     public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
353 
354     /**
355      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
356      *
357      * Included extras:
358      * {@link #EXTRA_BSSID_LONG}
359      * {@link #EXTRA_ANQP_ELEMENT_DATA}
360      *
361      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
362      *
363      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
364      * components will be launched.
365      *
366      * @hide
367      */
368     public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
369             "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
370     /**
371      * Raw binary data of an ANQP (Access Network Query Protocol) element.
372      *
373      * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}.
374      *
375      * @hide
376      */
377     public static final String EXTRA_ANQP_ELEMENT_DATA =
378             "android.net.wifi.extra.ANQP_ELEMENT_DATA";
379 
380     /**
381      * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
382      *
383      * Included extras:
384      * {@link #EXTRA_BSSID_LONG}
385      * {@link #EXTRA_ESS}
386      * {@link #EXTRA_DELAY}
387      * {@link #EXTRA_URL}
388      *
389      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
390      *
391      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
392      * components will be launched.
393      *
394      * @hide
395      */
396     public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
397             "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
398     /**
399      * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to
400      * {@code true} for ESS.
401      *
402      * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}.
403      *
404      * @hide
405      */
406     public static final String EXTRA_ESS = "android.net.wifi.extra.ESS";
407     /**
408      * Delay in seconds.
409      *
410      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
411      *
412      * @hide
413      */
414     public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
415 
416     /**
417      * Broadcast intent action indicating a Passpoint subscription remediation frame has been
418      * received.
419      *
420      * Included extras:
421      * {@link #EXTRA_BSSID_LONG}
422      * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD}
423      * {@link #EXTRA_URL}
424      *
425      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
426      *
427      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
428      * components will be launched.
429      *
430      * @hide
431      */
432     public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
433             "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
434     /**
435      * The protocol supported by the subscription remediation server. The possible values are:
436      * 0 - OMA DM
437      * 1 - SOAP XML SPP
438      *
439      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
440      *
441      * @hide
442      */
443     public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD =
444             "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
445 
446     /**
447      * Activity Action: Receiver should launch Passpoint OSU (Online Sign Up) view.
448      * Included extras:
449      *
450      * {@link #EXTRA_OSU_NETWORK}: {@link Network} instance associated with OSU AP.
451      * {@link #EXTRA_URL}: String representation of a server URL used for OSU process.
452      *
453      * @hide
454      */
455     @SystemApi
456     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
457     public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW =
458             "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
459 
460     /**
461      * The lookup key for a {@link android.net.Network} associated with a Passpoint OSU server.
462      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
463      *
464      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
465      *
466      * @hide
467      */
468     @SystemApi
469     public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
470 
471     /**
472      * String representation of an URL for Passpoint OSU.
473      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
474      *
475      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
476      *
477      * @hide
478      */
479     @SystemApi
480     public static final String EXTRA_URL = "android.net.wifi.extra.URL";
481 
482     /**
483      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
484      * enabling, disabling, or unknown. One extra provides this state as an int.
485      * Another extra provides the previous state, if available.  No network-related
486      * permissions are required to subscribe to this broadcast.
487      *
488      * <p class="note">This broadcast is not delivered to manifest receivers in
489      * applications that target API version 26 or later.
490      *
491      * @see #EXTRA_WIFI_STATE
492      * @see #EXTRA_PREVIOUS_WIFI_STATE
493      */
494     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
495     public static final String WIFI_STATE_CHANGED_ACTION =
496         "android.net.wifi.WIFI_STATE_CHANGED";
497     /**
498      * The lookup key for an int that indicates whether Wi-Fi is enabled,
499      * disabled, enabling, disabling, or unknown.  Retrieve it with
500      * {@link android.content.Intent#getIntExtra(String,int)}.
501      *
502      * @see #WIFI_STATE_DISABLED
503      * @see #WIFI_STATE_DISABLING
504      * @see #WIFI_STATE_ENABLED
505      * @see #WIFI_STATE_ENABLING
506      * @see #WIFI_STATE_UNKNOWN
507      */
508     public static final String EXTRA_WIFI_STATE = "wifi_state";
509     /**
510      * The previous Wi-Fi state.
511      *
512      * @see #EXTRA_WIFI_STATE
513      */
514     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
515 
516     /**
517      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
518      * it finishes successfully.
519      *
520      * @see #WIFI_STATE_CHANGED_ACTION
521      * @see #getWifiState()
522      */
523     public static final int WIFI_STATE_DISABLING = 0;
524     /**
525      * Wi-Fi is disabled.
526      *
527      * @see #WIFI_STATE_CHANGED_ACTION
528      * @see #getWifiState()
529      */
530     public static final int WIFI_STATE_DISABLED = 1;
531     /**
532      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
533      * it finishes successfully.
534      *
535      * @see #WIFI_STATE_CHANGED_ACTION
536      * @see #getWifiState()
537      */
538     public static final int WIFI_STATE_ENABLING = 2;
539     /**
540      * Wi-Fi is enabled.
541      *
542      * @see #WIFI_STATE_CHANGED_ACTION
543      * @see #getWifiState()
544      */
545     public static final int WIFI_STATE_ENABLED = 3;
546     /**
547      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
548      * or disabling.
549      *
550      * @see #WIFI_STATE_CHANGED_ACTION
551      * @see #getWifiState()
552      */
553     public static final int WIFI_STATE_UNKNOWN = 4;
554 
555     /**
556      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
557      * enabling, disabling, or failed.
558      *
559      * @hide
560      */
561     @SystemApi
562     public static final String WIFI_AP_STATE_CHANGED_ACTION =
563         "android.net.wifi.WIFI_AP_STATE_CHANGED";
564 
565     /**
566      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
567      * disabled, enabling, disabling, or failed.  Retrieve it with
568      * {@link android.content.Intent#getIntExtra(String,int)}.
569      *
570      * @see #WIFI_AP_STATE_DISABLED
571      * @see #WIFI_AP_STATE_DISABLING
572      * @see #WIFI_AP_STATE_ENABLED
573      * @see #WIFI_AP_STATE_ENABLING
574      * @see #WIFI_AP_STATE_FAILED
575      *
576      * @hide
577      */
578     @SystemApi
579     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
580 
581     /**
582      * An extra containing the int error code for Soft AP start failure.
583      * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
584      * {@link android.content.Intent#getIntExtra}.
585      * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
586      * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
587      *
588      * The error code will be one of:
589      * {@link #SAP_START_FAILURE_GENERAL},
590      * {@link #SAP_START_FAILURE_NO_CHANNEL},
591      * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
592      *
593      * @hide
594      */
595     @SystemApi
596     public static final String EXTRA_WIFI_AP_FAILURE_REASON =
597             "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
598     /**
599      * The previous Wi-Fi state.
600      *
601      * @see #EXTRA_WIFI_AP_STATE
602      *
603      * @hide
604      */
605     @SystemApi
606     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
607     /**
608      * The lookup key for a String extra that stores the interface name used for the Soft AP.
609      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
610      * Retrieve its value with {@link android.content.Intent#getStringExtra(String)}.
611      *
612      * @hide
613      */
614     @SystemApi
615     public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
616             "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
617     /**
618      * The lookup key for an int extra that stores the intended IP mode for this Soft AP.
619      * One of {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
620      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
621      * Retrieve its value with {@link android.content.Intent#getIntExtra(String, int)}.
622      *
623      * @hide
624      */
625     @SystemApi
626     public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
627 
628     /** @hide */
629     @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
630         WIFI_AP_STATE_DISABLING,
631         WIFI_AP_STATE_DISABLED,
632         WIFI_AP_STATE_ENABLING,
633         WIFI_AP_STATE_ENABLED,
634         WIFI_AP_STATE_FAILED,
635     })
636     @Retention(RetentionPolicy.SOURCE)
637     public @interface WifiApState {}
638 
639     /**
640      * Wi-Fi AP is currently being disabled. The state will change to
641      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
642      *
643      * @see #WIFI_AP_STATE_CHANGED_ACTION
644      * @see #getWifiApState()
645      *
646      * @hide
647      */
648     @SystemApi
649     public static final int WIFI_AP_STATE_DISABLING = 10;
650     /**
651      * Wi-Fi AP is disabled.
652      *
653      * @see #WIFI_AP_STATE_CHANGED_ACTION
654      * @see #getWifiState()
655      *
656      * @hide
657      */
658     @SystemApi
659     public static final int WIFI_AP_STATE_DISABLED = 11;
660     /**
661      * Wi-Fi AP is currently being enabled. The state will change to
662      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
663      *
664      * @see #WIFI_AP_STATE_CHANGED_ACTION
665      * @see #getWifiApState()
666      *
667      * @hide
668      */
669     @SystemApi
670     public static final int WIFI_AP_STATE_ENABLING = 12;
671     /**
672      * Wi-Fi AP is enabled.
673      *
674      * @see #WIFI_AP_STATE_CHANGED_ACTION
675      * @see #getWifiApState()
676      *
677      * @hide
678      */
679     @SystemApi
680     public static final int WIFI_AP_STATE_ENABLED = 13;
681     /**
682      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
683      * enabling or disabling
684      *
685      * @see #WIFI_AP_STATE_CHANGED_ACTION
686      * @see #getWifiApState()
687      *
688      * @hide
689      */
690     @SystemApi
691     public static final int WIFI_AP_STATE_FAILED = 14;
692 
693     /** @hide */
694     @IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = {
695         SAP_START_FAILURE_GENERAL,
696         SAP_START_FAILURE_NO_CHANNEL,
697         SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION,
698     })
699     @Retention(RetentionPolicy.SOURCE)
700     public @interface SapStartFailure {}
701 
702     /**
703      *  All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL} and
704      *  {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
705      *
706      *  @hide
707      */
708     @SystemApi
709     public static final int SAP_START_FAILURE_GENERAL= 0;
710 
711     /**
712      *  If Wi-Fi AP start failed, this reason code means that no legal channel exists on user
713      *  selected band due to regulatory constraints.
714      *
715      *  @hide
716      */
717     @SystemApi
718     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
719 
720     /**
721      *  If Wi-Fi AP start failed, this reason code means that the specified configuration
722      *  is not supported by the current HAL version.
723      *
724      *  @hide
725      */
726     @SystemApi
727     public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2;
728 
729 
730     /** @hide */
731     @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = {
732         SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER,
733         SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS,
734     })
735     @Retention(RetentionPolicy.SOURCE)
736     public @interface SapClientBlockedReason {}
737 
738     /**
739      *  If Soft Ap client is blocked, this reason code means that client doesn't exist in the
740      *  specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
741      *  and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
742      *  and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
743      *  is configured as well.
744      *  @hide
745      */
746     @SystemApi
747     public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0;
748 
749     /**
750      *  If Soft Ap client is blocked, this reason code means that no more clients can be
751      *  associated to this AP since it reached maximum capacity. The maximum capacity is
752      *  the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and
753      *  {@link SoftApCapability#getMaxSupportedClients} which get from
754      *  {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}.
755      *
756      *  @hide
757      */
758     @SystemApi
759     public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1;
760 
761     /**
762      * Client disconnected for unspecified reason. This could for example be because the AP is being
763      * shut down.
764      * @hide
765      */
766     public static final int SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED = 2;
767 
768     /** @hide */
769     @Retention(RetentionPolicy.SOURCE)
770     @IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
771             IFACE_IP_MODE_UNSPECIFIED,
772             IFACE_IP_MODE_CONFIGURATION_ERROR,
773             IFACE_IP_MODE_TETHERED,
774             IFACE_IP_MODE_LOCAL_ONLY})
775     public @interface IfaceIpMode {}
776 
777     /**
778      * Interface IP mode unspecified.
779      *
780      * @see #updateInterfaceIpState(String, int)
781      *
782      * @hide
783      */
784     @SystemApi
785     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
786 
787     /**
788      * Interface IP mode for configuration error.
789      *
790      * @see #updateInterfaceIpState(String, int)
791      *
792      * @hide
793      */
794     @SystemApi
795     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
796 
797     /**
798      * Interface IP mode for tethering.
799      *
800      * @see #updateInterfaceIpState(String, int)
801      *
802      * @hide
803      */
804     @SystemApi
805     public static final int IFACE_IP_MODE_TETHERED = 1;
806 
807     /**
808      * Interface IP mode for Local Only Hotspot.
809      *
810      * @see #updateInterfaceIpState(String, int)
811      *
812      * @hide
813      */
814     @SystemApi
815     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
816 
817     /**
818      * Broadcast intent action indicating that the wifi network settings
819      * had been reset.
820      *
821      * Note: This intent is sent as a directed broadcast to each manifest registered receiver.
822      * Intent will not be received by dynamically registered receivers.
823      * @hide
824      */
825     @SystemApi
826     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
827     public static final String ACTION_NETWORK_SETTINGS_RESET =
828             "android.net.wifi.action.NETWORK_SETTINGS_RESET";
829 
830     /**
831      * Broadcast intent action indicating that a connection to the supplicant has
832      * been established (and it is now possible
833      * to perform Wi-Fi operations) or the connection to the supplicant has been
834      * lost. One extra provides the connection state as a boolean, where {@code true}
835      * means CONNECTED.
836      * @deprecated This is no longer supported.
837      * @see #EXTRA_SUPPLICANT_CONNECTED
838      */
839     @Deprecated
840     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
841     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
842         "android.net.wifi.supplicant.CONNECTION_CHANGE";
843     /**
844      * The lookup key for a boolean that indicates whether a connection to
845      * the supplicant daemon has been gained or lost. {@code true} means
846      * a connection now exists.
847      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
848      * @deprecated This is no longer supported.
849      */
850     @Deprecated
851     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
852     /**
853      * Broadcast intent action indicating that the state of Wi-Fi connectivity
854      * has changed. An extra provides the new state
855      * in the form of a {@link android.net.NetworkInfo} object.  No network-related
856      * permissions are required to subscribe to this broadcast.
857      *
858      * <p class="note">This broadcast is not delivered to manifest receivers in
859      * applications that target API version 26 or later.
860      * @see #EXTRA_NETWORK_INFO
861      */
862     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
863     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
864     /**
865      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
866      * Wi-Fi network. Retrieve with
867      * {@link android.content.Intent#getParcelableExtra(String)}.
868      */
869     public static final String EXTRA_NETWORK_INFO = "networkInfo";
870     /**
871      * The lookup key for a String giving the BSSID of the access point to which
872      * we are connected. No longer used.
873      */
874     @Deprecated
875     public static final String EXTRA_BSSID = "bssid";
876     /**
877      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
878      * information about the access point to which we are connected.
879      * No longer used.
880      */
881     @Deprecated
882     public static final String EXTRA_WIFI_INFO = "wifiInfo";
883     /**
884      * Broadcast intent action indicating that the state of establishing a connection to
885      * an access point has changed.One extra provides the new
886      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
887      * is not generally the most useful thing to look at if you are just interested in
888      * the overall state of connectivity.
889      * @see #EXTRA_NEW_STATE
890      * @see #EXTRA_SUPPLICANT_ERROR
891      * @deprecated This is no longer supported.
892      */
893     @Deprecated
894     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
895     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
896         "android.net.wifi.supplicant.STATE_CHANGE";
897     /**
898      * The lookup key for a {@link SupplicantState} describing the new state
899      * Retrieve with
900      * {@link android.content.Intent#getParcelableExtra(String)}.
901      * @deprecated This is no longer supported.
902      */
903     @Deprecated
904     public static final String EXTRA_NEW_STATE = "newState";
905 
906     /**
907      * The lookup key for a {@link SupplicantState} describing the supplicant
908      * error code if any
909      * Retrieve with
910      * {@link android.content.Intent#getIntExtra(String, int)}.
911      * @see #ERROR_AUTHENTICATING
912      * @deprecated This is no longer supported.
913      */
914     @Deprecated
915     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
916 
917     /**
918      * The lookup key for a {@link SupplicantState} describing the supplicant
919      * error reason if any
920      * Retrieve with
921      * {@link android.content.Intent#getIntExtra(String, int)}.
922      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
923      * @deprecated This is no longer supported.
924      * @hide
925      */
926     @Deprecated
927     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
928 
929     /**
930      * Broadcast intent action indicating that the configured networks changed.
931      * This can be as a result of adding/updating/deleting a network.
932      * <br />
933      * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
934      * {@link #EXTRA_WIFI_CONFIGURATION} is never set starting in Android 11.
935      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
936      * its value is always true, even if only a single network changed.
937      * <br />
938      * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
939      * required to receive this broadcast.
940      *
941      * @hide
942      */
943     @SystemApi
944     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
945         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
946     /**
947      * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
948      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
949      * broadcast is sent.
950      * Note: this extra is never set starting in Android 11.
951      * @hide
952      */
953     @SystemApi
954     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
955     /**
956      * Multiple network configurations have changed.
957      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
958      * Note: this extra is always true starting in Android 11.
959      * @hide
960      */
961     @SystemApi
962     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
963     /**
964      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
965      * has changed. One of {@link #CHANGE_REASON_ADDED}, {@link #CHANGE_REASON_REMOVED},
966      * {@link #CHANGE_REASON_CONFIG_CHANGE}.
967      *
968      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
969      * @hide
970      */
971     @SystemApi
972     public static final String EXTRA_CHANGE_REASON = "changeReason";
973     /**
974      * The configuration is new and was added.
975      * @hide
976      */
977     @SystemApi
978     public static final int CHANGE_REASON_ADDED = 0;
979     /**
980      * The configuration was removed and is no longer present in the system's list of
981      * configured networks.
982      * @hide
983      */
984     @SystemApi
985     public static final int CHANGE_REASON_REMOVED = 1;
986     /**
987      * The configuration has changed as a result of explicit action or because the system
988      * took an automated action such as disabling a malfunctioning configuration.
989      * @hide
990      */
991     @SystemApi
992     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
993     /**
994      * An access point scan has completed, and results are available.
995      * Call {@link #getScanResults()} to obtain the results.
996      * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
997      * and a {@code boolean} value indicating if the scan was successful.
998      */
999     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1000     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
1001 
1002     /**
1003      * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
1004      * representing if the scan was successful or not.
1005      * Scans may fail for multiple reasons, these may include:
1006      * <ol>
1007      * <li>An app requested too many scans in a certain period of time.
1008      * This may lead to additional scan request rejections via "scan throttling" for both
1009      * foreground and background apps.
1010      * Note: Apps holding android.Manifest.permission.NETWORK_SETTINGS permission are
1011      * exempted from scan throttling.
1012      * </li>
1013      * <li>The device is idle and scanning is disabled.</li>
1014      * <li>Wifi hardware reported a scan failure.</li>
1015      * </ol>
1016      * @return true scan was successful, results are updated
1017      * @return false scan was not successful, results haven't been updated since previous scan
1018      */
1019     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
1020 
1021     /**
1022      * A batch of access point scans has been completed and the results areavailable.
1023      * Call {@link #getBatchedScanResults()} to obtain the results.
1024      * @deprecated This API is nolonger supported.
1025      * Use {@link android.net.wifi.WifiScanner} API
1026      * @hide
1027      */
1028     @Deprecated
1029     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1030     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
1031             "android.net.wifi.BATCHED_RESULTS";
1032 
1033     /**
1034      * The RSSI (signal strength) has changed.
1035      *
1036      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1037      * @see #EXTRA_NEW_RSSI
1038      */
1039     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1040     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
1041     /**
1042      * The lookup key for an {@code int} giving the new RSSI in dBm.
1043      */
1044     public static final String EXTRA_NEW_RSSI = "newRssi";
1045 
1046     /**
1047      * @see #ACTION_LINK_CONFIGURATION_CHANGED
1048      * @hide
1049      */
1050     @UnsupportedAppUsage
1051     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
1052             "android.net.wifi.LINK_CONFIGURATION_CHANGED";
1053 
1054     /**
1055      * Broadcast intent action indicating that the link configuration changed on wifi.
1056      * <br />Included Extras:
1057      * <br />{@link #EXTRA_LINK_PROPERTIES}: {@link android.net.LinkProperties} object associated
1058      * with the Wi-Fi network.
1059      * <br /> No permissions are required to listen to this broadcast.
1060      * @hide
1061      */
1062     @SystemApi
1063     public static final String ACTION_LINK_CONFIGURATION_CHANGED =
1064             // should be android.net.wifi.action.LINK_CONFIGURATION_CHANGED, but due to
1065             // @UnsupportedAppUsage leaving it as android.net.wifi.LINK_CONFIGURATION_CHANGED.
1066             LINK_CONFIGURATION_CHANGED_ACTION;
1067 
1068     /**
1069      * The lookup key for a {@link android.net.LinkProperties} object associated with the
1070      * Wi-Fi network.
1071      * Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
1072      *
1073      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1074      * @hide
1075      */
1076     @SystemApi
1077     public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
1078 
1079     /**
1080      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
1081      * Wi-Fi network. Retrieve with
1082      * {@link android.content.Intent#getParcelableExtra(String)}.
1083      * @hide
1084      */
1085     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
1086 
1087     /**
1088      * The network IDs of the configured networks could have changed.
1089      */
1090     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1091     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
1092 
1093     /**
1094      * Activity Action: Show a system activity that allows the user to enable
1095      * scans to be available even with Wi-Fi turned off.
1096      *
1097      * <p>Notification of the result of this activity is posted using the
1098      * {@link android.app.Activity#onActivityResult} callback. The
1099      * <code>resultCode</code>
1100      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
1101      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
1102      * has rejected the request or an error has occurred.
1103      */
1104     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1105     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
1106             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
1107 
1108     /**
1109      * Activity Action: Pick a Wi-Fi network to connect to.
1110      * <p>Input: Nothing.
1111      * <p>Output: Nothing.
1112      */
1113     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1114     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
1115 
1116     /**
1117      * Activity Action: Receiver should show UI to get user approval to enable WiFi.
1118      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1119      *           the name of the app requesting the action.
1120      * <p>Output: Nothing.
1121      * <p>No permissions are required to send this action.
1122      * @hide
1123      */
1124     @SystemApi
1125     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1126     public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
1127 
1128     /**
1129      * Activity Action: Receiver should show UI to get user approval to disable WiFi.
1130      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1131      *           the name of the app requesting the action.
1132      * <p>Output: Nothing.
1133      * <p>No permissions are required to send this action.
1134      * @hide
1135      */
1136     @SystemApi
1137     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1138     public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
1139 
1140     /**
1141      * Directed broadcast intent action indicating that the device has connected to one of the
1142      * network suggestions provided by the app. This will be sent post connection to a network
1143      * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
1144      * boolean)}
1145      * flag set.
1146      * <p>
1147      * Note: The broadcast is sent to the app only if it holds
1148      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
1149      *
1150      * @see #EXTRA_NETWORK_SUGGESTION
1151      */
1152     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1153     public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION =
1154             "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
1155     /**
1156      * Sent as as a part of {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} that holds
1157      * an instance of {@link WifiNetworkSuggestion} corresponding to the connected network.
1158      */
1159     public static final String EXTRA_NETWORK_SUGGESTION =
1160             "android.net.wifi.extra.NETWORK_SUGGESTION";
1161 
1162     /**
1163      * Internally used Wi-Fi lock mode representing the case were no locks are held.
1164      * @hide
1165      */
1166     public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
1167 
1168     /**
1169      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1170      * and will behave normally, i.e., it will attempt to automatically
1171      * establish a connection to a remembered access point that is
1172      * within range, and will do periodic scans if there are remembered
1173      * access points but none are in range.
1174      *
1175      * @deprecated This API is non-functional and will have no impact.
1176      */
1177     @Deprecated
1178     public static final int WIFI_MODE_FULL = 1;
1179 
1180     /**
1181      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1182      * but the only operation that will be supported is initiation of
1183      * scans, and the subsequent reporting of scan results. No attempts
1184      * will be made to automatically connect to remembered access points,
1185      * nor will periodic scans be automatically performed looking for
1186      * remembered access points. Scans must be explicitly requested by
1187      * an application in this mode.
1188      *
1189      * @deprecated This API is non-functional and will have no impact.
1190      */
1191     @Deprecated
1192     public static final int WIFI_MODE_SCAN_ONLY = 2;
1193 
1194     /**
1195      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
1196      * This results in operating with low packet latency.
1197      * The lock is only active when the device is connected to an access point.
1198      * The lock is active even when the device screen is off or the acquiring application is
1199      * running in the background.
1200      * This mode will consume more power and hence should be used only
1201      * when there is a need for this tradeoff.
1202      * <p>
1203      * An example use case is when a voice connection needs to be
1204      * kept active even after the device screen goes off.
1205      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
1206      * duration of the voice call may improve the call quality.
1207      * <p>
1208      * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
1209      * lock will have no impact.
1210      */
1211     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
1212 
1213     /**
1214      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
1215      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock has the following limitations:
1216      * <ol>
1217      * <li>The lock is only active when the device is connected to an access point.</li>
1218      * <li>The lock is only active when the screen is on.</li>
1219      * <li>The lock is only active when the acquiring app is running in the foreground.</li>
1220      * </ol>
1221      * Low latency mode optimizes for reduced packet latency,
1222      * and as a result other performance measures may suffer when there are trade-offs to make:
1223      * <ol>
1224      * <li>Battery life may be reduced.</li>
1225      * <li>Throughput may be reduced.</li>
1226      * <li>Frequency of Wi-Fi scanning may be reduced. This may result in: </li>
1227      * <ul>
1228      * <li>The device may not roam or switch to the AP with highest signal quality.</li>
1229      * <li>Location accuracy may be reduced.</li>
1230      * </ul>
1231      * </ol>
1232      * <p>
1233      * Example use cases are real time gaming or virtual reality applications where
1234      * low latency is a key factor for user experience.
1235      * <p>
1236      * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and
1237      * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY}
1238      * lock will be effective when app is running in foreground and screen is on,
1239      * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
1240      */
1241     public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
1242 
1243 
1244     /** Anything worse than or equal to this will show 0 bars. */
1245     @UnsupportedAppUsage
1246     private static final int MIN_RSSI = -100;
1247 
1248     /** Anything better than or equal to this will show the max bars. */
1249     @UnsupportedAppUsage
1250     private static final int MAX_RSSI = -55;
1251 
1252     /**
1253      * Number of RSSI levels used in the framework to initiate {@link #RSSI_CHANGED_ACTION}
1254      * broadcast, where each level corresponds to a range of RSSI values.
1255      * The {@link #RSSI_CHANGED_ACTION} broadcast will only fire if the RSSI
1256      * change is significant enough to change the RSSI signal level.
1257      * @hide
1258      */
1259     @UnsupportedAppUsage
1260     public static final int RSSI_LEVELS = 5;
1261 
1262     //TODO (b/146346676): This needs to be removed, not used in the code.
1263     /**
1264      * Auto settings in the driver. The driver could choose to operate on both
1265      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
1266      * @hide
1267      */
1268     @UnsupportedAppUsage
1269     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
1270 
1271     /**
1272      * Operation on 5 GHz alone
1273      * @hide
1274      */
1275     @UnsupportedAppUsage
1276     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
1277 
1278     /**
1279      * Operation on 2.4 GHz alone
1280      * @hide
1281      */
1282     @UnsupportedAppUsage
1283     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
1284 
1285     /** @hide */
1286     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
1287 
1288     /**
1289      * Maximum number of active locks we allow.
1290      * This limit was added to prevent apps from creating a ridiculous number
1291      * of locks and crashing the system by overflowing the global ref table.
1292      */
1293     private static final int MAX_ACTIVE_LOCKS = 50;
1294 
1295     /** Indicates an invalid SSID. */
1296     public static final String UNKNOWN_SSID = "<unknown ssid>";
1297 
1298     /** @hide */
1299     public static final MacAddress ALL_ZEROS_MAC_ADDRESS =
1300             MacAddress.fromString("00:00:00:00:00:00");
1301 
1302     /* Number of currently active WifiLocks and MulticastLocks */
1303     @UnsupportedAppUsage
1304     private int mActiveLockCount;
1305 
1306     private Context mContext;
1307     @UnsupportedAppUsage
1308     IWifiManager mService;
1309     private final int mTargetSdkVersion;
1310 
1311     private Looper mLooper;
1312     private boolean mVerboseLoggingEnabled = false;
1313 
1314     private final Object mLock = new Object(); // lock guarding access to the following vars
1315     @GuardedBy("mLock")
1316     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
1317     @GuardedBy("mLock")
1318     private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
1319 
1320     /**
1321      * Create a new WifiManager instance.
1322      * Applications will almost always want to use
1323      * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve
1324      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
1325      *
1326      * @param context the application context
1327      * @param service the Binder interface
1328      * @param looper the Looper used to deliver callbacks
1329      * @hide - hide this because it takes in a parameter of type IWifiManager, which
1330      * is a system private class.
1331      */
WifiManager(@onNull Context context, @NonNull IWifiManager service, @NonNull Looper looper)1332     public WifiManager(@NonNull Context context, @NonNull IWifiManager service,
1333         @NonNull Looper looper) {
1334         mContext = context;
1335         mService = service;
1336         mLooper = looper;
1337         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
1338         updateVerboseLoggingEnabledFromService();
1339     }
1340 
1341     /**
1342      * Return a list of all the networks configured for the current foreground
1343      * user.
1344      *
1345      * Not all fields of WifiConfiguration are returned. Only the following
1346      * fields are filled in:
1347      * <ul>
1348      * <li>networkId</li>
1349      * <li>SSID</li>
1350      * <li>BSSID</li>
1351      * <li>priority</li>
1352      * <li>allowedProtocols</li>
1353      * <li>allowedKeyManagement</li>
1354      * <li>allowedAuthAlgorithms</li>
1355      * <li>allowedPairwiseCiphers</li>
1356      * <li>allowedGroupCiphers</li>
1357      * <li>status</li>
1358      * </ul>
1359      * @return a list of network configurations in the form of a list
1360      * of {@link WifiConfiguration} objects.
1361      *
1362      * @deprecated
1363      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1364      * mechanism to trigger connection to a Wi-Fi network.
1365      * b) See {@link #addNetworkSuggestions(List)},
1366      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1367      * when auto-connecting to wifi.
1368      * <b>Compatibility Note:</b> For applications targeting
1369      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return an
1370      * empty list.
1371      * <p>
1372      * Deprecation Exemptions:
1373      * <ul>
1374      * <li>Device Owner (DO), Profile Owner (PO) and system apps will have access to the full list.
1375      * <li>Callers with Carrier privilege will receive a restricted list only containing
1376      * configurations which they created.
1377      * </ul>
1378      */
1379     @Deprecated
1380     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
getConfiguredNetworks()1381     public List<WifiConfiguration> getConfiguredNetworks() {
1382         try {
1383             ParceledListSlice<WifiConfiguration> parceledList =
1384                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
1385                             mContext.getAttributionTag());
1386             if (parceledList == null) {
1387                 return Collections.emptyList();
1388             }
1389             return parceledList.getList();
1390         } catch (RemoteException e) {
1391             throw e.rethrowFromSystemServer();
1392         }
1393     }
1394 
1395     /** @hide */
1396     @SystemApi
1397     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL})
getPrivilegedConfiguredNetworks()1398     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
1399         try {
1400             ParceledListSlice<WifiConfiguration> parceledList =
1401                     mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
1402                             mContext.getAttributionTag());
1403             if (parceledList == null) {
1404                 return Collections.emptyList();
1405             }
1406             return parceledList.getList();
1407         } catch (RemoteException e) {
1408             throw e.rethrowFromSystemServer();
1409         }
1410     }
1411 
1412     /**
1413      * Returns a list of all matching WifiConfigurations for a given list of ScanResult.
1414      *
1415      * An empty list will be returned when no configurations are installed or if no configurations
1416      * match the ScanResult.
1417      *
1418      * @param scanResults a list of scanResult that represents the BSSID
1419      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
1420      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
1421      * @hide
1422      */
1423     @SystemApi
1424     @RequiresPermission(anyOf = {
1425             android.Manifest.permission.NETWORK_SETTINGS,
1426             android.Manifest.permission.NETWORK_SETUP_WIZARD
1427     })
1428     @NonNull
getAllMatchingWifiConfigs( @onNull List<ScanResult> scanResults)1429     public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
1430             @NonNull List<ScanResult> scanResults) {
1431         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
1432         try {
1433             Map<String, Map<Integer, List<ScanResult>>> results =
1434                     mService.getAllMatchingPasspointProfilesForScanResults(scanResults);
1435             if (results.isEmpty()) {
1436                 return configs;
1437             }
1438             List<WifiConfiguration> wifiConfigurations =
1439                     mService.getWifiConfigsForPasspointProfiles(
1440                             new ArrayList<>(results.keySet()));
1441             for (WifiConfiguration configuration : wifiConfigurations) {
1442                 Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
1443                         results.get(configuration.getKey());
1444                 if (scanResultsPerNetworkType != null) {
1445                     configs.add(Pair.create(configuration, scanResultsPerNetworkType));
1446                 }
1447             }
1448         } catch (RemoteException e) {
1449             throw e.rethrowFromSystemServer();
1450         }
1451 
1452         return configs;
1453     }
1454 
1455     /**
1456      * Retrieve a list of {@link WifiConfiguration} for available {@link WifiNetworkSuggestion}
1457      * matching the given list of {@link ScanResult}.
1458      *
1459      * An available {@link WifiNetworkSuggestion} must satisfy:
1460      * <ul>
1461      * <li> Matching one of the {@link ScanResult} from the given list.
1462      * <li> and {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} set
1463      * to true.
1464      * </ul>
1465      *
1466      * @param scanResults a list of scanResult.
1467      * @return a list of @link WifiConfiguration} for available {@link WifiNetworkSuggestion}
1468      * @hide
1469      */
1470     @SystemApi
1471     @RequiresPermission(anyOf = {
1472             android.Manifest.permission.NETWORK_SETTINGS,
1473             android.Manifest.permission.NETWORK_SETUP_WIZARD
1474     })
1475     @NonNull
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( @onNull List<ScanResult> scanResults)1476     public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
1477             @NonNull List<ScanResult> scanResults) {
1478         try {
1479             return mService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults);
1480         } catch (RemoteException e) {
1481             throw e.rethrowAsRuntimeException();
1482         }
1483     }
1484 
1485     /**
1486      * Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
1487      * list of ScanResult.
1488      *
1489      * An empty list will be returned if no match is found.
1490      *
1491      * @param scanResults a list of ScanResult
1492      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
1493      * @hide
1494      */
1495     @SystemApi
1496     @RequiresPermission(anyOf = {
1497             android.Manifest.permission.NETWORK_SETTINGS,
1498             android.Manifest.permission.NETWORK_SETUP_WIZARD
1499     })
1500     @NonNull
getMatchingOsuProviders( @ullable List<ScanResult> scanResults)1501     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
1502             @Nullable List<ScanResult> scanResults) {
1503         if (scanResults == null) {
1504             return new HashMap<>();
1505         }
1506         try {
1507             return mService.getMatchingOsuProviders(scanResults);
1508         } catch (RemoteException e) {
1509             throw e.rethrowFromSystemServer();
1510         }
1511     }
1512 
1513     /**
1514      * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers.
1515      *
1516      * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2
1517      * configurations in the device.
1518      * An empty map will be returned when there is no matching Passpoint R2 configuration for the
1519      * given OsuProviders.
1520      *
1521      * @param osuProviders a set of {@link OsuProvider}
1522      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
1523      * @hide
1524      */
1525     @SystemApi
1526     @RequiresPermission(anyOf = {
1527             android.Manifest.permission.NETWORK_SETTINGS,
1528             android.Manifest.permission.NETWORK_SETUP_WIZARD
1529     })
1530     @NonNull
getMatchingPasspointConfigsForOsuProviders( @onNull Set<OsuProvider> osuProviders)1531     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
1532             @NonNull Set<OsuProvider> osuProviders) {
1533         try {
1534             return mService.getMatchingPasspointConfigsForOsuProviders(
1535                     new ArrayList<>(osuProviders));
1536         } catch (RemoteException e) {
1537             throw e.rethrowFromSystemServer();
1538         }
1539     }
1540 
1541     /**
1542      * Add a new network description to the set of configured networks.
1543      * The {@code networkId} field of the supplied configuration object
1544      * is ignored.
1545      * <p/>
1546      * The new network will be marked DISABLED by default. To enable it,
1547      * called {@link #enableNetwork}.
1548      *
1549      * @param config the set of variables that describe the configuration,
1550      *            contained in a {@link WifiConfiguration} object.
1551      *            If the {@link WifiConfiguration} has an Http Proxy set
1552      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
1553      * @return the ID of the newly created network description. This is used in
1554      *         other operations to specified the network to be acted upon.
1555      *         Returns {@code -1} on failure.
1556      *
1557      * @deprecated
1558      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1559      * mechanism to trigger connection to a Wi-Fi network.
1560      * b) See {@link #addNetworkSuggestions(List)},
1561      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1562      * when auto-connecting to wifi.
1563      * <b>Compatibility Note:</b> For applications targeting
1564      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
1565      * {@code -1}.
1566      * <p>
1567      * Deprecation Exemptions:
1568      * <ul>
1569      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
1570      * </ul>
1571      */
1572     @Deprecated
addNetwork(WifiConfiguration config)1573     public int addNetwork(WifiConfiguration config) {
1574         if (config == null) {
1575             return -1;
1576         }
1577         config.networkId = -1;
1578         return addOrUpdateNetwork(config);
1579     }
1580 
1581     /**
1582      * Update the network description of an existing configured network.
1583      *
1584      * @param config the set of variables that describe the configuration,
1585      *            contained in a {@link WifiConfiguration} object. It may
1586      *            be sparse, so that only the items that are being changed
1587      *            are non-<code>null</code>. The {@code networkId} field
1588      *            must be set to the ID of the existing network being updated.
1589      *            If the {@link WifiConfiguration} has an Http Proxy set
1590      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
1591      * @return Returns the {@code networkId} of the supplied
1592      *         {@code WifiConfiguration} on success.
1593      *         <br/>
1594      *         Returns {@code -1} on failure, including when the {@code networkId}
1595      *         field of the {@code WifiConfiguration} does not refer to an
1596      *         existing network.
1597      *
1598      * @deprecated
1599      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1600      * mechanism to trigger connection to a Wi-Fi network.
1601      * b) See {@link #addNetworkSuggestions(List)},
1602      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1603      * when auto-connecting to wifi.
1604      * <b>Compatibility Note:</b> For applications targeting
1605      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
1606      * {@code -1}.
1607      * <p>
1608      * Deprecation Exemptions:
1609      * <ul>
1610      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
1611      * </ul>
1612      */
1613     @Deprecated
updateNetwork(WifiConfiguration config)1614     public int updateNetwork(WifiConfiguration config) {
1615         if (config == null || config.networkId < 0) {
1616             return -1;
1617         }
1618         return addOrUpdateNetwork(config);
1619     }
1620 
1621     /**
1622      * Internal method for doing the RPC that creates a new network description
1623      * or updates an existing one.
1624      *
1625      * @param config The possibly sparse object containing the variables that
1626      *         are to set or updated in the network description.
1627      * @return the ID of the network on success, {@code -1} on failure.
1628      */
addOrUpdateNetwork(WifiConfiguration config)1629     private int addOrUpdateNetwork(WifiConfiguration config) {
1630         try {
1631             return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
1632         } catch (RemoteException e) {
1633             throw e.rethrowFromSystemServer();
1634         }
1635     }
1636 
1637     /**
1638      * Interface for indicating user selection from the list of networks presented in the
1639      * {@link NetworkRequestMatchCallback#onMatch(List)}.
1640      *
1641      * The platform will implement this callback and pass it along with the
1642      * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
1643      * NetworkRequestUserSelectionCallback)}. The UI component handling
1644      * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
1645      * {@link #reject()} to return the user's selection back to the platform via this callback.
1646      * @hide
1647      */
1648     @SystemApi
1649     public interface NetworkRequestUserSelectionCallback {
1650         /**
1651          * User selected this network to connect to.
1652          * @param wifiConfiguration WifiConfiguration object corresponding to the network
1653          *                          user selected.
1654          */
1655         @SuppressLint("CallbackMethodName")
select(@onNull WifiConfiguration wifiConfiguration)1656         default void select(@NonNull WifiConfiguration wifiConfiguration) {}
1657 
1658         /**
1659          * User rejected the app's request.
1660          */
1661         @SuppressLint("CallbackMethodName")
reject()1662         default void reject() {}
1663     }
1664 
1665     /**
1666      * Interface for network request callback. Should be implemented by applications and passed when
1667      * calling {@link #registerNetworkRequestMatchCallback(Executor,
1668      * WifiManager.NetworkRequestMatchCallback)}.
1669      *
1670      * This is meant to be implemented by a UI component to present the user with a list of networks
1671      * matching the app's request. The user is allowed to pick one of these networks to connect to
1672      * or reject the request by the app.
1673      * @hide
1674      */
1675     @SystemApi
1676     public interface NetworkRequestMatchCallback {
1677         /**
1678          * Invoked to register a callback to be invoked to convey user selection. The callback
1679          * object passed in this method is to be invoked by the UI component after the service sends
1680          * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
1681          * from that list.
1682          *
1683          * @param userSelectionCallback Callback object to send back the user selection.
1684          */
onUserSelectionCallbackRegistration( @onNull NetworkRequestUserSelectionCallback userSelectionCallback)1685         default void onUserSelectionCallbackRegistration(
1686                 @NonNull NetworkRequestUserSelectionCallback userSelectionCallback) {}
1687 
1688         /**
1689          * Invoked when the active network request is aborted, either because
1690          * <li> The app released the request, OR</li>
1691          * <li> Request was overridden by a new request</li>
1692          * This signals the end of processing for the current request and should stop the UI
1693          * component. No subsequent calls from the UI component will be handled by the platform.
1694          */
onAbort()1695         default void onAbort() {}
1696 
1697         /**
1698          * Invoked when a network request initiated by an app matches some networks in scan results.
1699          * This may be invoked multiple times for a single network request as the platform finds new
1700          * matching networks in scan results.
1701          *
1702          * @param scanResults List of {@link ScanResult} objects corresponding to the networks
1703          *                    matching the request.
1704          */
onMatch(@onNull List<ScanResult> scanResults)1705         default void onMatch(@NonNull List<ScanResult> scanResults) {}
1706 
1707         /**
1708          * Invoked on a successful connection with the network that the user selected
1709          * via {@link NetworkRequestUserSelectionCallback}.
1710          *
1711          * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
1712          *                          user selected.
1713          */
onUserSelectionConnectSuccess(@onNull WifiConfiguration wifiConfiguration)1714         default void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration) {}
1715 
1716         /**
1717          * Invoked on failure to establish connection with the network that the user selected
1718          * via {@link NetworkRequestUserSelectionCallback}.
1719          *
1720          * @param wifiConfiguration WifiConfiguration object corresponding to the network
1721          *                          user selected.
1722          */
onUserSelectionConnectFailure(@onNull WifiConfiguration wifiConfiguration)1723         default void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration) {}
1724     }
1725 
1726     /**
1727      * Callback proxy for NetworkRequestUserSelectionCallback objects.
1728      * @hide
1729      */
1730     private class NetworkRequestUserSelectionCallbackProxy implements
1731             NetworkRequestUserSelectionCallback {
1732         private final INetworkRequestUserSelectionCallback mCallback;
1733 
NetworkRequestUserSelectionCallbackProxy( INetworkRequestUserSelectionCallback callback)1734         NetworkRequestUserSelectionCallbackProxy(
1735                 INetworkRequestUserSelectionCallback callback) {
1736             mCallback = callback;
1737         }
1738 
1739         @Override
select(@onNull WifiConfiguration wifiConfiguration)1740         public void select(@NonNull WifiConfiguration wifiConfiguration) {
1741             if (mVerboseLoggingEnabled) {
1742                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
1743                         + "wificonfiguration: " + wifiConfiguration);
1744             }
1745             try {
1746                 mCallback.select(wifiConfiguration);
1747             } catch (RemoteException e) {
1748                 Log.e(TAG, "Failed to invoke onSelected", e);
1749                 throw e.rethrowFromSystemServer();
1750             }
1751         }
1752 
1753         @Override
reject()1754         public void reject() {
1755             if (mVerboseLoggingEnabled) {
1756                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
1757             }
1758             try {
1759                 mCallback.reject();
1760             } catch (RemoteException e) {
1761                 Log.e(TAG, "Failed to invoke onRejected", e);
1762                 throw e.rethrowFromSystemServer();
1763             }
1764         }
1765     }
1766 
1767     /**
1768      * Callback proxy for NetworkRequestMatchCallback objects.
1769      * @hide
1770      */
1771     private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
1772         private final Executor mExecutor;
1773         private final NetworkRequestMatchCallback mCallback;
1774 
NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback)1775         NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback) {
1776             mExecutor = executor;
1777             mCallback = callback;
1778         }
1779 
1780         @Override
onUserSelectionCallbackRegistration( INetworkRequestUserSelectionCallback userSelectionCallback)1781         public void onUserSelectionCallbackRegistration(
1782                 INetworkRequestUserSelectionCallback userSelectionCallback) {
1783             if (mVerboseLoggingEnabled) {
1784                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
1785                         + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
1786             }
1787             Binder.clearCallingIdentity();
1788             mExecutor.execute(() -> {
1789                 mCallback.onUserSelectionCallbackRegistration(
1790                         new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
1791             });
1792         }
1793 
1794         @Override
onAbort()1795         public void onAbort() {
1796             if (mVerboseLoggingEnabled) {
1797                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onAbort");
1798             }
1799             Binder.clearCallingIdentity();
1800             mExecutor.execute(() -> {
1801                 mCallback.onAbort();
1802             });
1803         }
1804 
1805         @Override
onMatch(List<ScanResult> scanResults)1806         public void onMatch(List<ScanResult> scanResults) {
1807             if (mVerboseLoggingEnabled) {
1808                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch scanResults: "
1809                         + scanResults);
1810             }
1811             Binder.clearCallingIdentity();
1812             mExecutor.execute(() -> {
1813                 mCallback.onMatch(scanResults);
1814             });
1815         }
1816 
1817         @Override
onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration)1818         public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
1819             if (mVerboseLoggingEnabled) {
1820                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
1821                         + " wificonfiguration: " + wifiConfiguration);
1822             }
1823             Binder.clearCallingIdentity();
1824             mExecutor.execute(() -> {
1825                 mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
1826             });
1827         }
1828 
1829         @Override
onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration)1830         public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
1831             if (mVerboseLoggingEnabled) {
1832                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
1833                         + " wificonfiguration: " + wifiConfiguration);
1834             }
1835             Binder.clearCallingIdentity();
1836             mExecutor.execute(() -> {
1837                 mCallback.onUserSelectionConnectFailure(wifiConfiguration);
1838             });
1839         }
1840     }
1841 
1842     /**
1843      * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
1844      * Caller can unregister a previously registered callback using
1845      * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
1846      * <p>
1847      * Applications should have the
1848      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
1849      * without the permission will trigger a {@link java.lang.SecurityException}.
1850      * <p>
1851      *
1852      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
1853      *                 object.
1854      * @param callback Callback for network match events to register.
1855      * @hide
1856      */
1857     @SystemApi
1858     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerNetworkRequestMatchCallback(@onNull @allbackExecutor Executor executor, @NonNull NetworkRequestMatchCallback callback)1859     public void registerNetworkRequestMatchCallback(@NonNull @CallbackExecutor Executor executor,
1860             @NonNull NetworkRequestMatchCallback callback) {
1861         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
1862         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
1863         Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
1864                 + ", executor=" + executor);
1865 
1866         Binder binder = new Binder();
1867         try {
1868             mService.registerNetworkRequestMatchCallback(
1869                     binder, new NetworkRequestMatchCallbackProxy(executor, callback),
1870                     callback.hashCode());
1871         } catch (RemoteException e) {
1872             throw e.rethrowFromSystemServer();
1873         }
1874     }
1875 
1876     /**
1877      * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
1878      * <p>
1879      * Applications should have the
1880      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
1881      * without the permission will trigger a {@link java.lang.SecurityException}.
1882      * <p>
1883      *
1884      * @param callback Callback for network match events to unregister.
1885      * @hide
1886      */
1887     @SystemApi
1888     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterNetworkRequestMatchCallback( @onNull NetworkRequestMatchCallback callback)1889     public void unregisterNetworkRequestMatchCallback(
1890             @NonNull NetworkRequestMatchCallback callback) {
1891         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
1892         Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
1893 
1894         try {
1895             mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
1896         } catch (RemoteException e) {
1897             throw e.rethrowFromSystemServer();
1898         }
1899     }
1900 
1901     /**
1902      * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
1903      * for a detailed explanation of the parameters.
1904      * When the device decides to connect to one of the provided network suggestions, platform sends
1905      * a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
1906      * the network was created with
1907      * {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(boolean)} flag set and the
1908      * app holds {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
1909      * permission.
1910      *<p>
1911      * NOTE:
1912      * <li> These networks are just a suggestion to the platform. The platform will ultimately
1913      * decide on which network the device connects to. </li>
1914      * <li> When an app is uninstalled or disabled, all its suggested networks are discarded.
1915      * If the device is currently connected to a suggested network which is being removed then the
1916      * device will disconnect from that network.</li>
1917      * <li> If user reset network settings, all added suggestions will be discarded. Apps can use
1918      * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
1919      * <li> In-place modification of existing suggestions are allowed.
1920      * <li> If the provided suggestions include any previously provided suggestions by the app,
1921      * previous suggestions will be updated.</li>
1922      * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and
1923      * the device is currently connected to that suggested network, then the device will disconnect
1924      * from that network. The system will immediately re-evaluate all the network candidates
1925      * and possibly reconnect back to the same suggestion. This disconnect is to make sure that any
1926      * traffic flowing over unmetered networks isn't accidentally continued over a metered network.
1927      * </li>
1928      * </li>
1929      *
1930      * @param networkSuggestions List of network suggestions provided by the app.
1931      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
1932      * @throws {@link SecurityException} if the caller is missing required permissions.
1933      * @see WifiNetworkSuggestion#equals(Object)
1934      */
1935     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
addNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)1936     public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
1937             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
1938         try {
1939             return mService.addNetworkSuggestions(
1940                     networkSuggestions, mContext.getOpPackageName(), mContext.getAttributionTag());
1941         } catch (RemoteException e) {
1942             throw e.rethrowFromSystemServer();
1943         }
1944     }
1945 
1946     /**
1947      * Remove some or all of the network suggestions that were previously provided by the app.
1948      * If one of the suggestions being removed was used to establish connection to the current
1949      * network, then the device will immediately disconnect from that network.
1950      *
1951      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
1952      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
1953      *
1954      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
1955      *                           to remove all the previous suggestions provided by the app.
1956      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
1957      * Any matching suggestions are removed from the device and will not be considered for any
1958      * further connection attempts.
1959      */
1960     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)1961     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
1962             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
1963         try {
1964             return mService.removeNetworkSuggestions(
1965                     networkSuggestions, mContext.getOpPackageName());
1966         } catch (RemoteException e) {
1967             throw e.rethrowFromSystemServer();
1968         }
1969     }
1970 
1971     /**
1972      * Get all network suggestions provided by the calling app.
1973      * See {@link #addNetworkSuggestions(List)}
1974      * See {@link #removeNetworkSuggestions(List)}
1975      * @return a list of {@link WifiNetworkSuggestion}
1976      */
1977     @RequiresPermission(ACCESS_WIFI_STATE)
getNetworkSuggestions()1978     public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
1979         try {
1980             return mService.getNetworkSuggestions(mContext.getOpPackageName());
1981         } catch (RemoteException e) {
1982             throw e.rethrowAsRuntimeException();
1983         }
1984     }
1985 
1986     /**
1987      * Returns the max number of network suggestions that are allowed per app on the device.
1988      * @see #addNetworkSuggestions(List)
1989      * @see #removeNetworkSuggestions(List)
1990      */
getMaxNumberOfNetworkSuggestionsPerApp()1991     public int getMaxNumberOfNetworkSuggestionsPerApp() {
1992         return getMaxNumberOfNetworkSuggestionsPerApp(
1993                 mContext.getSystemService(ActivityManager.class).isLowRamDevice());
1994     }
1995 
1996     /** @hide */
getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice)1997     public static int getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice) {
1998         return isLowRamDevice
1999                 ? NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM
2000                 : NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM;
2001     }
2002 
2003     /**
2004      * Add or update a Passpoint configuration.  The configuration provides a credential
2005      * for connecting to Passpoint networks that are operated by the Passpoint
2006      * service provider specified in the configuration.
2007      *
2008      * Each configuration is uniquely identified by a unique key which depends on the contents of
2009      * the configuration. This allows the caller to install multiple profiles with the same FQDN
2010      * (Fully qualified domain name). Therefore, in order to update an existing profile, it is
2011      * first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
2012      * Otherwise, a new profile will be added with both configuration.
2013      *
2014      * @param config The Passpoint configuration to be added
2015      * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
2016      *                                  the device.
2017      *
2018      * Deprecated for general app usage - except DO/PO apps.
2019      * See {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} to
2020      * create a passpoint suggestion.
2021      * See {@link #addNetworkSuggestions(List)}, {@link #removeNetworkSuggestions(List)} for new
2022      * API to add Wi-Fi networks for consideration when auto-connecting to wifi.
2023      * <b>Compatibility Note:</b> For applications targeting
2024      * {@link android.os.Build.VERSION_CODES#R} or above, this API will always fail and throw
2025      * {@link IllegalArgumentException}.
2026      * <p>
2027      * Deprecation Exemptions:
2028      * <ul>
2029      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2030      * </ul>
2031      */
addOrUpdatePasspointConfiguration(PasspointConfiguration config)2032     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
2033         try {
2034             if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
2035                 throw new IllegalArgumentException();
2036             }
2037         } catch (RemoteException e) {
2038             throw e.rethrowFromSystemServer();
2039         }
2040     }
2041 
2042     /**
2043      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name) added
2044      * by the caller.
2045      *
2046      * @param fqdn The FQDN of the Passpoint configuration added by the caller to be removed
2047      * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
2048      *                                  Passpoint is not enabled on the device.
2049      * @deprecated This will be non-functional in a future release.
2050      */
2051     @Deprecated
2052     @RequiresPermission(anyOf = {
2053             android.Manifest.permission.NETWORK_SETTINGS,
2054             android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
2055     })
removePasspointConfiguration(String fqdn)2056     public void removePasspointConfiguration(String fqdn) {
2057         try {
2058             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
2059                 throw new IllegalArgumentException();
2060             }
2061         } catch (RemoteException e) {
2062             throw e.rethrowFromSystemServer();
2063         }
2064     }
2065 
2066     /**
2067      * Return the list of installed Passpoint configurations added by the caller.
2068      *
2069      * An empty list will be returned when no configurations are installed.
2070      *
2071      * @return A list of {@link PasspointConfiguration} added by the caller
2072      * @deprecated This will be non-functional in a future release.
2073      */
2074     @Deprecated
2075     @RequiresPermission(anyOf = {
2076             android.Manifest.permission.NETWORK_SETTINGS,
2077             android.Manifest.permission.NETWORK_SETUP_WIZARD
2078     })
getPasspointConfigurations()2079     public List<PasspointConfiguration> getPasspointConfigurations() {
2080         try {
2081             return mService.getPasspointConfigurations(mContext.getOpPackageName());
2082         } catch (RemoteException e) {
2083             throw e.rethrowFromSystemServer();
2084         }
2085     }
2086 
2087     /**
2088      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
2089      * will be broadcasted once the request is completed.  The presence of the intent extra
2090      * {@link #EXTRA_ICON} will indicate the result of the request.
2091      * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
2092      *
2093      * @param bssid The BSSID of the AP
2094      * @param fileName Name of the icon file (remote file) to query from the AP
2095      *
2096      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
2097      * @hide
2098      */
queryPasspointIcon(long bssid, String fileName)2099     public void queryPasspointIcon(long bssid, String fileName) {
2100         try {
2101             mService.queryPasspointIcon(bssid, fileName);
2102         } catch (RemoteException e) {
2103             throw e.rethrowFromSystemServer();
2104         }
2105     }
2106 
2107     /**
2108      * Match the currently associated network against the SP matching the given FQDN
2109      * @param fqdn FQDN of the SP
2110      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
2111      * @hide
2112      */
matchProviderWithCurrentNetwork(String fqdn)2113     public int matchProviderWithCurrentNetwork(String fqdn) {
2114         try {
2115             return mService.matchProviderWithCurrentNetwork(fqdn);
2116         } catch (RemoteException e) {
2117             throw e.rethrowFromSystemServer();
2118         }
2119     }
2120 
2121     /**
2122      * Deauthenticate and set the re-authentication hold off time for the current network
2123      * @param holdoff hold off time in milliseconds
2124      * @param ess set if the hold off pertains to an ESS rather than a BSS
2125      * @hide
2126      *
2127      * TODO (140167680): This needs to be removed, the implementation is empty!
2128      */
deauthenticateNetwork(long holdoff, boolean ess)2129     public void deauthenticateNetwork(long holdoff, boolean ess) {
2130         try {
2131             mService.deauthenticateNetwork(holdoff, ess);
2132         } catch (RemoteException e) {
2133             throw e.rethrowFromSystemServer();
2134         }
2135     }
2136 
2137     /**
2138      * Remove the specified network from the list of configured networks.
2139      * This may result in the asynchronous delivery of state change
2140      * events.
2141      *
2142      * Applications are not allowed to remove networks created by other
2143      * applications.
2144      *
2145      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
2146      *        #getConfiguredNetworks}.
2147      * @return {@code true} if the operation succeeded
2148      *
2149      * @deprecated
2150      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2151      * mechanism to trigger connection to a Wi-Fi network.
2152      * b) See {@link #addNetworkSuggestions(List)},
2153      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2154      * when auto-connecting to wifi.
2155      * <b>Compatibility Note:</b> For applications targeting
2156      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2157      * {@code false}.
2158      * <p>
2159      * Deprecation Exemptions:
2160      * <ul>
2161      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2162      * </ul>
2163      */
2164     @Deprecated
removeNetwork(int netId)2165     public boolean removeNetwork(int netId) {
2166         try {
2167             return mService.removeNetwork(netId, mContext.getOpPackageName());
2168         } catch (RemoteException e) {
2169             throw e.rethrowFromSystemServer();
2170         }
2171     }
2172 
2173     /**
2174      * Allow a previously configured network to be associated with. If
2175      * <code>attemptConnect</code> is true, an attempt to connect to the selected
2176      * network is initiated. This may result in the asynchronous delivery
2177      * of state change events.
2178      * <p>
2179      * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
2180      * traffic may instead be sent through another network, such as cellular data,
2181      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
2182      * Wi-Fi network that does not provide Internet access (e.g. a wireless
2183      * printer), if another network that does offer Internet access (e.g.
2184      * cellular data) is available. Applications that need to ensure that their
2185      * network traffic uses Wi-Fi should use APIs such as
2186      * {@link Network#bindSocket(java.net.Socket)},
2187      * {@link Network#openConnection(java.net.URL)}, or
2188      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
2189      *
2190      * Applications are not allowed to enable networks created by other
2191      * applications.
2192      *
2193      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
2194      *        #getConfiguredNetworks}.
2195      * @param attemptConnect The way to select a particular network to connect to is specify
2196      *        {@code true} for this parameter.
2197      * @return {@code true} if the operation succeeded
2198      *
2199      * @deprecated
2200      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2201      * mechanism to trigger connection to a Wi-Fi network.
2202      * b) See {@link #addNetworkSuggestions(List)},
2203      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2204      * when auto-connecting to wifi.
2205      * <b>Compatibility Note:</b> For applications targeting
2206      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2207      * {@code false}.
2208      * Deprecation Exemptions:
2209      * <ul>
2210      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2211      * </ul>
2212      */
2213     @Deprecated
enableNetwork(int netId, boolean attemptConnect)2214     public boolean enableNetwork(int netId, boolean attemptConnect) {
2215         try {
2216             return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
2217         } catch (RemoteException e) {
2218             throw e.rethrowFromSystemServer();
2219         }
2220     }
2221 
2222     /**
2223      * Disable a configured network. The specified network will not be
2224      * a candidate for associating. This may result in the asynchronous
2225      * delivery of state change events.
2226      *
2227      * Applications are not allowed to disable networks created by other
2228      * applications.
2229      *
2230      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
2231      *        #getConfiguredNetworks}.
2232      * @return {@code true} if the operation succeeded
2233      *
2234      * @deprecated
2235      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2236      * mechanism to trigger connection to a Wi-Fi network.
2237      * b) See {@link #addNetworkSuggestions(List)},
2238      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2239      * when auto-connecting to wifi.
2240      * <b>Compatibility Note:</b> For applications targeting
2241      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2242      * {@code false}.
2243      * <p>
2244      * Deprecation Exemptions:
2245      * <ul>
2246      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2247      * </ul>
2248      */
2249     @Deprecated
disableNetwork(int netId)2250     public boolean disableNetwork(int netId) {
2251         try {
2252             return mService.disableNetwork(netId, mContext.getOpPackageName());
2253         } catch (RemoteException e) {
2254             throw e.rethrowFromSystemServer();
2255         }
2256     }
2257 
2258     /**
2259      * Disassociate from the currently active access point. This may result
2260      * in the asynchronous delivery of state change events.
2261      * @return {@code true} if the operation succeeded
2262      *
2263      * @deprecated
2264      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2265      * mechanism to trigger connection to a Wi-Fi network.
2266      * b) See {@link #addNetworkSuggestions(List)},
2267      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2268      * when auto-connecting to wifi.
2269      * <b>Compatibility Note:</b> For applications targeting
2270      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2271      * {@code false}.
2272      * <p>
2273      * Deprecation Exemptions:
2274      * <ul>
2275      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2276      * </ul>
2277      */
2278     @Deprecated
disconnect()2279     public boolean disconnect() {
2280         try {
2281             return mService.disconnect(mContext.getOpPackageName());
2282         } catch (RemoteException e) {
2283             throw e.rethrowFromSystemServer();
2284         }
2285     }
2286 
2287     /**
2288      * Reconnect to the currently active access point, if we are currently
2289      * disconnected. This may result in the asynchronous delivery of state
2290      * change events.
2291      * @return {@code true} if the operation succeeded
2292      *
2293      * @deprecated
2294      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2295      * mechanism to trigger connection to a Wi-Fi network.
2296      * b) See {@link #addNetworkSuggestions(List)},
2297      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2298      * when auto-connecting to wifi.
2299      * <b>Compatibility Note:</b> For applications targeting
2300      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2301      * {@code false}.
2302      * <p>
2303      * Deprecation Exemptions:
2304      * <ul>
2305      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2306      * </ul>
2307      */
2308     @Deprecated
reconnect()2309     public boolean reconnect() {
2310         try {
2311             return mService.reconnect(mContext.getOpPackageName());
2312         } catch (RemoteException e) {
2313             throw e.rethrowFromSystemServer();
2314         }
2315     }
2316 
2317     /**
2318      * Reconnect to the currently active access point, even if we are already
2319      * connected. This may result in the asynchronous delivery of state
2320      * change events.
2321      * @return {@code true} if the operation succeeded
2322      *
2323      * @deprecated
2324      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2325      * mechanism to trigger connection to a Wi-Fi network.
2326      * b) See {@link #addNetworkSuggestions(List)},
2327      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2328      * when auto-connecting to wifi.
2329      * <b>Compatibility Note:</b> For applications targeting
2330      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
2331      */
2332     @Deprecated
reassociate()2333     public boolean reassociate() {
2334         try {
2335             return mService.reassociate(mContext.getOpPackageName());
2336         } catch (RemoteException e) {
2337             throw e.rethrowFromSystemServer();
2338         }
2339     }
2340 
2341     /**
2342      * Check that the supplicant daemon is responding to requests.
2343      * @return {@code true} if we were able to communicate with the supplicant and
2344      * it returned the expected response to the PING message.
2345      * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
2346      */
2347     @Deprecated
pingSupplicant()2348     public boolean pingSupplicant() {
2349         return isWifiEnabled();
2350     }
2351 
2352     /** @hide */
2353     public static final long WIFI_FEATURE_INFRA            = 0x0001L;  // Basic infrastructure mode
2354     /** @hide */
2355     public static final long WIFI_FEATURE_PASSPOINT        = 0x0004L;  // Support for GAS/ANQP
2356     /** @hide */
2357     public static final long WIFI_FEATURE_P2P              = 0x0008L;  // Wifi-Direct
2358     /** @hide */
2359     public static final long WIFI_FEATURE_MOBILE_HOTSPOT   = 0x0010L;  // Soft AP
2360     /** @hide */
2361     public static final long WIFI_FEATURE_SCANNER          = 0x0020L;  // WifiScanner APIs
2362     /** @hide */
2363     public static final long WIFI_FEATURE_AWARE            = 0x0040L;  // Wi-Fi AWare networking
2364     /** @hide */
2365     public static final long WIFI_FEATURE_D2D_RTT          = 0x0080L;  // Device-to-device RTT
2366     /** @hide */
2367     public static final long WIFI_FEATURE_D2AP_RTT         = 0x0100L;  // Device-to-AP RTT
2368     /** @hide */
2369     public static final long WIFI_FEATURE_BATCH_SCAN       = 0x0200L;  // Batched Scan (deprecated)
2370     /** @hide */
2371     public static final long WIFI_FEATURE_PNO              = 0x0400L;  // Preferred network offload
2372     /** @hide */
2373     public static final long WIFI_FEATURE_ADDITIONAL_STA   = 0x0800L;  // Support for two STAs
2374     /** @hide */
2375     public static final long WIFI_FEATURE_TDLS             = 0x1000L;  // Tunnel directed link setup
2376     /** @hide */
2377     public static final long WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000L;  // TDLS off channel
2378     /** @hide */
2379     public static final long WIFI_FEATURE_EPR              = 0x4000L;  // Enhanced power reporting
2380     /** @hide */
2381     public static final long WIFI_FEATURE_AP_STA           = 0x8000L;  // AP STA Concurrency
2382     /** @hide */
2383     public static final long WIFI_FEATURE_LINK_LAYER_STATS = 0x10000L; // Link layer stats
2384     /** @hide */
2385     public static final long WIFI_FEATURE_LOGGER           = 0x20000L; // WiFi Logger
2386     /** @hide */
2387     public static final long WIFI_FEATURE_HAL_EPNO         = 0x40000L; // Enhanced PNO
2388     /** @hide */
2389     public static final long WIFI_FEATURE_RSSI_MONITOR     = 0x80000L; // RSSI Monitor
2390     /** @hide */
2391     public static final long WIFI_FEATURE_MKEEP_ALIVE      = 0x100000L; // mkeep_alive
2392     /** @hide */
2393     public static final long WIFI_FEATURE_CONFIG_NDO       = 0x200000L; // ND offload
2394     /** @hide */
2395     public static final long WIFI_FEATURE_TRANSMIT_POWER   = 0x400000L; // Capture transmit power
2396     /** @hide */
2397     public static final long WIFI_FEATURE_CONTROL_ROAMING  = 0x800000L; // Control firmware roaming
2398     /** @hide */
2399     public static final long WIFI_FEATURE_IE_WHITELIST     = 0x1000000L; // Probe IE white listing
2400     /** @hide */
2401     public static final long WIFI_FEATURE_SCAN_RAND        = 0x2000000L; // Random MAC & Probe seq
2402     /** @hide */
2403     public static final long WIFI_FEATURE_TX_POWER_LIMIT   = 0x4000000L; // Set Tx power limit
2404     /** @hide */
2405     public static final long WIFI_FEATURE_WPA3_SAE         = 0x8000000L; // WPA3-Personal SAE
2406     /** @hide */
2407     public static final long WIFI_FEATURE_WPA3_SUITE_B     = 0x10000000L; // WPA3-Enterprise Suite-B
2408     /** @hide */
2409     public static final long WIFI_FEATURE_OWE              = 0x20000000L; // Enhanced Open
2410     /** @hide */
2411     public static final long WIFI_FEATURE_LOW_LATENCY      = 0x40000000L; // Low Latency modes
2412     /** @hide */
2413     public static final long WIFI_FEATURE_DPP              = 0x80000000L; // DPP (Easy-Connect)
2414     /** @hide */
2415     public static final long WIFI_FEATURE_P2P_RAND_MAC     = 0x100000000L; // Random P2P MAC
2416     /** @hide */
2417     public static final long WIFI_FEATURE_CONNECTED_RAND_MAC    = 0x200000000L; // Random STA MAC
2418     /** @hide */
2419     public static final long WIFI_FEATURE_AP_RAND_MAC      = 0x400000000L; // Random AP MAC
2420     /** @hide */
2421     public static final long WIFI_FEATURE_MBO              = 0x800000000L; // MBO Support
2422     /** @hide */
2423     public static final long WIFI_FEATURE_OCE              = 0x1000000000L; // OCE Support
2424     /** @hide */
2425     public static final long WIFI_FEATURE_WAPI             = 0x2000000000L; // WAPI
2426 
2427     /** @hide */
2428     public static final long WIFI_FEATURE_FILS_SHA256     = 0x4000000000L; // FILS-SHA256
2429 
2430     /** @hide */
2431     public static final long WIFI_FEATURE_FILS_SHA384     = 0x8000000000L; // FILS-SHA384
2432 
getSupportedFeatures()2433     private long getSupportedFeatures() {
2434         try {
2435             return mService.getSupportedFeatures();
2436         } catch (RemoteException e) {
2437             throw e.rethrowFromSystemServer();
2438         }
2439     }
2440 
isFeatureSupported(long feature)2441     private boolean isFeatureSupported(long feature) {
2442         return (getSupportedFeatures() & feature) == feature;
2443     }
2444 
2445     /**
2446      * @return true if this adapter supports Passpoint
2447      * @hide
2448      */
isPasspointSupported()2449     public boolean isPasspointSupported() {
2450         return isFeatureSupported(WIFI_FEATURE_PASSPOINT);
2451     }
2452 
2453     /**
2454      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
2455      */
isP2pSupported()2456     public boolean isP2pSupported() {
2457         return isFeatureSupported(WIFI_FEATURE_P2P);
2458     }
2459 
2460     /**
2461      * @return true if this adapter supports portable Wi-Fi hotspot
2462      * @hide
2463      */
2464     @SystemApi
isPortableHotspotSupported()2465     public boolean isPortableHotspotSupported() {
2466         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
2467     }
2468 
2469     /**
2470      * @return true if this adapter supports WifiScanner APIs
2471      * @hide
2472      */
2473     @SystemApi
isWifiScannerSupported()2474     public boolean isWifiScannerSupported() {
2475         return isFeatureSupported(WIFI_FEATURE_SCANNER);
2476     }
2477 
2478     /**
2479      * @return true if this adapter supports Neighbour Awareness Network APIs
2480      * @hide
2481      */
isWifiAwareSupported()2482     public boolean isWifiAwareSupported() {
2483         return isFeatureSupported(WIFI_FEATURE_AWARE);
2484     }
2485 
2486     /**
2487      * Query whether the device supports Station (STA) + Access point (AP) concurrency or not.
2488      *
2489      * @return true if this device supports STA + AP concurrency, false otherwise.
2490      */
isStaApConcurrencySupported()2491     public boolean isStaApConcurrencySupported() {
2492         return isFeatureSupported(WIFI_FEATURE_AP_STA);
2493     }
2494 
2495     /**
2496      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
2497      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
2498      * {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
2499      *
2500      * @return true if this adapter supports Device-to-device RTT
2501      * @hide
2502      */
2503     @Deprecated
2504     @SystemApi
isDeviceToDeviceRttSupported()2505     public boolean isDeviceToDeviceRttSupported() {
2506         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
2507     }
2508 
2509     /**
2510      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
2511      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT}.
2512      *
2513      * @return true if this adapter supports Device-to-AP RTT
2514      */
2515     @Deprecated
isDeviceToApRttSupported()2516     public boolean isDeviceToApRttSupported() {
2517         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
2518     }
2519 
2520     /**
2521      * @return true if this adapter supports offloaded connectivity scan
2522      */
isPreferredNetworkOffloadSupported()2523     public boolean isPreferredNetworkOffloadSupported() {
2524         return isFeatureSupported(WIFI_FEATURE_PNO);
2525     }
2526 
2527     /**
2528      * @return true if this adapter supports multiple simultaneous connections
2529      * @hide
2530      */
isAdditionalStaSupported()2531     public boolean isAdditionalStaSupported() {
2532         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
2533     }
2534 
2535     /**
2536      * @return true if this adapter supports Tunnel Directed Link Setup
2537      */
isTdlsSupported()2538     public boolean isTdlsSupported() {
2539         return isFeatureSupported(WIFI_FEATURE_TDLS);
2540     }
2541 
2542     /**
2543      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
2544      * @hide
2545      */
isOffChannelTdlsSupported()2546     public boolean isOffChannelTdlsSupported() {
2547         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
2548     }
2549 
2550     /**
2551      * @return true if this adapter supports advanced power/performance counters
2552      */
isEnhancedPowerReportingSupported()2553     public boolean isEnhancedPowerReportingSupported() {
2554         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
2555     }
2556 
2557     /**
2558      * @return true if this device supports connected MAC randomization.
2559      * @hide
2560      */
2561     @SystemApi
isConnectedMacRandomizationSupported()2562     public boolean isConnectedMacRandomizationSupported() {
2563         return isFeatureSupported(WIFI_FEATURE_CONNECTED_RAND_MAC);
2564     }
2565 
2566     /**
2567      * @return true if this device supports connected MAC randomization.
2568      * @hide
2569      */
2570     @SystemApi
isApMacRandomizationSupported()2571     public boolean isApMacRandomizationSupported() {
2572         return isFeatureSupported(WIFI_FEATURE_AP_RAND_MAC);
2573     }
2574 
2575     /**
2576      * Check if the chipset supports 5GHz band.
2577      * @return {@code true} if supported, {@code false} otherwise.
2578      */
is5GHzBandSupported()2579     public boolean is5GHzBandSupported() {
2580         try {
2581             return mService.is5GHzBandSupported();
2582         } catch (RemoteException e) {
2583             throw e.rethrowFromSystemServer();
2584         }
2585     }
2586 
2587     /**
2588      * Check if the chipset supports 6GHz band.
2589      * @return {@code true} if supported, {@code false} otherwise.
2590      */
is6GHzBandSupported()2591     public boolean is6GHzBandSupported() {
2592         try {
2593             return mService.is6GHzBandSupported();
2594         } catch (RemoteException e) {
2595             throw e.rethrowFromSystemServer();
2596         }
2597     }
2598 
2599     /**
2600      * Check if the chipset supports a certain Wi-Fi standard.
2601      * @param standard the IEEE 802.11 standard to check on.
2602      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
2603      * @return {@code true} if supported, {@code false} otherwise.
2604      */
isWifiStandardSupported(@ifiAnnotations.WifiStandard int standard)2605     public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
2606         try {
2607             return mService.isWifiStandardSupported(standard);
2608         } catch (RemoteException e) {
2609             throw e.rethrowFromSystemServer();
2610         }
2611     }
2612 
2613     /**
2614      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
2615      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
2616      *
2617      * @hide
2618      */
2619     @SystemApi
2620     public interface OnWifiActivityEnergyInfoListener {
2621         /**
2622          * Called when Wi-Fi activity energy info is available.
2623          * Note: this listener is triggered at most once for each call to
2624          * {@link #getWifiActivityEnergyInfoAsync}.
2625          *
2626          * @param info the latest {@link WifiActivityEnergyInfo}, or null if unavailable.
2627          */
onWifiActivityEnergyInfo(@ullable WifiActivityEnergyInfo info)2628         void onWifiActivityEnergyInfo(@Nullable WifiActivityEnergyInfo info);
2629     }
2630 
2631     private static class OnWifiActivityEnergyInfoProxy
2632             extends IOnWifiActivityEnergyInfoListener.Stub {
2633         private final Object mLock = new Object();
2634         @Nullable @GuardedBy("mLock") private Executor mExecutor;
2635         @Nullable @GuardedBy("mLock") private OnWifiActivityEnergyInfoListener mListener;
2636 
OnWifiActivityEnergyInfoProxy(Executor executor, OnWifiActivityEnergyInfoListener listener)2637         OnWifiActivityEnergyInfoProxy(Executor executor,
2638                 OnWifiActivityEnergyInfoListener listener) {
2639             mExecutor = executor;
2640             mListener = listener;
2641         }
2642 
2643         @Override
onWifiActivityEnergyInfo(WifiActivityEnergyInfo info)2644         public void onWifiActivityEnergyInfo(WifiActivityEnergyInfo info) {
2645             Executor executor;
2646             OnWifiActivityEnergyInfoListener listener;
2647             synchronized (mLock) {
2648                 if (mExecutor == null || mListener == null) {
2649                     return;
2650                 }
2651                 executor = mExecutor;
2652                 listener = mListener;
2653                 // null out to allow garbage collection, prevent triggering listener more than once
2654                 mExecutor = null;
2655                 mListener = null;
2656             }
2657             Binder.clearCallingIdentity();
2658             executor.execute(() -> listener.onWifiActivityEnergyInfo(info));
2659         }
2660     }
2661 
2662     /**
2663      * Request to get the current {@link WifiActivityEnergyInfo} asynchronously.
2664      * Note: This method will return null if {@link #isEnhancedPowerReportingSupported()} returns
2665      * false.
2666      *
2667      * @param executor the executor that the listener will be invoked on
2668      * @param listener the listener that will receive the {@link WifiActivityEnergyInfo} object
2669      *                 when it becomes available. The listener will be triggered at most once for
2670      *                 each call to this method.
2671      *
2672      * @hide
2673      */
2674     @SystemApi
2675     @RequiresPermission(ACCESS_WIFI_STATE)
getWifiActivityEnergyInfoAsync( @onNull @allbackExecutor Executor executor, @NonNull OnWifiActivityEnergyInfoListener listener)2676     public void getWifiActivityEnergyInfoAsync(
2677             @NonNull @CallbackExecutor Executor executor,
2678             @NonNull OnWifiActivityEnergyInfoListener listener) {
2679         Objects.requireNonNull(executor, "executor cannot be null");
2680         Objects.requireNonNull(listener, "listener cannot be null");
2681         try {
2682             mService.getWifiActivityEnergyInfoAsync(
2683                     new OnWifiActivityEnergyInfoProxy(executor, listener));
2684         } catch (RemoteException e) {
2685             throw e.rethrowFromSystemServer();
2686         }
2687     }
2688 
2689     /**
2690      * Request a scan for access points. Returns immediately. The availability
2691      * of the results is made known later by means of an asynchronous event sent
2692      * on completion of the scan.
2693      * <p>
2694      * To initiate a Wi-Fi scan, declare the
2695      * {@link android.Manifest.permission#CHANGE_WIFI_STATE}
2696      * permission in the manifest, and perform these steps:
2697      * </p>
2698      * <ol style="1">
2699      * <li>Invoke the following method:
2700      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>
2701      * <li>
2702      * Register a BroadcastReceiver to listen to
2703      * {@code SCAN_RESULTS_AVAILABLE_ACTION}.</li>
2704      * <li>When a broadcast is received, call:
2705      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>
2706      * </ol>
2707      * @return {@code true} if the operation succeeded, i.e., the scan was initiated.
2708      * @deprecated The ability for apps to trigger scan requests will be removed in a future
2709      * release.
2710      */
2711     @Deprecated
startScan()2712     public boolean startScan() {
2713         return startScan(null);
2714     }
2715 
2716     /** @hide */
2717     @SystemApi
2718     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
startScan(WorkSource workSource)2719     public boolean startScan(WorkSource workSource) {
2720         try {
2721             String packageName = mContext.getOpPackageName();
2722             String attributionTag = mContext.getAttributionTag();
2723             return mService.startScan(packageName, attributionTag);
2724         } catch (RemoteException e) {
2725             throw e.rethrowFromSystemServer();
2726         }
2727     }
2728 
2729     /**
2730      * WPS has been deprecated from Client mode operation.
2731      *
2732      * @return null
2733      * @hide
2734      * @deprecated This API is deprecated
2735      */
getCurrentNetworkWpsNfcConfigurationToken()2736     public String getCurrentNetworkWpsNfcConfigurationToken() {
2737         return null;
2738     }
2739 
2740     /**
2741      * Return dynamic information about the current Wi-Fi connection, if any is active.
2742      * <p>
2743      * In the connected state, access to the SSID and BSSID requires
2744      * the same permissions as {@link #getScanResults}. If such access is not allowed,
2745      * {@link WifiInfo#getSSID} will return {@link #UNKNOWN_SSID} and
2746      * {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
2747      * {@link WifiInfo#getPasspointFqdn()} will return null.
2748      * {@link WifiInfo#getPasspointProviderFriendlyName()} will return null.
2749      *
2750      * @return the Wi-Fi information, contained in {@link WifiInfo}.
2751      */
getConnectionInfo()2752     public WifiInfo getConnectionInfo() {
2753         try {
2754             return mService.getConnectionInfo(mContext.getOpPackageName(),
2755                     mContext.getAttributionTag());
2756         } catch (RemoteException e) {
2757             throw e.rethrowFromSystemServer();
2758         }
2759     }
2760 
2761     /**
2762      * Return the results of the latest access point scan.
2763      * @return the list of access points found in the most recent scan. An app must hold
2764      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
2765      * in order to get valid results.
2766      */
getScanResults()2767     public List<ScanResult> getScanResults() {
2768         try {
2769             return mService.getScanResults(mContext.getOpPackageName(),
2770                     mContext.getAttributionTag());
2771         } catch (RemoteException e) {
2772             throw e.rethrowFromSystemServer();
2773         }
2774     }
2775 
2776     /**
2777      * Get the filtered ScanResults which match the network configurations specified by the
2778      * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
2779      * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
2780      * use the matching rules of Hotspot 2.0.
2781      * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
2782      * These may or may not be suggestions which are installed on the device.
2783      * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
2784      * the Wi-Fi service will use the most recent scan results which the system has.
2785      * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
2786      * corresponding to networks which match them.
2787      * @hide
2788      */
2789     @SystemApi
2790     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
2791     @NonNull
getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestionsToMatch, @Nullable List<ScanResult> scanResults)2792     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
2793             @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
2794             @Nullable List<ScanResult> scanResults) {
2795         if (networkSuggestionsToMatch == null) {
2796             throw new IllegalArgumentException("networkSuggestions must not be null.");
2797         }
2798         try {
2799             return mService.getMatchingScanResults(
2800                     networkSuggestionsToMatch, scanResults,
2801                     mContext.getOpPackageName(), mContext.getAttributionTag());
2802         } catch (RemoteException e) {
2803             throw e.rethrowFromSystemServer();
2804         }
2805     }
2806 
2807     /**
2808      * Set if scanning is always available.
2809      *
2810      * If set to {@code true}, apps can issue {@link #startScan} and fetch scan results
2811      * even when Wi-Fi is turned off.
2812      *
2813      * @param isAvailable true to enable, false to disable.
2814      * @hide
2815      * @see #isScanAlwaysAvailable()
2816      */
2817     @SystemApi
2818     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanAlwaysAvailable(boolean isAvailable)2819     public void setScanAlwaysAvailable(boolean isAvailable) {
2820         try {
2821             mService.setScanAlwaysAvailable(isAvailable);
2822         } catch (RemoteException e) {
2823             throw e.rethrowFromSystemServer();
2824         }
2825     }
2826 
2827     /**
2828      * Check if scanning is always available.
2829      *
2830      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
2831      * even when Wi-Fi is turned off.
2832      *
2833      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
2834      * @deprecated The ability for apps to trigger scan requests will be removed in a future
2835      * release.
2836      */
2837     @Deprecated
isScanAlwaysAvailable()2838     public boolean isScanAlwaysAvailable() {
2839         try {
2840             return mService.isScanAlwaysAvailable();
2841         } catch (RemoteException e) {
2842             throw e.rethrowFromSystemServer();
2843         }
2844     }
2845 
2846     /**
2847      * Tell the device to persist the current list of configured networks.
2848      * <p>
2849      * Note: It is possible for this method to change the network IDs of
2850      * existing networks. You should assume the network IDs can be different
2851      * after calling this method.
2852      *
2853      * @return {@code false}.
2854      * @deprecated There is no need to call this method -
2855      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
2856      * and {@link #removeNetwork(int)} already persist the configurations automatically.
2857      */
2858     @Deprecated
saveConfiguration()2859     public boolean saveConfiguration() {
2860         return false;
2861     }
2862 
2863     /**
2864      * Get the country code.
2865      * @return the country code in ISO 3166 alpha-2 (2-letter) uppercase format, or null if
2866      * there is no country code configured.
2867      * @hide
2868      */
2869     @Nullable
2870     @SystemApi
2871     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getCountryCode()2872     public String getCountryCode() {
2873         try {
2874             return mService.getCountryCode();
2875         } catch (RemoteException e) {
2876             throw e.rethrowFromSystemServer();
2877         }
2878     }
2879 
2880     /**
2881      * Return the DHCP-assigned addresses from the last successful DHCP request,
2882      * if any.
2883      * @return the DHCP information
2884      */
getDhcpInfo()2885     public DhcpInfo getDhcpInfo() {
2886         try {
2887             return mService.getDhcpInfo();
2888         } catch (RemoteException e) {
2889             throw e.rethrowFromSystemServer();
2890         }
2891     }
2892 
2893     /**
2894      * Enable or disable Wi-Fi.
2895      * <p>
2896      * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
2897      * permission to toggle wifi.
2898      *
2899      * @param enabled {@code true} to enable, {@code false} to disable.
2900      * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
2901      *         either already in the requested state, or in progress toward the requested state.
2902      * @throws  {@link java.lang.SecurityException} if the caller is missing required permissions.
2903      *
2904      * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
2905      * enable/disable Wi-Fi.
2906      * <b>Compatibility Note:</b> For applications targeting
2907      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2908      * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
2909      * or below), they can continue to use this API.
2910      * <p>
2911      * Deprecation Exemptions:
2912      * <ul>
2913      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2914      * </ul>
2915      */
2916     @Deprecated
setWifiEnabled(boolean enabled)2917     public boolean setWifiEnabled(boolean enabled) {
2918         try {
2919             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
2920         } catch (RemoteException e) {
2921             throw e.rethrowFromSystemServer();
2922         }
2923     }
2924 
2925     /**
2926      * Gets the Wi-Fi enabled state.
2927      * @return One of {@link #WIFI_STATE_DISABLED},
2928      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
2929      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
2930      * @see #isWifiEnabled()
2931      */
getWifiState()2932     public int getWifiState() {
2933         try {
2934             return mService.getWifiEnabledState();
2935         } catch (RemoteException e) {
2936             throw e.rethrowFromSystemServer();
2937         }
2938     }
2939 
2940     /**
2941      * Return whether Wi-Fi is enabled or disabled.
2942      * @return {@code true} if Wi-Fi is enabled
2943      * @see #getWifiState()
2944      */
isWifiEnabled()2945     public boolean isWifiEnabled() {
2946         return getWifiState() == WIFI_STATE_ENABLED;
2947     }
2948 
2949     /**
2950      * Calculates the level of the signal. This should be used any time a signal
2951      * is being shown.
2952      *
2953      * @param rssi The power of the signal measured in RSSI.
2954      * @param numLevels The number of levels to consider in the calculated level.
2955      * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive).
2956      * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the
2957      * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level
2958      * themselves using their own formula.
2959      */
2960     @Deprecated
calculateSignalLevel(int rssi, int numLevels)2961     public static int calculateSignalLevel(int rssi, int numLevels) {
2962         if (rssi <= MIN_RSSI) {
2963             return 0;
2964         } else if (rssi >= MAX_RSSI) {
2965             return numLevels - 1;
2966         } else {
2967             float inputRange = (MAX_RSSI - MIN_RSSI);
2968             float outputRange = (numLevels - 1);
2969             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
2970         }
2971     }
2972 
2973     /**
2974      * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI
2975      * quality rating thresholds.
2976      * @param rssi a raw RSSI value, in dBm, usually between -55 and -90
2977      * @return the RSSI signal quality rating, in the range
2978      * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
2979      * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
2980      */
2981     @IntRange(from = 0)
calculateSignalLevel(int rssi)2982     public int calculateSignalLevel(int rssi) {
2983         try {
2984             return mService.calculateSignalLevel(rssi);
2985         } catch (RemoteException e) {
2986             throw e.rethrowFromSystemServer();
2987         }
2988     }
2989 
2990     /**
2991      * Get the system default maximum signal level.
2992      * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
2993      */
2994     @IntRange(from = 0)
getMaxSignalLevel()2995     public int getMaxSignalLevel() {
2996         return calculateSignalLevel(Integer.MAX_VALUE);
2997     }
2998 
2999     /**
3000      * Compares two signal strengths.
3001      *
3002      * @param rssiA The power of the first signal measured in RSSI.
3003      * @param rssiB The power of the second signal measured in RSSI.
3004      * @return Returns <0 if the first signal is weaker than the second signal,
3005      *         0 if the two signals have the same strength, and >0 if the first
3006      *         signal is stronger than the second signal.
3007      */
compareSignalLevel(int rssiA, int rssiB)3008     public static int compareSignalLevel(int rssiA, int rssiB) {
3009         return rssiA - rssiB;
3010     }
3011 
3012     /**
3013      * Call allowing ConnectivityService to update WifiService with interface mode changes.
3014      *
3015      * @param ifaceName String name of the updated interface, or null to represent all interfaces
3016      * @param mode int representing the new mode, one of:
3017      *             {@link #IFACE_IP_MODE_TETHERED},
3018      *             {@link #IFACE_IP_MODE_LOCAL_ONLY},
3019      *             {@link #IFACE_IP_MODE_CONFIGURATION_ERROR},
3020      *             {@link #IFACE_IP_MODE_UNSPECIFIED}
3021      *
3022      * @hide
3023      */
3024     @SystemApi
3025     @RequiresPermission(anyOf = {
3026             android.Manifest.permission.NETWORK_STACK,
3027             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3028     })
updateInterfaceIpState(@ullable String ifaceName, @IfaceIpMode int mode)3029     public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
3030         try {
3031             mService.updateInterfaceIpState(ifaceName, mode);
3032         } catch (RemoteException e) {
3033             throw e.rethrowFromSystemServer();
3034         }
3035     }
3036 
3037     /**
3038      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
3039      * Note that starting Soft AP mode may disable station mode operation if the device does not
3040      * support concurrency.
3041      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
3042      *                   use the persisted Soft AP configuration that was previously set using
3043      *                   {@link #setWifiApConfiguration(WifiConfiguration)}.
3044      * @return {@code true} if the operation succeeded, {@code false} otherwise
3045      *
3046      * @hide
3047      */
3048     @RequiresPermission(anyOf = {
3049             android.Manifest.permission.NETWORK_STACK,
3050             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3051     })
startSoftAp(@ullable WifiConfiguration wifiConfig)3052     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
3053         try {
3054             return mService.startSoftAp(wifiConfig);
3055         } catch (RemoteException e) {
3056             throw e.rethrowFromSystemServer();
3057         }
3058     }
3059 
3060     /**
3061      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
3062      * Note that starting Soft AP mode may disable station mode operation if the device does not
3063      * support concurrency.
3064      * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
3065      *                     or null to use the persisted Soft AP configuration that was previously
3066      *                     set using {@link #setSoftApConfiguration(softApConfiguration)}.
3067      * @return {@code true} if the operation succeeded, {@code false} otherwise
3068      *
3069      * @hide
3070      */
3071     @SystemApi
3072     @RequiresPermission(anyOf = {
3073             android.Manifest.permission.NETWORK_STACK,
3074             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3075     })
startTetheredHotspot(@ullable SoftApConfiguration softApConfig)3076     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
3077         try {
3078             return mService.startTetheredHotspot(softApConfig);
3079         } catch (RemoteException e) {
3080             throw e.rethrowFromSystemServer();
3081         }
3082     }
3083 
3084 
3085     /**
3086      * Stop SoftAp mode.
3087      * Note that stopping softap mode will restore the previous wifi mode.
3088      * @return {@code true} if the operation succeeds, {@code false} otherwise
3089      *
3090      * @hide
3091      */
3092     @SystemApi
3093     @RequiresPermission(anyOf = {
3094             android.Manifest.permission.NETWORK_STACK,
3095             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3096     })
stopSoftAp()3097     public boolean stopSoftAp() {
3098         try {
3099             return mService.stopSoftAp();
3100         } catch (RemoteException e) {
3101             throw e.rethrowFromSystemServer();
3102         }
3103     }
3104 
3105     /**
3106      * Request a local only hotspot that an application can use to communicate between co-located
3107      * devices connected to the created WiFi hotspot.  The network created by this method will not
3108      * have Internet access.  Each application can make a single request for the hotspot, but
3109      * multiple applications could be requesting the hotspot at the same time.  When multiple
3110      * applications have successfully registered concurrently, they will be sharing the underlying
3111      * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called
3112      * when the hotspot is ready for use by the application.
3113      * <p>
3114      * Each application can make a single active call to this method. The {@link
3115      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
3116      * requestor with a {@link LocalOnlyHotspotReservation} that contains a
3117      * {@link SoftApConfiguration} with the SSID, security type and credentials needed to connect
3118      * to the hotspot.  Communicating this information is up to the application.
3119      * <p>
3120      * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
3121      * method will be called. Example failures include errors bringing up the network or if
3122      * there is an incompatible operating mode.  For example, if the user is currently using Wifi
3123      * Tethering to provide an upstream to another device, LocalOnlyHotspot will not start due to
3124      * an incompatible mode. The possible error codes include:
3125      * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL},
3126      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC},
3127      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and
3128      * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}.
3129      * <p>
3130      * Internally, requests will be tracked to prevent the hotspot from being torn down while apps
3131      * are still using it.  The {@link LocalOnlyHotspotReservation} object passed in the  {@link
3132      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when
3133      * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}.
3134      * Since the hotspot may be shared among multiple applications, removing the final registered
3135      * application request will trigger the hotspot teardown.  This means that applications should
3136      * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after
3137      * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is
3138      * called, applications will not receive callbacks of any kind.
3139      * <p>
3140      * Applications should be aware that the user may also stop the LocalOnlyHotspot through the
3141      * Settings UI; it is not guaranteed to stay up as long as there is a requesting application.
3142      * The requestors will be notified of this case via
3143      * {@link LocalOnlyHotspotCallback#onStopped()}.  Other cases may arise where the hotspot is
3144      * torn down (Emergency mode, etc).  Application developers should be aware that it can stop
3145      * unexpectedly, but they will receive a notification if they have properly registered.
3146      * <p>
3147      * Applications should also be aware that this network will be shared with other applications.
3148      * Applications are responsible for protecting their data on this network (e.g., TLS).
3149      * <p>
3150      * Applications need to have the following permissions to start LocalOnlyHotspot: {@link
3151      * android.Manifest.permission#CHANGE_WIFI_STATE} and {@link
3152      * android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}.  Callers without
3153      * the permissions will trigger a {@link java.lang.SecurityException}.
3154      * <p>
3155      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
3156      * operating status.
3157      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
3158      * main thread will be used.
3159      */
3160     @RequiresPermission(allOf = {
3161             android.Manifest.permission.CHANGE_WIFI_STATE,
3162             android.Manifest.permission.ACCESS_FINE_LOCATION})
startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler)3163     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
3164             @Nullable Handler handler) {
3165         Executor executor = handler == null ? null : new HandlerExecutor(handler);
3166         startLocalOnlyHotspotInternal(null, executor, callback);
3167     }
3168 
3169     /**
3170      * Starts a local-only hotspot with a specific configuration applied. See
3171      * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
3172      *
3173      * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} or
3174      * {@link android.Manifest.permission#NETWORK_SETTINGS} to call this method.
3175      *
3176      * Since custom configuration settings may be incompatible with each other, the hotspot started
3177      * through this method cannot coexist with another hotspot created through
3178      * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others
3179      * receive {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
3180      * {@link LocalOnlyHotspotCallback#onFailed}.
3181      *
3182      * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
3183      * @param executor Executor to run callback methods on, or null to use the main thread.
3184      * @param callback Callback object for updates about hotspot status, or null for no updates.
3185      * @hide
3186      */
3187     @SystemApi
3188     @RequiresPermission(anyOf = {
3189             android.Manifest.permission.NETWORK_SETTINGS,
3190             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startLocalOnlyHotspot(@onNull SoftApConfiguration config, @Nullable Executor executor, @Nullable LocalOnlyHotspotCallback callback)3191     public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config,
3192             @Nullable Executor executor,
3193             @Nullable LocalOnlyHotspotCallback callback) {
3194         Objects.requireNonNull(config);
3195         startLocalOnlyHotspotInternal(config, executor, callback);
3196     }
3197 
3198     /**
3199      * Common implementation of both configurable and non-configurable LOHS.
3200      *
3201      * @param config App-specified configuration, or null. When present, additional privileges are
3202      *               required, and the hotspot cannot be shared with other clients.
3203      * @param executor Executor to run callback methods on, or null to use the main thread.
3204      * @param callback Callback object for updates about hotspot status, or null for no updates.
3205      */
startLocalOnlyHotspotInternal( @ullable SoftApConfiguration config, @Nullable Executor executor, @Nullable LocalOnlyHotspotCallback callback)3206     private void startLocalOnlyHotspotInternal(
3207             @Nullable SoftApConfiguration config,
3208             @Nullable Executor executor,
3209             @Nullable LocalOnlyHotspotCallback callback) {
3210         if (executor == null) {
3211             executor = mContext.getMainExecutor();
3212         }
3213         synchronized (mLock) {
3214             LocalOnlyHotspotCallbackProxy proxy =
3215                     new LocalOnlyHotspotCallbackProxy(this, executor, callback);
3216             try {
3217                 String packageName = mContext.getOpPackageName();
3218                 String featureId = mContext.getAttributionTag();
3219                 int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
3220                         config);
3221                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
3222                     // Send message to the proxy to make sure we call back on the correct thread
3223                     proxy.onHotspotFailed(returnCode);
3224                     return;
3225                 }
3226                 mLOHSCallbackProxy = proxy;
3227             } catch (RemoteException e) {
3228                 throw e.rethrowFromSystemServer();
3229             }
3230         }
3231     }
3232 
3233     /**
3234      * Cancels a pending local only hotspot request.  This can be used by the calling application to
3235      * cancel the existing request if the provided callback has not been triggered.  Calling this
3236      * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not
3237      * explicitly required.
3238      * <p>
3239      * When cancelling this request, application developers should be aware that there may still be
3240      * outstanding local only hotspot requests and the hotspot may still start, or continue running.
3241      * Additionally, if a callback was registered, it will no longer be triggered after calling
3242      * cancel.
3243      *
3244      * @hide
3245      */
3246     @UnsupportedAppUsage
cancelLocalOnlyHotspotRequest()3247     public void cancelLocalOnlyHotspotRequest() {
3248         synchronized (mLock) {
3249             stopLocalOnlyHotspot();
3250         }
3251     }
3252 
3253     /**
3254      *  Method used to inform WifiService that the LocalOnlyHotspot is no longer needed.  This
3255      *  method is used by WifiManager to release LocalOnlyHotspotReservations held by calling
3256      *  applications and removes the internal tracking for the hotspot request.  When all requesting
3257      *  applications are finished using the hotspot, it will be stopped and WiFi will return to the
3258      *  previous operational mode.
3259      *
3260      *  This method should not be called by applications.  Instead, they should call the close()
3261      *  method on their LocalOnlyHotspotReservation.
3262      */
stopLocalOnlyHotspot()3263     private void stopLocalOnlyHotspot() {
3264         synchronized (mLock) {
3265             if (mLOHSCallbackProxy == null) {
3266                 // nothing to do, the callback was already cleaned up.
3267                 return;
3268             }
3269             mLOHSCallbackProxy = null;
3270             try {
3271                 mService.stopLocalOnlyHotspot();
3272             } catch (RemoteException e) {
3273                 throw e.rethrowFromSystemServer();
3274             }
3275         }
3276     }
3277 
3278     /**
3279      * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes.  Callers will
3280      * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
3281      * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
3282      * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(SoftApConfiguration)} and
3283      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
3284      * <p>
3285      * Applications should have the
3286      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
3287      * permission.  Callers without the permission will trigger a
3288      * {@link java.lang.SecurityException}.
3289      * <p>
3290      * @param observer LocalOnlyHotspotObserver callback.
3291      * @param handler Handler to use for callbacks
3292      *
3293      * @hide
3294      */
watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, @Nullable Handler handler)3295     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
3296             @Nullable Handler handler) {
3297         Executor executor = handler == null ? mContext.getMainExecutor()
3298                 : new HandlerExecutor(handler);
3299         synchronized (mLock) {
3300             mLOHSObserverProxy =
3301                     new LocalOnlyHotspotObserverProxy(this, executor, observer);
3302             try {
3303                 mService.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
3304                 mLOHSObserverProxy.registered();
3305             } catch (RemoteException e) {
3306                 mLOHSObserverProxy = null;
3307                 throw e.rethrowFromSystemServer();
3308             }
3309         }
3310     }
3311 
3312     /**
3313      * Allow callers to stop watching LocalOnlyHotspot state changes.  After calling this method,
3314      * applications will no longer receive callbacks.
3315      *
3316      * @hide
3317      */
unregisterLocalOnlyHotspotObserver()3318     public void unregisterLocalOnlyHotspotObserver() {
3319         synchronized (mLock) {
3320             if (mLOHSObserverProxy == null) {
3321                 // nothing to do, the callback was already cleaned up
3322                 return;
3323             }
3324             mLOHSObserverProxy = null;
3325             try {
3326                 mService.stopWatchLocalOnlyHotspot();
3327             } catch (RemoteException e) {
3328                 throw e.rethrowFromSystemServer();
3329             }
3330         }
3331     }
3332 
3333     /**
3334      * Gets the tethered Wi-Fi hotspot enabled state.
3335      * @return One of {@link #WIFI_AP_STATE_DISABLED},
3336      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
3337      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
3338      * @see #isWifiApEnabled()
3339      *
3340      * @hide
3341      */
3342     @SystemApi
3343     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getWifiApState()3344     public int getWifiApState() {
3345         try {
3346             return mService.getWifiApEnabledState();
3347         } catch (RemoteException e) {
3348             throw e.rethrowFromSystemServer();
3349         }
3350     }
3351 
3352     /**
3353      * Return whether tethered Wi-Fi AP is enabled or disabled.
3354      * @return {@code true} if tethered  Wi-Fi AP is enabled
3355      * @see #getWifiApState()
3356      *
3357      * @hide
3358      */
3359     @SystemApi
3360     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiApEnabled()3361     public boolean isWifiApEnabled() {
3362         return getWifiApState() == WIFI_AP_STATE_ENABLED;
3363     }
3364 
3365     /**
3366      * Gets the tethered Wi-Fi AP Configuration.
3367      * @return AP details in WifiConfiguration
3368      *
3369      * Note that AP detail may contain configuration which is cannot be represented
3370      * by the legacy WifiConfiguration, in such cases a null will be returned.
3371      *
3372      * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
3373      * @hide
3374      */
3375     @Nullable
3376     @SystemApi
3377     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
3378     @Deprecated
getWifiApConfiguration()3379     public WifiConfiguration getWifiApConfiguration() {
3380         try {
3381             return mService.getWifiApConfiguration();
3382         } catch (RemoteException e) {
3383             throw e.rethrowFromSystemServer();
3384         }
3385     }
3386 
3387     /**
3388      * Gets the Wi-Fi tethered AP Configuration.
3389      * @return AP details in {@link SoftApConfiguration}
3390      *
3391      * @hide
3392      */
3393     @NonNull
3394     @SystemApi
3395     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getSoftApConfiguration()3396     public SoftApConfiguration getSoftApConfiguration() {
3397         try {
3398             return mService.getSoftApConfiguration();
3399         } catch (RemoteException e) {
3400             throw e.rethrowFromSystemServer();
3401         }
3402     }
3403 
3404     /**
3405      * Sets the tethered Wi-Fi AP Configuration.
3406      * @return {@code true} if the operation succeeded, {@code false} otherwise
3407      *
3408      * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
3409      * instead.
3410      * @hide
3411      */
3412     @SystemApi
3413     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
3414     @Deprecated
setWifiApConfiguration(WifiConfiguration wifiConfig)3415     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
3416         try {
3417             return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
3418         } catch (RemoteException e) {
3419             throw e.rethrowFromSystemServer();
3420         }
3421     }
3422 
3423     /**
3424      * Sets the tethered Wi-Fi AP Configuration.
3425      *
3426      * If the API is called while the tethered soft AP is enabled, the configuration will apply to
3427      * the current soft AP if the new configuration only includes
3428      * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
3429      * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
3430      * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
3431      * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
3432      * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
3433      *
3434      * Otherwise, the configuration changes will be applied when the Soft AP is next started
3435      * (the framework will not stop/start the AP).
3436      *
3437      * @param softApConfig  A valid SoftApConfiguration specifying the configuration of the SAP.
3438      * @return {@code true} if the operation succeeded, {@code false} otherwise
3439      *
3440      * @hide
3441      */
3442     @SystemApi
3443     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setSoftApConfiguration(@onNull SoftApConfiguration softApConfig)3444     public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
3445         try {
3446             return mService.setSoftApConfiguration(
3447                     softApConfig, mContext.getOpPackageName());
3448         } catch (RemoteException e) {
3449             throw e.rethrowFromSystemServer();
3450         }
3451     }
3452 
3453     /**
3454      * Enable/Disable TDLS on a specific local route.
3455      *
3456      * <p>
3457      * TDLS enables two wireless endpoints to talk to each other directly
3458      * without going through the access point that is managing the local
3459      * network. It saves bandwidth and improves quality of the link.
3460      * </p>
3461      * <p>
3462      * This API enables/disables the option of using TDLS. If enabled, the
3463      * underlying hardware is free to use TDLS or a hop through the access
3464      * point. If disabled, existing TDLS session is torn down and
3465      * hardware is restricted to use access point for transferring wireless
3466      * packets. Default value for all routes is 'disabled', meaning restricted
3467      * to use access point for transferring packets.
3468      * </p>
3469      *
3470      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
3471      * @param enable true = setup and false = tear down TDLS
3472      */
setTdlsEnabled(InetAddress remoteIPAddress, boolean enable)3473     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
3474         try {
3475             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
3476         } catch (RemoteException e) {
3477             throw e.rethrowFromSystemServer();
3478         }
3479     }
3480 
3481     /**
3482      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
3483      * this version allows you to specify remote endpoint with a MAC address.
3484      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
3485      * @param enable true = setup and false = tear down TDLS
3486      */
setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable)3487     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
3488         try {
3489             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
3490         } catch (RemoteException e) {
3491             throw e.rethrowFromSystemServer();
3492         }
3493     }
3494 
3495     /**
3496      * Passed with {@link ActionListener#onFailure}.
3497      * Indicates that the operation failed due to an internal error.
3498      * @hide
3499      */
3500     public static final int ERROR                       = 0;
3501 
3502     /**
3503      * Passed with {@link ActionListener#onFailure}.
3504      * Indicates that the operation is already in progress
3505      * @hide
3506      */
3507     public static final int IN_PROGRESS                 = 1;
3508 
3509     /**
3510      * Passed with {@link ActionListener#onFailure}.
3511      * Indicates that the operation failed because the framework is busy and
3512      * unable to service the request
3513      * @hide
3514      */
3515     public static final int BUSY                        = 2;
3516 
3517     /** @hide */
3518     @Retention(RetentionPolicy.SOURCE)
3519     @IntDef({ERROR, IN_PROGRESS, BUSY})
3520     public @interface ActionListenerFailureReason {}
3521 
3522     /* WPS specific errors */
3523     /** WPS overlap detected
3524      * @deprecated This is deprecated
3525      */
3526     public static final int WPS_OVERLAP_ERROR           = 3;
3527     /** WEP on WPS is prohibited
3528      * @deprecated This is deprecated
3529      */
3530     public static final int WPS_WEP_PROHIBITED          = 4;
3531     /** TKIP only prohibited
3532      * @deprecated This is deprecated
3533      */
3534     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
3535     /** Authentication failure on WPS
3536      * @deprecated This is deprecated
3537      */
3538     public static final int WPS_AUTH_FAILURE            = 6;
3539     /** WPS timed out
3540      * @deprecated This is deprecated
3541      */
3542     public static final int WPS_TIMED_OUT               = 7;
3543 
3544     /**
3545      * Passed with {@link ActionListener#onFailure}.
3546      * Indicates that the operation failed due to invalid inputs
3547      * @hide
3548      */
3549     public static final int INVALID_ARGS                = 8;
3550 
3551     /**
3552      * Passed with {@link ActionListener#onFailure}.
3553      * Indicates that the operation failed due to user permissions.
3554      * @hide
3555      */
3556     public static final int NOT_AUTHORIZED              = 9;
3557 
3558     /**
3559      * Interface for callback invocation on an application action
3560      * @hide
3561      */
3562     @SystemApi
3563     public interface ActionListener {
3564         /**
3565          * The operation succeeded.
3566          */
onSuccess()3567         void onSuccess();
3568         /**
3569          * The operation failed.
3570          * @param reason The reason for failure depends on the operation.
3571          */
onFailure(@ctionListenerFailureReason int reason)3572         void onFailure(@ActionListenerFailureReason int reason);
3573     }
3574 
3575     /** Interface for callback invocation on a start WPS action
3576      * @deprecated This is deprecated
3577      */
3578     public static abstract class WpsCallback {
3579 
3580         /** WPS start succeeded
3581          * @deprecated This API is deprecated
3582          */
onStarted(String pin)3583         public abstract void onStarted(String pin);
3584 
3585         /** WPS operation completed successfully
3586          * @deprecated This API is deprecated
3587          */
onSucceeded()3588         public abstract void onSucceeded();
3589 
3590         /**
3591          * WPS operation failed
3592          * @param reason The reason for failure could be one of
3593          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
3594          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
3595          * and some generic errors.
3596          * @deprecated This API is deprecated
3597          */
onFailed(int reason)3598         public abstract void onFailed(int reason);
3599     }
3600 
3601     /**
3602      * Base class for soft AP callback. Should be extended by applications and set when calling
3603      * {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
3604      *
3605      * @hide
3606      */
3607     @SystemApi
3608     public interface SoftApCallback {
3609         /**
3610          * Called when soft AP state changes.
3611          *
3612          * @param state         the new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
3613          *                      {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
3614          *                      {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
3615          * @param failureReason reason when in failed state. One of
3616          *                      {@link #SAP_START_FAILURE_GENERAL},
3617          *                      {@link #SAP_START_FAILURE_NO_CHANNEL},
3618          *                      {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
3619          */
onStateChanged(@ifiApState int state, @SapStartFailure int failureReason)3620         default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
3621 
3622         /**
3623          * Called when the connected clients to soft AP changes.
3624          *
3625          * @param clients the currently connected clients
3626          */
onConnectedClientsChanged(@onNull List<WifiClient> clients)3627         default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
3628 
3629         /**
3630          * Called when information of softap changes.
3631          *
3632          * @param softApInfo is the softap information. {@link SoftApInfo}
3633          */
onInfoChanged(@onNull SoftApInfo softApInfo)3634         default void onInfoChanged(@NonNull SoftApInfo softApInfo) {
3635             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
3636         }
3637 
3638         /**
3639          * Called when capability of softap changes.
3640          *
3641          * @param softApCapability is the softap capability. {@link SoftApCapability}
3642          */
onCapabilityChanged(@onNull SoftApCapability softApCapability)3643         default void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
3644             // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported
3645             // client number) to the UI.
3646         }
3647 
3648         /**
3649          * Called when client trying to connect but device blocked the client with specific reason.
3650          *
3651          * Can be used to ask user to update client to allowed list or blocked list
3652          * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or
3653          * indicate the block due to maximum supported client number limitation when reason is
3654          * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}.
3655          *
3656          * @param client the currently blocked client.
3657          * @param blockedReason one of blocked reason from {@link SapClientBlockedReason}
3658          */
onBlockedClientConnecting(@onNull WifiClient client, @SapClientBlockedReason int blockedReason)3659         default void onBlockedClientConnecting(@NonNull WifiClient client,
3660                 @SapClientBlockedReason int blockedReason) {
3661             // Do nothing: can be used to ask user to update client to allowed list or blocked list.
3662         }
3663     }
3664 
3665     /**
3666      * Callback proxy for SoftApCallback objects.
3667      *
3668      * @hide
3669      */
3670     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
3671         private final Executor mExecutor;
3672         private final SoftApCallback mCallback;
3673 
SoftApCallbackProxy(Executor executor, SoftApCallback callback)3674         SoftApCallbackProxy(Executor executor, SoftApCallback callback) {
3675             mExecutor = executor;
3676             mCallback = callback;
3677         }
3678 
3679         @Override
onStateChanged(int state, int failureReason)3680         public void onStateChanged(int state, int failureReason) {
3681             if (mVerboseLoggingEnabled) {
3682                 Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state
3683                         + ", failureReason=" + failureReason);
3684             }
3685 
3686             Binder.clearCallingIdentity();
3687             mExecutor.execute(() -> {
3688                 mCallback.onStateChanged(state, failureReason);
3689             });
3690         }
3691 
3692         @Override
onConnectedClientsChanged(List<WifiClient> clients)3693         public void onConnectedClientsChanged(List<WifiClient> clients) {
3694             if (mVerboseLoggingEnabled) {
3695                 Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsChanged: clients="
3696                         + clients.size() + " clients");
3697             }
3698 
3699             Binder.clearCallingIdentity();
3700             mExecutor.execute(() -> {
3701                 mCallback.onConnectedClientsChanged(clients);
3702             });
3703         }
3704 
3705         @Override
onInfoChanged(SoftApInfo softApInfo)3706         public void onInfoChanged(SoftApInfo softApInfo) {
3707             if (mVerboseLoggingEnabled) {
3708                 Log.v(TAG, "SoftApCallbackProxy: onInfoChange: softApInfo=" + softApInfo);
3709             }
3710 
3711             Binder.clearCallingIdentity();
3712             mExecutor.execute(() -> {
3713                 mCallback.onInfoChanged(softApInfo);
3714             });
3715         }
3716 
3717         @Override
onCapabilityChanged(SoftApCapability capability)3718         public void onCapabilityChanged(SoftApCapability capability) {
3719             if (mVerboseLoggingEnabled) {
3720                 Log.v(TAG, "SoftApCallbackProxy: onCapabilityChanged: SoftApCapability="
3721                         + capability);
3722             }
3723 
3724             Binder.clearCallingIdentity();
3725             mExecutor.execute(() -> {
3726                 mCallback.onCapabilityChanged(capability);
3727             });
3728         }
3729 
3730         @Override
onBlockedClientConnecting(@onNull WifiClient client, int blockedReason)3731         public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) {
3732             if (mVerboseLoggingEnabled) {
3733                 Log.v(TAG, "SoftApCallbackProxy: onBlockedClientConnecting: client=" + client
3734                         + " with reason = " + blockedReason);
3735             }
3736 
3737             Binder.clearCallingIdentity();
3738             mExecutor.execute(() -> {
3739                 mCallback.onBlockedClientConnecting(client, blockedReason);
3740             });
3741         }
3742     }
3743 
3744     /**
3745      * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the
3746      * following callbacks on registration:
3747      * <ul>
3748      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
3749      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
3750      * <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
3751      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
3752      * </ul>
3753      * These will be dispatched on registration to provide the caller with the current state
3754      * (and are not an indication of any current change). Note that receiving an immediate
3755      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
3756      * soft AP has failed. Caller can unregister a previously registered callback using
3757      * {@link #unregisterSoftApCallback}
3758      * <p>
3759      * Applications should have the
3760      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
3761      * without the permission will trigger a {@link java.lang.SecurityException}.
3762      * <p>
3763      *
3764      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
3765      *                 object.
3766      * @param callback Callback for soft AP events
3767      * @hide
3768      */
3769     @SystemApi
3770     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)3771     public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
3772             @NonNull SoftApCallback callback) {
3773         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
3774         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3775         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
3776 
3777         Binder binder = new Binder();
3778         try {
3779             mService.registerSoftApCallback(
3780                     binder, new SoftApCallbackProxy(executor, callback), callback.hashCode());
3781         } catch (RemoteException e) {
3782             throw e.rethrowFromSystemServer();
3783         }
3784     }
3785 
3786     /**
3787      * Allow callers to unregister a previously registered callback. After calling this method,
3788      * applications will no longer receive soft AP events.
3789      *
3790      * @param callback Callback to unregister for soft AP events
3791      *
3792      * @hide
3793      */
3794     @SystemApi
3795     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterSoftApCallback(@onNull SoftApCallback callback)3796     public void unregisterSoftApCallback(@NonNull SoftApCallback callback) {
3797         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3798         Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
3799 
3800         try {
3801             mService.unregisterSoftApCallback(callback.hashCode());
3802         } catch (RemoteException e) {
3803             throw e.rethrowFromSystemServer();
3804         }
3805     }
3806 
3807     /**
3808      * LocalOnlyHotspotReservation that contains the {@link SoftApConfiguration} for the active
3809      * LocalOnlyHotspot request.
3810      * <p>
3811      * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
3812      * LocalOnlyHotspotReservation in the
3813      * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call.  This
3814      * reservation contains the relevant {@link SoftApConfiguration}.
3815      * When an application is done with the LocalOnlyHotspot, they should call {@link
3816      * LocalOnlyHotspotReservation#close()}.  Once this happens, the application will not receive
3817      * any further callbacks. If the LocalOnlyHotspot is stopped due to a
3818      * user triggered mode change, applications will be notified via the {@link
3819      * LocalOnlyHotspotCallback#onStopped()} callback.
3820      */
3821     public class LocalOnlyHotspotReservation implements AutoCloseable {
3822 
3823         private final CloseGuard mCloseGuard = new CloseGuard();
3824         private final SoftApConfiguration mSoftApConfig;
3825         private final WifiConfiguration mWifiConfig;
3826         private boolean mClosed = false;
3827 
3828         /** @hide */
3829         @VisibleForTesting
LocalOnlyHotspotReservation(SoftApConfiguration config)3830         public LocalOnlyHotspotReservation(SoftApConfiguration config) {
3831             mSoftApConfig = config;
3832             mWifiConfig = config.toWifiConfiguration();
3833             mCloseGuard.open("close");
3834         }
3835 
3836         /**
3837          * Returns the {@link WifiConfiguration} of the current Local Only Hotspot (LOHS).
3838          * May be null if hotspot enabled and security type is not
3839          * {@code WifiConfiguration.KeyMgmt.None} or {@code WifiConfiguration.KeyMgmt.WPA2_PSK}.
3840          *
3841          * @deprecated Use {@code WifiManager#getSoftApConfiguration()} to get the
3842          * LOHS configuration.
3843          */
3844         @Deprecated
3845         @Nullable
getWifiConfiguration()3846         public WifiConfiguration getWifiConfiguration() {
3847             return mWifiConfig;
3848         }
3849 
3850         /**
3851          * Returns the {@link SoftApConfiguration} of the current Local Only Hotspot (LOHS).
3852          */
3853         @NonNull
getSoftApConfiguration()3854         public SoftApConfiguration getSoftApConfiguration() {
3855             return mSoftApConfig;
3856         }
3857 
3858         @Override
close()3859         public void close() {
3860             try {
3861                 synchronized (mLock) {
3862                     if (!mClosed) {
3863                         mClosed = true;
3864                         stopLocalOnlyHotspot();
3865                         mCloseGuard.close();
3866                     }
3867                 }
3868             } catch (Exception e) {
3869                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
3870             } finally {
3871                 Reference.reachabilityFence(this);
3872             }
3873         }
3874 
3875         @Override
finalize()3876         protected void finalize() throws Throwable {
3877             try {
3878                 if (mCloseGuard != null) {
3879                     mCloseGuard.warnIfOpen();
3880                 }
3881                 close();
3882             } finally {
3883                 super.finalize();
3884             }
3885         }
3886     }
3887 
3888     /**
3889      * Callback class for applications to receive updates about the LocalOnlyHotspot status.
3890      */
3891     public static class LocalOnlyHotspotCallback {
3892         /** @hide */
3893         public static final int REQUEST_REGISTERED = 0;
3894 
3895         public static final int ERROR_NO_CHANNEL = 1;
3896         public static final int ERROR_GENERIC = 2;
3897         public static final int ERROR_INCOMPATIBLE_MODE = 3;
3898         public static final int ERROR_TETHERING_DISALLOWED = 4;
3899 
3900         /** LocalOnlyHotspot start succeeded. */
onStarted(LocalOnlyHotspotReservation reservation)3901         public void onStarted(LocalOnlyHotspotReservation reservation) {};
3902 
3903         /**
3904          * LocalOnlyHotspot stopped.
3905          * <p>
3906          * The LocalOnlyHotspot can be disabled at any time by the user.  When this happens,
3907          * applications will be notified that it was stopped. This will not be invoked when an
3908          * application calls {@link LocalOnlyHotspotReservation#close()}.
3909          */
onStopped()3910         public void onStopped() {};
3911 
3912         /**
3913          * LocalOnlyHotspot failed to start.
3914          * <p>
3915          * Applications can attempt to call
3916          * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at
3917          * a later time.
3918          * <p>
3919          * @param reason The reason for failure could be one of: {@link
3920          * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE},
3921          * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}.
3922          */
onFailed(int reason)3923         public void onFailed(int reason) { };
3924     }
3925 
3926     /**
3927      * Callback proxy for LocalOnlyHotspotCallback objects.
3928      */
3929     private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub {
3930         private final WeakReference<WifiManager> mWifiManager;
3931         private final Executor mExecutor;
3932         private final LocalOnlyHotspotCallback mCallback;
3933 
3934         /**
3935          * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor.  All
3936          * callbacks will run using the given executor.
3937          *
3938          * @param manager WifiManager
3939          * @param executor Executor for delivering callbacks.
3940          * @param callback LocalOnlyHotspotCallback to notify the calling application, or null.
3941          */
LocalOnlyHotspotCallbackProxy( @onNull WifiManager manager, @NonNull Executor executor, @Nullable LocalOnlyHotspotCallback callback)3942         LocalOnlyHotspotCallbackProxy(
3943                 @NonNull WifiManager manager,
3944                 @NonNull Executor executor,
3945                 @Nullable LocalOnlyHotspotCallback callback) {
3946             mWifiManager = new WeakReference<>(manager);
3947             mExecutor = executor;
3948             mCallback = callback;
3949         }
3950 
3951         @Override
onHotspotStarted(SoftApConfiguration config)3952         public void onHotspotStarted(SoftApConfiguration config) {
3953             WifiManager manager = mWifiManager.get();
3954             if (manager == null) return;
3955 
3956             if (config == null) {
3957                 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
3958                 onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
3959                 return;
3960             }
3961             final LocalOnlyHotspotReservation reservation =
3962                     manager.new LocalOnlyHotspotReservation(config);
3963             if (mCallback == null) return;
3964             mExecutor.execute(() -> mCallback.onStarted(reservation));
3965         }
3966 
3967         @Override
onHotspotStopped()3968         public void onHotspotStopped() {
3969             WifiManager manager = mWifiManager.get();
3970             if (manager == null) return;
3971 
3972             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
3973             if (mCallback == null) return;
3974             mExecutor.execute(() -> mCallback.onStopped());
3975         }
3976 
3977         @Override
onHotspotFailed(int reason)3978         public void onHotspotFailed(int reason) {
3979             WifiManager manager = mWifiManager.get();
3980             if (manager == null) return;
3981 
3982             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
3983                     + reason);
3984             if (mCallback == null) return;
3985             mExecutor.execute(() -> mCallback.onFailed(reason));
3986         }
3987     }
3988 
3989     /**
3990      * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications
3991      * watching for LocalOnlyHotspot changes.
3992      *
3993      * @hide
3994      */
3995     public class LocalOnlyHotspotSubscription implements AutoCloseable {
3996         private final CloseGuard mCloseGuard = new CloseGuard();
3997 
3998         /** @hide */
3999         @VisibleForTesting
LocalOnlyHotspotSubscription()4000         public LocalOnlyHotspotSubscription() {
4001             mCloseGuard.open("close");
4002         }
4003 
4004         @Override
close()4005         public void close() {
4006             try {
4007                 unregisterLocalOnlyHotspotObserver();
4008                 mCloseGuard.close();
4009             } catch (Exception e) {
4010                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
4011             } finally {
4012                 Reference.reachabilityFence(this);
4013             }
4014         }
4015 
4016         @Override
finalize()4017         protected void finalize() throws Throwable {
4018             try {
4019                 if (mCloseGuard != null) {
4020                     mCloseGuard.warnIfOpen();
4021                 }
4022                 close();
4023             } finally {
4024                 super.finalize();
4025             }
4026         }
4027     }
4028 
4029     /**
4030      * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates.
4031      *
4032      * @hide
4033      */
4034     public static class LocalOnlyHotspotObserver {
4035         /**
4036          * Confirm registration for LocalOnlyHotspotChanges by returning a
4037          * LocalOnlyHotspotSubscription.
4038          */
onRegistered(LocalOnlyHotspotSubscription subscription)4039         public void onRegistered(LocalOnlyHotspotSubscription subscription) {};
4040 
4041         /**
4042          * LocalOnlyHotspot started with the supplied config.
4043          */
onStarted(SoftApConfiguration config)4044         public void onStarted(SoftApConfiguration config) {};
4045 
4046         /**
4047          * LocalOnlyHotspot stopped.
4048          */
onStopped()4049         public void onStopped() {};
4050     }
4051 
4052     /**
4053      * Callback proxy for LocalOnlyHotspotObserver objects.
4054      */
4055     private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub {
4056         private final WeakReference<WifiManager> mWifiManager;
4057         private final Executor mExecutor;
4058         private final LocalOnlyHotspotObserver mObserver;
4059 
4060         /**
4061          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
4062          * All callbacks will be delivered on the thread of the specified looper.
4063          *
4064          * @param manager WifiManager
4065          * @param executor Executor for delivering callbacks
4066          * @param observer LocalOnlyHotspotObserver to notify the calling application.
4067          */
LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor, final LocalOnlyHotspotObserver observer)4068         LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor,
4069                 final LocalOnlyHotspotObserver observer) {
4070             mWifiManager = new WeakReference<>(manager);
4071             mExecutor = executor;
4072             mObserver = observer;
4073         }
4074 
registered()4075         public void registered() throws RemoteException {
4076             WifiManager manager = mWifiManager.get();
4077             if (manager == null) return;
4078 
4079             mExecutor.execute(() ->
4080                     mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription()));
4081         }
4082 
4083         @Override
onHotspotStarted(SoftApConfiguration config)4084         public void onHotspotStarted(SoftApConfiguration config) {
4085             WifiManager manager = mWifiManager.get();
4086             if (manager == null) return;
4087 
4088             if (config == null) {
4089                 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
4090                 return;
4091             }
4092             mExecutor.execute(() -> mObserver.onStarted(config));
4093         }
4094 
4095         @Override
onHotspotStopped()4096         public void onHotspotStopped() {
4097             WifiManager manager = mWifiManager.get();
4098             if (manager == null) return;
4099 
4100             mExecutor.execute(() -> mObserver.onStopped());
4101         }
4102 
4103         @Override
onHotspotFailed(int reason)4104         public void onHotspotFailed(int reason) {
4105             // do nothing
4106         }
4107     }
4108 
4109     /**
4110      * Callback proxy for ActionListener objects.
4111      */
4112     private class ActionListenerProxy extends IActionListener.Stub {
4113         private final String mActionTag;
4114         private final Handler mHandler;
4115         private final ActionListener mCallback;
4116 
ActionListenerProxy(String actionTag, Looper looper, ActionListener callback)4117         ActionListenerProxy(String actionTag, Looper looper, ActionListener callback) {
4118             mActionTag = actionTag;
4119             mHandler = new Handler(looper);
4120             mCallback = callback;
4121         }
4122 
4123         @Override
onSuccess()4124         public void onSuccess() {
4125             if (mVerboseLoggingEnabled) {
4126                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onSuccess");
4127             }
4128             mHandler.post(() -> {
4129                 mCallback.onSuccess();
4130             });
4131         }
4132 
4133         @Override
onFailure(@ctionListenerFailureReason int reason)4134         public void onFailure(@ActionListenerFailureReason int reason) {
4135             if (mVerboseLoggingEnabled) {
4136                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onFailure=" + reason);
4137             }
4138             mHandler.post(() -> {
4139                 mCallback.onFailure(reason);
4140             });
4141         }
4142     }
4143 
connectInternal(@ullable WifiConfiguration config, int networkId, @Nullable ActionListener listener)4144     private void connectInternal(@Nullable WifiConfiguration config, int networkId,
4145             @Nullable ActionListener listener) {
4146         ActionListenerProxy listenerProxy = null;
4147         Binder binder = null;
4148         if (listener != null) {
4149             listenerProxy = new ActionListenerProxy("connect", mLooper, listener);
4150             binder = new Binder();
4151         }
4152         try {
4153             mService.connect(config, networkId, binder, listenerProxy,
4154                     listener == null ? 0 : listener.hashCode());
4155         } catch (RemoteException e) {
4156             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
4157         } catch (SecurityException e) {
4158             if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
4159         }
4160     }
4161 
4162     /**
4163      * Connect to a network with the given configuration. The network also
4164      * gets added to the list of configured networks for the foreground user.
4165      *
4166      * For a new network, this function is used instead of a
4167      * sequence of addNetwork(), enableNetwork(), and reconnect()
4168      *
4169      * @param config the set of variables that describe the configuration,
4170      *            contained in a {@link WifiConfiguration} object.
4171      * @param listener for callbacks on success or failure. Can be null.
4172      * @throws IllegalStateException if the WifiManager instance needs to be
4173      * initialized again
4174      *
4175      * @hide
4176      */
4177     @SystemApi
4178     @RequiresPermission(anyOf = {
4179             android.Manifest.permission.NETWORK_SETTINGS,
4180             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4181             android.Manifest.permission.NETWORK_STACK
4182     })
connect(@onNull WifiConfiguration config, @Nullable ActionListener listener)4183     public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
4184         if (config == null) throw new IllegalArgumentException("config cannot be null");
4185         connectInternal(config, WifiConfiguration.INVALID_NETWORK_ID, listener);
4186     }
4187 
4188     /**
4189      * Connect to a network with the given networkId.
4190      *
4191      * This function is used instead of a enableNetwork() and reconnect()
4192      *
4193      * <li> This API will cause reconnect if the credentials of the current active
4194      * connection has been changed.</li>
4195      * <li> This API will cause reconnect if the current active connection is marked metered.</li>
4196      *
4197      * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
4198      *        getConfiguredNetworks}.
4199      * @param listener for callbacks on success or failure. Can be null.
4200      * @throws IllegalStateException if the WifiManager instance needs to be
4201      * initialized again
4202      * @hide
4203      */
4204     @SystemApi
4205     @RequiresPermission(anyOf = {
4206             android.Manifest.permission.NETWORK_SETTINGS,
4207             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4208             android.Manifest.permission.NETWORK_STACK
4209     })
connect(int networkId, @Nullable ActionListener listener)4210     public void connect(int networkId, @Nullable ActionListener listener) {
4211         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
4212         connectInternal(null, networkId, listener);
4213     }
4214 
4215     /**
4216      * Save the given network to the list of configured networks for the
4217      * foreground user. If the network already exists, the configuration
4218      * is updated. Any new network is enabled by default.
4219      *
4220      * For a new network, this function is used instead of a
4221      * sequence of addNetwork() and enableNetwork().
4222      *
4223      * For an existing network, it accomplishes the task of updateNetwork()
4224      *
4225      * <li> This API will cause reconnect if the credentials of the current active
4226      * connection has been changed.</li>
4227      * <li> This API will cause disconnect if the current active connection is marked metered.</li>
4228      *
4229      * @param config the set of variables that describe the configuration,
4230      *            contained in a {@link WifiConfiguration} object.
4231      * @param listener for callbacks on success or failure. Can be null.
4232      * @throws IllegalStateException if the WifiManager instance needs to be
4233      * initialized again
4234      * @hide
4235      */
4236     @SystemApi
4237     @RequiresPermission(anyOf = {
4238             android.Manifest.permission.NETWORK_SETTINGS,
4239             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4240             android.Manifest.permission.NETWORK_STACK
4241     })
save(@onNull WifiConfiguration config, @Nullable ActionListener listener)4242     public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
4243         if (config == null) throw new IllegalArgumentException("config cannot be null");
4244         ActionListenerProxy listenerProxy = null;
4245         Binder binder = null;
4246         if (listener != null) {
4247             listenerProxy = new ActionListenerProxy("save", mLooper, listener);
4248             binder = new Binder();
4249         }
4250         try {
4251             mService.save(config, binder, listenerProxy,
4252                     listener == null ? 0 : listener.hashCode());
4253         } catch (RemoteException e) {
4254             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
4255         } catch (SecurityException e) {
4256             if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
4257         }
4258     }
4259 
4260     /**
4261      * Delete the network from the list of configured networks for the
4262      * foreground user.
4263      *
4264      * This function is used instead of a sequence of removeNetwork()
4265      *
4266      * @param config the set of variables that describe the configuration,
4267      *            contained in a {@link WifiConfiguration} object.
4268      * @param listener for callbacks on success or failure. Can be null.
4269      * @throws IllegalStateException if the WifiManager instance needs to be
4270      * initialized again
4271      * @hide
4272      */
4273     @SystemApi
4274     @RequiresPermission(anyOf = {
4275             android.Manifest.permission.NETWORK_SETTINGS,
4276             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4277             android.Manifest.permission.NETWORK_STACK
4278     })
forget(int netId, @Nullable ActionListener listener)4279     public void forget(int netId, @Nullable ActionListener listener) {
4280         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
4281         ActionListenerProxy listenerProxy = null;
4282         Binder binder = null;
4283         if (listener != null) {
4284             listenerProxy = new ActionListenerProxy("forget", mLooper, listener);
4285             binder = new Binder();
4286         }
4287         try {
4288             mService.forget(netId, binder, listenerProxy,
4289                     listener == null ? 0 : listener.hashCode());
4290         } catch (RemoteException e) {
4291             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
4292         } catch (SecurityException e) {
4293             if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
4294         }
4295     }
4296 
4297     /**
4298      * Disable network
4299      *
4300      * @param netId is the network Id
4301      * @param listener for callbacks on success or failure. Can be null.
4302      * @throws IllegalStateException if the WifiManager instance needs to be
4303      * initialized again
4304      * @deprecated This API is deprecated. Use {@link #disableNetwork(int)} instead.
4305      * @hide
4306      */
4307     @SystemApi
4308     @RequiresPermission(anyOf = {
4309             android.Manifest.permission.NETWORK_SETTINGS,
4310             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4311             android.Manifest.permission.NETWORK_STACK
4312     })
4313     @Deprecated
disable(int netId, @Nullable ActionListener listener)4314     public void disable(int netId, @Nullable ActionListener listener) {
4315         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
4316         // Simple wrapper which forwards the call to disableNetwork. This is a temporary
4317         // implementation until we can remove this API completely.
4318         boolean status = disableNetwork(netId);
4319         if (listener != null) {
4320             if (status) {
4321                 listener.onSuccess();
4322             } else {
4323                 listener.onFailure(ERROR);
4324             }
4325         }
4326     }
4327 
4328     /**
4329      * Enable/disable auto-join globally.
4330      *
4331      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
4332      * @hide
4333      */
4334     @SystemApi
4335     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoinGlobal(boolean allowAutojoin)4336     public void allowAutojoinGlobal(boolean allowAutojoin) {
4337         try {
4338             mService.allowAutojoinGlobal(allowAutojoin);
4339         } catch (RemoteException e) {
4340             throw e.rethrowFromSystemServer();
4341         }
4342     }
4343 
4344 
4345     /**
4346      * Sets the user choice for allowing auto-join to a network.
4347      * The updated choice will be made available through the updated config supplied by the
4348      * CONFIGURED_NETWORKS_CHANGED broadcast.
4349      *
4350      * @param netId the id of the network to allow/disallow auto-join for.
4351      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
4352      * @hide
4353      */
4354     @SystemApi
4355     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoin(int netId, boolean allowAutojoin)4356     public void allowAutojoin(int netId, boolean allowAutojoin) {
4357         try {
4358             mService.allowAutojoin(netId, allowAutojoin);
4359         } catch (RemoteException e) {
4360             throw e.rethrowFromSystemServer();
4361         }
4362     }
4363 
4364     /**
4365      * Configure auto-join settings for a Passpoint profile.
4366      *
4367      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
4368      * @param allowAutojoin true to enable auto-join, false to disable auto-join.
4369      * @hide
4370      */
4371     @SystemApi
4372     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoinPasspoint(@onNull String fqdn, boolean allowAutojoin)4373     public void allowAutojoinPasspoint(@NonNull String fqdn, boolean allowAutojoin) {
4374         try {
4375             mService.allowAutojoinPasspoint(fqdn, allowAutojoin);
4376         } catch (RemoteException e) {
4377             throw e.rethrowFromSystemServer();
4378         }
4379     }
4380 
4381     /**
4382      * Configure MAC randomization setting for a Passpoint profile.
4383      * MAC randomization is enabled by default.
4384      *
4385      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
4386      * @param enable true to enable MAC randomization, false to disable MAC randomization.
4387      * @hide
4388      */
4389     @SystemApi
4390     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setMacRandomizationSettingPasspointEnabled(@onNull String fqdn, boolean enable)4391     public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
4392         try {
4393             mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
4394         } catch (RemoteException e) {
4395             throw e.rethrowFromSystemServer();
4396         }
4397     }
4398 
4399     /**
4400      * Sets the user's choice of metered override for a Passpoint profile.
4401      *
4402      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
4403      * @param meteredOverride One of three values: {@link WifiConfiguration#METERED_OVERRIDE_NONE},
4404      *                        {@link WifiConfiguration#METERED_OVERRIDE_METERED},
4405      *                        {@link WifiConfiguration#METERED_OVERRIDE_NOT_METERED}
4406      * @hide
4407      */
4408     @SystemApi
4409     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setPasspointMeteredOverride(@onNull String fqdn, @WifiConfiguration.MeteredOverride int meteredOverride)4410     public void setPasspointMeteredOverride(@NonNull String fqdn,
4411             @WifiConfiguration.MeteredOverride int meteredOverride) {
4412         try {
4413             mService.setPasspointMeteredOverride(fqdn, meteredOverride);
4414         } catch (RemoteException e) {
4415             throw e.rethrowFromSystemServer();
4416         }
4417     }
4418 
4419     /**
4420      * Temporarily disable a network. Should always trigger with user disconnect network.
4421      *
4422      * @param network Input can be SSID or FQDN. And caller must ensure that the SSID passed thru
4423      *                this API matched the WifiConfiguration.SSID rules, and thus be surrounded by
4424      *                quotes.
4425      * @hide
4426      */
4427     @SystemApi
4428     @RequiresPermission(anyOf = {
4429             android.Manifest.permission.NETWORK_SETTINGS,
4430             android.Manifest.permission.NETWORK_STACK
4431     })
disableEphemeralNetwork(@onNull String network)4432     public void disableEphemeralNetwork(@NonNull String network) {
4433         if (TextUtils.isEmpty(network)) {
4434             throw new IllegalArgumentException("SSID cannot be null or empty!");
4435         }
4436         try {
4437             mService.disableEphemeralNetwork(network, mContext.getOpPackageName());
4438         } catch (RemoteException e) {
4439             throw e.rethrowFromSystemServer();
4440         }
4441     }
4442 
4443     /**
4444      * WPS suport has been deprecated from Client mode and this method will immediately trigger
4445      * {@link WpsCallback#onFailed(int)} with a generic error.
4446      *
4447      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
4448      * @param listener for callbacks on success or failure. Can be null.
4449      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
4450      * @deprecated This API is deprecated
4451      */
startWps(WpsInfo config, WpsCallback listener)4452     public void startWps(WpsInfo config, WpsCallback listener) {
4453         if (listener != null ) {
4454             listener.onFailed(ERROR);
4455         }
4456     }
4457 
4458     /**
4459      * WPS support has been deprecated from Client mode and this method will immediately trigger
4460      * {@link WpsCallback#onFailed(int)} with a generic error.
4461      *
4462      * @param listener for callbacks on success or failure. Can be null.
4463      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
4464      * @deprecated This API is deprecated
4465      */
cancelWps(WpsCallback listener)4466     public void cancelWps(WpsCallback listener) {
4467         if (listener != null) {
4468             listener.onFailed(ERROR);
4469         }
4470     }
4471 
4472     /**
4473      * Allows an application to keep the Wi-Fi radio awake.
4474      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
4475      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
4476      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
4477      * WifiLocks are held in any application.
4478      * <p>
4479      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
4480      * could function over a mobile network, if available.  A program that needs to download large
4481      * files should hold a WifiLock to ensure that the download will complete, but a program whose
4482      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
4483      * affecting battery life.
4484      * <p>
4485      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
4486      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
4487      * is idle.
4488      * <p>
4489      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
4490      * permission in an {@code <uses-permission>} element of the application's manifest.
4491      */
4492     public class WifiLock {
4493         private String mTag;
4494         private final IBinder mBinder;
4495         private int mRefCount;
4496         int mLockType;
4497         private boolean mRefCounted;
4498         private boolean mHeld;
4499         private WorkSource mWorkSource;
4500 
WifiLock(int lockType, String tag)4501         private WifiLock(int lockType, String tag) {
4502             mTag = tag;
4503             mLockType = lockType;
4504             mBinder = new Binder();
4505             mRefCount = 0;
4506             mRefCounted = true;
4507             mHeld = false;
4508         }
4509 
4510         /**
4511          * Locks the Wi-Fi radio on until {@link #release} is called.
4512          *
4513          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
4514          * reference count, and the radio will remain locked as long as the reference count is
4515          * above zero.
4516          *
4517          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
4518          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
4519          * will be required, regardless of the number of times that {@code acquire} is called.
4520          */
acquire()4521         public void acquire() {
4522             synchronized (mBinder) {
4523                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
4524                     try {
4525                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
4526                         synchronized (WifiManager.this) {
4527                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
4528                                 mService.releaseWifiLock(mBinder);
4529                                 throw new UnsupportedOperationException(
4530                                             "Exceeded maximum number of wifi locks");
4531                             }
4532                             mActiveLockCount++;
4533                         }
4534                     } catch (RemoteException e) {
4535                         throw e.rethrowFromSystemServer();
4536                     }
4537                     mHeld = true;
4538                 }
4539             }
4540         }
4541 
4542         /**
4543          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
4544          *
4545          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
4546          * reference count, and the radio will be unlocked only when the reference count reaches
4547          * zero.  If the reference count goes below zero (that is, if {@code release} is called
4548          * a greater number of times than {@link #acquire}), an exception is thrown.
4549          *
4550          * If this WifiLock is not reference-counted, the first call to {@code release} (after
4551          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
4552          * calls will be ignored.
4553          */
release()4554         public void release() {
4555             synchronized (mBinder) {
4556                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
4557                     try {
4558                         mService.releaseWifiLock(mBinder);
4559                         synchronized (WifiManager.this) {
4560                             mActiveLockCount--;
4561                         }
4562                     } catch (RemoteException e) {
4563                         throw e.rethrowFromSystemServer();
4564                     }
4565                     mHeld = false;
4566                 }
4567                 if (mRefCount < 0) {
4568                     throw new RuntimeException("WifiLock under-locked " + mTag);
4569                 }
4570             }
4571         }
4572 
4573         /**
4574          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
4575          *
4576          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
4577          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
4578          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
4579          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
4580          * radio whenever {@link #release} is called and it is locked.
4581          *
4582          * @param refCounted true if this WifiLock should keep a reference count
4583          */
setReferenceCounted(boolean refCounted)4584         public void setReferenceCounted(boolean refCounted) {
4585             mRefCounted = refCounted;
4586         }
4587 
4588         /**
4589          * Checks whether this WifiLock is currently held.
4590          *
4591          * @return true if this WifiLock is held, false otherwise
4592          */
isHeld()4593         public boolean isHeld() {
4594             synchronized (mBinder) {
4595                 return mHeld;
4596             }
4597         }
4598 
setWorkSource(WorkSource ws)4599         public void setWorkSource(WorkSource ws) {
4600             synchronized (mBinder) {
4601                 if (ws != null && ws.isEmpty()) {
4602                     ws = null;
4603                 }
4604                 boolean changed = true;
4605                 if (ws == null) {
4606                     mWorkSource = null;
4607                 } else {
4608                     ws = ws.withoutNames();
4609                     if (mWorkSource == null) {
4610                         changed = mWorkSource != null;
4611                         mWorkSource = new WorkSource(ws);
4612                     } else {
4613                         changed = !mWorkSource.equals(ws);
4614                         if (changed) {
4615                             mWorkSource.set(ws);
4616                         }
4617                     }
4618                 }
4619                 if (changed && mHeld) {
4620                     try {
4621                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
4622                     } catch (RemoteException e) {
4623                         throw e.rethrowFromSystemServer();
4624                     }
4625                 }
4626             }
4627         }
4628 
toString()4629         public String toString() {
4630             String s1, s2, s3;
4631             synchronized (mBinder) {
4632                 s1 = Integer.toHexString(System.identityHashCode(this));
4633                 s2 = mHeld ? "held; " : "";
4634                 if (mRefCounted) {
4635                     s3 = "refcounted: refcount = " + mRefCount;
4636                 } else {
4637                     s3 = "not refcounted";
4638                 }
4639                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
4640             }
4641         }
4642 
4643         @Override
finalize()4644         protected void finalize() throws Throwable {
4645             super.finalize();
4646             synchronized (mBinder) {
4647                 if (mHeld) {
4648                     try {
4649                         mService.releaseWifiLock(mBinder);
4650                         synchronized (WifiManager.this) {
4651                             mActiveLockCount--;
4652                         }
4653                     } catch (RemoteException e) {
4654                         throw e.rethrowFromSystemServer();
4655                     }
4656                 }
4657             }
4658         }
4659     }
4660 
4661     /**
4662      * Creates a new WifiLock.
4663      *
4664      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL_HIGH_PERF}
4665      * and {@link #WIFI_MODE_FULL_LOW_LATENCY} for descriptions of the types of Wi-Fi locks.
4666      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
4667      *            never shown to the user under normal conditions, but should be descriptive
4668      *            enough to identify your application and the specific WifiLock within it, if it
4669      *            holds multiple WifiLocks.
4670      *
4671      * @return a new, unacquired WifiLock with the given tag.
4672      *
4673      * @see WifiLock
4674      */
createWifiLock(int lockType, String tag)4675     public WifiLock createWifiLock(int lockType, String tag) {
4676         return new WifiLock(lockType, tag);
4677     }
4678 
4679     /**
4680      * Creates a new WifiLock.
4681      *
4682      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
4683      *            never shown to the user under normal conditions, but should be descriptive
4684      *            enough to identify your application and the specific WifiLock within it, if it
4685      *            holds multiple WifiLocks.
4686      *
4687      * @return a new, unacquired WifiLock with the given tag.
4688      *
4689      * @see WifiLock
4690      *
4691      * @deprecated This API is non-functional.
4692      */
4693     @Deprecated
createWifiLock(String tag)4694     public WifiLock createWifiLock(String tag) {
4695         return new WifiLock(WIFI_MODE_FULL, tag);
4696     }
4697 
4698     /**
4699      * Create a new MulticastLock
4700      *
4701      * @param tag a tag for the MulticastLock to identify it in debugging
4702      *            messages.  This string is never shown to the user under
4703      *            normal conditions, but should be descriptive enough to
4704      *            identify your application and the specific MulticastLock
4705      *            within it, if it holds multiple MulticastLocks.
4706      *
4707      * @return a new, unacquired MulticastLock with the given tag.
4708      *
4709      * @see MulticastLock
4710      */
createMulticastLock(String tag)4711     public MulticastLock createMulticastLock(String tag) {
4712         return new MulticastLock(tag);
4713     }
4714 
4715     /**
4716      * Allows an application to receive Wifi Multicast packets.
4717      * Normally the Wifi stack filters out packets not explicitly
4718      * addressed to this device.  Acquring a MulticastLock will
4719      * cause the stack to receive packets addressed to multicast
4720      * addresses.  Processing these extra packets can cause a noticeable
4721      * battery drain and should be disabled when not needed.
4722      */
4723     public class MulticastLock {
4724         private String mTag;
4725         private final IBinder mBinder;
4726         private int mRefCount;
4727         private boolean mRefCounted;
4728         private boolean mHeld;
4729 
MulticastLock(String tag)4730         private MulticastLock(String tag) {
4731             mTag = tag;
4732             mBinder = new Binder();
4733             mRefCount = 0;
4734             mRefCounted = true;
4735             mHeld = false;
4736         }
4737 
4738         /**
4739          * Locks Wifi Multicast on until {@link #release} is called.
4740          *
4741          * If this MulticastLock is reference-counted each call to
4742          * {@code acquire} will increment the reference count, and the
4743          * wifi interface will receive multicast packets as long as the
4744          * reference count is above zero.
4745          *
4746          * If this MulticastLock is not reference-counted, the first call to
4747          * {@code acquire} will turn on the multicast packets, but subsequent
4748          * calls will be ignored.  Only one call to {@link #release} will
4749          * be required, regardless of the number of times that {@code acquire}
4750          * is called.
4751          *
4752          * Note that other applications may also lock Wifi Multicast on.
4753          * Only they can relinquish their lock.
4754          *
4755          * Also note that applications cannot leave Multicast locked on.
4756          * When an app exits or crashes, any Multicast locks will be released.
4757          */
acquire()4758         public void acquire() {
4759             synchronized (mBinder) {
4760                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
4761                     try {
4762                         mService.acquireMulticastLock(mBinder, mTag);
4763                         synchronized (WifiManager.this) {
4764                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
4765                                 mService.releaseMulticastLock(mTag);
4766                                 throw new UnsupportedOperationException(
4767                                         "Exceeded maximum number of wifi locks");
4768                             }
4769                             mActiveLockCount++;
4770                         }
4771                     } catch (RemoteException e) {
4772                         throw e.rethrowFromSystemServer();
4773                     }
4774                     mHeld = true;
4775                 }
4776             }
4777         }
4778 
4779         /**
4780          * Unlocks Wifi Multicast, restoring the filter of packets
4781          * not addressed specifically to this device and saving power.
4782          *
4783          * If this MulticastLock is reference-counted, each call to
4784          * {@code release} will decrement the reference count, and the
4785          * multicast packets will only stop being received when the reference
4786          * count reaches zero.  If the reference count goes below zero (that
4787          * is, if {@code release} is called a greater number of times than
4788          * {@link #acquire}), an exception is thrown.
4789          *
4790          * If this MulticastLock is not reference-counted, the first call to
4791          * {@code release} (after the radio was multicast locked using
4792          * {@link #acquire}) will unlock the multicast, and subsequent calls
4793          * will be ignored.
4794          *
4795          * Note that if any other Wifi Multicast Locks are still outstanding
4796          * this {@code release} call will not have an immediate effect.  Only
4797          * when all applications have released all their Multicast Locks will
4798          * the Multicast filter be turned back on.
4799          *
4800          * Also note that when an app exits or crashes all of its Multicast
4801          * Locks will be automatically released.
4802          */
release()4803         public void release() {
4804             synchronized (mBinder) {
4805                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
4806                     try {
4807                         mService.releaseMulticastLock(mTag);
4808                         synchronized (WifiManager.this) {
4809                             mActiveLockCount--;
4810                         }
4811                     } catch (RemoteException e) {
4812                         throw e.rethrowFromSystemServer();
4813                     }
4814                     mHeld = false;
4815                 }
4816                 if (mRefCount < 0) {
4817                     throw new RuntimeException("MulticastLock under-locked "
4818                             + mTag);
4819                 }
4820             }
4821         }
4822 
4823         /**
4824          * Controls whether this is a reference-counted or non-reference-
4825          * counted MulticastLock.
4826          *
4827          * Reference-counted MulticastLocks keep track of the number of calls
4828          * to {@link #acquire} and {@link #release}, and only stop the
4829          * reception of multicast packets when every call to {@link #acquire}
4830          * has been balanced with a call to {@link #release}.  Non-reference-
4831          * counted MulticastLocks allow the reception of multicast packets
4832          * whenever {@link #acquire} is called and stop accepting multicast
4833          * packets whenever {@link #release} is called.
4834          *
4835          * @param refCounted true if this MulticastLock should keep a reference
4836          * count
4837          */
setReferenceCounted(boolean refCounted)4838         public void setReferenceCounted(boolean refCounted) {
4839             mRefCounted = refCounted;
4840         }
4841 
4842         /**
4843          * Checks whether this MulticastLock is currently held.
4844          *
4845          * @return true if this MulticastLock is held, false otherwise
4846          */
isHeld()4847         public boolean isHeld() {
4848             synchronized (mBinder) {
4849                 return mHeld;
4850             }
4851         }
4852 
toString()4853         public String toString() {
4854             String s1, s2, s3;
4855             synchronized (mBinder) {
4856                 s1 = Integer.toHexString(System.identityHashCode(this));
4857                 s2 = mHeld ? "held; " : "";
4858                 if (mRefCounted) {
4859                     s3 = "refcounted: refcount = " + mRefCount;
4860                 } else {
4861                     s3 = "not refcounted";
4862                 }
4863                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
4864             }
4865         }
4866 
4867         @Override
finalize()4868         protected void finalize() throws Throwable {
4869             super.finalize();
4870             setReferenceCounted(false);
4871             release();
4872         }
4873     }
4874 
4875     /**
4876      * Check multicast filter status.
4877      *
4878      * @return true if multicast packets are allowed.
4879      *
4880      * @hide pending API council approval
4881      */
isMulticastEnabled()4882     public boolean isMulticastEnabled() {
4883         try {
4884             return mService.isMulticastEnabled();
4885         } catch (RemoteException e) {
4886             throw e.rethrowFromSystemServer();
4887         }
4888     }
4889 
4890     /**
4891      * Initialize the multicast filtering to 'on'
4892      * @hide no intent to publish
4893      */
4894     @UnsupportedAppUsage
initializeMulticastFiltering()4895     public boolean initializeMulticastFiltering() {
4896         try {
4897             mService.initializeMulticastFiltering();
4898             return true;
4899         } catch (RemoteException e) {
4900             throw e.rethrowFromSystemServer();
4901         }
4902     }
4903 
4904     /**
4905      * Set Wi-Fi verbose logging level from developer settings.
4906      *
4907      * @param enable true to enable verbose logging, false to disable.
4908      *
4909      * @hide
4910      */
4911     @SystemApi
4912     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setVerboseLoggingEnabled(boolean enable)4913     public void setVerboseLoggingEnabled(boolean enable) {
4914         enableVerboseLogging(enable ? 1 : 0);
4915     }
4916 
4917     /** @hide */
4918     @UnsupportedAppUsage(
4919             maxTargetSdk = Build.VERSION_CODES.Q,
4920             publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead."
4921     )
4922     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
enableVerboseLogging(int verbose)4923     public void enableVerboseLogging (int verbose) {
4924         try {
4925             mService.enableVerboseLogging(verbose);
4926         } catch (Exception e) {
4927             //ignore any failure here
4928             Log.e(TAG, "enableVerboseLogging " + e.toString());
4929         }
4930     }
4931 
4932     /**
4933      * Get the persisted Wi-Fi verbose logging level, set by
4934      * {@link #setVerboseLoggingEnabled(boolean)}.
4935      * No permissions are required to call this method.
4936      *
4937      * @return true to indicate that verbose logging is enabled, false to indicate that verbose
4938      * logging is disabled.
4939      *
4940      * @hide
4941      */
4942     @SystemApi
isVerboseLoggingEnabled()4943     public boolean isVerboseLoggingEnabled() {
4944         return getVerboseLoggingLevel() > 0;
4945     }
4946 
4947     /** @hide */
4948     // TODO(b/145484145): remove once SUW stops calling this via reflection
4949     @UnsupportedAppUsage(
4950             maxTargetSdk = Build.VERSION_CODES.Q,
4951             publicAlternatives = "Use {@code #isVerboseLoggingEnabled()} instead."
4952     )
getVerboseLoggingLevel()4953     public int getVerboseLoggingLevel() {
4954         try {
4955             return mService.getVerboseLoggingLevel();
4956         } catch (RemoteException e) {
4957             throw e.rethrowFromSystemServer();
4958         }
4959     }
4960 
4961     /**
4962      * Removes all saved Wi-Fi networks, Passpoint configurations, ephemeral networks, Network
4963      * Requests, and Network Suggestions.
4964      *
4965      * @hide
4966      */
4967     @SystemApi
4968     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
factoryReset()4969     public void factoryReset() {
4970         try {
4971             mService.factoryReset(mContext.getOpPackageName());
4972         } catch (RemoteException e) {
4973             throw e.rethrowFromSystemServer();
4974         }
4975     }
4976 
4977     /**
4978      * Get {@link Network} object of current wifi network, or null if not connected.
4979      * @hide
4980      */
4981     @Nullable
4982     @SystemApi
4983     @RequiresPermission(anyOf = {
4984             android.Manifest.permission.NETWORK_SETTINGS,
4985             android.Manifest.permission.NETWORK_SETUP_WIZARD
4986     })
getCurrentNetwork()4987     public Network getCurrentNetwork() {
4988         try {
4989             return mService.getCurrentNetwork();
4990         } catch (RemoteException e) {
4991             throw e.rethrowFromSystemServer();
4992         }
4993     }
4994 
4995     /**
4996      * Deprecated
4997      * returns false
4998      * @hide
4999      * @deprecated
5000      */
setEnableAutoJoinWhenAssociated(boolean enabled)5001     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
5002         return false;
5003     }
5004 
5005     /**
5006      * Deprecated
5007      * returns false
5008      * @hide
5009      * @deprecated
5010      */
getEnableAutoJoinWhenAssociated()5011     public boolean getEnableAutoJoinWhenAssociated() {
5012         return false;
5013     }
5014 
5015     /**
5016      * Returns a byte stream representing the data that needs to be backed up to save the
5017      * current Wifi state.
5018      * This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}.
5019      * @hide
5020      */
5021     @NonNull
5022     @SystemApi
5023     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveBackupData()5024     public byte[] retrieveBackupData() {
5025         try {
5026             return mService.retrieveBackupData();
5027         } catch (RemoteException e) {
5028             throw e.rethrowFromSystemServer();
5029         }
5030     }
5031 
5032     /**
5033      * Restore state from the backed up data.
5034      * @param data byte stream in the same format produced by {@link #retrieveBackupData()}
5035      * @hide
5036      */
5037     @SystemApi
5038     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreBackupData(@onNull byte[] data)5039     public void restoreBackupData(@NonNull byte[] data) {
5040         try {
5041             mService.restoreBackupData(data);
5042         } catch (RemoteException e) {
5043             throw e.rethrowFromSystemServer();
5044         }
5045     }
5046 
5047     /**
5048      * Returns a byte stream representing the data that needs to be backed up to save the
5049      * current soft ap config data.
5050      *
5051      * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
5052      * @hide
5053      */
5054     @NonNull
5055     @SystemApi
5056     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveSoftApBackupData()5057     public byte[] retrieveSoftApBackupData() {
5058         try {
5059             return mService.retrieveSoftApBackupData();
5060         } catch (RemoteException e) {
5061             throw e.rethrowFromSystemServer();
5062         }
5063     }
5064 
5065     /**
5066      * Returns soft ap config from the backed up data or null if data is invalid.
5067      * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
5068      *
5069      * @hide
5070      */
5071     @Nullable
5072     @SystemApi
5073     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSoftApBackupData(@onNull byte[] data)5074     public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
5075         try {
5076             return mService.restoreSoftApBackupData(data);
5077         } catch (RemoteException e) {
5078             throw e.rethrowFromSystemServer();
5079         }
5080     }
5081 
5082     /**
5083      * Restore state from the older version of back up data.
5084      * The old backup data was essentially a backup of wpa_supplicant.conf
5085      * and ipconfig.txt file.
5086      * @param supplicantData bytes representing wpa_supplicant.conf
5087      * @param ipConfigData bytes representing ipconfig.txt
5088      * @hide
5089      */
5090     @SystemApi
5091     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSupplicantBackupData( @onNull byte[] supplicantData, @NonNull byte[] ipConfigData)5092     public void restoreSupplicantBackupData(
5093             @NonNull byte[] supplicantData, @NonNull byte[] ipConfigData) {
5094         try {
5095             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
5096         } catch (RemoteException e) {
5097             throw e.rethrowFromSystemServer();
5098         }
5099     }
5100 
5101     /**
5102      * Start subscription provisioning flow
5103      *
5104      * @param provider {@link OsuProvider} to provision with
5105      * @param executor the Executor on which to run the callback.
5106      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
5107      * @hide
5108      */
5109     @SystemApi
5110     @RequiresPermission(anyOf = {
5111             android.Manifest.permission.NETWORK_SETTINGS,
5112             android.Manifest.permission.NETWORK_SETUP_WIZARD
5113     })
startSubscriptionProvisioning(@onNull OsuProvider provider, @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback)5114     public void startSubscriptionProvisioning(@NonNull OsuProvider provider,
5115             @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback) {
5116         // Verify arguments
5117         if (executor == null) {
5118             throw new IllegalArgumentException("executor must not be null");
5119         }
5120         if (callback == null) {
5121             throw new IllegalArgumentException("callback must not be null");
5122         }
5123         try {
5124             mService.startSubscriptionProvisioning(provider,
5125                     new ProvisioningCallbackProxy(executor, callback));
5126         } catch (RemoteException e) {
5127             throw e.rethrowFromSystemServer();
5128         }
5129     }
5130 
5131     /**
5132      * Helper class to support OSU Provisioning callbacks
5133      */
5134     private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
5135         private final Executor mExecutor;
5136         private final ProvisioningCallback mCallback;
5137 
ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback)5138         ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback) {
5139             mExecutor = executor;
5140             mCallback = callback;
5141         }
5142 
5143         @Override
onProvisioningStatus(int status)5144         public void onProvisioningStatus(int status) {
5145             mExecutor.execute(() -> mCallback.onProvisioningStatus(status));
5146         }
5147 
5148         @Override
onProvisioningFailure(int status)5149         public void onProvisioningFailure(int status) {
5150             mExecutor.execute(() -> mCallback.onProvisioningFailure(status));
5151         }
5152 
5153         @Override
onProvisioningComplete()5154         public void onProvisioningComplete() {
5155             mExecutor.execute(() -> mCallback.onProvisioningComplete());
5156         }
5157     }
5158 
5159     /**
5160      * Interface for Traffic state callback. Should be extended by applications and set when
5161      * calling {@link #registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}.
5162      * @hide
5163      */
5164     @SystemApi
5165     public interface TrafficStateCallback {
5166         /** @hide */
5167         @Retention(RetentionPolicy.SOURCE)
5168         @IntDef(prefix = {"DATA_ACTIVITY_"}, value = {
5169                 DATA_ACTIVITY_NONE,
5170                 DATA_ACTIVITY_IN,
5171                 DATA_ACTIVITY_OUT,
5172                 DATA_ACTIVITY_INOUT})
5173         @interface DataActivity {}
5174 
5175         // Lowest bit indicates data reception and the second lowest bit indicates data transmitted
5176         /** No data in or out */
5177         int DATA_ACTIVITY_NONE         = 0x00;
5178         /** Data in, no data out */
5179         int DATA_ACTIVITY_IN           = 0x01;
5180         /** Data out, no data in */
5181         int DATA_ACTIVITY_OUT          = 0x02;
5182         /** Data in and out */
5183         int DATA_ACTIVITY_INOUT        = 0x03;
5184 
5185         /**
5186          * Callback invoked to inform clients about the current traffic state.
5187          *
5188          * @param state One of the values: {@link #DATA_ACTIVITY_NONE}, {@link #DATA_ACTIVITY_IN},
5189          * {@link #DATA_ACTIVITY_OUT} & {@link #DATA_ACTIVITY_INOUT}.
5190          */
onStateChanged(@ataActivity int state)5191         void onStateChanged(@DataActivity int state);
5192     }
5193 
5194     /**
5195      * Callback proxy for TrafficStateCallback objects.
5196      *
5197      * @hide
5198      */
5199     private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub {
5200         private final Executor mExecutor;
5201         private final TrafficStateCallback mCallback;
5202 
TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback)5203         TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback) {
5204             mExecutor = executor;
5205             mCallback = callback;
5206         }
5207 
5208         @Override
onStateChanged(int state)5209         public void onStateChanged(int state) {
5210             if (mVerboseLoggingEnabled) {
5211                 Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state);
5212             }
5213             Binder.clearCallingIdentity();
5214             mExecutor.execute(() -> {
5215                 mCallback.onStateChanged(state);
5216             });
5217         }
5218     }
5219 
5220     /**
5221      * Registers a callback for monitoring traffic state. See {@link TrafficStateCallback}. These
5222      * callbacks will be invoked periodically by platform to inform clients about the current
5223      * traffic state. Caller can unregister a previously registered callback using
5224      * {@link #unregisterTrafficStateCallback(TrafficStateCallback)}
5225      * <p>
5226      * Applications should have the
5227      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
5228      * without the permission will trigger a {@link java.lang.SecurityException}.
5229      * <p>
5230      *
5231      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
5232      *                 object.
5233      * @param callback Callback for traffic state events
5234      * @hide
5235      */
5236     @SystemApi
5237     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerTrafficStateCallback(@onNull @allbackExecutor Executor executor, @NonNull TrafficStateCallback callback)5238     public void registerTrafficStateCallback(@NonNull @CallbackExecutor Executor executor,
5239                                              @NonNull TrafficStateCallback callback) {
5240         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5241         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5242         Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", executor=" + executor);
5243 
5244         Binder binder = new Binder();
5245         try {
5246             mService.registerTrafficStateCallback(
5247                     binder, new TrafficStateCallbackProxy(executor, callback), callback.hashCode());
5248         } catch (RemoteException e) {
5249             throw e.rethrowFromSystemServer();
5250         }
5251     }
5252 
5253     /**
5254      * Allow callers to unregister a previously registered callback. After calling this method,
5255      * applications will no longer receive traffic state notifications.
5256      *
5257      * @param callback Callback to unregister for traffic state events
5258      * @hide
5259      */
5260     @SystemApi
5261     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterTrafficStateCallback(@onNull TrafficStateCallback callback)5262     public void unregisterTrafficStateCallback(@NonNull TrafficStateCallback callback) {
5263         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5264         Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
5265 
5266         try {
5267             mService.unregisterTrafficStateCallback(callback.hashCode());
5268         } catch (RemoteException e) {
5269             throw e.rethrowFromSystemServer();
5270         }
5271     }
5272 
5273     /**
5274      * Helper method to update the local verbose logging flag based on the verbose logging
5275      * level from wifi service.
5276      */
updateVerboseLoggingEnabledFromService()5277     private void updateVerboseLoggingEnabledFromService() {
5278         mVerboseLoggingEnabled = isVerboseLoggingEnabled();
5279     }
5280 
5281     /**
5282      * @return true if this device supports WPA3-Personal SAE
5283      */
isWpa3SaeSupported()5284     public boolean isWpa3SaeSupported() {
5285         return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
5286     }
5287 
5288     /**
5289      * @return true if this device supports WPA3-Enterprise Suite-B-192
5290      */
isWpa3SuiteBSupported()5291     public boolean isWpa3SuiteBSupported() {
5292         return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
5293     }
5294 
5295     /**
5296      * @return true if this device supports Wi-Fi Enhanced Open (OWE)
5297      */
isEnhancedOpenSupported()5298     public boolean isEnhancedOpenSupported() {
5299         return isFeatureSupported(WIFI_FEATURE_OWE);
5300     }
5301 
5302     /**
5303      * Wi-Fi Easy Connect (DPP) introduces standardized mechanisms to simplify the provisioning and
5304      * configuration of Wi-Fi devices.
5305      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
5306      * search for "Easy Connect" or "Device Provisioning Protocol specification".
5307      *
5308      * @return true if this device supports Wi-Fi Easy-connect (Device Provisioning Protocol)
5309      */
isEasyConnectSupported()5310     public boolean isEasyConnectSupported() {
5311         return isFeatureSupported(WIFI_FEATURE_DPP);
5312     }
5313 
5314     /**
5315      * @return true if this device supports WAPI.
5316      */
isWapiSupported()5317     public boolean isWapiSupported() {
5318         return isFeatureSupported(WIFI_FEATURE_WAPI);
5319     }
5320 
5321     /**
5322      * Gets the factory Wi-Fi MAC addresses.
5323      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
5324      * if failed.
5325      * @hide
5326      */
5327     @NonNull
5328     @SystemApi
5329     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getFactoryMacAddresses()5330     public String[] getFactoryMacAddresses() {
5331         try {
5332             return mService.getFactoryMacAddresses();
5333         } catch (RemoteException e) {
5334             throw e.rethrowFromSystemServer();
5335         }
5336     }
5337 
5338     /** @hide */
5339     @Retention(RetentionPolicy.SOURCE)
5340     @IntDef(prefix = {"DEVICE_MOBILITY_STATE_"}, value = {
5341             DEVICE_MOBILITY_STATE_UNKNOWN,
5342             DEVICE_MOBILITY_STATE_HIGH_MVMT,
5343             DEVICE_MOBILITY_STATE_LOW_MVMT,
5344             DEVICE_MOBILITY_STATE_STATIONARY})
5345     public @interface DeviceMobilityState {}
5346 
5347     /**
5348      * Unknown device mobility state
5349      *
5350      * @see #setDeviceMobilityState(int)
5351      *
5352      * @hide
5353      */
5354     @SystemApi
5355     public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0;
5356 
5357     /**
5358      * High movement device mobility state.
5359      * e.g. on a bike, in a motor vehicle
5360      *
5361      * @see #setDeviceMobilityState(int)
5362      *
5363      * @hide
5364      */
5365     @SystemApi
5366     public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1;
5367 
5368     /**
5369      * Low movement device mobility state.
5370      * e.g. walking, running
5371      *
5372      * @see #setDeviceMobilityState(int)
5373      *
5374      * @hide
5375      */
5376     @SystemApi
5377     public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2;
5378 
5379     /**
5380      * Stationary device mobility state
5381      *
5382      * @see #setDeviceMobilityState(int)
5383      *
5384      * @hide
5385      */
5386     @SystemApi
5387     public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3;
5388 
5389     /**
5390      * Updates the device mobility state. Wifi uses this information to adjust the interval between
5391      * Wifi scans in order to balance power consumption with scan accuracy.
5392      * The default mobility state when the device boots is {@link #DEVICE_MOBILITY_STATE_UNKNOWN}.
5393      * This API should be called whenever there is a change in the mobility state.
5394      * @param state the updated device mobility state
5395      * @hide
5396      */
5397     @SystemApi
5398     @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
setDeviceMobilityState(@eviceMobilityState int state)5399     public void setDeviceMobilityState(@DeviceMobilityState int state) {
5400         try {
5401             mService.setDeviceMobilityState(state);
5402         } catch (RemoteException e) {
5403             throw e.rethrowFromSystemServer();
5404         }
5405     }
5406 
5407     /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
5408 
5409     /**
5410      * Easy Connect Network role: Station.
5411      *
5412      * @hide
5413      */
5414     @SystemApi
5415     public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
5416 
5417     /**
5418      * Easy Connect Network role: Access Point.
5419      *
5420      * @hide
5421      */
5422     @SystemApi
5423     public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
5424 
5425     /** @hide */
5426     @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
5427             EASY_CONNECT_NETWORK_ROLE_STA,
5428             EASY_CONNECT_NETWORK_ROLE_AP,
5429     })
5430     @Retention(RetentionPolicy.SOURCE)
5431     public @interface EasyConnectNetworkRole {
5432     }
5433 
5434     /**
5435      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
5436      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
5437      * the specified network using the Easy Connect protocol on an encrypted link.
5438      *
5439      * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
5440      * @param selectedNetworkId   Selected network ID to be sent to the peer
5441      * @param enrolleeNetworkRole The network role of the enrollee
5442      * @param callback            Callback for status updates
5443      * @param executor            The Executor on which to run the callback.
5444      * @hide
5445      */
5446     @SystemApi
5447     @RequiresPermission(anyOf = {
5448             android.Manifest.permission.NETWORK_SETTINGS,
5449             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsConfiguratorInitiator(@onNull String enrolleeUri, int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)5450     public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
5451             int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
5452             @NonNull @CallbackExecutor Executor executor,
5453             @NonNull EasyConnectStatusCallback callback) {
5454         Binder binder = new Binder();
5455         try {
5456             mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
5457                     enrolleeNetworkRole, new EasyConnectCallbackProxy(executor, callback));
5458         } catch (RemoteException e) {
5459             throw e.rethrowFromSystemServer();
5460         }
5461     }
5462 
5463     /**
5464      * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
5465      * Connect bootstrapping with a peer, and receive the SSID and password from the peer
5466      * configurator.
5467      *
5468      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
5469      * @param callback        Callback for status updates
5470      * @param executor        The Executor on which to run the callback.
5471      * @hide
5472      */
5473     @SystemApi
5474     @RequiresPermission(anyOf = {
5475             android.Manifest.permission.NETWORK_SETTINGS,
5476             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsEnrolleeInitiator(@onNull String configuratorUri, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)5477     public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
5478             @NonNull @CallbackExecutor Executor executor,
5479             @NonNull EasyConnectStatusCallback callback) {
5480         Binder binder = new Binder();
5481         try {
5482             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
5483                     new EasyConnectCallbackProxy(executor, callback));
5484         } catch (RemoteException e) {
5485             throw e.rethrowFromSystemServer();
5486         }
5487     }
5488 
5489     /**
5490      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
5491      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
5492      * expect any callbacks once this call is made. However, due to the asynchronous nature of
5493      * this call, a callback may be fired if it was already pending in the queue.
5494      *
5495      * @hide
5496      */
5497     @SystemApi
5498     @RequiresPermission(anyOf = {
5499             android.Manifest.permission.NETWORK_SETTINGS,
5500             android.Manifest.permission.NETWORK_SETUP_WIZARD})
stopEasyConnectSession()5501     public void stopEasyConnectSession() {
5502         try {
5503             /* Request lower layers to stop/abort and clear resources */
5504             mService.stopDppSession();
5505         } catch (RemoteException e) {
5506             throw e.rethrowFromSystemServer();
5507         }
5508     }
5509 
5510     /**
5511      * Helper class to support Easy Connect (DPP) callbacks
5512      *
5513      * @hide
5514      */
5515     private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
5516         private final Executor mExecutor;
5517         private final EasyConnectStatusCallback mEasyConnectStatusCallback;
5518 
EasyConnectCallbackProxy(Executor executor, EasyConnectStatusCallback easyConnectStatusCallback)5519         EasyConnectCallbackProxy(Executor executor,
5520                 EasyConnectStatusCallback easyConnectStatusCallback) {
5521             mExecutor = executor;
5522             mEasyConnectStatusCallback = easyConnectStatusCallback;
5523         }
5524 
5525         @Override
onSuccessConfigReceived(int newNetworkId)5526         public void onSuccessConfigReceived(int newNetworkId) {
5527             Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
5528             Binder.clearCallingIdentity();
5529             mExecutor.execute(() -> {
5530                 mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
5531             });
5532         }
5533 
5534         @Override
onSuccess(int status)5535         public void onSuccess(int status) {
5536             Log.d(TAG, "Easy Connect onSuccess callback");
5537             Binder.clearCallingIdentity();
5538             mExecutor.execute(() -> {
5539                 mEasyConnectStatusCallback.onConfiguratorSuccess(status);
5540             });
5541         }
5542 
5543         @Override
onFailure(int status, String ssid, String channelList, int[] operatingClassArray)5544         public void onFailure(int status, String ssid, String channelList,
5545                 int[] operatingClassArray) {
5546             Log.d(TAG, "Easy Connect onFailure callback");
5547             Binder.clearCallingIdentity();
5548             mExecutor.execute(() -> {
5549                 SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
5550                 mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
5551                         operatingClassArray);
5552             });
5553         }
5554 
5555         @Override
onProgress(int status)5556         public void onProgress(int status) {
5557             Log.d(TAG, "Easy Connect onProgress callback");
5558             Binder.clearCallingIdentity();
5559             mExecutor.execute(() -> {
5560                 mEasyConnectStatusCallback.onProgress(status);
5561             });
5562         }
5563     }
5564 
5565     /**
5566      * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
5567      * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor,
5568      * OnWifiUsabilityStatsListener)}.
5569      *
5570      * @hide
5571      */
5572     @SystemApi
5573     public interface OnWifiUsabilityStatsListener {
5574         /**
5575          * Called when Wi-Fi usability statistics is updated.
5576          *
5577          * @param seqNum The sequence number of statistics, used to derive the timing of updated
5578          *               Wi-Fi usability statistics, set by framework and incremented by one after
5579          *               each update.
5580          * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
5581          *                           network stays the same or not relative to the last update of
5582          *                           Wi-Fi usability stats.
5583          * @param stats The updated Wi-Fi usability statistics.
5584          */
onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, @NonNull WifiUsabilityStatsEntry stats)5585         void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
5586                 @NonNull WifiUsabilityStatsEntry stats);
5587     }
5588 
5589     /**
5590      * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}.
5591      * Multiple listeners can be added. Callers will be invoked periodically by framework to
5592      * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
5593      * added listener using {@link removeOnWifiUsabilityStatsListener}.
5594      *
5595      * @param executor The executor on which callback will be invoked.
5596      * @param listener Listener for Wifi usability statistics.
5597      *
5598      * @hide
5599      */
5600     @SystemApi
5601     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
addOnWifiUsabilityStatsListener(@onNull @allbackExecutor Executor executor, @NonNull OnWifiUsabilityStatsListener listener)5602     public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
5603             @NonNull OnWifiUsabilityStatsListener listener) {
5604         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5605         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
5606         if (mVerboseLoggingEnabled) {
5607             Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
5608         }
5609         try {
5610             mService.addOnWifiUsabilityStatsListener(new Binder(),
5611                     new IOnWifiUsabilityStatsListener.Stub() {
5612                         @Override
5613                         public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
5614                                 WifiUsabilityStatsEntry stats) {
5615                             if (mVerboseLoggingEnabled) {
5616                                 Log.v(TAG, "OnWifiUsabilityStatsListener: "
5617                                         + "onWifiUsabilityStats: seqNum=" + seqNum);
5618                             }
5619                             Binder.clearCallingIdentity();
5620                             executor.execute(() -> listener.onWifiUsabilityStats(
5621                                     seqNum, isSameBssidAndFreq, stats));
5622                         }
5623                     },
5624                     listener.hashCode()
5625             );
5626         } catch (RemoteException e) {
5627             throw e.rethrowFromSystemServer();
5628         }
5629     }
5630 
5631     /**
5632      * Allow callers to remove a previously registered listener. After calling this method,
5633      * applications will no longer receive Wi-Fi usability statistics.
5634      *
5635      * @param listener Listener to remove the Wi-Fi usability statistics.
5636      *
5637      * @hide
5638      */
5639     @SystemApi
5640     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
removeOnWifiUsabilityStatsListener(@onNull OnWifiUsabilityStatsListener listener)5641     public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) {
5642         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
5643         if (mVerboseLoggingEnabled) {
5644             Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
5645         }
5646         try {
5647             mService.removeOnWifiUsabilityStatsListener(listener.hashCode());
5648         } catch (RemoteException e) {
5649             throw e.rethrowFromSystemServer();
5650         }
5651     }
5652 
5653     /**
5654      * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
5655      * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
5656      * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
5657      * is used to quantify whether Wi-Fi is usable in a future time.
5658      *
5659      * @param seqNum Sequence number of the Wi-Fi usability score.
5660      * @param score The Wi-Fi usability score, expected range: [0, 100].
5661      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
5662      *                             expected range: [0, 30].
5663      *
5664      * @hide
5665      */
5666     @SystemApi
5667     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)5668     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
5669         try {
5670             mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
5671         } catch (RemoteException e) {
5672             throw e.rethrowFromSystemServer();
5673         }
5674     }
5675 
5676     /**
5677      * Abstract class for scan results callback. Should be extended by applications and set when
5678      * calling {@link WifiManager#registerScanResultsCallback(Executor, ScanResultsCallback)}.
5679      */
5680     public abstract static class ScanResultsCallback {
5681         private final ScanResultsCallbackProxy mScanResultsCallbackProxy;
5682 
ScanResultsCallback()5683         public ScanResultsCallback() {
5684             mScanResultsCallbackProxy = new ScanResultsCallbackProxy();
5685         }
5686 
5687         /**
5688          * Called when new scan results are available.
5689          * Clients should use {@link WifiManager#getScanResults()} to get the scan results.
5690          */
onScanResultsAvailable()5691         public abstract void onScanResultsAvailable();
5692 
getProxy()5693         /*package*/ @NonNull ScanResultsCallbackProxy getProxy() {
5694             return mScanResultsCallbackProxy;
5695         }
5696 
5697         private static class ScanResultsCallbackProxy extends IScanResultsCallback.Stub {
5698             private final Object mLock = new Object();
5699             @Nullable @GuardedBy("mLock") private Executor mExecutor;
5700             @Nullable @GuardedBy("mLock") private ScanResultsCallback mCallback;
5701 
ScanResultsCallbackProxy()5702             ScanResultsCallbackProxy() {
5703                 mCallback = null;
5704                 mExecutor = null;
5705             }
5706 
initProxy(@onNull Executor executor, @NonNull ScanResultsCallback callback)5707             /*package*/ void initProxy(@NonNull Executor executor,
5708                     @NonNull ScanResultsCallback callback) {
5709                 synchronized (mLock) {
5710                     mExecutor = executor;
5711                     mCallback = callback;
5712                 }
5713             }
5714 
cleanUpProxy()5715             /*package*/ void cleanUpProxy() {
5716                 synchronized (mLock) {
5717                     mExecutor = null;
5718                     mCallback = null;
5719                 }
5720             }
5721 
5722             @Override
onScanResultsAvailable()5723             public void onScanResultsAvailable() {
5724                 ScanResultsCallback callback;
5725                 Executor executor;
5726                 synchronized (mLock) {
5727                     executor = mExecutor;
5728                     callback = mCallback;
5729                 }
5730                 if (callback == null || executor == null) {
5731                     return;
5732                 }
5733                 Binder.clearCallingIdentity();
5734                 executor.execute(callback::onScanResultsAvailable);
5735             }
5736         }
5737 
5738     }
5739 
5740     /**
5741      * Register a callback for Scan Results. See {@link ScanResultsCallback}.
5742      * Caller will receive the event when scan results are available.
5743      * Caller should use {@link WifiManager#getScanResults()} requires
5744      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results.
5745      * Caller can remove a previously registered callback using
5746      * {@link WifiManager#unregisterScanResultsCallback(ScanResultsCallback)}
5747      * Same caller can add multiple listeners.
5748      * <p>
5749      * Applications should have the
5750      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers
5751      * without the permission will trigger a {@link java.lang.SecurityException}.
5752      * <p>
5753      *
5754      * @param executor The executor to execute the callback of the {@code callback} object.
5755      * @param callback callback for Scan Results events
5756      */
5757 
5758     @RequiresPermission(ACCESS_WIFI_STATE)
registerScanResultsCallback(@onNull @allbackExecutor Executor executor, @NonNull ScanResultsCallback callback)5759     public void registerScanResultsCallback(@NonNull @CallbackExecutor Executor executor,
5760             @NonNull ScanResultsCallback callback) {
5761         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5762         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5763 
5764         Log.v(TAG, "registerScanResultsCallback: callback=" + callback
5765                 + ", executor=" + executor);
5766         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
5767         proxy.initProxy(executor, callback);
5768         try {
5769             mService.registerScanResultsCallback(proxy);
5770         } catch (RemoteException e) {
5771             throw e.rethrowFromSystemServer();
5772         }
5773     }
5774 
5775     /**
5776      * Allow callers to unregister a previously registered callback. After calling this method,
5777      * applications will no longer receive Scan Results events.
5778      *
5779      * @param callback callback to unregister for Scan Results events
5780      */
5781     @RequiresPermission(ACCESS_WIFI_STATE)
unregisterScanResultsCallback(@onNull ScanResultsCallback callback)5782     public void unregisterScanResultsCallback(@NonNull ScanResultsCallback callback) {
5783         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5784         Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback);
5785         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
5786         try {
5787             mService.unregisterScanResultsCallback(proxy);
5788         } catch (RemoteException e) {
5789             throw e.rethrowFromSystemServer();
5790         } finally {
5791             proxy.cleanUpProxy();
5792         }
5793     }
5794 
5795     /**
5796      * Interface for suggestion connection status listener.
5797      * Should be implemented by applications and set when calling
5798      * {@link WifiManager#addSuggestionConnectionStatusListener(
5799      * Executor, SuggestionConnectionStatusListener)}.
5800      */
5801     public interface SuggestionConnectionStatusListener {
5802 
5803         /**
5804          * Called when the framework attempted to connect to a suggestion provided by the
5805          * registering app, but the connection to the suggestion failed.
5806          * @param wifiNetworkSuggestion The suggestion which failed to connect.
5807          * @param failureReason the connection failure reason code. One of
5808          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION},
5809          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION},
5810          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING}
5811          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN}
5812          */
onConnectionStatus( @onNull WifiNetworkSuggestion wifiNetworkSuggestion, @SuggestionConnectionStatusCode int failureReason)5813         void onConnectionStatus(
5814                 @NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
5815                 @SuggestionConnectionStatusCode int failureReason);
5816     }
5817 
5818     private class SuggestionConnectionStatusListenerProxy extends
5819             ISuggestionConnectionStatusListener.Stub {
5820         private final Executor mExecutor;
5821         private final SuggestionConnectionStatusListener mListener;
5822 
SuggestionConnectionStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionConnectionStatusListener listener)5823         SuggestionConnectionStatusListenerProxy(@NonNull Executor executor,
5824                 @NonNull SuggestionConnectionStatusListener listener) {
5825             mExecutor = executor;
5826             mListener = listener;
5827         }
5828 
5829         @Override
onConnectionStatus(@onNull WifiNetworkSuggestion wifiNetworkSuggestion, int failureReason)5830         public void onConnectionStatus(@NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
5831                 int failureReason) {
5832             mExecutor.execute(() ->
5833                     mListener.onConnectionStatus(wifiNetworkSuggestion, failureReason));
5834         }
5835 
5836     }
5837 
5838     /**
5839      * Add a listener for suggestion networks. See {@link SuggestionConnectionStatusListener}.
5840      * Caller will receive the event when suggested network have connection failure.
5841      * Caller can remove a previously registered listener using
5842      * {@link WifiManager#removeSuggestionConnectionStatusListener(
5843      * SuggestionConnectionStatusListener)}
5844      * Same caller can add multiple listeners to monitor the event.
5845      * <p>
5846      * Applications should have the
5847      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
5848      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permissions.
5849      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
5850      * <p>
5851      *
5852      * @param executor The executor to execute the listener of the {@code listener} object.
5853      * @param listener listener for suggestion network connection failure.
5854      */
5855     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
addSuggestionConnectionStatusListener(@onNull @allbackExecutor Executor executor, @NonNull SuggestionConnectionStatusListener listener)5856     public void addSuggestionConnectionStatusListener(@NonNull @CallbackExecutor Executor executor,
5857             @NonNull SuggestionConnectionStatusListener listener) {
5858         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
5859         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
5860         Log.v(TAG, "addSuggestionConnectionStatusListener listener=" + listener
5861                 + ", executor=" + executor);
5862         try {
5863             mService.registerSuggestionConnectionStatusListener(new Binder(),
5864                     new SuggestionConnectionStatusListenerProxy(executor, listener),
5865                     listener.hashCode(), mContext.getOpPackageName(), mContext.getAttributionTag());
5866         } catch (RemoteException e) {
5867             throw e.rethrowFromSystemServer();
5868         }
5869 
5870     }
5871 
5872     /**
5873      * Allow callers to remove a previously registered listener. After calling this method,
5874      * applications will no longer receive suggestion connection events through that listener.
5875      *
5876      * @param listener listener to remove.
5877      */
5878     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionConnectionStatusListener( @onNull SuggestionConnectionStatusListener listener)5879     public void removeSuggestionConnectionStatusListener(
5880             @NonNull SuggestionConnectionStatusListener listener) {
5881         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
5882         Log.v(TAG, "removeSuggestionConnectionStatusListener: listener=" + listener);
5883         try {
5884             mService.unregisterSuggestionConnectionStatusListener(listener.hashCode(),
5885                     mContext.getOpPackageName());
5886         } catch (RemoteException e) {
5887             throw e.rethrowFromSystemServer();
5888         }
5889     }
5890 
5891     /**
5892      * Parse the list of channels the DPP enrollee reports when it fails to find an AP.
5893      *
5894      * @param channelList List of channels in the format defined in the DPP specification.
5895      * @return A parsed sparse array, where the operating class is the key.
5896      * @hide
5897      */
5898     @VisibleForTesting
parseDppChannelList(String channelList)5899     public static SparseArray<int[]> parseDppChannelList(String channelList) {
5900         SparseArray<int[]> channelListArray = new SparseArray<>();
5901 
5902         if (TextUtils.isEmpty(channelList)) {
5903             return channelListArray;
5904         }
5905         StringTokenizer str = new StringTokenizer(channelList, ",");
5906         String classStr = null;
5907         List<Integer> channelsInClass = new ArrayList<>();
5908 
5909         try {
5910             while (str.hasMoreElements()) {
5911                 String cur = str.nextToken();
5912 
5913                 /**
5914                  * Example for a channel list:
5915                  *
5916                  * 81/1,2,3,4,5,6,7,8,9,10,11,115/36,40,44,48,118/52,56,60,64,121/100,104,108,112,
5917                  * 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
5918                  *
5919                  * Detect operating class by the delimiter of '/' and use a string tokenizer with
5920                  * ',' as a delimiter.
5921                  */
5922                 int classDelim = cur.indexOf('/');
5923                 if (classDelim != -1) {
5924                     if (classStr != null) {
5925                         // Store the last channel array in the sparse array, where the operating
5926                         // class is the key (as an integer).
5927                         int[] channelsArray = new int[channelsInClass.size()];
5928                         for (int i = 0; i < channelsInClass.size(); i++) {
5929                             channelsArray[i] = channelsInClass.get(i);
5930                         }
5931                         channelListArray.append(Integer.parseInt(classStr), channelsArray);
5932                         channelsInClass = new ArrayList<>();
5933                     }
5934 
5935                     // Init a new operating class and store the first channel
5936                     classStr = cur.substring(0, classDelim);
5937                     String channelStr = cur.substring(classDelim + 1);
5938                     channelsInClass.add(Integer.parseInt(channelStr));
5939                 } else {
5940                     if (classStr == null) {
5941                         // Invalid format
5942                         Log.e(TAG, "Cannot parse DPP channel list");
5943                         return new SparseArray<>();
5944                     }
5945                     channelsInClass.add(Integer.parseInt(cur));
5946                 }
5947             }
5948 
5949             // Store the last array
5950             if (classStr != null) {
5951                 int[] channelsArray = new int[channelsInClass.size()];
5952                 for (int i = 0; i < channelsInClass.size(); i++) {
5953                     channelsArray[i] = channelsInClass.get(i);
5954                 }
5955                 channelListArray.append(Integer.parseInt(classStr), channelsArray);
5956             }
5957             return channelListArray;
5958         } catch (NumberFormatException e) {
5959             Log.e(TAG, "Cannot parse DPP channel list");
5960             return new SparseArray<>();
5961         }
5962     }
5963 
5964     /**
5965      * Callback interface for framework to receive network status updates and trigger of updating
5966      * {@link WifiUsabilityStatsEntry}.
5967      *
5968      * @hide
5969      */
5970     @SystemApi
5971     public interface ScoreUpdateObserver {
5972         /**
5973          * Called by applications to indicate network status.
5974          *
5975          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
5976          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
5977          * @param score The score representing link quality of current Wi-Fi network connection.
5978          *              Populated by connected network scorer in applications..
5979          */
notifyScoreUpdate(int sessionId, int score)5980         void notifyScoreUpdate(int sessionId, int score);
5981 
5982         /**
5983          * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
5984          * To receive update applications need to add WifiUsabilityStatsEntry listener. See
5985          * {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
5986          *
5987          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
5988          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
5989          */
triggerUpdateOfWifiUsabilityStats(int sessionId)5990         void triggerUpdateOfWifiUsabilityStats(int sessionId);
5991     }
5992 
5993     /**
5994      * Callback proxy for {@link ScoreUpdateObserver} objects.
5995      *
5996      * @hide
5997      */
5998     private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
5999         private final IScoreUpdateObserver mScoreUpdateObserver;
6000 
ScoreUpdateObserverProxy(IScoreUpdateObserver observer)6001         private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
6002             mScoreUpdateObserver = observer;
6003         }
6004 
6005         @Override
notifyScoreUpdate(int sessionId, int score)6006         public void notifyScoreUpdate(int sessionId, int score) {
6007             try {
6008                 mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
6009             } catch (RemoteException e) {
6010                 throw e.rethrowFromSystemServer();
6011             }
6012         }
6013 
6014         @Override
triggerUpdateOfWifiUsabilityStats(int sessionId)6015         public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
6016             try {
6017                 mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
6018             } catch (RemoteException e) {
6019                 throw e.rethrowFromSystemServer();
6020             }
6021         }
6022     }
6023 
6024     /**
6025      * Interface for Wi-Fi connected network scorer. Should be implemented by applications and set
6026      * when calling
6027      * {@link WifiManager#setWifiConnectedNetworkScorer(Executor, WifiConnectedNetworkScorer)}.
6028      *
6029      * @hide
6030      */
6031     @SystemApi
6032     public interface WifiConnectedNetworkScorer {
6033         /**
6034          * Called by framework to indicate the start of a network connection.
6035          * @param sessionId The ID to indicate current Wi-Fi network connection.
6036          */
onStart(int sessionId)6037         void onStart(int sessionId);
6038 
6039         /**
6040          * Called by framework to indicate the end of a network connection.
6041          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
6042          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
6043          */
onStop(int sessionId)6044         void onStop(int sessionId);
6045 
6046         /**
6047          * Framework sets callback for score change events after application sets its scorer.
6048          * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
6049          * implemented and instantiated by framework.
6050          */
onSetScoreUpdateObserver(@onNull ScoreUpdateObserver observerImpl)6051         void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
6052     }
6053 
6054     /**
6055      * Callback proxy for {@link WifiConnectedNetworkScorer} objects.
6056      *
6057      * @hide
6058      */
6059     private class WifiConnectedNetworkScorerProxy extends IWifiConnectedNetworkScorer.Stub {
6060         private Executor mExecutor;
6061         private WifiConnectedNetworkScorer mScorer;
6062 
WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer)6063         WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer) {
6064             mExecutor = executor;
6065             mScorer = scorer;
6066         }
6067 
6068         @Override
onStart(int sessionId)6069         public void onStart(int sessionId) {
6070             if (mVerboseLoggingEnabled) {
6071                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionId=" + sessionId);
6072             }
6073             Binder.clearCallingIdentity();
6074             mExecutor.execute(() -> mScorer.onStart(sessionId));
6075         }
6076 
6077         @Override
onStop(int sessionId)6078         public void onStop(int sessionId) {
6079             if (mVerboseLoggingEnabled) {
6080                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
6081             }
6082             Binder.clearCallingIdentity();
6083             mExecutor.execute(() -> mScorer.onStop(sessionId));
6084         }
6085 
6086         @Override
onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl)6087         public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
6088             if (mVerboseLoggingEnabled) {
6089                 Log.v(TAG, "WifiConnectedNetworkScorer: "
6090                         + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
6091             }
6092             Binder.clearCallingIdentity();
6093             mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
6094                     new ScoreUpdateObserverProxy(observerImpl)));
6095         }
6096     }
6097 
6098     /**
6099      * Set a callback for Wi-Fi connected network scorer.  See {@link WifiConnectedNetworkScorer}.
6100      * Only a single scorer can be set. Caller will be invoked periodically by framework to inform
6101      * client about start and stop of Wi-Fi connection. Caller can clear a previously set scorer
6102      * using {@link clearWifiConnectedNetworkScorer()}.
6103      *
6104      * @param executor The executor on which callback will be invoked.
6105      * @param scorer Scorer for Wi-Fi network implemented by application.
6106      * @return true Scorer is set successfully.
6107      *
6108      * @hide
6109      */
6110     @SystemApi
6111     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
setWifiConnectedNetworkScorer(@onNull @allbackExecutor Executor executor, @NonNull WifiConnectedNetworkScorer scorer)6112     public boolean setWifiConnectedNetworkScorer(@NonNull @CallbackExecutor Executor executor,
6113             @NonNull WifiConnectedNetworkScorer scorer) {
6114         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
6115         if (scorer == null) throw new IllegalArgumentException("scorer cannot be null");
6116         if (mVerboseLoggingEnabled) {
6117             Log.v(TAG, "setWifiConnectedNetworkScorer: scorer=" + scorer);
6118         }
6119         try {
6120             return mService.setWifiConnectedNetworkScorer(new Binder(),
6121                     new WifiConnectedNetworkScorerProxy(executor, scorer));
6122         } catch (RemoteException e) {
6123             throw e.rethrowFromSystemServer();
6124         }
6125     }
6126 
6127     /**
6128      * Allow caller to clear a previously set scorer. After calling this method,
6129      * client will no longer receive information about start and stop of Wi-Fi connection.
6130      *
6131      * @hide
6132      */
6133     @SystemApi
6134     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
clearWifiConnectedNetworkScorer()6135     public void clearWifiConnectedNetworkScorer() {
6136         if (mVerboseLoggingEnabled) {
6137             Log.v(TAG, "clearWifiConnectedNetworkScorer");
6138         }
6139         try {
6140             mService.clearWifiConnectedNetworkScorer();
6141         } catch (RemoteException e) {
6142             throw e.rethrowFromSystemServer();
6143         }
6144     }
6145 
6146     /**
6147      * Enable/disable wifi scan throttling from 3rd party apps.
6148      *
6149      * <p>
6150      * The throttling limits for apps are described in
6151      * <a href="Wi-Fi Scan Throttling">
6152      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
6153      * </p>
6154      *
6155      * @param enable true to allow scan throttling, false to disallow scan throttling.
6156      * @hide
6157      */
6158     @SystemApi
6159     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanThrottleEnabled(boolean enable)6160     public void setScanThrottleEnabled(boolean enable) {
6161         try {
6162             mService.setScanThrottleEnabled(enable);
6163         } catch (RemoteException e) {
6164             throw e.rethrowFromSystemServer();
6165         }
6166     }
6167 
6168     /**
6169      * Get the persisted Wi-Fi scan throttle state. Defaults to true, unless changed by the user via
6170      * Developer options.
6171      *
6172      * <p>
6173      * The throttling limits for apps are described in
6174      * <a href="Wi-Fi Scan Throttling">
6175      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
6176      * </p>
6177      *
6178      * @return true to indicate that scan throttling is enabled, false to indicate that scan
6179      * throttling is disabled.
6180      */
6181     @RequiresPermission(ACCESS_WIFI_STATE)
isScanThrottleEnabled()6182     public boolean isScanThrottleEnabled() {
6183         try {
6184             return mService.isScanThrottleEnabled();
6185         } catch (RemoteException e) {
6186             throw e.rethrowFromSystemServer();
6187         }
6188     }
6189 
6190     /**
6191      * Enable/disable wifi auto wakeup feature.
6192      *
6193      * <p>
6194      * The feature is described in
6195      * <a href="Wi-Fi Turn on automatically">
6196      * https://source.android.com/devices/tech/connect/wifi-infrastructure
6197      * #turn_on_wi-fi_automatically
6198      * </a>
6199      *
6200      * @param enable true to enable, false to disable.
6201      * @hide
6202      */
6203     @SystemApi
6204     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setAutoWakeupEnabled(boolean enable)6205     public void setAutoWakeupEnabled(boolean enable) {
6206         try {
6207             mService.setAutoWakeupEnabled(enable);
6208         } catch (RemoteException e) {
6209             throw e.rethrowFromSystemServer();
6210         }
6211     }
6212 
6213     /**
6214      * Get the persisted Wi-Fi auto wakeup feature state. Defaults to false, unless changed by the
6215      * user via Settings.
6216      *
6217      * <p>
6218      * The feature is described in
6219      * <a href="Wi-Fi Turn on automatically">
6220      * https://source.android.com/devices/tech/connect/wifi-infrastructure
6221      * #turn_on_wi-fi_automatically
6222      * </a>
6223      *
6224      * @return true to indicate that wakeup feature is enabled, false to indicate that wakeup
6225      * feature is disabled.
6226      */
6227     @RequiresPermission(ACCESS_WIFI_STATE)
isAutoWakeupEnabled()6228     public boolean isAutoWakeupEnabled() {
6229         try {
6230             return mService.isAutoWakeupEnabled();
6231         } catch (RemoteException e) {
6232             throw e.rethrowFromSystemServer();
6233         }
6234     }
6235 }
6236