• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.wifi;
18 
19 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
20 import static android.Manifest.permission.ACCESS_WIFI_STATE;
21 import static android.Manifest.permission.CHANGE_WIFI_STATE;
22 import static android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION;
23 import static android.Manifest.permission.NEARBY_WIFI_DEVICES;
24 import static android.Manifest.permission.READ_WIFI_CREDENTIAL;
25 import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
26 
27 import android.Manifest;
28 import android.annotation.CallbackExecutor;
29 import android.annotation.IntDef;
30 import android.annotation.IntRange;
31 import android.annotation.NonNull;
32 import android.annotation.Nullable;
33 import android.annotation.RequiresPermission;
34 import android.annotation.SdkConstant;
35 import android.annotation.SdkConstant.SdkConstantType;
36 import android.annotation.SuppressLint;
37 import android.annotation.SystemApi;
38 import android.annotation.SystemService;
39 import android.app.ActivityManager;
40 import android.app.admin.WifiSsidPolicy;
41 import android.compat.annotation.ChangeId;
42 import android.compat.annotation.EnabledAfter;
43 import android.compat.annotation.UnsupportedAppUsage;
44 import android.content.Context;
45 import android.net.ConnectivityManager;
46 import android.net.ConnectivityManager.NetworkCallback;
47 import android.net.DhcpInfo;
48 import android.net.DhcpOption;
49 import android.net.LinkProperties;
50 import android.net.MacAddress;
51 import android.net.Network;
52 import android.net.NetworkCapabilities;
53 import android.net.NetworkRequest;
54 import android.net.NetworkStack;
55 import android.net.Uri;
56 import android.net.wifi.hotspot2.IProvisioningCallback;
57 import android.net.wifi.hotspot2.OsuProvider;
58 import android.net.wifi.hotspot2.PasspointConfiguration;
59 import android.net.wifi.hotspot2.ProvisioningCallback;
60 import android.net.wifi.p2p.WifiP2pConfig;
61 import android.net.wifi.p2p.WifiP2pManager;
62 import android.os.Binder;
63 import android.os.Build;
64 import android.os.Bundle;
65 import android.os.Handler;
66 import android.os.IBinder;
67 import android.os.Looper;
68 import android.os.Parcel;
69 import android.os.Parcelable;
70 import android.os.RemoteException;
71 import android.os.WorkSource;
72 import android.os.connectivity.WifiActivityEnergyInfo;
73 import android.telephony.SubscriptionInfo;
74 import android.telephony.TelephonyManager;
75 import android.text.TextUtils;
76 import android.util.ArraySet;
77 import android.util.CloseGuard;
78 import android.util.Log;
79 import android.util.Pair;
80 import android.util.SparseArray;
81 
82 import androidx.annotation.RequiresApi;
83 
84 import com.android.internal.annotations.GuardedBy;
85 import com.android.internal.annotations.VisibleForTesting;
86 import com.android.modules.utils.HandlerExecutor;
87 import com.android.modules.utils.ParceledListSlice;
88 import com.android.modules.utils.build.SdkLevel;
89 
90 import java.lang.annotation.Retention;
91 import java.lang.annotation.RetentionPolicy;
92 import java.lang.ref.Reference;
93 import java.lang.ref.WeakReference;
94 import java.net.InetAddress;
95 import java.time.Duration;
96 import java.util.ArrayList;
97 import java.util.Arrays;
98 import java.util.Collections;
99 import java.util.HashMap;
100 import java.util.List;
101 import java.util.Map;
102 import java.util.Objects;
103 import java.util.Set;
104 import java.util.StringTokenizer;
105 import java.util.concurrent.Executor;
106 import java.util.function.BiConsumer;
107 import java.util.function.Consumer;
108 
109 /**
110  * This class provides the primary API for managing all aspects of Wi-Fi
111  * connectivity.
112  * <p>
113  * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
114  * should only be obtained from an {@linkplain Context#getApplicationContext()
115  * application context}, and not from any other derived context to avoid memory
116  * leaks within the calling process.
117  * <p>
118  * It deals with several categories of items:
119  * </p>
120  * <ul>
121  * <li>The list of configured networks. The list can be viewed and updated, and
122  * attributes of individual entries can be modified.</li>
123  * <li>The currently active Wi-Fi network, if any. Connectivity can be
124  * established or torn down, and dynamic information about the state of the
125  * network can be queried.</li>
126  * <li>Results of access point scans, containing enough information to make
127  * decisions about what access point to connect to.</li>
128  * <li>It defines the names of various Intent actions that are broadcast upon
129  * any sort of change in Wi-Fi state.
130  * </ul>
131  * <p>
132  * This is the API to use when performing Wi-Fi specific operations. To perform
133  * operations that pertain to network connectivity at an abstract level, use
134  * {@link android.net.ConnectivityManager}.
135  * </p>
136  */
137 @SystemService(Context.WIFI_SERVICE)
138 public class WifiManager {
139 
140     private static final String TAG = "WifiManager";
141 
142     /**
143      * Local networks should not be modified by B&R since the user may have
144      * updated it with the latest configurations.
145      * @hide
146      */
147     @ChangeId
148     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
149     public static final long NOT_OVERRIDE_EXISTING_NETWORKS_ON_RESTORE = 234793325L;
150 
151     // Supplicant error codes:
152     /**
153      * The error code if there was a problem authenticating.
154      * @deprecated This is no longer supported.
155      */
156     @Deprecated
157     public static final int ERROR_AUTHENTICATING = 1;
158 
159     /**
160      * The reason code if there is no error during authentication.
161      * It could also imply that there no authentication in progress,
162      * this reason code also serves as a reset value.
163      * @deprecated This is no longer supported.
164      * @hide
165      */
166     @Deprecated
167     public static final int ERROR_AUTH_FAILURE_NONE = 0;
168 
169     /**
170      * The reason code if there was a timeout authenticating.
171      * @deprecated This is no longer supported.
172      * @hide
173      */
174     @Deprecated
175     public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
176 
177     /**
178      * The reason code if there was a wrong password while
179      * authenticating.
180      * @deprecated This is no longer supported.
181      * @hide
182      */
183     @Deprecated
184     public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
185 
186     /**
187      * The reason code if there was EAP failure while
188      * authenticating.
189      * @deprecated This is no longer supported.
190      * @hide
191      */
192     @Deprecated
193     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
194 
195     /** @hide */
196     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM = 256;
197 
198     /** @hide */
199     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM = 1024;
200 
201     /**
202      * Reason code if all of the network suggestions were successfully added or removed.
203      */
204     public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0;
205 
206     /**
207      * Reason code if there was an internal error in the platform while processing the addition or
208      * removal of suggestions.
209      */
210     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1;
211 
212     /**
213      * Reason code if the user has disallowed "android:change_wifi_state" app-ops from the app.
214      * @see android.app.AppOpsManager#unsafeCheckOp(String, int, String).
215      */
216     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2;
217 
218     /**
219      * Reason code if one or more of the network suggestions added already exists in platform's
220      * database.
221      * Note: this code will not be returned with Android 11 as in-place modification is allowed,
222      * please check {@link #addNetworkSuggestions(List)}.
223      * @see WifiNetworkSuggestion#equals(Object)
224      */
225     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
226 
227     /**
228      * Reason code if the number of network suggestions provided by the app crosses the max
229      * threshold set per app.
230      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} if
231      * the total size exceeds the limit.
232      * @see #getMaxNumberOfNetworkSuggestionsPerApp()
233      */
234     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
235 
236     /**
237      * Reason code if one or more of the network suggestions removed does not exist in platform's
238      * database.
239      * The framework won't remove any suggestions if one or more of suggestions provided
240      * by {@link #removeNetworkSuggestions(List)} does not exist in database.
241      * @see WifiNetworkSuggestion#equals(Object)
242      */
243     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
244 
245     /**
246      * Reason code if one or more of the network suggestions added is not allowed.
247      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
248      * if one or more of them is not allowed.
249      * This error may be caused by suggestion is using SIM-based encryption method, but calling app
250      * is not carrier privileged.
251      */
252     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6;
253 
254     /**
255      * Reason code if one or more of the network suggestions added is invalid. Framework will reject
256      * all the suggestions in the list.
257      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
258      * if one or more of them is invalid.
259      * Please use {@link WifiNetworkSuggestion.Builder} to create network suggestions.
260      */
261     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7;
262 
263     /**
264      * Reason code if {@link android.os.UserManager#DISALLOW_ADD_WIFI_CONFIG} user restriction
265      * is set and calling app is restricted by device admin.
266      */
267     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_RESTRICTED_BY_ADMIN = 8;
268 
269     /** @hide */
270     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
271             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
272             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
273             STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED,
274             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
275             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
276             STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
277             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED,
278             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
279             STATUS_NETWORK_SUGGESTIONS_ERROR_RESTRICTED_BY_ADMIN,
280     })
281     @Retention(RetentionPolicy.SOURCE)
282     public @interface NetworkSuggestionsStatusCode {}
283 
284     /**
285      * Reason code if suggested network connection attempt failed with an unknown failure.
286      */
287     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN = 0;
288     /**
289      * Reason code if suggested network connection attempt failed with association failure.
290      */
291     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1;
292     /**
293      * Reason code if suggested network connection attempt failed with an authentication failure.
294      */
295     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2;
296     /**
297      * Reason code if suggested network connection attempt failed with an IP provision failure.
298      */
299     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3;
300 
301     /** @hide */
302     @IntDef(prefix = {"STATUS_SUGGESTION_CONNECTION_FAILURE_"},
303             value = {STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN,
304                     STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION,
305                     STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION,
306                     STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING
307     })
308     @Retention(RetentionPolicy.SOURCE)
309     public @interface SuggestionConnectionStatusCode {}
310 
311     /**
312      * Reason code if local-only network connection attempt failed with an unknown failure.
313      */
314     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_UNKNOWN = 0;
315     /**
316      * Reason code if local-only network connection attempt failed with association failure.
317      */
318     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_ASSOCIATION = 1;
319     /**
320      * Reason code if local-only network connection attempt failed with an authentication failure.
321      */
322     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION = 2;
323     /**
324      * Reason code if local-only network connection attempt failed with an IP provisioning failure.
325      */
326     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_IP_PROVISIONING = 3;
327     /**
328      * Reason code if local-only network connection attempt failed with AP not in range.
329      */
330     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NOT_FOUND = 4;
331     /**
332      * Reason code if local-only network connection attempt failed with AP not responding
333      */
334     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NO_RESPONSE = 5;
335 
336     /** @hide */
337     @IntDef(prefix = {"STATUS_LOCAL_ONLY_CONNECTION_FAILURE_"},
338             value = {STATUS_LOCAL_ONLY_CONNECTION_FAILURE_UNKNOWN,
339                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_ASSOCIATION,
340                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION,
341                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_IP_PROVISIONING,
342                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NOT_FOUND,
343                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NO_RESPONSE
344             })
345     @Retention(RetentionPolicy.SOURCE)
346     public @interface LocalOnlyConnectionStatusCode {}
347 
348     /**
349      * Status code if suggestion approval status is unknown, an App which hasn't made any
350      * suggestions will get this code.
351      */
352     public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0;
353 
354     /**
355      * Status code if the calling app is still pending user approval for suggestions.
356      */
357     public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1;
358 
359     /**
360      * Status code if the calling app got the user approval for suggestions.
361      */
362     public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2;
363 
364     /**
365      * Status code if the calling app suggestions were rejected by the user.
366      */
367     public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3;
368 
369     /**
370      * Status code if the calling app was approved by virtue of being a carrier privileged app.
371      * @see TelephonyManager#hasCarrierPrivileges().
372      */
373     public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4;
374 
375     /** @hide */
376     @IntDef(prefix = {"STATUS_SUGGESTION_APPROVAL_"},
377             value = {STATUS_SUGGESTION_APPROVAL_UNKNOWN,
378                     STATUS_SUGGESTION_APPROVAL_PENDING,
379                     STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
380                     STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER,
381                     STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE
382             })
383     @Retention(RetentionPolicy.SOURCE)
384     public @interface SuggestionUserApprovalStatus {}
385 
386     /**
387      * If one of the removed suggestions is currently connected, that network will be disconnected
388      * after a short delay as opposed to immediately (which will be done by
389      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT}). The {@link ConnectivityManager} may call the
390      * {@link NetworkCallback#onLosing(Network, int)} on such networks.
391      */
392     public static final int ACTION_REMOVE_SUGGESTION_LINGER = 1;
393 
394     /**
395      * If one of the removed suggestions is currently connected, trigger an immediate disconnect
396      * after suggestions removal
397      */
398     public static final int ACTION_REMOVE_SUGGESTION_DISCONNECT = 2;
399 
400     /** @hide */
401     @IntDef(prefix = {"ACTION_REMOVE_SUGGESTION_"},
402             value = {ACTION_REMOVE_SUGGESTION_LINGER,
403                     ACTION_REMOVE_SUGGESTION_DISCONNECT
404             })
405     @Retention(RetentionPolicy.SOURCE)
406     public @interface ActionAfterRemovingSuggestion {}
407 
408     /**
409      * Only available on Android S or later.
410      * @hide
411      **/
412     public static final String EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE =
413             "EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE";
414 
415     /**
416      * Broadcast intent action indicating whether Wi-Fi scanning is currently available.
417      * Available extras:
418      * - {@link #EXTRA_SCAN_AVAILABLE}
419      */
420     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
421     public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED =
422             "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
423 
424     /**
425      * A boolean extra indicating whether scanning is currently available.
426      * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABILITY_CHANGED}.
427      * Its value is true if scanning is currently available, false otherwise.
428      */
429     public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
430 
431     /**
432      * Broadcast intent action indicating that the credential of a Wi-Fi network
433      * has been changed. One extra provides the ssid of the network. Another
434      * extra provides the event type, whether the credential is saved or forgot.
435      * @hide
436      */
437     @SystemApi
438     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
439             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
440     /** @hide */
441     @SystemApi
442     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
443     /** @hide */
444     @SystemApi
445     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
446     /** @hide */
447     @SystemApi
448     public static final int WIFI_CREDENTIAL_SAVED = 0;
449     /** @hide */
450     @SystemApi
451     public static final int WIFI_CREDENTIAL_FORGOT = 1;
452 
453     /** @hide */
454     @SystemApi
455     public static final int PASSPOINT_HOME_NETWORK = 0;
456 
457     /** @hide */
458     @SystemApi
459     public static final int PASSPOINT_ROAMING_NETWORK = 1;
460 
461     /** @hide */
462     @Retention(RetentionPolicy.SOURCE)
463     @IntDef(value = {
464             API_SCANNING_ENABLED,
465             API_WIFI_ENABLED,
466             API_SOFT_AP,
467             API_TETHERED_HOTSPOT,
468             API_AUTOJOIN_GLOBAL,
469             API_SET_SCAN_SCHEDULE,
470             API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY,
471             API_SET_NETWORK_SELECTION_CONFIG,
472             API_SET_THIRD_PARTY_APPS_ENABLING_WIFI_CONFIRMATION_DIALOG,
473             API_ADD_NETWORK,
474             API_UPDATE_NETWORK,
475             API_ALLOW_AUTOJOIN,
476             API_CONNECT_CONFIG,
477             API_CONNECT_NETWORK_ID,
478             API_DISABLE_NETWORK,
479             API_ENABLE_NETWORK,
480             API_FORGET,
481             API_SAVE,
482             API_START_SCAN,
483             API_START_LOCAL_ONLY_HOTSPOT,
484             API_P2P_DISCOVER_PEERS,
485             API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS,
486             API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY,
487             API_P2P_STOP_PEER_DISCOVERY,
488             API_P2P_CONNECT,
489             API_P2P_CANCEL_CONNECT,
490             API_P2P_CREATE_GROUP,
491             API_P2P_CREATE_GROUP_P2P_CONFIG,
492             API_P2P_REMOVE_GROUP,
493             API_P2P_START_LISTENING,
494             API_P2P_STOP_LISTENING,
495             API_P2P_SET_CHANNELS,
496             API_WIFI_SCANNER_START_SCAN,
497             API_SET_TDLS_ENABLED,
498             API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS
499     })
500     public @interface ApiType {}
501 
502     /**
503      * A constant used in
504      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
505      * Tracks usage of {@link WifiScanner#setScanningEnabled(boolean)}
506      * @hide
507      */
508     @SystemApi
509     public static final int API_SCANNING_ENABLED = 1;
510     /**
511      * A constant used in
512      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
513      * Tracks usage of {@link WifiManager#setWifiEnabled(boolean)} .
514      * @hide
515      */
516     @SystemApi
517     public static final int API_WIFI_ENABLED = 2;
518     /**
519      * A constant used in
520      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
521      * Tracks usage of {@link WifiManager#startSoftAp(WifiConfiguration)} and
522      * {@link WifiManager#stopSoftAp()}.
523      * @hide
524      */
525     @SystemApi
526     public static final int API_SOFT_AP = 3;
527     /**
528      * A constant used in
529      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
530      * Tracks usage of {@link WifiManager#startTetheredHotspot(SoftApConfiguration)}.
531      * @hide
532      */
533     @SystemApi
534     public static final int API_TETHERED_HOTSPOT = 4;
535     /**
536      * A constant used in
537      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
538      * Tracks usage of {@link WifiManager#allowAutojoinGlobal(boolean)}.
539      * @hide
540      */
541     @SystemApi
542     public static final int API_AUTOJOIN_GLOBAL = 5;
543     /**
544      * A constant used in
545      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
546      * Tracks usage of {@link WifiManager#setScreenOnScanSchedule(List)}.
547      * @hide
548      */
549     @SystemApi
550     public static final int API_SET_SCAN_SCHEDULE = 6;
551 
552     /**
553      * A constant used in
554      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
555      * Tracks usage of {@link WifiManager#setOneShotScreenOnConnectivityScanDelayMillis(int)}.
556      * @hide
557      */
558     @SystemApi
559     public static final int API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY = 7;
560 
561     /**
562      * A constant used in
563      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
564      * Tracks usage of
565      * {@link WifiManager#setNetworkSelectionConfig(WifiNetworkSelectionConfig)}
566      * @hide
567      */
568     @SystemApi
569     public static final int API_SET_NETWORK_SELECTION_CONFIG = 8;
570 
571     /**
572      * A constant used in
573      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
574      * Tracks usage of
575      * {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)}
576      * @hide
577      */
578     @SystemApi
579     public static final int API_SET_THIRD_PARTY_APPS_ENABLING_WIFI_CONFIRMATION_DIALOG = 9;
580 
581     /**
582      * A constant used in
583      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
584      * Tracks usage of
585      * {@link WifiManager#addNetwork(WifiConfiguration)}
586      * @hide
587      */
588     @SystemApi
589     public static final int API_ADD_NETWORK = 10;
590 
591     /**
592      * A constant used in
593      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
594      * Tracks usage of
595      * {@link WifiManager#updateNetwork(WifiConfiguration)}
596      * @hide
597      */
598     @SystemApi
599     public static final int API_UPDATE_NETWORK = 11;
600 
601     /**
602      * A constant used in
603      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
604      * Tracks usage of
605      * {@link WifiManager#allowAutojoin(int, boolean)}
606      * @hide
607      */
608     @SystemApi
609     public static final int API_ALLOW_AUTOJOIN = 12;
610 
611     /**
612      * A constant used in
613      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
614      * Tracks usage of
615      * {@link WifiManager#connect(WifiConfiguration, ActionListener)}
616      * @hide
617      */
618     @SystemApi
619     public static final int API_CONNECT_CONFIG = 13;
620 
621     /**
622      * A constant used in
623      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
624      * Tracks usage of
625      * {@link WifiManager#connect(int, ActionListener)}
626      * @hide
627      */
628     @SystemApi
629     public static final int API_CONNECT_NETWORK_ID = 14;
630 
631     /**
632      * A constant used in
633      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
634      * Tracks usage of
635      * {@link WifiManager#disableNetwork(int)}
636      * @hide
637      */
638     @SystemApi
639     public static final int API_DISABLE_NETWORK = 15;
640 
641     /**
642      * A constant used in
643      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
644      * Tracks usage of
645      * {@link WifiManager#enableNetwork(int, boolean)}
646      * @hide
647      */
648     @SystemApi
649     public static final int API_ENABLE_NETWORK = 16;
650 
651     /**
652      * A constant used in
653      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
654      * Tracks usage of
655      * {@link WifiManager#forget(int, ActionListener)}
656      * @hide
657      */
658     @SystemApi
659     public static final int API_FORGET = 17;
660 
661     /**
662      * A constant used in
663      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
664      * Tracks usage of
665      * {@link WifiManager#save(WifiConfiguration, ActionListener)}
666      * @hide
667      */
668     @SystemApi
669     public static final int API_SAVE = 18;
670 
671     /**
672      * A constant used in
673      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
674      * Tracks usage of
675      * {@link WifiManager#startScan()}
676      * @hide
677      */
678     @SystemApi
679     public static final int API_START_SCAN = 19;
680 
681     /**
682      * A constant used in
683      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
684      * Tracks usage of
685      * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}
686      * @hide
687      */
688     @SystemApi
689     public static final int API_START_LOCAL_ONLY_HOTSPOT = 20;
690 
691     /**
692      * A constant used in
693      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
694      * Tracks usage of
695      * {@link WifiP2pManager#discoverPeers(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
696      * @hide
697      */
698     @SystemApi
699     public static final int API_P2P_DISCOVER_PEERS = 21;
700 
701     /**
702      * A constant used in
703      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
704      * Tracks usage of
705      * {@link WifiP2pManager#discoverPeersOnSocialChannels(WifiP2pManager.Channel,
706      * WifiP2pManager.ActionListener)}
707      * @hide
708      */
709     @SystemApi
710     public static final int API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS = 22;
711 
712     /**
713      * A constant used in
714      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
715      * Tracks usage of
716      * {@link WifiP2pManager#discoverPeersOnSpecificFrequency(WifiP2pManager.Channel, int,
717      * WifiP2pManager.ActionListener)}
718      * @hide
719      */
720     @SystemApi
721     public static final int API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY = 23;
722 
723     /**
724      * A constant used in
725      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
726      * Tracks usage of
727      * {@link WifiP2pManager#stopPeerDiscovery(WifiP2pManager.Channel,
728      * WifiP2pManager.ActionListener)}
729      * @hide
730      */
731     @SystemApi
732     public static final int API_P2P_STOP_PEER_DISCOVERY = 24;
733 
734     /**
735      * A constant used in
736      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
737      * Tracks usage of
738      * {@link WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
739      * WifiP2pManager.ActionListener)}
740      * @hide
741      */
742     @SystemApi
743     public static final int API_P2P_CONNECT = 25;
744 
745     /**
746      * A constant used in
747      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
748      * Tracks usage of
749      * {@link WifiP2pManager#cancelConnect(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
750      * @hide
751      */
752     @SystemApi
753     public static final int API_P2P_CANCEL_CONNECT = 26;
754 
755     /**
756      * A constant used in
757      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
758      * Tracks usage of
759      * {@link WifiP2pManager#createGroup(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
760      * @hide
761      */
762     @SystemApi
763     public static final int API_P2P_CREATE_GROUP = 27;
764 
765     /**
766      * A constant used in
767      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
768      * Tracks usage of
769      * {@link WifiP2pManager#createGroup(WifiP2pManager.Channel, WifiP2pConfig,
770      * WifiP2pManager.ActionListener)}
771      * @hide
772      */
773     @SystemApi
774     public static final int API_P2P_CREATE_GROUP_P2P_CONFIG = 28;
775 
776     /**
777      * A constant used in
778      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
779      * Tracks usage of
780      * {@link WifiP2pManager#removeGroup(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
781      * @hide
782      */
783     @SystemApi
784     public static final int API_P2P_REMOVE_GROUP = 29;
785 
786     /**
787      * A constant used in
788      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
789      * Tracks usage of
790      * {@link WifiP2pManager#startListening(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
791      * @hide
792      */
793     @SystemApi
794     public static final int API_P2P_START_LISTENING = 30;
795 
796     /**
797      * A constant used in
798      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
799      * Tracks usage of
800      * {@link WifiP2pManager#stopListening(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
801      * @hide
802      */
803     @SystemApi
804     public static final int API_P2P_STOP_LISTENING = 31;
805 
806     /**
807      * A constant used in
808      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
809      * Tracks usage of
810      * {@link WifiP2pManager#setWifiP2pChannels(WifiP2pManager.Channel, int, int,
811      * WifiP2pManager.ActionListener)}
812      * @hide
813      */
814     @SystemApi
815     public static final int API_P2P_SET_CHANNELS = 32;
816 
817     /**
818      * A constant used in
819      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
820      * Tracks usage of
821      * {@link WifiScanner#startScan(WifiScanner.ScanSettings, WifiScanner.ScanListener)}
822      * @hide
823      */
824     @SystemApi
825     public static final int API_WIFI_SCANNER_START_SCAN = 33;
826 
827     /**
828      * A constant used in
829      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
830      * Tracks usage of
831      * {@link WifiManager#setTdlsEnabled(InetAddress, boolean)} and
832      * {@link WifiManager#setTdlsEnabled(InetAddress, boolean, Executor, Consumer)}
833      * @hide
834      */
835     @SystemApi
836     public static final int API_SET_TDLS_ENABLED = 34;
837 
838     /**
839      * A constant used in
840      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
841      * Tracks usage of
842      * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean)} and
843      * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
844      * @hide
845      */
846     @SystemApi
847     public static final int API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS = 35;
848 
849     /**
850      * Used internally to keep track of boundary.
851      * @hide
852      */
853     public static final int API_MAX = 36;
854 
855     /**
856      * Broadcast intent action indicating that a Passpoint provider icon has been received.
857      *
858      * Included extras:
859      * {@link #EXTRA_BSSID_LONG}
860      * {@link #EXTRA_FILENAME}
861      * {@link #EXTRA_ICON}
862      *
863      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
864      *
865      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
866      * components will be launched.
867      *
868      * @hide
869      */
870     public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
871     /**
872      * BSSID of an AP in long representation.  The {@link #EXTRA_BSSID} contains BSSID in
873      * String representation.
874      *
875      * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}.
876      *
877      * @hide
878      */
879     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
880     /**
881      * Icon data.
882      *
883      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
884      * {@link android.graphics.drawable.Icon}.
885      *
886      * @hide
887      */
888     public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
889     /**
890      * Name of a file.
891      *
892      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
893      *
894      * @hide
895      */
896     public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
897 
898     /**
899      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
900      *
901      * Included extras:
902      * {@link #EXTRA_BSSID_LONG}
903      * {@link #EXTRA_ANQP_ELEMENT_DATA}
904      *
905      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
906      *
907      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
908      * components will be launched.
909      *
910      * @hide
911      */
912     public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
913             "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
914     /**
915      * Raw binary data of an ANQP (Access Network Query Protocol) element.
916      *
917      * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}.
918      *
919      * @hide
920      */
921     public static final String EXTRA_ANQP_ELEMENT_DATA =
922             "android.net.wifi.extra.ANQP_ELEMENT_DATA";
923 
924     /**
925      * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
926      *
927      * Included extras:
928      * {@link #EXTRA_BSSID_LONG}
929      * {@link #EXTRA_ESS}
930      * {@link #EXTRA_DELAY}
931      * {@link #EXTRA_URL}
932      *
933      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
934      *
935      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
936      * components will be launched.
937      *
938      * @hide
939      */
940     public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
941             "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
942     /**
943      * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to
944      * {@code true} for ESS.
945      *
946      * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}.
947      *
948      * @hide
949      */
950     public static final String EXTRA_ESS = "android.net.wifi.extra.ESS";
951     /**
952      * Delay in seconds.
953      *
954      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
955      *
956      * @hide
957      */
958     public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
959 
960     /**
961      * Broadcast intent action indicating a Passpoint subscription remediation frame has been
962      * received.
963      *
964      * Included extras:
965      * {@link #EXTRA_BSSID_LONG}
966      * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD}
967      * {@link #EXTRA_URL}
968      *
969      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
970      *
971      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
972      * components will be launched.
973      *
974      * @hide
975      */
976     public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
977             "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
978     /**
979      * The protocol supported by the subscription remediation server. The possible values are:
980      * 0 - OMA DM
981      * 1 - SOAP XML SPP
982      *
983      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
984      *
985      * @hide
986      */
987     public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD =
988             "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
989 
990     /**
991      * Activity Action: Receiver should launch Passpoint OSU (Online Sign Up) view.
992      * Included extras:
993      *
994      * {@link #EXTRA_OSU_NETWORK}: {@link Network} instance associated with OSU AP.
995      * {@link #EXTRA_URL}: String representation of a server URL used for OSU process.
996      *
997      * @hide
998      */
999     @SystemApi
1000     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1001     public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW =
1002             "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
1003 
1004     /**
1005      * The lookup key for a {@link android.net.Network} associated with a Passpoint OSU server.
1006      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
1007      *
1008      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1009      *
1010      * @hide
1011      */
1012     @SystemApi
1013     public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
1014 
1015     /**
1016      * String representation of an URL for Passpoint OSU.
1017      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
1018      *
1019      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
1020      *
1021      * @hide
1022      */
1023     @SystemApi
1024     public static final String EXTRA_URL = "android.net.wifi.extra.URL";
1025 
1026     /**
1027      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
1028      * enabling, disabling, or unknown. One extra provides this state as an int.
1029      * Another extra provides the previous state, if available.  No network-related
1030      * permissions are required to subscribe to this broadcast.
1031      *
1032      * <p class="note">This broadcast is not delivered to manifest receivers in
1033      * applications that target API version 26 or later.
1034      *
1035      * @see #EXTRA_WIFI_STATE
1036      * @see #EXTRA_PREVIOUS_WIFI_STATE
1037      */
1038     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1039     public static final String WIFI_STATE_CHANGED_ACTION =
1040         "android.net.wifi.WIFI_STATE_CHANGED";
1041     /**
1042      * The lookup key for an int that indicates whether Wi-Fi is enabled,
1043      * disabled, enabling, disabling, or unknown.  Retrieve it with
1044      * {@link android.content.Intent#getIntExtra(String,int)}.
1045      *
1046      * @see #WIFI_STATE_DISABLED
1047      * @see #WIFI_STATE_DISABLING
1048      * @see #WIFI_STATE_ENABLED
1049      * @see #WIFI_STATE_ENABLING
1050      * @see #WIFI_STATE_UNKNOWN
1051      */
1052     public static final String EXTRA_WIFI_STATE = "wifi_state";
1053     /**
1054      * The previous Wi-Fi state.
1055      *
1056      * @see #EXTRA_WIFI_STATE
1057      */
1058     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
1059 
1060     /**
1061      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
1062      * it finishes successfully.
1063      *
1064      * @see #WIFI_STATE_CHANGED_ACTION
1065      * @see #getWifiState()
1066      */
1067     public static final int WIFI_STATE_DISABLING = 0;
1068     /**
1069      * Wi-Fi is disabled.
1070      *
1071      * @see #WIFI_STATE_CHANGED_ACTION
1072      * @see #getWifiState()
1073      */
1074     public static final int WIFI_STATE_DISABLED = 1;
1075     /**
1076      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
1077      * it finishes successfully.
1078      *
1079      * @see #WIFI_STATE_CHANGED_ACTION
1080      * @see #getWifiState()
1081      */
1082     public static final int WIFI_STATE_ENABLING = 2;
1083     /**
1084      * Wi-Fi is enabled.
1085      *
1086      * @see #WIFI_STATE_CHANGED_ACTION
1087      * @see #getWifiState()
1088      */
1089     public static final int WIFI_STATE_ENABLED = 3;
1090     /**
1091      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
1092      * or disabling.
1093      *
1094      * @see #WIFI_STATE_CHANGED_ACTION
1095      * @see #getWifiState()
1096      */
1097     public static final int WIFI_STATE_UNKNOWN = 4;
1098 
1099     /**
1100      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
1101      * enabling, disabling, or failed.
1102      *
1103      * @hide
1104      */
1105     @SystemApi
1106     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
1107     public static final String WIFI_AP_STATE_CHANGED_ACTION =
1108         "android.net.wifi.WIFI_AP_STATE_CHANGED";
1109 
1110     /**
1111      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
1112      * disabled, enabling, disabling, or failed.  Retrieve it with
1113      * {@link android.content.Intent#getIntExtra(String,int)}.
1114      *
1115      * @see #WIFI_AP_STATE_DISABLED
1116      * @see #WIFI_AP_STATE_DISABLING
1117      * @see #WIFI_AP_STATE_ENABLED
1118      * @see #WIFI_AP_STATE_ENABLING
1119      * @see #WIFI_AP_STATE_FAILED
1120      *
1121      * @hide
1122      */
1123     @SystemApi
1124     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
1125 
1126     /**
1127      * An extra containing the int error code for Soft AP start failure.
1128      * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
1129      * {@link android.content.Intent#getIntExtra}.
1130      * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
1131      * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
1132      *
1133      * The error code will be one of:
1134      * {@link #SAP_START_FAILURE_GENERAL},
1135      * {@link #SAP_START_FAILURE_NO_CHANNEL},
1136      * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
1137      * {@link #SAP_START_FAILURE_USER_REJECTED}
1138      *
1139      * @hide
1140      */
1141     @SystemApi
1142     public static final String EXTRA_WIFI_AP_FAILURE_REASON =
1143             "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
1144     /**
1145      * The previous Wi-Fi state.
1146      *
1147      * @see #EXTRA_WIFI_AP_STATE
1148      *
1149      * @hide
1150      */
1151     @SystemApi
1152     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
1153     /**
1154      * The lookup key for a String extra that stores the interface name used for the Soft AP.
1155      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
1156      * Retrieve its value with {@link android.content.Intent#getStringExtra(String)}.
1157      *
1158      * @hide
1159      */
1160     @SystemApi
1161     public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
1162             "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
1163     /**
1164      * The lookup key for an int extra that stores the intended IP mode for this Soft AP.
1165      * One of {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
1166      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
1167      * Retrieve its value with {@link android.content.Intent#getIntExtra(String, int)}.
1168      *
1169      * @hide
1170      */
1171     @SystemApi
1172     public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
1173 
1174     /** @hide */
1175     @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
1176         WIFI_AP_STATE_DISABLING,
1177         WIFI_AP_STATE_DISABLED,
1178         WIFI_AP_STATE_ENABLING,
1179         WIFI_AP_STATE_ENABLED,
1180         WIFI_AP_STATE_FAILED,
1181     })
1182     @Retention(RetentionPolicy.SOURCE)
1183     public @interface WifiApState {}
1184 
1185     /**
1186      * Wi-Fi AP is currently being disabled. The state will change to
1187      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
1188      *
1189      * @see #WIFI_AP_STATE_CHANGED_ACTION
1190      * @see #getWifiApState()
1191      *
1192      * @hide
1193      */
1194     @SystemApi
1195     public static final int WIFI_AP_STATE_DISABLING = 10;
1196     /**
1197      * Wi-Fi AP is disabled.
1198      *
1199      * @see #WIFI_AP_STATE_CHANGED_ACTION
1200      * @see #getWifiState()
1201      *
1202      * @hide
1203      */
1204     @SystemApi
1205     public static final int WIFI_AP_STATE_DISABLED = 11;
1206     /**
1207      * Wi-Fi AP is currently being enabled. The state will change to
1208      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
1209      *
1210      * @see #WIFI_AP_STATE_CHANGED_ACTION
1211      * @see #getWifiApState()
1212      *
1213      * @hide
1214      */
1215     @SystemApi
1216     public static final int WIFI_AP_STATE_ENABLING = 12;
1217     /**
1218      * Wi-Fi AP is enabled.
1219      *
1220      * @see #WIFI_AP_STATE_CHANGED_ACTION
1221      * @see #getWifiApState()
1222      *
1223      * @hide
1224      */
1225     @SystemApi
1226     public static final int WIFI_AP_STATE_ENABLED = 13;
1227     /**
1228      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
1229      * enabling or disabling
1230      *
1231      * @see #WIFI_AP_STATE_CHANGED_ACTION
1232      * @see #getWifiApState()
1233      *
1234      * @hide
1235      */
1236     @SystemApi
1237     public static final int WIFI_AP_STATE_FAILED = 14;
1238 
1239     /** @hide */
1240     @IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = {
1241         SAP_START_FAILURE_GENERAL,
1242         SAP_START_FAILURE_NO_CHANNEL,
1243         SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION,
1244         SAP_START_FAILURE_USER_REJECTED,
1245     })
1246     @Retention(RetentionPolicy.SOURCE)
1247     public @interface SapStartFailure {}
1248 
1249     /**
1250      *  All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL},
1251      *  {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}, and
1252      *  {@link #SAP_START_FAILURE_USER_REJECTED}.
1253      *
1254      *  @hide
1255      */
1256     @SystemApi
1257     public static final int SAP_START_FAILURE_GENERAL= 0;
1258 
1259     /**
1260      *  If Wi-Fi AP start failed, this reason code means that no legal channel exists on user
1261      *  selected band due to regulatory constraints.
1262      *
1263      *  @hide
1264      */
1265     @SystemApi
1266     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
1267 
1268     /**
1269      *  If Wi-Fi AP start failed, this reason code means that the specified configuration
1270      *  is not supported by the current HAL version.
1271      *
1272      *  @hide
1273      */
1274     @SystemApi
1275     public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2;
1276 
1277     /**
1278      *  If Wi-Fi AP start failed, this reason code means that the user was asked for confirmation to
1279      *  create the AP and the user declined.
1280      *
1281      *  @hide
1282      */
1283     @SystemApi
1284     public static final int SAP_START_FAILURE_USER_REJECTED = 3;
1285 
1286     /** @hide */
1287     @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = {
1288         SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER,
1289         SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS,
1290     })
1291     @Retention(RetentionPolicy.SOURCE)
1292     public @interface SapClientBlockedReason {}
1293 
1294     /**
1295      *  If Soft Ap client is blocked, this reason code means that client doesn't exist in the
1296      *  specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
1297      *  and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
1298      *  and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
1299      *  is configured as well.
1300      *  @hide
1301      */
1302     @SystemApi
1303     public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0;
1304 
1305     /**
1306      *  If Soft Ap client is blocked, this reason code means that no more clients can be
1307      *  associated to this AP since it reached maximum capacity. The maximum capacity is
1308      *  the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and
1309      *  {@link SoftApCapability#getMaxSupportedClients} which get from
1310      *  {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}.
1311      *
1312      *  @hide
1313      */
1314     @SystemApi
1315     public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1;
1316 
1317     /**
1318      * Client disconnected for unspecified reason. This could for example be because the AP is being
1319      * shut down.
1320      * @hide
1321      */
1322     public static final int SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED = 2;
1323 
1324     /** @hide */
1325     @Retention(RetentionPolicy.SOURCE)
1326     @IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
1327             IFACE_IP_MODE_UNSPECIFIED,
1328             IFACE_IP_MODE_CONFIGURATION_ERROR,
1329             IFACE_IP_MODE_TETHERED,
1330             IFACE_IP_MODE_LOCAL_ONLY})
1331     public @interface IfaceIpMode {}
1332 
1333     /**
1334      * Interface IP mode unspecified.
1335      *
1336      * @see #updateInterfaceIpState(String, int)
1337      *
1338      * @hide
1339      */
1340     @SystemApi
1341     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
1342 
1343     /**
1344      * Interface IP mode for configuration error.
1345      *
1346      * @see #updateInterfaceIpState(String, int)
1347      *
1348      * @hide
1349      */
1350     @SystemApi
1351     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
1352 
1353     /**
1354      * Interface IP mode for tethering.
1355      *
1356      * @see #updateInterfaceIpState(String, int)
1357      *
1358      * @hide
1359      */
1360     @SystemApi
1361     public static final int IFACE_IP_MODE_TETHERED = 1;
1362 
1363     /**
1364      * Interface IP mode for Local Only Hotspot.
1365      *
1366      * @see #updateInterfaceIpState(String, int)
1367      *
1368      * @hide
1369      */
1370     @SystemApi
1371     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
1372 
1373     /**
1374      * Broadcast intent action indicating that the wifi network settings
1375      * had been reset.
1376      *
1377      * Note: This intent is sent as a directed broadcast to each manifest registered receiver.
1378      * Intent will not be received by dynamically registered receivers.
1379      * @hide
1380      */
1381     @SystemApi
1382     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
1383     public static final String ACTION_NETWORK_SETTINGS_RESET =
1384             "android.net.wifi.action.NETWORK_SETTINGS_RESET";
1385 
1386     /**
1387      * Broadcast intent action indicating that the wifi network profiles provisioned
1388      * may need refresh.
1389      *
1390      * Note: This intent is sent as a directed broadcast to each manifest registered receiver;
1391      * And restricted to those apps which have the NETWORK_CARRIER_PROVISIONING permission.
1392      * Intent will not be received by dynamically registered receivers.
1393      * @hide
1394      */
1395     @SystemApi
1396     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
1397     public static final String ACTION_REFRESH_USER_PROVISIONING =
1398             "android.net.wifi.action.REFRESH_USER_PROVISIONING";
1399 
1400     /**
1401      * Broadcast intent action indicating that a connection to the supplicant has
1402      * been established (and it is now possible
1403      * to perform Wi-Fi operations) or the connection to the supplicant has been
1404      * lost. One extra provides the connection state as a boolean, where {@code true}
1405      * means CONNECTED.
1406      * @deprecated This is no longer supported.
1407      * @see #EXTRA_SUPPLICANT_CONNECTED
1408      */
1409     @Deprecated
1410     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1411     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
1412         "android.net.wifi.supplicant.CONNECTION_CHANGE";
1413     /**
1414      * The lookup key for a boolean that indicates whether a connection to
1415      * the supplicant daemon has been gained or lost. {@code true} means
1416      * a connection now exists.
1417      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
1418      * @deprecated This is no longer supported.
1419      */
1420     @Deprecated
1421     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
1422     /**
1423      * Broadcast intent action indicating that the state of Wi-Fi connectivity
1424      * has changed. An extra provides the new state
1425      * in the form of a {@link android.net.NetworkInfo} object.  No network-related
1426      * permissions are required to subscribe to this broadcast.
1427      *
1428      * <p class="note">This broadcast is not delivered to manifest receivers in
1429      * applications that target API version 26 or later.
1430      * @see #EXTRA_NETWORK_INFO
1431      */
1432     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1433     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
1434     /**
1435      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
1436      * Wi-Fi network. Retrieve with
1437      * {@link android.content.Intent#getParcelableExtra(String)}.
1438      */
1439     public static final String EXTRA_NETWORK_INFO = "networkInfo";
1440     /**
1441      * The lookup key for a String giving the BSSID of the access point to which
1442      * we are connected. No longer used.
1443      */
1444     @Deprecated
1445     public static final String EXTRA_BSSID = "bssid";
1446     /**
1447      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
1448      * information about the access point to which we are connected.
1449      * No longer used.
1450      */
1451     @Deprecated
1452     public static final String EXTRA_WIFI_INFO = "wifiInfo";
1453     /**
1454      * Broadcast intent action indicating that the state of establishing a connection to
1455      * an access point has changed.One extra provides the new
1456      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
1457      * is not generally the most useful thing to look at if you are just interested in
1458      * the overall state of connectivity.
1459      * @see #EXTRA_NEW_STATE
1460      * @see #EXTRA_SUPPLICANT_ERROR
1461      * @deprecated This is no longer supported.
1462      */
1463     @Deprecated
1464     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1465     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
1466         "android.net.wifi.supplicant.STATE_CHANGE";
1467     /**
1468      * The lookup key for a {@link SupplicantState} describing the new state
1469      * Retrieve with
1470      * {@link android.content.Intent#getParcelableExtra(String)}.
1471      * @deprecated This is no longer supported.
1472      */
1473     @Deprecated
1474     public static final String EXTRA_NEW_STATE = "newState";
1475 
1476     /**
1477      * The lookup key for a {@link SupplicantState} describing the supplicant
1478      * error code if any
1479      * Retrieve with
1480      * {@link android.content.Intent#getIntExtra(String, int)}.
1481      * @see #ERROR_AUTHENTICATING
1482      * @deprecated This is no longer supported.
1483      */
1484     @Deprecated
1485     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
1486 
1487     /**
1488      * The lookup key for a {@link SupplicantState} describing the supplicant
1489      * error reason if any
1490      * Retrieve with
1491      * {@link android.content.Intent#getIntExtra(String, int)}.
1492      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
1493      * @deprecated This is no longer supported.
1494      * @hide
1495      */
1496     @Deprecated
1497     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
1498 
1499     /**
1500      * Broadcast intent action indicating that the configured networks changed.
1501      * This can be as a result of adding/updating/deleting a network.
1502      * <br />
1503      * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
1504      * {@link #EXTRA_WIFI_CONFIGURATION} is never set beginning in
1505      * {@link android.os.Build.VERSION_CODES#R}.
1506      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
1507      * its value is always true beginning in {@link android.os.Build.VERSION_CODES#R}, even if only
1508      * a single network changed.
1509      * <br />
1510      * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
1511      * required to receive this broadcast.
1512      *
1513      * @hide
1514      */
1515     @SystemApi
1516     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
1517         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
1518     /**
1519      * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
1520      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
1521      * broadcast is sent.
1522      * @deprecated This extra is never set beginning in {@link android.os.Build.VERSION_CODES#R},
1523      * regardless of the target SDK version. Use {@link #getConfiguredNetworks} to get the full list
1524      * of configured networks.
1525      * @hide
1526      */
1527     @Deprecated
1528     @SystemApi
1529     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
1530     /**
1531      * Multiple network configurations have changed.
1532      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
1533      * @deprecated This extra's value is always true beginning in
1534      * {@link android.os.Build.VERSION_CODES#R}, regardless of the target SDK version.
1535      * @hide
1536      */
1537     @Deprecated
1538     @SystemApi
1539     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
1540     /**
1541      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
1542      * has changed. One of {@link #CHANGE_REASON_ADDED}, {@link #CHANGE_REASON_REMOVED},
1543      * {@link #CHANGE_REASON_CONFIG_CHANGE}.
1544      *
1545      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
1546      * @hide
1547      */
1548     @SystemApi
1549     public static final String EXTRA_CHANGE_REASON = "changeReason";
1550     /**
1551      * The configuration is new and was added.
1552      * @hide
1553      */
1554     @SystemApi
1555     public static final int CHANGE_REASON_ADDED = 0;
1556     /**
1557      * The configuration was removed and is no longer present in the system's list of
1558      * configured networks.
1559      * @hide
1560      */
1561     @SystemApi
1562     public static final int CHANGE_REASON_REMOVED = 1;
1563     /**
1564      * The configuration has changed as a result of explicit action or because the system
1565      * took an automated action such as disabling a malfunctioning configuration.
1566      * @hide
1567      */
1568     @SystemApi
1569     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
1570     /**
1571      * An access point scan has completed, and results are available.
1572      * Call {@link #getScanResults()} to obtain the results.
1573      * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
1574      * and a {@code boolean} value indicating if the scan was successful.
1575      */
1576     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1577     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
1578 
1579     /**
1580      * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
1581      * representing if the scan was successful or not.
1582      * Scans may fail for multiple reasons, these may include:
1583      * <ol>
1584      * <li>An app requested too many scans in a certain period of time.
1585      * This may lead to additional scan request rejections via "scan throttling" for both
1586      * foreground and background apps.
1587      * Note: Apps holding android.Manifest.permission.NETWORK_SETTINGS permission are
1588      * exempted from scan throttling.
1589      * </li>
1590      * <li>The device is idle and scanning is disabled.</li>
1591      * <li>Wifi hardware reported a scan failure.</li>
1592      * </ol>
1593      * @return true scan was successful, results are updated
1594      * @return false scan was not successful, results haven't been updated since previous scan
1595      */
1596     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
1597 
1598     /**
1599      * A batch of access point scans has been completed and the results areavailable.
1600      * Call {@link #getBatchedScanResults()} to obtain the results.
1601      * @deprecated This API is nolonger supported.
1602      * Use {@link WifiScanner} API
1603      * @hide
1604      */
1605     @Deprecated
1606     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1607     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
1608             "android.net.wifi.BATCHED_RESULTS";
1609 
1610     /**
1611      * The RSSI (signal strength) has changed.
1612      *
1613      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1614      * @see #EXTRA_NEW_RSSI
1615      */
1616     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1617     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
1618     /**
1619      * The lookup key for an {@code int} giving the new RSSI in dBm.
1620      */
1621     public static final String EXTRA_NEW_RSSI = "newRssi";
1622 
1623     /**
1624      * @see #ACTION_LINK_CONFIGURATION_CHANGED
1625      * @hide
1626      */
1627     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1628     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
1629             "android.net.wifi.LINK_CONFIGURATION_CHANGED";
1630 
1631     /**
1632      * Broadcast intent action indicating that the link configuration changed on wifi.
1633      * <br /> No permissions are required to listen to this broadcast.
1634      * @hide
1635      */
1636     @SystemApi
1637     public static final String ACTION_LINK_CONFIGURATION_CHANGED =
1638             // should be android.net.wifi.action.LINK_CONFIGURATION_CHANGED, but due to
1639             // @UnsupportedAppUsage leaving it as android.net.wifi.LINK_CONFIGURATION_CHANGED.
1640             LINK_CONFIGURATION_CHANGED_ACTION;
1641 
1642     /**
1643      * The lookup key for a {@link android.net.LinkProperties} object associated with the
1644      * Wi-Fi network.
1645      * Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
1646      *
1647      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1648      *
1649      * @deprecated this extra is no longer populated.
1650      *
1651      * @hide
1652      */
1653     @Deprecated
1654     @SystemApi
1655     public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
1656 
1657     /**
1658      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
1659      * Wi-Fi network. Retrieve with
1660      * {@link android.content.Intent#getParcelableExtra(String)}.
1661      * @hide
1662      */
1663     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
1664 
1665     /**
1666      * The network IDs of the configured networks could have changed.
1667      */
1668     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1669     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
1670 
1671     /**
1672      * Activity Action: Show a system activity that allows the user to enable
1673      * scans to be available even with Wi-Fi turned off.
1674      *
1675      * <p>Notification of the result of this activity is posted using the
1676      * {@link android.app.Activity#onActivityResult} callback. The
1677      * <code>resultCode</code>
1678      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
1679      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
1680      * has rejected the request or an error has occurred.
1681      */
1682     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1683     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
1684             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
1685 
1686     /**
1687      * Activity Action: Pick a Wi-Fi network to connect to.
1688      * <p>Input: Nothing.
1689      * <p>Output: Nothing.
1690      */
1691     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1692     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
1693 
1694     /**
1695      * Activity Action: Receiver should show UI to get user approval to enable WiFi.
1696      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1697      *           the name of the app requesting the action.
1698      * <p>Output: Nothing.
1699      * <p>No permissions are required to send this action.
1700      * @hide
1701      */
1702     @SystemApi
1703     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1704     public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
1705 
1706     /**
1707      * Activity Action: Receiver should show UI to get user approval to disable WiFi.
1708      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1709      *           the name of the app requesting the action.
1710      * <p>Output: Nothing.
1711      * <p>No permissions are required to send this action.
1712      * @hide
1713      */
1714     @SystemApi
1715     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1716     public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
1717 
1718     /**
1719      * Directed broadcast intent action indicating that the device has connected to one of the
1720      * network suggestions provided by the app. This will be sent post connection to a network
1721      * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
1722      * boolean)}
1723      * flag set.
1724      * <p>
1725      * Note: The broadcast is sent to the app only if it holds
1726      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
1727      *
1728      * @see #EXTRA_NETWORK_SUGGESTION
1729      */
1730     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1731     public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION =
1732             "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
1733     /**
1734      * Sent as as a part of {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} that holds
1735      * an instance of {@link WifiNetworkSuggestion} corresponding to the connected network.
1736      */
1737     public static final String EXTRA_NETWORK_SUGGESTION =
1738             "android.net.wifi.extra.NETWORK_SUGGESTION";
1739 
1740     /**
1741      * Internally used Wi-Fi lock mode representing the case were no locks are held.
1742      * @hide
1743      */
1744     public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
1745 
1746     /**
1747      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1748      * and will behave normally, i.e., it will attempt to automatically
1749      * establish a connection to a remembered access point that is
1750      * within range, and will do periodic scans if there are remembered
1751      * access points but none are in range.
1752      *
1753      * @deprecated This API is non-functional and will have no impact.
1754      */
1755     @Deprecated
1756     public static final int WIFI_MODE_FULL = 1;
1757 
1758     /**
1759      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1760      * but the only operation that will be supported is initiation of
1761      * scans, and the subsequent reporting of scan results. No attempts
1762      * will be made to automatically connect to remembered access points,
1763      * nor will periodic scans be automatically performed looking for
1764      * remembered access points. Scans must be explicitly requested by
1765      * an application in this mode.
1766      *
1767      * @deprecated This API is non-functional and will have no impact.
1768      */
1769     @Deprecated
1770     public static final int WIFI_MODE_SCAN_ONLY = 2;
1771 
1772     /**
1773      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
1774      * This results in operating with low packet latency.
1775      * The lock is only active when the device is connected to an access point.
1776      * The lock is active even when the device screen is off or the acquiring application is
1777      * running in the background.
1778      * This mode will consume more power and hence should be used only
1779      * when there is a need for this tradeoff.
1780      * <p>
1781      * An example use case is when a voice connection needs to be
1782      * kept active even after the device screen goes off.
1783      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
1784      * duration of the voice call may improve the call quality.
1785      * <p>
1786      * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
1787      * lock will have no impact.
1788      *
1789      * @deprecated The {@code WIFI_MODE_FULL_HIGH_PERF} is deprecated and is automatically replaced
1790      * with {@link #WIFI_MODE_FULL_LOW_LATENCY} with all the restrictions documented on that lock.
1791      * I.e. any request to the {@code WIFI_MODE_FULL_HIGH_PERF} will now obtain a
1792      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock instead.
1793      * Deprecation is due to the impact of {@code WIFI_MODE_FULL_HIGH_PERF} on power dissipation.
1794      * The {@link #WIFI_MODE_FULL_LOW_LATENCY} provides much of the same desired functionality with
1795      * less impact on power dissipation.
1796      */
1797     @Deprecated
1798     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
1799 
1800     /**
1801      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
1802      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock has the following limitations:
1803      * <ol>
1804      * <li>The lock is only active when the device is connected to an access point.</li>
1805      * <li>The lock is only active when the screen is on.</li>
1806      * <li>The lock is only active when the acquiring app is running in the foreground.</li>
1807      * </ol>
1808      * Low latency mode optimizes for reduced packet latency,
1809      * and as a result other performance measures may suffer when there are trade-offs to make:
1810      * <ol>
1811      * <li>Battery life may be reduced.</li>
1812      * <li>Throughput may be reduced.</li>
1813      * <li>Frequency of Wi-Fi scanning may be reduced. This may result in: </li>
1814      * <ul>
1815      * <li>The device may not roam or switch to the AP with highest signal quality.</li>
1816      * <li>Location accuracy may be reduced.</li>
1817      * </ul>
1818      * </ol>
1819      * <p>
1820      * Example use cases are real time gaming or virtual reality applications where
1821      * low latency is a key factor for user experience.
1822      * <p>
1823      * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and
1824      * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY}
1825      * lock will be effective when app is running in foreground and screen is on,
1826      * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
1827      */
1828     public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
1829 
1830 
1831     /** Anything worse than or equal to this will show 0 bars. */
1832     @UnsupportedAppUsage
1833     private static final int MIN_RSSI = -100;
1834 
1835     /** Anything better than or equal to this will show the max bars. */
1836     @UnsupportedAppUsage
1837     private static final int MAX_RSSI = -55;
1838 
1839     /**
1840      * Number of RSSI levels used in the framework to initiate {@link #RSSI_CHANGED_ACTION}
1841      * broadcast, where each level corresponds to a range of RSSI values.
1842      * The {@link #RSSI_CHANGED_ACTION} broadcast will only fire if the RSSI
1843      * change is significant enough to change the RSSI signal level.
1844      * @hide
1845      */
1846     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1847     public static final int RSSI_LEVELS = 5;
1848 
1849     //TODO (b/146346676): This needs to be removed, not used in the code.
1850     /**
1851      * Auto settings in the driver. The driver could choose to operate on both
1852      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
1853      * @hide
1854      */
1855     @UnsupportedAppUsage
1856     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
1857 
1858     /**
1859      * Operation on 5 GHz alone
1860      * @hide
1861      */
1862     @UnsupportedAppUsage
1863     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
1864 
1865     /**
1866      * Operation on 2.4 GHz alone
1867      * @hide
1868      */
1869     @UnsupportedAppUsage
1870     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
1871 
1872     /** @hide */
1873     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
1874 
1875     /**
1876      * Maximum number of active locks we allow.
1877      * This limit was added to prevent apps from creating a ridiculous number
1878      * of locks and crashing the system by overflowing the global ref table.
1879      */
1880     private static final int MAX_ACTIVE_LOCKS = 50;
1881 
1882     /** Indicates an invalid SSID. */
1883     public static final String UNKNOWN_SSID = "<unknown ssid>";
1884 
1885     /** @hide */
1886     public static final MacAddress ALL_ZEROS_MAC_ADDRESS =
1887             MacAddress.fromString("00:00:00:00:00:00");
1888 
1889     /** @hide */
1890     @IntDef(flag = false, prefix = { "WIFI_MULTI_INTERNET_MODE_" }, value = {
1891         WIFI_MULTI_INTERNET_MODE_DISABLED,
1892         WIFI_MULTI_INTERNET_MODE_DBS_AP,
1893         WIFI_MULTI_INTERNET_MODE_MULTI_AP,
1894     })
1895     @Retention(RetentionPolicy.SOURCE)
1896     public @interface WifiMultiInternetMode {}
1897 
1898     /**
1899      * Wi-Fi simultaneous connection to multiple internet-providing Wi-Fi networks (APs) is
1900      * disabled.
1901      *
1902      * @see #getStaConcurrencyForMultiInternetMode()
1903      *
1904      */
1905     public static final int WIFI_MULTI_INTERNET_MODE_DISABLED = 0;
1906     /**
1907      * Wi-Fi simultaneous connection to multiple internet-providing Wi-FI networks (APs) is enabled
1908      * and restricted to a single network on different bands (e.g. a DBS AP).
1909      *
1910      * @see #getStaConcurrencyForMultiInternetMode()
1911      *
1912      */
1913     public static final int WIFI_MULTI_INTERNET_MODE_DBS_AP = 1;
1914     /**
1915      * Wi-Fi simultaneous connection to multiple internet-providing Wi-Fi networks (APs) is enabled.
1916      * The device can connect to any networks/APs - it is just restricted to using different bands
1917      * for individual connections.
1918      *
1919      * @see #getStaConcurrencyForMultiInternetMode()
1920      *
1921      */
1922     public static final int WIFI_MULTI_INTERNET_MODE_MULTI_AP = 2;
1923 
1924     /**
1925      * The bundle key string for the channel frequency in MHz.
1926      * See {@link #getChannelData(Executor, Consumer)}
1927      */
1928     public static final String CHANNEL_DATA_KEY_FREQUENCY_MHZ = "CHANNEL_DATA_KEY_FREQUENCY_MHZ";
1929     /**
1930      * The bundle key for the number of APs found on the corresponding channel specified by
1931      * {@link WifiManager#CHANNEL_DATA_KEY_FREQUENCY_MHZ}.
1932      * See {@link #getChannelData(Executor, Consumer)}
1933      */
1934     public static final String CHANNEL_DATA_KEY_NUM_AP = "CHANNEL_DATA_KEY_NUM_AP";
1935 
1936     /**
1937      * This policy is being tracked by the Wifi service.
1938      * Indicates success for {@link #addQosPolicies(List, Executor, Consumer)}.
1939      * @hide
1940      */
1941     @SystemApi
1942     public static final int QOS_REQUEST_STATUS_TRACKING = 0;
1943 
1944     /**
1945      * A policy with the same policy ID is already being tracked.
1946      * @hide
1947      */
1948     @SystemApi
1949     public static final int QOS_REQUEST_STATUS_ALREADY_ACTIVE = 1;
1950 
1951     /**
1952      * There are insufficient resources to handle this request at this time.
1953      * @hide
1954      */
1955     @SystemApi
1956     public static final int QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES = 2;
1957 
1958     /**
1959      * The parameters in the policy request are invalid.
1960      * @hide
1961      */
1962     @SystemApi
1963     public static final int QOS_REQUEST_STATUS_INVALID_PARAMETERS = 3;
1964 
1965     /**
1966      * An unspecified failure occurred while processing this request.
1967      * @hide
1968      */
1969     @SystemApi
1970     public static final int QOS_REQUEST_STATUS_FAILURE_UNKNOWN = 4;
1971 
1972     /** @hide */
1973     @Retention(RetentionPolicy.SOURCE)
1974     @IntDef(prefix = {"QOS_REQUEST_STATUS_"}, value = {
1975             QOS_REQUEST_STATUS_TRACKING,
1976             QOS_REQUEST_STATUS_ALREADY_ACTIVE,
1977             QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES,
1978             QOS_REQUEST_STATUS_INVALID_PARAMETERS,
1979             QOS_REQUEST_STATUS_FAILURE_UNKNOWN})
1980     public @interface QosRequestStatus {}
1981 
1982     /**
1983      * Maximum number of policies that can be included in a QoS add/remove request.
1984      */
1985     private static final int MAX_POLICIES_PER_QOS_REQUEST = 16;
1986 
1987     /**
1988      * Get the maximum number of policies that can be included in a request to
1989      * {@link #addQosPolicies(List, Executor, Consumer)} or {@link #removeQosPolicies(int[])}.
1990      * @hide
1991      */
1992     @SystemApi
getMaxNumberOfPoliciesPerQosRequest()1993     public static int getMaxNumberOfPoliciesPerQosRequest() {
1994         return MAX_POLICIES_PER_QOS_REQUEST;
1995     }
1996 
1997     /* Number of currently active WifiLocks and MulticastLocks */
1998     @UnsupportedAppUsage
1999     private int mActiveLockCount;
2000 
2001     private Context mContext;
2002     @UnsupportedAppUsage
2003     IWifiManager mService;
2004     private final int mTargetSdkVersion;
2005 
2006     private Looper mLooper;
2007     private boolean mVerboseLoggingEnabled = false;
2008 
2009     private final Object mLock = new Object(); // lock guarding access to the following vars
2010     @GuardedBy("mLock")
2011     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
2012     @GuardedBy("mLock")
2013     private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
2014 
2015     private static final SparseArray<IOnWifiUsabilityStatsListener>
2016             sOnWifiUsabilityStatsListenerMap = new SparseArray();
2017     private static final SparseArray<ISuggestionConnectionStatusListener>
2018             sSuggestionConnectionStatusListenerMap = new SparseArray();
2019     private static final SparseArray<ISuggestionUserApprovalStatusListener>
2020             sSuggestionUserApprovalStatusListenerMap = new SparseArray();
2021     private static final SparseArray<IWifiVerboseLoggingStatusChangedListener>
2022             sWifiVerboseLoggingStatusChangedListenerMap = new SparseArray();
2023     private static final SparseArray<INetworkRequestMatchCallback>
2024             sNetworkRequestMatchCallbackMap = new SparseArray();
2025     private static final SparseArray<ITrafficStateCallback>
2026             sTrafficStateCallbackMap = new SparseArray();
2027     private static final SparseArray<ISoftApCallback> sSoftApCallbackMap = new SparseArray();
2028     private static final SparseArray<IOnWifiDriverCountryCodeChangedListener>
2029             sActiveCountryCodeChangedCallbackMap = new SparseArray();
2030     private static final SparseArray<ISoftApCallback>
2031             sLocalOnlyHotspotSoftApCallbackMap = new SparseArray();
2032     private static final SparseArray<ILocalOnlyConnectionStatusListener>
2033             sLocalOnlyConnectionStatusListenerMap = new SparseArray();
2034     private static final SparseArray<IWifiNetworkStateChangedListener>
2035             sOnWifiNetworkStateChangedListenerMap = new SparseArray<>();
2036     private static final SparseArray<IWifiLowLatencyLockListener>
2037             sWifiLowLatencyLockListenerMap = new SparseArray<>();
2038 
2039     /**
2040      * Multi-link operation (MLO) will allow Wi-Fi devices to operate on multiple links at the same
2041      * time through a single connection, aiming to support applications that require lower latency,
2042      * and higher capacity. Chip vendors have algorithms that run on the chip to use available links
2043      * based on incoming traffic and various inputs. Below is a list of Multi-Link Operation modes
2044      * that applications can suggest to be accommodated in the algorithm.
2045      *
2046      * The default MLO mode is for chip vendors to use algorithms to select the optimum links to
2047      * operate on, without any guidance from the calling app.
2048      *
2049      * @hide
2050      */
2051     @SystemApi
2052     public static final int MLO_MODE_DEFAULT = 0;
2053 
2054     /**
2055      * Low latency mode for Multi-link operation. In this mode, the chip vendor's algorithm
2056      * should select MLO links that will achieve low latency.
2057      *
2058      * @hide
2059      */
2060     @SystemApi
2061     public static final int MLO_MODE_LOW_LATENCY = 1;
2062 
2063     /**
2064      * High throughput mode for Multi-link operation. In this mode, the chip vendor's algorithm
2065      * should select MLO links that will achieve higher throughput.
2066      *
2067      * @hide
2068      */
2069     @SystemApi
2070     public static final int MLO_MODE_HIGH_THROUGHPUT = 2;
2071 
2072     /**
2073      * Low power mode for Multi-link operation. In this mode, the chip vendor's algorithm
2074      * should select MLO links that will achieve low power.
2075      *
2076      * @hide
2077      */
2078     @SystemApi
2079     public static final int MLO_MODE_LOW_POWER = 3;
2080 
2081     /** @hide */
2082     @Retention(RetentionPolicy.SOURCE)
2083     @IntDef(prefix = {"MLO_MODE_"}, value = {
2084             MLO_MODE_DEFAULT,
2085             MLO_MODE_LOW_LATENCY,
2086             MLO_MODE_HIGH_THROUGHPUT,
2087             MLO_MODE_LOW_POWER})
2088     public @interface MloMode {
2089     }
2090 
2091     /**
2092      * Create a new WifiManager instance.
2093      * Applications will almost always want to use
2094      * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve
2095      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
2096      *
2097      * @param context the application context
2098      * @param service the Binder interface
2099      * @param looper the Looper used to deliver callbacks
2100      * @hide - hide this because it takes in a parameter of type IWifiManager, which
2101      * is a system private class.
2102      */
WifiManager(@onNull Context context, @NonNull IWifiManager service, @NonNull Looper looper)2103     public WifiManager(@NonNull Context context, @NonNull IWifiManager service,
2104         @NonNull Looper looper) {
2105         mContext = context;
2106         mService = service;
2107         mLooper = looper;
2108         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
2109         updateVerboseLoggingEnabledFromService();
2110     }
2111 
2112     /**
2113      * Return a list of all the networks configured for the current foreground
2114      * user.
2115      *
2116      * Not all fields of WifiConfiguration are returned. Only the following
2117      * fields are filled in:
2118      * <ul>
2119      * <li>networkId</li>
2120      * <li>SSID</li>
2121      * <li>BSSID</li>
2122      * <li>priority</li>
2123      * <li>allowedProtocols</li>
2124      * <li>allowedKeyManagement</li>
2125      * <li>allowedAuthAlgorithms</li>
2126      * <li>allowedPairwiseCiphers</li>
2127      * <li>allowedGroupCiphers</li>
2128      * <li>status</li>
2129      * </ul>
2130      * @return a list of network configurations in the form of a list
2131      * of {@link WifiConfiguration} objects.
2132      *
2133      * @deprecated
2134      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2135      * mechanism to trigger connection to a Wi-Fi network.
2136      * b) See {@link #addNetworkSuggestions(List)},
2137      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2138      * when auto-connecting to wifi.
2139      * <b>Compatibility Note:</b> For applications targeting
2140      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return an
2141      * empty list.
2142      * <p>
2143      * Deprecation Exemptions:
2144      * <ul>
2145      * <li>Device Owner (DO), Profile Owner (PO) and system apps will have access to the full list.
2146      * <li>Callers with Carrier privilege will receive a restricted list only containing
2147      * configurations which they created.
2148      * </ul>
2149      */
2150     @Deprecated
2151     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
getConfiguredNetworks()2152     public List<WifiConfiguration> getConfiguredNetworks() {
2153         try {
2154             ParceledListSlice<WifiConfiguration> parceledList =
2155                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
2156                             mContext.getAttributionTag(), false);
2157             if (parceledList == null) {
2158                 return Collections.emptyList();
2159             }
2160             return parceledList.getList();
2161         } catch (RemoteException e) {
2162             throw e.rethrowFromSystemServer();
2163         }
2164     }
2165 
2166     /**
2167      * Return a list of all the networks previously configured by the calling app. Can
2168      * be called by Device Owner (DO), Profile Owner (PO), Callers with Carrier privilege and
2169      * system apps.
2170      *
2171      * @return a list of network configurations in the form of a list
2172      * of {@link WifiConfiguration} objects.
2173      * @throws SecurityException if the caller is not allowed to call this API
2174      */
2175     @RequiresPermission(ACCESS_WIFI_STATE)
2176     @NonNull
getCallerConfiguredNetworks()2177     public List<WifiConfiguration> getCallerConfiguredNetworks() {
2178         try {
2179             ParceledListSlice<WifiConfiguration> parceledList =
2180                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
2181                             mContext.getAttributionTag(), true);
2182             if (parceledList == null) {
2183                 return Collections.emptyList();
2184             }
2185             return parceledList.getList();
2186         } catch (RemoteException e) {
2187             throw e.rethrowFromSystemServer();
2188         }
2189     }
2190 
2191 
2192     /**
2193      * Applications targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later need to have
2194      * the following permissions: {@link android.Manifest.permission#NEARBY_WIFI_DEVICES},
2195      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
2196      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2197      * Applications targeting {@link Build.VERSION_CODES#S} or prior SDK levels need to have the
2198      * following permissions: {@link android.Manifest.permission#ACCESS_FINE_LOCATION},
2199      * {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
2200      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2201      * <p> See {@link #getPrivilegedConnectedNetwork()} to get the WifiConfiguration for only the
2202      * connected network that's providing internet by default.
2203      *
2204      * @hide
2205      **/
2206     @SystemApi
2207     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, NEARBY_WIFI_DEVICES, ACCESS_WIFI_STATE,
2208             READ_WIFI_CREDENTIAL},
2209             conditional = true)
getPrivilegedConfiguredNetworks()2210     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
2211         try {
2212             Bundle extras = new Bundle();
2213             if (SdkLevel.isAtLeastS()) {
2214                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
2215                         mContext.getAttributionSource());
2216             }
2217             ParceledListSlice<WifiConfiguration> parceledList =
2218                     mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
2219                             mContext.getAttributionTag(), extras);
2220             if (parceledList == null) {
2221                 return Collections.emptyList();
2222             }
2223             return parceledList.getList();
2224         } catch (RemoteException e) {
2225             throw e.rethrowFromSystemServer();
2226         }
2227     }
2228 
2229     /**
2230      * Gets the {@link WifiConfiguration} with credentials of the connected wifi network
2231      * that's providing internet by default.
2232      * <p>
2233      * On {@link android.os.Build.VERSION_CODES#TIRAMISU} or later SDKs, the caller need to have
2234      * the following permissions: {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2235      * android:usesPermissionFlags="neverForLocation",
2236      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
2237      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}. If the app does not have
2238      * android:usesPermissionFlags="neverForLocation", then it must also have
2239      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2240      * <p>
2241      * On {@link Build.VERSION_CODES#S} or prior SDKs, the caller need to have the
2242      * following permissions: {@link android.Manifest.permission#ACCESS_FINE_LOCATION},
2243      * {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
2244      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2245      *
2246      * @return The WifiConfiguration representation of the connected wifi network providing
2247      * internet, or null if wifi is not connected.
2248      *
2249      * @throws SecurityException if caller does not have the required permissions
2250      * @hide
2251      **/
2252     @SystemApi
2253     @RequiresPermission(allOf = {NEARBY_WIFI_DEVICES, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL},
2254             conditional = true)
2255     @Nullable
getPrivilegedConnectedNetwork()2256     public WifiConfiguration getPrivilegedConnectedNetwork() {
2257         try {
2258             Bundle extras = new Bundle();
2259             if (SdkLevel.isAtLeastS()) {
2260                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
2261                         mContext.getAttributionSource());
2262             }
2263             return mService.getPrivilegedConnectedNetwork(mContext.getOpPackageName(),
2264                     mContext.getAttributionTag(), extras);
2265         } catch (RemoteException e) {
2266             throw e.rethrowFromSystemServer();
2267         }
2268     }
2269 
2270     /**
2271      * Returns a list of all matching WifiConfigurations of PasspointConfiguration for a given list
2272      * of ScanResult.
2273      *
2274      * An empty list will be returned when no PasspointConfiguration are installed or if no
2275      * PasspointConfiguration match the ScanResult.
2276      *
2277      * @param scanResults a list of scanResult that represents the BSSID
2278      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
2279      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
2280      * @hide
2281      */
2282     @SystemApi
2283     @RequiresPermission(anyOf = {
2284             android.Manifest.permission.NETWORK_SETTINGS,
2285             android.Manifest.permission.NETWORK_SETUP_WIZARD
2286     })
2287     @NonNull
getAllMatchingWifiConfigs( @onNull List<ScanResult> scanResults)2288     public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
2289             @NonNull List<ScanResult> scanResults) {
2290         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
2291         try {
2292             Map<String, Map<Integer, List<ScanResult>>> results =
2293                     mService.getAllMatchingPasspointProfilesForScanResults(scanResults);
2294             if (results.isEmpty()) {
2295                 return configs;
2296             }
2297             List<WifiConfiguration> wifiConfigurations =
2298                     mService.getWifiConfigsForPasspointProfiles(
2299                             new ArrayList<>(results.keySet()));
2300             for (WifiConfiguration configuration : wifiConfigurations) {
2301                 Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
2302                         results.get(configuration.getProfileKey());
2303                 if (scanResultsPerNetworkType != null) {
2304                     configs.add(Pair.create(configuration, scanResultsPerNetworkType));
2305                 }
2306             }
2307         } catch (RemoteException e) {
2308             throw e.rethrowFromSystemServer();
2309         }
2310 
2311         return configs;
2312     }
2313 
2314     /**
2315      * To be used with setScreenOnScanSchedule.
2316      * @hide
2317      */
2318     @SystemApi
2319     public static class ScreenOnScanSchedule {
2320         private final Duration mScanInterval;
2321         private final int mScanType;
2322 
2323         /**
2324          * Creates a ScreenOnScanSchedule.
2325          * @param scanInterval Interval between framework-initiated connectivity scans.
2326          * @param scanType One of the {@code WifiScanner.SCAN_TYPE_} values.
2327          */
ScreenOnScanSchedule(@onNull Duration scanInterval, @WifiAnnotations.ScanType int scanType)2328         public ScreenOnScanSchedule(@NonNull Duration scanInterval,
2329                 @WifiAnnotations.ScanType int scanType) {
2330             if (scanInterval == null) {
2331                 throw new IllegalArgumentException("scanInterval can't be null");
2332             }
2333             mScanInterval = scanInterval;
2334             mScanType = scanType;
2335         }
2336 
2337         /**
2338          * Gets the interval between framework-initiated connectivity scans.
2339          */
getScanInterval()2340         public @NonNull Duration getScanInterval() {
2341             return mScanInterval;
2342         }
2343 
2344         /**
2345          * Gets the type of scan to be used. One of the {@code WifiScanner.SCAN_TYPE_} values.
2346          */
getScanType()2347         public @WifiAnnotations.ScanType int getScanType() {
2348             return mScanType;
2349         }
2350     }
2351 
2352     /**
2353      * This API allows a privileged app to customize the wifi framework's network selection logic.
2354      * To revert to default behavior, call this API with a {@link WifiNetworkSelectionConfig}
2355      * created from a default {@link WifiNetworkSelectionConfig.Builder}.
2356      *
2357      * Use {@link WifiManager#getNetworkSelectionConfig(Executor, Consumer)} to get the current
2358      * network selection configuration.
2359      * <P>
2360      * @param nsConfig an Object representing the network selection configuration being programmed.
2361      *                 This should be created with a {@link WifiNetworkSelectionConfig.Builder}.
2362      *
2363      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2364      * @throws IllegalArgumentException if input is invalid.
2365      * @throws SecurityException if the caller does not have permission.
2366      * @hide
2367      */
2368     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2369     @RequiresPermission(anyOf = {
2370             android.Manifest.permission.NETWORK_SETTINGS,
2371             MANAGE_WIFI_NETWORK_SELECTION
2372     })
2373     @SystemApi
setNetworkSelectionConfig(@onNull WifiNetworkSelectionConfig nsConfig)2374     public void setNetworkSelectionConfig(@NonNull WifiNetworkSelectionConfig nsConfig) {
2375         try {
2376             if (nsConfig == null) {
2377                 throw new IllegalArgumentException("nsConfig can not be null");
2378             }
2379             mService.setNetworkSelectionConfig(nsConfig);
2380         } catch (RemoteException e) {
2381             throw e.rethrowFromSystemServer();
2382         }
2383     }
2384 
2385     /**
2386      * This API allows a privileged app to retrieve the {@link WifiNetworkSelectionConfig}
2387      * currently being used by the network selector.
2388      *
2389      * Use {@link WifiManager#setNetworkSelectionConfig(WifiNetworkSelectionConfig)} to set a
2390      * new network selection configuration.
2391      * <P>
2392      * @param executor The executor on which callback will be invoked.
2393      * @param resultsCallback An asynchronous callback that will return
2394      *                        {@link WifiNetworkSelectionConfig}
2395      *
2396      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2397      * @throws SecurityException if the caller does not have permission.
2398      * @throws NullPointerException if the caller provided invalid inputs.
2399      * @hide
2400      */
2401     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2402     @RequiresPermission(anyOf = {
2403             android.Manifest.permission.NETWORK_SETTINGS,
2404             MANAGE_WIFI_NETWORK_SELECTION
2405     })
2406     @SystemApi
getNetworkSelectionConfig(@onNull @allbackExecutor Executor executor, @NonNull Consumer<WifiNetworkSelectionConfig> resultsCallback)2407     public void getNetworkSelectionConfig(@NonNull @CallbackExecutor Executor executor,
2408             @NonNull Consumer<WifiNetworkSelectionConfig> resultsCallback) {
2409         Objects.requireNonNull(executor, "executor cannot be null");
2410         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
2411         try {
2412             mService.getNetworkSelectionConfig(
2413                     new IWifiNetworkSelectionConfigListener.Stub() {
2414                         @Override
2415                         public void onResult(WifiNetworkSelectionConfig value) {
2416                             Binder.clearCallingIdentity();
2417                             executor.execute(() -> {
2418                                 resultsCallback.accept(value);
2419                             });
2420                         }
2421                     });
2422         } catch (RemoteException e) {
2423             throw e.rethrowFromSystemServer();
2424         }
2425     }
2426 
2427     /**
2428      * Allows a privileged app to enable/disable whether a confirmation dialog should be displayed
2429      * when third-party apps attempt to turn on WiFi.
2430      *
2431      * Use {@link #isThirdPartyAppEnablingWifiConfirmationDialogEnabled()} to get the
2432      * currently configured value.
2433      *
2434      * Note: Only affects behavior for apps with targetSDK < Q, since third party apps are not
2435      * allowed to enable wifi on targetSDK >= Q.
2436      *
2437      * This overrides the overlay value |config_showConfirmationDialogForThirdPartyAppsEnablingWifi|
2438      * <P>
2439      * @param enable true to enable the confirmation dialog, false otherwise
2440      *
2441      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2442      * @throws SecurityException if the caller does not have permission.
2443      * @hide
2444      */
2445     @RequiresPermission(anyOf = {
2446             android.Manifest.permission.NETWORK_SETTINGS,
2447             android.Manifest.permission.NETWORK_SETUP_WIZARD
2448     })
2449     @SystemApi
setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable)2450     public void setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable) {
2451         try {
2452             mService.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(enable);
2453         } catch (RemoteException e) {
2454             throw e.rethrowFromSystemServer();
2455         }
2456     }
2457 
2458     /**
2459      * Check whether the wifi configuration indicates that a confirmation dialog should be displayed
2460      * when third-party apps attempt to turn on WiFi.
2461      *
2462      * Use {@link #setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)} to set this
2463      * value.
2464      *
2465      * Note: This setting only affects behavior for apps with targetSDK < Q, since third party apps
2466      *       are not allowed to enable wifi on targetSDK >= Q.
2467      *
2468      * <P>
2469      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2470      * @throws SecurityException if the caller does not have permission.
2471      * @return true if dialog should be displayed, false otherwise.
2472      * @hide
2473      */
2474     @RequiresPermission(anyOf = {
2475             android.Manifest.permission.NETWORK_SETTINGS,
2476             android.Manifest.permission.NETWORK_SETUP_WIZARD
2477     })
2478     @SystemApi
isThirdPartyAppEnablingWifiConfirmationDialogEnabled()2479     public boolean isThirdPartyAppEnablingWifiConfirmationDialogEnabled() {
2480         try {
2481             return mService.isThirdPartyAppEnablingWifiConfirmationDialogEnabled();
2482         } catch (RemoteException e) {
2483             throw e.rethrowFromSystemServer();
2484         }
2485     }
2486 
2487     /**
2488      * Allows a privileged app to customize the screen-on scan behavior. When a non-null schedule
2489      * is set via this API, it will always get used instead of the scan schedules defined in the
2490      * overlay. When a null schedule is set via this API, the wifi subsystem will go back to using
2491      * the scan schedules defined in the overlay. Also note, the scan schedule will be truncated
2492      * (rounded down) to the nearest whole second.
2493      * <p>
2494      * Example usage:
2495      * The following call specifies that first scheduled scan should be in 20 seconds using
2496      * {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, and all
2497      * scheduled scans later should happen every 40 seconds using
2498      * {@link WifiScanner#SCAN_TYPE_LOW_POWER}.
2499      * <pre>
2500      * List<ScreenOnScanSchedule> schedule = new ArrayList<>();
2501      * schedule.add(new ScreenOnScanSchedule(Duration.ofSeconds(20),
2502      *         WifiScanner.SCAN_TYPE_HIGH_ACCURACY));
2503      * schedule.add(new ScreenOnScanSchedule(Duration.ofSeconds(40),
2504      *         WifiScanner.SCAN_TYPE_LOW_POWER));
2505      * wifiManager.setScreenOnScanSchedule(schedule);
2506      * </pre>
2507      * @param screenOnScanSchedule defines the screen-on scan schedule and the corresponding
2508      *                             scan type. Set to null to clear any previously set value.
2509      *
2510      * @throws IllegalStateException if input is invalid
2511      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2512      * @throws SecurityException if the caller does not have permission.
2513      * @hide
2514      */
2515     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2516     @RequiresPermission(anyOf = {
2517             android.Manifest.permission.NETWORK_SETTINGS,
2518             MANAGE_WIFI_NETWORK_SELECTION
2519     })
2520     @SystemApi
setScreenOnScanSchedule(@ullable List<ScreenOnScanSchedule> screenOnScanSchedule)2521     public void setScreenOnScanSchedule(@Nullable List<ScreenOnScanSchedule> screenOnScanSchedule) {
2522         try {
2523             if (screenOnScanSchedule == null) {
2524                 mService.setScreenOnScanSchedule(null, null);
2525                 return;
2526             }
2527             if (screenOnScanSchedule.isEmpty()) {
2528                 throw new IllegalArgumentException("The input should either be null or a non-empty"
2529                         + " list");
2530             }
2531             int[] scanSchedule = new int[screenOnScanSchedule.size()];
2532             int[] scanType = new int[screenOnScanSchedule.size()];
2533             for (int i = 0; i < screenOnScanSchedule.size(); i++) {
2534                 scanSchedule[i] = (int) screenOnScanSchedule.get(i).getScanInterval().toSeconds();
2535                 scanType[i] = screenOnScanSchedule.get(i).getScanType();
2536             }
2537             mService.setScreenOnScanSchedule(scanSchedule, scanType);
2538         } catch (RemoteException e) {
2539             throw e.rethrowFromSystemServer();
2540         }
2541     }
2542 
2543     /**
2544      * The Wi-Fi framework may trigger connectivity scans in response to the screen turning on for
2545      * network selection purposes. This API allows a privileged app to set a delay to the next
2546      * connectivity scan triggered by the Wi-Fi framework in response to the next screen-on event.
2547      * This gives a window for the privileged app to issue their own custom scans to influence Wi-Fi
2548      * network selection. The expected usage is the privileged app monitor for the screen turning
2549      * off, and then call this API if it believes delaying the next screen-on connectivity scan is
2550      * needed.
2551      * <p>
2552      * Note that this API will only delay screen-on connectivity scans once. This API will need to
2553      * be called again if further screen-on scan delays are needed after it resolves.
2554      * @param delayMs defines the time in milliseconds to delay the next screen-on connectivity
2555      *                scan. Setting this to 0 will remove the delay.
2556      *
2557      * @throws IllegalStateException if input is invalid
2558      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2559      * @throws SecurityException if the caller does not have permission.
2560      * @hide
2561      */
2562     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2563     @RequiresPermission(anyOf = {
2564             android.Manifest.permission.NETWORK_SETTINGS,
2565             MANAGE_WIFI_NETWORK_SELECTION
2566     })
2567     @SystemApi
setOneShotScreenOnConnectivityScanDelayMillis(@ntRangefrom = 0) int delayMs)2568     public void setOneShotScreenOnConnectivityScanDelayMillis(@IntRange(from = 0) int delayMs) {
2569         try {
2570             mService.setOneShotScreenOnConnectivityScanDelayMillis(delayMs);
2571         } catch (RemoteException e) {
2572             throw e.rethrowFromSystemServer();
2573         }
2574     }
2575 
2576     /**
2577      * Retrieve a list of {@link WifiConfiguration} for available {@link WifiNetworkSuggestion}
2578      * matching the given list of {@link ScanResult}.
2579      *
2580      * An available {@link WifiNetworkSuggestion} must satisfy:
2581      * <ul>
2582      * <li> Matching one of the {@link ScanResult} from the given list.
2583      * <li> and {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} set
2584      * to true.
2585      * </ul>
2586      *
2587      * @param scanResults a list of scanResult.
2588      * @return a list of @link WifiConfiguration} for available {@link WifiNetworkSuggestion}
2589      * @hide
2590      */
2591     @SystemApi
2592     @RequiresPermission(anyOf = {
2593             android.Manifest.permission.NETWORK_SETTINGS,
2594             android.Manifest.permission.NETWORK_SETUP_WIZARD
2595     })
2596     @NonNull
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( @onNull List<ScanResult> scanResults)2597     public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
2598             @NonNull List<ScanResult> scanResults) {
2599         try {
2600             return mService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults);
2601         } catch (RemoteException e) {
2602             throw e.rethrowAsRuntimeException();
2603         }
2604     }
2605 
2606     /**
2607      * Specify a set of SSIDs that will not get disabled internally by the Wi-Fi subsystem when
2608      * connection issues occur. To clear the list, call this API with an empty Set.
2609      * <p>
2610      * {@link #getSsidsAllowlist()} can be used to check the SSIDs that have been set.
2611      * @param ssids - list of WifiSsid that will not get disabled internally
2612      * @throws SecurityException if the calling app is not a Device Owner (DO), Profile Owner (PO),
2613      *                           or a privileged app that has one of the permissions required by
2614      *                           this API.
2615      * @throws IllegalArgumentException if the input is null.
2616      * @hide
2617      */
2618     @SystemApi
2619     @RequiresPermission(anyOf = {
2620             android.Manifest.permission.NETWORK_SETTINGS,
2621             android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional = true)
setSsidsAllowlist(@onNull Set<WifiSsid> ssids)2622     public void setSsidsAllowlist(@NonNull Set<WifiSsid> ssids) {
2623         if (ssids == null) {
2624             throw new IllegalArgumentException(TAG + ": ssids can not be null");
2625         }
2626         try {
2627             mService.setSsidsAllowlist(mContext.getOpPackageName(), new ArrayList<>(ssids));
2628         } catch (RemoteException e) {
2629             throw e.rethrowFromSystemServer();
2630         }
2631     }
2632 
2633     /**
2634      * Get the Set of SSIDs that will not get disabled internally by the Wi-Fi subsystem when
2635      * connection issues occur.
2636      * @throws SecurityException if the calling app is not a Device Owner (DO), Profile Owner (PO),
2637      *                           or a privileged app that has one of the permissions required by
2638      *                           this API.
2639      * @hide
2640      */
2641     @SystemApi
2642     @RequiresPermission(anyOf = {
2643             android.Manifest.permission.NETWORK_SETTINGS,
2644             android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional = true)
getSsidsAllowlist()2645     public @NonNull Set<WifiSsid> getSsidsAllowlist() {
2646         try {
2647             return new ArraySet<WifiSsid>(
2648                     mService.getSsidsAllowlist(mContext.getOpPackageName()));
2649         } catch (RemoteException e) {
2650             throw e.rethrowFromSystemServer();
2651         }
2652     }
2653 
2654     /**
2655      * Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
2656      * list of ScanResult.
2657      *
2658      * An empty list will be returned if no match is found.
2659      *
2660      * @param scanResults a list of ScanResult
2661      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
2662      * @hide
2663      */
2664     @SystemApi
2665     @RequiresPermission(anyOf = {
2666             android.Manifest.permission.NETWORK_SETTINGS,
2667             android.Manifest.permission.NETWORK_SETUP_WIZARD
2668     })
2669     @NonNull
getMatchingOsuProviders( @ullable List<ScanResult> scanResults)2670     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
2671             @Nullable List<ScanResult> scanResults) {
2672         if (scanResults == null) {
2673             return new HashMap<>();
2674         }
2675         try {
2676             return mService.getMatchingOsuProviders(scanResults);
2677         } catch (RemoteException e) {
2678             throw e.rethrowFromSystemServer();
2679         }
2680     }
2681 
2682     /**
2683      * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers.
2684      *
2685      * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2
2686      * configurations in the device.
2687      * An empty map will be returned when there is no matching Passpoint R2 configuration for the
2688      * given OsuProviders.
2689      *
2690      * @param osuProviders a set of {@link OsuProvider}
2691      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
2692      * @hide
2693      */
2694     @SystemApi
2695     @RequiresPermission(anyOf = {
2696             android.Manifest.permission.NETWORK_SETTINGS,
2697             android.Manifest.permission.NETWORK_SETUP_WIZARD
2698     })
2699     @NonNull
getMatchingPasspointConfigsForOsuProviders( @onNull Set<OsuProvider> osuProviders)2700     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
2701             @NonNull Set<OsuProvider> osuProviders) {
2702         try {
2703             return mService.getMatchingPasspointConfigsForOsuProviders(
2704                     new ArrayList<>(osuProviders));
2705         } catch (RemoteException e) {
2706             throw e.rethrowFromSystemServer();
2707         }
2708     }
2709 
2710     /**
2711      * Add a new network description to the set of configured networks.
2712      * The {@code networkId} field of the supplied configuration object
2713      * is ignored.
2714      * <p/>
2715      * The new network will be marked DISABLED by default. To enable it,
2716      * called {@link #enableNetwork}.
2717      *
2718      * @param config the set of variables that describe the configuration,
2719      *            contained in a {@link WifiConfiguration} object.
2720      *            If the {@link WifiConfiguration} has an Http Proxy set
2721      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
2722      * @return the ID of the newly created network description. This is used in
2723      *         other operations to specified the network to be acted upon.
2724      *         Returns {@code -1} on failure.
2725      *
2726      * @deprecated
2727      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2728      * mechanism to trigger connection to a Wi-Fi network.
2729      * b) See {@link #addNetworkSuggestions(List)},
2730      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2731      * when auto-connecting to wifi.
2732      * <b>Compatibility Note:</b> For applications targeting
2733      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2734      * {@code -1}.
2735      * <p>
2736      * Deprecation Exemptions:
2737      * <ul>
2738      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2739      * </ul>
2740      */
2741     @Deprecated
addNetwork(WifiConfiguration config)2742     public int addNetwork(WifiConfiguration config) {
2743         if (config == null) {
2744             return -1;
2745         }
2746         config.networkId = -1;
2747         return addOrUpdateNetwork(config);
2748     }
2749 
2750     /**
2751      * This is a new version of {@link #addNetwork(WifiConfiguration)} which returns more detailed
2752      * failure codes. The usage of this API is limited to Device Owner (DO), Profile Owner (PO),
2753      * system app, and privileged apps.
2754      * <p>
2755      * Add a new network description to the set of configured networks. The {@code networkId}
2756      * field of the supplied configuration object is ignored. The new network will be marked
2757      * DISABLED by default. To enable it, call {@link #enableNetwork}.
2758      * <p>
2759      * @param config the set of variables that describe the configuration,
2760      *            contained in a {@link WifiConfiguration} object.
2761      *            If the {@link WifiConfiguration} has an Http Proxy set
2762      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
2763      * @return A {@link AddNetworkResult} Object.
2764      * @throws SecurityException if the calling app is not a Device Owner (DO),
2765      *                           Profile Owner (PO), system app, or a privileged app that has one of
2766      *                           the permissions required by this API.
2767      * @throws IllegalArgumentException if the input configuration is null or if the
2768      *            security type in input configuration is not supported.
2769      */
2770     @RequiresPermission(anyOf = {
2771             android.Manifest.permission.NETWORK_SETTINGS,
2772             android.Manifest.permission.NETWORK_STACK,
2773             android.Manifest.permission.NETWORK_SETUP_WIZARD,
2774             android.Manifest.permission.NETWORK_MANAGED_PROVISIONING
2775             }, conditional = true)
2776     @NonNull
addNetworkPrivileged(@onNull WifiConfiguration config)2777     public AddNetworkResult addNetworkPrivileged(@NonNull WifiConfiguration config) {
2778         if (config == null) throw new IllegalArgumentException("config cannot be null");
2779         if (config.isSecurityType(WifiInfo.SECURITY_TYPE_DPP)
2780                 && !isFeatureSupported(WIFI_FEATURE_DPP_AKM)) {
2781             throw new IllegalArgumentException("dpp akm is not supported");
2782         }
2783         config.networkId = -1;
2784         try {
2785             return mService.addOrUpdateNetworkPrivileged(config, mContext.getOpPackageName());
2786         } catch (RemoteException e) {
2787             throw e.rethrowFromSystemServer();
2788         }
2789     }
2790 
2791     /**
2792      * Provides the results of a call to {@link #addNetworkPrivileged(WifiConfiguration)}
2793      */
2794     public static final class AddNetworkResult implements Parcelable {
2795         /**
2796          * The operation has completed successfully.
2797          */
2798         public static final int STATUS_SUCCESS = 0;
2799         /**
2800          * The operation has failed due to an unknown reason.
2801          */
2802         public static final int STATUS_FAILURE_UNKNOWN = 1;
2803         /**
2804          * The calling app does not have permission to call this API.
2805          */
2806         public static final int STATUS_NO_PERMISSION = 2;
2807         /**
2808          * Generic failure code for adding a passpoint network.
2809          */
2810         public static final int STATUS_ADD_PASSPOINT_FAILURE = 3;
2811         /**
2812          * Generic failure code for adding a non-passpoint network.
2813          */
2814         public static final int STATUS_ADD_WIFI_CONFIG_FAILURE = 4;
2815         /**
2816          * The network configuration is invalid.
2817          */
2818         public static final int STATUS_INVALID_CONFIGURATION = 5;
2819         /**
2820          * The calling app has no permission to modify the configuration.
2821          */
2822         public static final int STATUS_NO_PERMISSION_MODIFY_CONFIG = 6;
2823         /**
2824          * The calling app has no permission to modify the proxy setting.
2825          */
2826         public static final int STATUS_NO_PERMISSION_MODIFY_PROXY_SETTING = 7;
2827         /**
2828          * The calling app has no permission to modify the MAC randomization setting.
2829          */
2830         public static final int STATUS_NO_PERMISSION_MODIFY_MAC_RANDOMIZATION = 8;
2831         /**
2832          * Internal failure in updating network keys..
2833          */
2834         public static final int STATUS_FAILURE_UPDATE_NETWORK_KEYS = 9;
2835         /**
2836          * The enterprise network is missing either the root CA or domain name.
2837          */
2838         public static final int STATUS_INVALID_CONFIGURATION_ENTERPRISE = 10;
2839 
2840         /** @hide */
2841         @IntDef(prefix = { "STATUS_" }, value = {
2842                 STATUS_SUCCESS,
2843                 STATUS_FAILURE_UNKNOWN,
2844                 STATUS_NO_PERMISSION,
2845                 STATUS_ADD_PASSPOINT_FAILURE,
2846                 STATUS_ADD_WIFI_CONFIG_FAILURE,
2847                 STATUS_INVALID_CONFIGURATION,
2848                 STATUS_NO_PERMISSION_MODIFY_CONFIG,
2849                 STATUS_NO_PERMISSION_MODIFY_PROXY_SETTING,
2850                 STATUS_NO_PERMISSION_MODIFY_MAC_RANDOMIZATION,
2851                 STATUS_FAILURE_UPDATE_NETWORK_KEYS,
2852                 STATUS_INVALID_CONFIGURATION_ENTERPRISE,
2853         })
2854         @Retention(RetentionPolicy.SOURCE)
2855         public @interface AddNetworkStatusCode {}
2856 
2857         @Override
describeContents()2858         public int describeContents() {
2859             return 0;
2860         }
2861 
2862         @Override
writeToParcel(@onNull Parcel dest, int flags)2863         public void writeToParcel(@NonNull Parcel dest, int flags) {
2864             dest.writeInt(statusCode);
2865             dest.writeInt(networkId);
2866         }
2867 
2868         /** Implement the Parcelable interface */
2869         public static final @android.annotation.NonNull Creator<AddNetworkResult> CREATOR =
2870                 new Creator<AddNetworkResult>() {
2871                     public AddNetworkResult createFromParcel(Parcel in) {
2872                         return new AddNetworkResult(in.readInt(), in.readInt());
2873                     }
2874 
2875                     public AddNetworkResult[] newArray(int size) {
2876                         return new AddNetworkResult[size];
2877                     }
2878                 };
2879 
2880         /**
2881          * One of the {@code STATUS_} values. If the operation is successful this field
2882          * will be set to {@code STATUS_SUCCESS}.
2883          */
2884         public final @AddNetworkStatusCode int statusCode;
2885         /**
2886          * The identifier of the added network, which could be used in other operations. This field
2887          * will be set to {@code -1} if the operation failed.
2888          */
2889         public final int networkId;
2890 
AddNetworkResult(@ddNetworkStatusCode int statusCode, int networkId)2891         public AddNetworkResult(@AddNetworkStatusCode int statusCode, int networkId) {
2892             this.statusCode = statusCode;
2893             this.networkId = networkId;
2894         }
2895     }
2896 
2897     /**
2898      * Update the network description of an existing configured network.
2899      *
2900      * @param config the set of variables that describe the configuration,
2901      *            contained in a {@link WifiConfiguration} object. It may
2902      *            be sparse, so that only the items that are being changed
2903      *            are non-<code>null</code>. The {@code networkId} field
2904      *            must be set to the ID of the existing network being updated.
2905      *            If the {@link WifiConfiguration} has an Http Proxy set
2906      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
2907      * @return Returns the {@code networkId} of the supplied
2908      *         {@code WifiConfiguration} on success.
2909      *         <br/>
2910      *         Returns {@code -1} on failure, including when the {@code networkId}
2911      *         field of the {@code WifiConfiguration} does not refer to an
2912      *         existing network.
2913      *
2914      * @deprecated
2915      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2916      * mechanism to trigger connection to a Wi-Fi network.
2917      * b) See {@link #addNetworkSuggestions(List)},
2918      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2919      * when auto-connecting to wifi.
2920      * <b>Compatibility Note:</b> For applications targeting
2921      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2922      * {@code -1}.
2923      * <p>
2924      * Deprecation Exemptions:
2925      * <ul>
2926      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2927      * </ul>
2928      */
2929     @Deprecated
updateNetwork(WifiConfiguration config)2930     public int updateNetwork(WifiConfiguration config) {
2931         if (config == null || config.networkId < 0) {
2932             return -1;
2933         }
2934         return addOrUpdateNetwork(config);
2935     }
2936 
2937     /**
2938      * Internal method for doing the RPC that creates a new network description
2939      * or updates an existing one.
2940      *
2941      * @param config The possibly sparse object containing the variables that
2942      *         are to set or updated in the network description.
2943      * @return the ID of the network on success, {@code -1} on failure.
2944      */
addOrUpdateNetwork(WifiConfiguration config)2945     private int addOrUpdateNetwork(WifiConfiguration config) {
2946         Bundle extras = new Bundle();
2947         if (SdkLevel.isAtLeastS()) {
2948             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
2949                     mContext.getAttributionSource());
2950         }
2951 
2952         try {
2953             return mService.addOrUpdateNetwork(config, mContext.getOpPackageName(), extras);
2954         } catch (RemoteException e) {
2955             throw e.rethrowFromSystemServer();
2956         }
2957     }
2958 
2959     /**
2960      * Interface for indicating user selection from the list of networks presented in the
2961      * {@link NetworkRequestMatchCallback#onMatch(List)}.
2962      *
2963      * The platform will implement this callback and pass it along with the
2964      * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
2965      * NetworkRequestUserSelectionCallback)}. The UI component handling
2966      * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
2967      * {@link #reject()} to return the user's selection back to the platform via this callback.
2968      * @hide
2969      */
2970     @SystemApi
2971     public interface NetworkRequestUserSelectionCallback {
2972         /**
2973          * User selected this network to connect to.
2974          * @param wifiConfiguration WifiConfiguration object corresponding to the network
2975          *                          user selected.
2976          */
2977         @SuppressLint("CallbackMethodName")
select(@onNull WifiConfiguration wifiConfiguration)2978         default void select(@NonNull WifiConfiguration wifiConfiguration) {}
2979 
2980         /**
2981          * User rejected the app's request.
2982          */
2983         @SuppressLint("CallbackMethodName")
reject()2984         default void reject() {}
2985     }
2986 
2987     /**
2988      * Interface for network request callback. Should be implemented by applications and passed when
2989      * calling {@link #registerNetworkRequestMatchCallback(Executor,
2990      * WifiManager.NetworkRequestMatchCallback)}.
2991      *
2992      * This is meant to be implemented by a UI component to present the user with a list of networks
2993      * matching the app's request. The user is allowed to pick one of these networks to connect to
2994      * or reject the request by the app.
2995      * @hide
2996      */
2997     @SystemApi
2998     public interface NetworkRequestMatchCallback {
2999         /**
3000          * Invoked to register a callback to be invoked to convey user selection. The callback
3001          * object passed in this method is to be invoked by the UI component after the service sends
3002          * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
3003          * from that list.
3004          *
3005          * @param userSelectionCallback Callback object to send back the user selection.
3006          */
onUserSelectionCallbackRegistration( @onNull NetworkRequestUserSelectionCallback userSelectionCallback)3007         default void onUserSelectionCallbackRegistration(
3008                 @NonNull NetworkRequestUserSelectionCallback userSelectionCallback) {}
3009 
3010         /**
3011          * Invoked when the active network request is aborted, either because
3012          * <li> The app released the request, OR</li>
3013          * <li> Request was overridden by a new request</li>
3014          * This signals the end of processing for the current request and should stop the UI
3015          * component. No subsequent calls from the UI component will be handled by the platform.
3016          */
onAbort()3017         default void onAbort() {}
3018 
3019         /**
3020          * Invoked when a network request initiated by an app matches some networks in scan results.
3021          * This may be invoked multiple times for a single network request as the platform finds new
3022          * matching networks in scan results.
3023          *
3024          * @param scanResults List of {@link ScanResult} objects corresponding to the networks
3025          *                    matching the request.
3026          */
onMatch(@onNull List<ScanResult> scanResults)3027         default void onMatch(@NonNull List<ScanResult> scanResults) {}
3028 
3029         /**
3030          * Invoked on a successful connection with the network that the user selected
3031          * via {@link NetworkRequestUserSelectionCallback}.
3032          *
3033          * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
3034          *                          user selected.
3035          */
onUserSelectionConnectSuccess(@onNull WifiConfiguration wifiConfiguration)3036         default void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration) {}
3037 
3038         /**
3039          * Invoked on failure to establish connection with the network that the user selected
3040          * via {@link NetworkRequestUserSelectionCallback}.
3041          *
3042          * @param wifiConfiguration WifiConfiguration object corresponding to the network
3043          *                          user selected.
3044          */
onUserSelectionConnectFailure(@onNull WifiConfiguration wifiConfiguration)3045         default void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration) {}
3046     }
3047 
3048     /**
3049      * Callback proxy for NetworkRequestUserSelectionCallback objects.
3050      * @hide
3051      */
3052     private class NetworkRequestUserSelectionCallbackProxy implements
3053             NetworkRequestUserSelectionCallback {
3054         private final INetworkRequestUserSelectionCallback mCallback;
3055 
NetworkRequestUserSelectionCallbackProxy( INetworkRequestUserSelectionCallback callback)3056         NetworkRequestUserSelectionCallbackProxy(
3057                 INetworkRequestUserSelectionCallback callback) {
3058             mCallback = callback;
3059         }
3060 
3061         @Override
select(@onNull WifiConfiguration wifiConfiguration)3062         public void select(@NonNull WifiConfiguration wifiConfiguration) {
3063             if (mVerboseLoggingEnabled) {
3064                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
3065                         + "wificonfiguration: " + wifiConfiguration);
3066             }
3067             try {
3068                 mCallback.select(wifiConfiguration);
3069             } catch (RemoteException e) {
3070                 Log.e(TAG, "Failed to invoke onSelected", e);
3071                 throw e.rethrowFromSystemServer();
3072             }
3073         }
3074 
3075         @Override
reject()3076         public void reject() {
3077             if (mVerboseLoggingEnabled) {
3078                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
3079             }
3080             try {
3081                 mCallback.reject();
3082             } catch (RemoteException e) {
3083                 Log.e(TAG, "Failed to invoke onRejected", e);
3084                 throw e.rethrowFromSystemServer();
3085             }
3086         }
3087     }
3088 
3089     /**
3090      * Callback proxy for NetworkRequestMatchCallback objects.
3091      * @hide
3092      */
3093     private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
3094         private final Executor mExecutor;
3095         private final NetworkRequestMatchCallback mCallback;
3096 
NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback)3097         NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback) {
3098             mExecutor = executor;
3099             mCallback = callback;
3100         }
3101 
3102         @Override
onUserSelectionCallbackRegistration( INetworkRequestUserSelectionCallback userSelectionCallback)3103         public void onUserSelectionCallbackRegistration(
3104                 INetworkRequestUserSelectionCallback userSelectionCallback) {
3105             if (mVerboseLoggingEnabled) {
3106                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
3107                         + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
3108             }
3109             Binder.clearCallingIdentity();
3110             mExecutor.execute(() -> {
3111                 mCallback.onUserSelectionCallbackRegistration(
3112                         new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
3113             });
3114         }
3115 
3116         @Override
onAbort()3117         public void onAbort() {
3118             if (mVerboseLoggingEnabled) {
3119                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onAbort");
3120             }
3121             Binder.clearCallingIdentity();
3122             mExecutor.execute(() -> {
3123                 mCallback.onAbort();
3124             });
3125         }
3126 
3127         @Override
onMatch(List<ScanResult> scanResults)3128         public void onMatch(List<ScanResult> scanResults) {
3129             if (mVerboseLoggingEnabled) {
3130                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch scanResults: "
3131                         + scanResults);
3132             }
3133             Binder.clearCallingIdentity();
3134             mExecutor.execute(() -> {
3135                 mCallback.onMatch(scanResults);
3136             });
3137         }
3138 
3139         @Override
onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration)3140         public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
3141             if (mVerboseLoggingEnabled) {
3142                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
3143                         + " wificonfiguration: " + wifiConfiguration);
3144             }
3145             Binder.clearCallingIdentity();
3146             mExecutor.execute(() -> {
3147                 mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
3148             });
3149         }
3150 
3151         @Override
onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration)3152         public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
3153             if (mVerboseLoggingEnabled) {
3154                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
3155                         + " wificonfiguration: " + wifiConfiguration);
3156             }
3157             Binder.clearCallingIdentity();
3158             mExecutor.execute(() -> {
3159                 mCallback.onUserSelectionConnectFailure(wifiConfiguration);
3160             });
3161         }
3162     }
3163 
3164     /**
3165      * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
3166      * Caller can unregister a previously registered callback using
3167      * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
3168      * <p>
3169      * Applications should have the
3170      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
3171      * without the permission will trigger a {@link java.lang.SecurityException}.
3172      * <p>
3173      *
3174      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
3175      *                 object.
3176      * @param callback Callback for network match events to register.
3177      * @hide
3178      */
3179     @SystemApi
3180     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerNetworkRequestMatchCallback(@onNull @allbackExecutor Executor executor, @NonNull NetworkRequestMatchCallback callback)3181     public void registerNetworkRequestMatchCallback(@NonNull @CallbackExecutor Executor executor,
3182             @NonNull NetworkRequestMatchCallback callback) {
3183         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
3184         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3185         Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
3186                 + ", executor=" + executor);
3187 
3188         try {
3189             synchronized (sNetworkRequestMatchCallbackMap) {
3190                 INetworkRequestMatchCallback.Stub binderCallback =
3191                         new NetworkRequestMatchCallbackProxy(executor, callback);
3192                 sNetworkRequestMatchCallbackMap.put(System.identityHashCode(callback),
3193                         binderCallback);
3194                 mService.registerNetworkRequestMatchCallback(binderCallback);
3195             }
3196         } catch (RemoteException e) {
3197             throw e.rethrowFromSystemServer();
3198         }
3199     }
3200 
3201     /**
3202      * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
3203      * <p>
3204      * Applications should have the
3205      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
3206      * without the permission will trigger a {@link java.lang.SecurityException}.
3207      * <p>
3208      *
3209      * @param callback Callback for network match events to unregister.
3210      * @hide
3211      */
3212     @SystemApi
3213     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterNetworkRequestMatchCallback( @onNull NetworkRequestMatchCallback callback)3214     public void unregisterNetworkRequestMatchCallback(
3215             @NonNull NetworkRequestMatchCallback callback) {
3216         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3217         Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
3218 
3219         try {
3220             synchronized (sNetworkRequestMatchCallbackMap) {
3221                 int callbackIdentifier = System.identityHashCode(callback);
3222                 if (!sNetworkRequestMatchCallbackMap.contains(callbackIdentifier)) {
3223                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
3224                     return;
3225                 }
3226                 mService.unregisterNetworkRequestMatchCallback(
3227                         sNetworkRequestMatchCallbackMap.get(callbackIdentifier));
3228                 sNetworkRequestMatchCallbackMap.remove(callbackIdentifier);
3229             }
3230         } catch (RemoteException e) {
3231             throw e.rethrowFromSystemServer();
3232         }
3233     }
3234 
3235     /**
3236      * Privileged API to revoke all app state from wifi stack (equivalent to operations that the
3237      * wifi stack performs to clear state for an app that was uninstalled.
3238      * This removes:
3239      * <li> All saved networks or passpoint profiles added by the app </li>
3240      * <li> All previously approved peer to peer connection to access points initiated by the app
3241      * using {@link WifiNetworkSpecifier}</li>
3242      * <li> All network suggestions and approvals provided using {@link WifiNetworkSuggestion}</li>
3243      * <p>
3244      * @param targetAppUid UID of the app.
3245      * @param targetAppPackageName Package name of the app.
3246      * @hide
3247      */
3248     @SystemApi
3249     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
removeAppState(int targetAppUid, @NonNull String targetAppPackageName)3250     public void removeAppState(int targetAppUid, @NonNull String targetAppPackageName) {
3251         try {
3252             mService.removeAppState(targetAppUid, targetAppPackageName);
3253         } catch (RemoteException e) {
3254             throw e.rethrowAsRuntimeException();
3255         }
3256     }
3257 
3258     /**
3259      * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
3260      * for a detailed explanation of the parameters.
3261      * When the device decides to connect to one of the provided network suggestions, platform sends
3262      * a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
3263      * the network was created with
3264      * {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(boolean)} flag set and the
3265      * app holds {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
3266      * permission.
3267      *<p>
3268      * NOTE:
3269      * <ul>
3270      * <li> These networks are just a suggestion to the platform. The platform will ultimately
3271      * decide on which network the device connects to. </li>
3272      * <li> When an app is uninstalled or disabled, all its suggested networks are discarded.
3273      * If the device is currently connected to a suggested network which is being removed then the
3274      * device will disconnect from that network.</li>
3275      * <li> If user reset network settings, all added suggestions will be discarded. Apps can use
3276      * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
3277      * <li> In-place modification of existing suggestions are allowed.</li>
3278      * <ul>
3279      * <li> If the provided suggestions include any previously provided suggestions by the app,
3280      * previous suggestions will be updated.</li>
3281      * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and
3282      * the device is currently connected to that suggested network, then the device will disconnect
3283      * from that network. The system will immediately re-evaluate all the network candidates
3284      * and possibly reconnect back to the same suggestion. This disconnect is to make sure that any
3285      * traffic flowing over unmetered networks isn't accidentally continued over a metered network.
3286      * </li>
3287      * <li>
3288      * On {@link android.os.Build.VERSION_CODES#TIRAMISU} or above If one of the provided
3289      * suggestions marks a previously trusted suggestion as untrusted and the device is currently
3290      * connected to that suggested network, then the device will disconnect from that network. The
3291      * system will immediately re-evaluate all the network candidates. This disconnect is to make
3292      * sure device will not remain connected to an untrusted network without a related
3293      * {@link android.net.NetworkRequest}.
3294      * </li>
3295      * </ul>
3296      * </ul>
3297      *
3298      * @param networkSuggestions List of network suggestions provided by the app.
3299      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
3300      * @throws SecurityException if the caller is missing required permissions.
3301      * @see WifiNetworkSuggestion#equals(Object)
3302      */
3303     @RequiresPermission(CHANGE_WIFI_STATE)
addNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)3304     public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
3305             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
3306         try {
3307             return mService.addNetworkSuggestions(
3308                     networkSuggestions, mContext.getOpPackageName(), mContext.getAttributionTag());
3309         } catch (RemoteException e) {
3310             throw e.rethrowFromSystemServer();
3311         }
3312     }
3313 
3314     /**
3315      * Remove some or all of the network suggestions that were previously provided by the app.
3316      * If one of the suggestions being removed was used to establish connection to the current
3317      * network, then the device will immediately disconnect from that network. This method is same
3318      * as {@link #removeNetworkSuggestions(List, int)} with
3319      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT}
3320      *
3321      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
3322      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
3323      * <p></
3324      * Note: Use {@link #removeNetworkSuggestions(List, int)}. An {@code action} of
3325      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT} is equivalent to the current behavior.
3326      *
3327      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
3328      *                           to remove all the previous suggestions provided by the app.
3329      * @return Status code for the operation. One of the {@code STATUS_NETWORK_SUGGESTIONS_*}
3330      * values. Any matching suggestions are removed from the device and will not be considered for
3331      * any further connection attempts.
3332      */
3333     @RequiresPermission(CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)3334     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
3335             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
3336         return removeNetworkSuggestions(networkSuggestions, ACTION_REMOVE_SUGGESTION_DISCONNECT);
3337     }
3338 
3339     /**
3340      * Remove some or all of the network suggestions that were previously provided by the app.
3341      * If one of the suggestions being removed was used to establish connection to the current
3342      * network, then the specified action will be executed.
3343      *
3344      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
3345      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
3346      *
3347      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
3348      *                           to remove all the previous suggestions provided by the app.
3349      * @param action Desired action to execute after removing the suggestion. One of
3350      *               {@code ACTION_REMOVE_SUGGESTION_*}
3351      * @return Status code for the operation. One of the {@code STATUS_NETWORK_SUGGESTIONS_*}
3352      * values. Any matching suggestions are removed from the device and will not be considered for
3353      * further connection attempts.
3354      */
3355     @RequiresPermission(CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions, @ActionAfterRemovingSuggestion int action)3356     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
3357             @NonNull List<WifiNetworkSuggestion> networkSuggestions,
3358             @ActionAfterRemovingSuggestion int action) {
3359         try {
3360             return mService.removeNetworkSuggestions(networkSuggestions,
3361                     mContext.getOpPackageName(), action);
3362         } catch (RemoteException e) {
3363             throw e.rethrowFromSystemServer();
3364         }
3365     }
3366 
3367     /**
3368      * Get all network suggestions provided by the calling app.
3369      * See {@link #addNetworkSuggestions(List)}
3370      * See {@link #removeNetworkSuggestions(List)}
3371      * @return a list of {@link WifiNetworkSuggestion}
3372      */
3373     @RequiresPermission(ACCESS_WIFI_STATE)
getNetworkSuggestions()3374     public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
3375         try {
3376             return mService.getNetworkSuggestions(mContext.getOpPackageName());
3377         } catch (RemoteException e) {
3378             throw e.rethrowAsRuntimeException();
3379         }
3380     }
3381 
3382     /**
3383      * Returns the max number of network suggestions that are allowed per app on the device.
3384      * @see #addNetworkSuggestions(List)
3385      * @see #removeNetworkSuggestions(List)
3386      */
getMaxNumberOfNetworkSuggestionsPerApp()3387     public int getMaxNumberOfNetworkSuggestionsPerApp() {
3388         return getMaxNumberOfNetworkSuggestionsPerApp(
3389                 mContext.getSystemService(ActivityManager.class).isLowRamDevice());
3390     }
3391 
3392     /** @hide */
getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice)3393     public static int getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice) {
3394         return isLowRamDevice
3395                 ? NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM
3396                 : NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM;
3397     }
3398 
3399     /**
3400      * Add or update a Passpoint configuration.  The configuration provides a credential
3401      * for connecting to Passpoint networks that are operated by the Passpoint
3402      * service provider specified in the configuration.
3403      *
3404      * Each configuration is uniquely identified by a unique key which depends on the contents of
3405      * the configuration. This allows the caller to install multiple profiles with the same FQDN
3406      * (Fully qualified domain name). Therefore, in order to update an existing profile, it is
3407      * first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
3408      * Otherwise, a new profile will be added with both configuration.
3409      *
3410      * Deprecated for general app usage - except DO/PO apps.
3411      * See {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} to
3412      * create a passpoint suggestion.
3413      * See {@link #addNetworkSuggestions(List)}, {@link #removeNetworkSuggestions(List)} for new
3414      * API to add Wi-Fi networks for consideration when auto-connecting to wifi.
3415      * <b>Compatibility Note:</b> For applications targeting
3416      * {@link android.os.Build.VERSION_CODES#R} or above, this API will always fail and throw
3417      * {@link IllegalArgumentException}.
3418      * <p>
3419      * Deprecation Exemptions:
3420      * <ul>
3421      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3422      * </ul>
3423      *
3424      * @param config The Passpoint configuration to be added
3425      * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
3426      *                                  the device.
3427      */
addOrUpdatePasspointConfiguration(PasspointConfiguration config)3428     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
3429         try {
3430             if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
3431                 throw new IllegalArgumentException();
3432             }
3433         } catch (RemoteException e) {
3434             throw e.rethrowFromSystemServer();
3435         }
3436     }
3437 
3438     /**
3439      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name) added
3440      * by the caller.
3441      *
3442      * @param fqdn The FQDN of the Passpoint configuration added by the caller to be removed
3443      * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
3444      *                                  Passpoint is not enabled on the device.
3445      * @deprecated This will be non-functional in a future release.
3446      * <br>
3447      * Requires {@code android.Manifest.permission.NETWORK_SETTINGS} or
3448      * {@code android.Manifest.permission.NETWORK_CARRIER_PROVISIONING}.
3449      */
3450     @Deprecated
removePasspointConfiguration(String fqdn)3451     public void removePasspointConfiguration(String fqdn) {
3452         try {
3453             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
3454                 throw new IllegalArgumentException();
3455             }
3456         } catch (RemoteException e) {
3457             throw e.rethrowFromSystemServer();
3458         }
3459     }
3460 
3461     /**
3462      * Return the list of installed Passpoint configurations added by the caller.
3463      *
3464      * An empty list will be returned when no configurations are installed.
3465      *
3466      * @return A list of {@link PasspointConfiguration} added by the caller
3467      * @deprecated This will be non-functional in a future release.
3468      * <br>
3469      * Requires {@code android.Manifest.permission.NETWORK_SETTINGS} or
3470      * {@code android.Manifest.permission.NETWORK_SETUP_WIZARD}.
3471      */
3472     @Deprecated
getPasspointConfigurations()3473     public List<PasspointConfiguration> getPasspointConfigurations() {
3474         try {
3475             return mService.getPasspointConfigurations(mContext.getOpPackageName());
3476         } catch (RemoteException e) {
3477             throw e.rethrowFromSystemServer();
3478         }
3479     }
3480 
3481     /**
3482      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
3483      * will be broadcasted once the request is completed.  The presence of the intent extra
3484      * {@link #EXTRA_ICON} will indicate the result of the request.
3485      * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
3486      *
3487      * @param bssid The BSSID of the AP
3488      * @param fileName Name of the icon file (remote file) to query from the AP
3489      *
3490      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
3491      * @hide
3492      */
queryPasspointIcon(long bssid, String fileName)3493     public void queryPasspointIcon(long bssid, String fileName) {
3494         try {
3495             mService.queryPasspointIcon(bssid, fileName);
3496         } catch (RemoteException e) {
3497             throw e.rethrowFromSystemServer();
3498         }
3499     }
3500 
3501     /**
3502      * Match the currently associated network against the SP matching the given FQDN
3503      * @param fqdn FQDN of the SP
3504      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
3505      * @hide
3506      */
matchProviderWithCurrentNetwork(String fqdn)3507     public int matchProviderWithCurrentNetwork(String fqdn) {
3508         try {
3509             return mService.matchProviderWithCurrentNetwork(fqdn);
3510         } catch (RemoteException e) {
3511             throw e.rethrowFromSystemServer();
3512         }
3513     }
3514 
3515     /**
3516      * Remove the specified network from the list of configured networks.
3517      * This may result in the asynchronous delivery of state change
3518      * events.
3519      *
3520      * Applications are not allowed to remove networks created by other
3521      * applications.
3522      *
3523      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3524      *        #getConfiguredNetworks}.
3525      * @return {@code true} if the operation succeeded
3526      *
3527      * @deprecated
3528      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3529      * mechanism to trigger connection to a Wi-Fi network.
3530      * b) See {@link #addNetworkSuggestions(List)},
3531      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3532      * when auto-connecting to wifi.
3533      * <b>Compatibility Note:</b> For applications targeting
3534      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3535      * {@code false}.
3536      * <p>
3537      * Deprecation Exemptions:
3538      * <ul>
3539      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3540      * </ul>
3541      */
3542     @Deprecated
removeNetwork(int netId)3543     public boolean removeNetwork(int netId) {
3544         try {
3545             return mService.removeNetwork(netId, mContext.getOpPackageName());
3546         } catch (RemoteException e) {
3547             throw e.rethrowFromSystemServer();
3548         }
3549     }
3550 
3551     /**
3552      * Remove all configured networks that were not created by the calling app. Can only
3553      * be called by a Device Owner (DO) app.
3554      *
3555      * @return {@code true} if at least one network is removed, {@code false} otherwise
3556      * @throws SecurityException if the caller is not a Device Owner app
3557      */
3558     @RequiresPermission(CHANGE_WIFI_STATE)
removeNonCallerConfiguredNetworks()3559     public boolean removeNonCallerConfiguredNetworks() {
3560         try {
3561             return mService.removeNonCallerConfiguredNetworks(mContext.getOpPackageName());
3562         } catch (RemoteException e) {
3563             throw e.rethrowFromSystemServer();
3564         }
3565     }
3566     /**
3567      * Allow a previously configured network to be associated with. If
3568      * <code>attemptConnect</code> is true, an attempt to connect to the selected
3569      * network is initiated. This may result in the asynchronous delivery
3570      * of state change events.
3571      * <p>
3572      * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
3573      * traffic may instead be sent through another network, such as cellular data,
3574      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
3575      * Wi-Fi network that does not provide Internet access (e.g. a wireless
3576      * printer), if another network that does offer Internet access (e.g.
3577      * cellular data) is available. Applications that need to ensure that their
3578      * network traffic uses Wi-Fi should use APIs such as
3579      * {@link Network#bindSocket(java.net.Socket)},
3580      * {@link Network#openConnection(java.net.URL)}, or
3581      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
3582      *
3583      * Applications are not allowed to enable networks created by other
3584      * applications.
3585      *
3586      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3587      *        #getConfiguredNetworks}.
3588      * @param attemptConnect The way to select a particular network to connect to is specify
3589      *        {@code true} for this parameter.
3590      * @return {@code true} if the operation succeeded
3591      *
3592      * @deprecated
3593      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3594      * mechanism to trigger connection to a Wi-Fi network.
3595      * b) See {@link #addNetworkSuggestions(List)},
3596      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3597      * when auto-connecting to wifi.
3598      * <b>Compatibility Note:</b> For applications targeting
3599      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3600      * {@code false}.
3601      * Deprecation Exemptions:
3602      * <ul>
3603      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3604      * </ul>
3605      */
3606     @Deprecated
enableNetwork(int netId, boolean attemptConnect)3607     public boolean enableNetwork(int netId, boolean attemptConnect) {
3608         try {
3609             return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
3610         } catch (RemoteException e) {
3611             throw e.rethrowFromSystemServer();
3612         }
3613     }
3614 
3615     /**
3616      * Disable a configured network. The specified network will not be
3617      * a candidate for associating. This may result in the asynchronous
3618      * delivery of state change events.
3619      *
3620      * Applications are not allowed to disable networks created by other
3621      * applications.
3622      *
3623      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3624      *        #getConfiguredNetworks}.
3625      * @return {@code true} if the operation succeeded
3626      *
3627      * @deprecated
3628      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3629      * mechanism to trigger connection to a Wi-Fi network.
3630      * b) See {@link #addNetworkSuggestions(List)},
3631      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3632      * when auto-connecting to wifi.
3633      * <b>Compatibility Note:</b> For applications targeting
3634      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3635      * {@code false}.
3636      * <p>
3637      * Deprecation Exemptions:
3638      * <ul>
3639      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3640      * </ul>
3641      */
3642     @Deprecated
disableNetwork(int netId)3643     public boolean disableNetwork(int netId) {
3644         try {
3645             return mService.disableNetwork(netId, mContext.getOpPackageName());
3646         } catch (RemoteException e) {
3647             throw e.rethrowFromSystemServer();
3648         }
3649     }
3650 
3651     /**
3652      * Disassociate from the currently active access point. This may result
3653      * in the asynchronous delivery of state change events.
3654      * @return {@code true} if the operation succeeded
3655      *
3656      * @deprecated
3657      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3658      * mechanism to trigger connection to a Wi-Fi network.
3659      * b) See {@link #addNetworkSuggestions(List)},
3660      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3661      * when auto-connecting to wifi.
3662      * <b>Compatibility Note:</b> For applications targeting
3663      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3664      * {@code false}.
3665      * <p>
3666      * Deprecation Exemptions:
3667      * <ul>
3668      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3669      * </ul>
3670      */
3671     @Deprecated
disconnect()3672     public boolean disconnect() {
3673         try {
3674             return mService.disconnect(mContext.getOpPackageName());
3675         } catch (RemoteException e) {
3676             throw e.rethrowFromSystemServer();
3677         }
3678     }
3679 
3680     /**
3681      * Reconnect to the currently active access point, if we are currently
3682      * disconnected. This may result in the asynchronous delivery of state
3683      * change events.
3684      * @return {@code true} if the operation succeeded
3685      *
3686      * @deprecated
3687      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3688      * mechanism to trigger connection to a Wi-Fi network.
3689      * b) See {@link #addNetworkSuggestions(List)},
3690      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3691      * when auto-connecting to wifi.
3692      * <b>Compatibility Note:</b> For applications targeting
3693      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3694      * {@code false}.
3695      * <p>
3696      * Deprecation Exemptions:
3697      * <ul>
3698      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3699      * </ul>
3700      */
3701     @Deprecated
reconnect()3702     public boolean reconnect() {
3703         try {
3704             return mService.reconnect(mContext.getOpPackageName());
3705         } catch (RemoteException e) {
3706             throw e.rethrowFromSystemServer();
3707         }
3708     }
3709 
3710     /**
3711      * Reconnect to the currently active access point, even if we are already
3712      * connected. This may result in the asynchronous delivery of state
3713      * change events.
3714      * @return {@code true} if the operation succeeded
3715      *
3716      * @deprecated
3717      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3718      * mechanism to trigger connection to a Wi-Fi network.
3719      * b) See {@link #addNetworkSuggestions(List)},
3720      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3721      * when auto-connecting to wifi.
3722      * <b>Compatibility Note:</b> For applications targeting
3723      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
3724      */
3725     @Deprecated
reassociate()3726     public boolean reassociate() {
3727         try {
3728             return mService.reassociate(mContext.getOpPackageName());
3729         } catch (RemoteException e) {
3730             throw e.rethrowFromSystemServer();
3731         }
3732     }
3733 
3734     /**
3735      * Check that the supplicant daemon is responding to requests.
3736      * @return {@code true} if we were able to communicate with the supplicant and
3737      * it returned the expected response to the PING message.
3738      * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
3739      */
3740     @Deprecated
pingSupplicant()3741     public boolean pingSupplicant() {
3742         return isWifiEnabled();
3743     }
3744 
3745     /** @hide */
3746     public static final long WIFI_FEATURE_INFRA            = 1L << 0;  // Basic infrastructure mode
3747     /** @hide */
3748     public static final long WIFI_FEATURE_PASSPOINT        = 1L << 2;  // Support for GAS/ANQP
3749     /** @hide */
3750     public static final long WIFI_FEATURE_P2P              = 1L << 3;  // Wifi-Direct
3751     /** @hide */
3752     public static final long WIFI_FEATURE_MOBILE_HOTSPOT   = 1L << 4;  // Soft AP
3753     /** @hide */
3754     public static final long WIFI_FEATURE_SCANNER          = 1L << 5;  // WifiScanner APIs
3755     /** @hide */
3756     public static final long WIFI_FEATURE_AWARE            = 1L << 6;  // Wi-Fi Aware networking
3757     /** @hide */
3758     public static final long WIFI_FEATURE_D2D_RTT          = 1L << 7;  // Device-to-device RTT
3759     /** @hide */
3760     public static final long WIFI_FEATURE_D2AP_RTT         = 1L << 8;  // Device-to-AP RTT
3761     /** @hide */
3762     public static final long WIFI_FEATURE_PNO              = 1L << 10;  // Preferred network offload
3763     /** @hide */
3764     public static final long WIFI_FEATURE_TDLS             = 1L << 12; // Tunnel directed link setup
3765     /** @hide */
3766     public static final long WIFI_FEATURE_TDLS_OFFCHANNEL  = 1L << 13; // TDLS off channel
3767     /** @hide */
3768     public static final long WIFI_FEATURE_AP_STA           = 1L << 15; // AP STA Concurrency
3769     /** @hide */
3770     public static final long WIFI_FEATURE_LINK_LAYER_STATS = 1L << 16; // Link layer stats
3771     /** @hide */
3772     public static final long WIFI_FEATURE_LOGGER           = 1L << 17; // WiFi Logger
3773     /** @hide */
3774     public static final long WIFI_FEATURE_RSSI_MONITOR     = 1L << 19; // RSSI Monitor
3775     /** @hide */
3776     public static final long WIFI_FEATURE_MKEEP_ALIVE      = 1L << 20; // mkeep_alive
3777     /** @hide */
3778     public static final long WIFI_FEATURE_CONFIG_NDO       = 1L << 21; // ND offload
3779     /** @hide */
3780     public static final long WIFI_FEATURE_CONTROL_ROAMING  = 1L << 23; // Control firmware roaming
3781     /** @hide */
3782     public static final long WIFI_FEATURE_IE_WHITELIST     = 1L << 24; // Probe IE white listing
3783     /** @hide */
3784     public static final long WIFI_FEATURE_SCAN_RAND        = 1L << 25; // Random MAC & Probe seq
3785     /** @hide */
3786     public static final long WIFI_FEATURE_TX_POWER_LIMIT   = 1L << 26; // Set Tx power limit
3787     /** @hide */
3788     public static final long WIFI_FEATURE_WPA3_SAE         = 1L << 27; // WPA3-Personal SAE
3789     /** @hide */
3790     public static final long WIFI_FEATURE_WPA3_SUITE_B     = 1L << 28; // WPA3-Enterprise Suite-B
3791     /** @hide */
3792     public static final long WIFI_FEATURE_OWE              = 1L << 29; // Enhanced Open
3793     /** @hide */
3794     public static final long WIFI_FEATURE_LOW_LATENCY      = 1L << 30; // Low Latency modes
3795     /** @hide */
3796     public static final long WIFI_FEATURE_DPP              = 1L << 31; // DPP (Easy-Connect)
3797     /** @hide */
3798     public static final long WIFI_FEATURE_P2P_RAND_MAC     = 1L << 32; // Random P2P MAC
3799     /** @hide */
3800     public static final long WIFI_FEATURE_CONNECTED_RAND_MAC    = 1L << 33; // Random STA MAC
3801     /** @hide */
3802     public static final long WIFI_FEATURE_AP_RAND_MAC      = 1L << 34; // Random AP MAC
3803     /** @hide */
3804     public static final long WIFI_FEATURE_MBO              = 1L << 35; // MBO Support
3805     /** @hide */
3806     public static final long WIFI_FEATURE_OCE              = 1L << 36; // OCE Support
3807     /** @hide */
3808     public static final long WIFI_FEATURE_WAPI             = 1L << 37; // WAPI
3809 
3810     /** @hide */
3811     public static final long WIFI_FEATURE_FILS_SHA256      = 1L << 38; // FILS-SHA256
3812 
3813     /** @hide */
3814     public static final long WIFI_FEATURE_FILS_SHA384      = 1L << 39; // FILS-SHA384
3815 
3816     /** @hide */
3817     public static final long WIFI_FEATURE_SAE_PK           = 1L << 40; // SAE-PK
3818 
3819     /** @hide */
3820     public static final long WIFI_FEATURE_STA_BRIDGED_AP   = 1L << 41; // STA + Bridged AP
3821 
3822     /** @hide */
3823     public static final long WIFI_FEATURE_BRIDGED_AP       = 1L << 42; // Bridged AP
3824 
3825     /** @hide */
3826     public static final long WIFI_FEATURE_INFRA_60G        = 1L << 43; // 60 GHz Band Support
3827 
3828     /**
3829      * Support for 2 STA's for the local-only (peer to peer) connection + internet connection
3830      * concurrency.
3831      * @hide
3832      */
3833     public static final long WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY = 1L << 44;
3834 
3835     /**
3836      * Support for 2 STA's for the make before break concurrency.
3837      * @hide
3838      */
3839     public static final long WIFI_FEATURE_ADDITIONAL_STA_MBB = 1L << 45;
3840 
3841     /**
3842      * Support for 2 STA's for the restricted connection + internet connection concurrency.
3843      * @hide
3844      */
3845     public static final long WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED = 1L << 46;
3846 
3847     /**
3848      * DPP (Easy-Connect) Enrollee Responder mode support
3849      * @hide
3850      */
3851     public static final long WIFI_FEATURE_DPP_ENROLLEE_RESPONDER = 1L << 47;
3852 
3853     /**
3854      * Passpoint Terms and Conditions feature support
3855      * @hide
3856      */
3857     public static final long WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS = 1L << 48;
3858 
3859      /** @hide */
3860     public static final long WIFI_FEATURE_SAE_H2E          = 1L << 49; // Hash-to-Element
3861 
3862      /** @hide */
3863     public static final long WIFI_FEATURE_WFD_R2           = 1L << 50; // Wi-Fi Display R2
3864 
3865     /**
3866      * RFC 7542 decorated identity support
3867      * @hide */
3868     public static final long WIFI_FEATURE_DECORATED_IDENTITY = 1L << 51;
3869 
3870     /**
3871      * Trust On First Use support for WPA Enterprise network
3872      * @hide
3873      */
3874     public static final long WIFI_FEATURE_TRUST_ON_FIRST_USE = 1L << 52;
3875 
3876     /**
3877      * Support for 2 STA's multi internet concurrency.
3878      * @hide
3879      */
3880     public static final long WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET = 1L << 53;
3881 
3882     /**
3883      * Support for DPP (Easy-Connect) AKM.
3884      * @hide
3885      */
3886     public static final long WIFI_FEATURE_DPP_AKM = 1L << 54;
3887 
3888     /**
3889      * Support for setting TLS minimum version.
3890      * @hide
3891      */
3892     public static final long WIFI_FEATURE_SET_TLS_MINIMUM_VERSION = 1L << 55;
3893 
3894     /**
3895      * Support for TLS v.13.
3896      * @hide
3897      */
3898     public static final long WIFI_FEATURE_TLS_V1_3 = 1L << 56;
3899 
3900     /**
3901      * Support for Dual Band Simultaneous (DBS) operation.
3902      * @hide
3903      */
3904     public static final long WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS = 1L << 57;
3905     /**
3906      * Support for TID-To-Link Mapping negotiation.
3907      * @hide
3908      */
3909     public static final long WIFI_FEATURE_T2LM_NEGOTIATION = 1L << 58;
3910 
getSupportedFeatures()3911     private long getSupportedFeatures() {
3912         try {
3913             return mService.getSupportedFeatures();
3914         } catch (RemoteException e) {
3915             throw e.rethrowFromSystemServer();
3916         }
3917     }
3918 
isFeatureSupported(long feature)3919     private boolean isFeatureSupported(long feature) {
3920         return (getSupportedFeatures() & feature) == feature;
3921     }
3922 
3923     /**
3924      * @return true if this adapter supports Passpoint
3925      * @hide
3926      */
isPasspointSupported()3927     public boolean isPasspointSupported() {
3928         return isFeatureSupported(WIFI_FEATURE_PASSPOINT);
3929     }
3930 
3931     /**
3932      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
3933      */
isP2pSupported()3934     public boolean isP2pSupported() {
3935         return isFeatureSupported(WIFI_FEATURE_P2P);
3936     }
3937 
3938     /**
3939      * @return true if this adapter supports portable Wi-Fi hotspot
3940      * @hide
3941      */
3942     @SystemApi
isPortableHotspotSupported()3943     public boolean isPortableHotspotSupported() {
3944         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
3945     }
3946 
3947     /**
3948      * @return true if this adapter supports WifiScanner APIs
3949      * @hide
3950      */
3951     @SystemApi
isWifiScannerSupported()3952     public boolean isWifiScannerSupported() {
3953         return isFeatureSupported(WIFI_FEATURE_SCANNER);
3954     }
3955 
3956     /**
3957      * @return true if this adapter supports Neighbour Awareness Network APIs
3958      * @hide
3959      */
isWifiAwareSupported()3960     public boolean isWifiAwareSupported() {
3961         return isFeatureSupported(WIFI_FEATURE_AWARE);
3962     }
3963 
3964     /**
3965      * Query whether or not the device supports Station (STA) + Access point (AP) concurrency.
3966      *
3967      * @return true if this device supports STA + AP concurrency, false otherwise.
3968      */
isStaApConcurrencySupported()3969     public boolean isStaApConcurrencySupported() {
3970         return isFeatureSupported(WIFI_FEATURE_AP_STA);
3971     }
3972 
3973     /**
3974      * Query whether or not the device supports concurrent station (STA) connections for local-only
3975      * connections using {@link WifiNetworkSpecifier}.
3976      *
3977      * @return true if this device supports multiple STA concurrency for this use-case, false
3978      * otherwise.
3979      */
isStaConcurrencyForLocalOnlyConnectionsSupported()3980     public boolean isStaConcurrencyForLocalOnlyConnectionsSupported() {
3981         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY);
3982     }
3983 
3984     /**
3985      * Query whether or not the device supports concurrent station (STA) connections for
3986      * make-before-break wifi to wifi switching.
3987      *
3988      * Note: This is an internal feature which is not available to apps.
3989      *
3990      * @return true if this device supports multiple STA concurrency for this use-case, false
3991      * otherwise.
3992      */
isMakeBeforeBreakWifiSwitchingSupported()3993     public boolean isMakeBeforeBreakWifiSwitchingSupported() {
3994         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_MBB);
3995     }
3996 
3997     /**
3998      * Query whether or not the device supports concurrent station (STA) connections for multi
3999      * internet connections.
4000      *
4001      * @return true if this device supports multiple STA concurrency for this use-case, false
4002      * otherwise.
4003      */
4004     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
isStaConcurrencyForMultiInternetSupported()4005     public boolean isStaConcurrencyForMultiInternetSupported() {
4006         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET);
4007     }
4008 
4009     /**
4010      * Query whether or not the device supports concurrent station (STA) connections for restricted
4011      * connections using {@link WifiNetworkSuggestion.Builder#setOemPaid(boolean)} /
4012      * {@link WifiNetworkSuggestion.Builder#setOemPrivate(boolean)}.
4013      *
4014      * @return true if this device supports multiple STA concurrency for this use-case, false
4015      * otherwise.
4016      * @hide
4017      */
4018     @SystemApi
isStaConcurrencyForRestrictedConnectionsSupported()4019     public boolean isStaConcurrencyForRestrictedConnectionsSupported() {
4020         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED);
4021     }
4022 
4023     /**
4024      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
4025      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
4026      * {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
4027      *
4028      * @return true if this adapter supports Device-to-device RTT
4029      * @hide
4030      */
4031     @Deprecated
4032     @SystemApi
isDeviceToDeviceRttSupported()4033     public boolean isDeviceToDeviceRttSupported() {
4034         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
4035     }
4036 
4037     /**
4038      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
4039      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT}.
4040      *
4041      * @return true if this adapter supports Device-to-AP RTT
4042      */
4043     @Deprecated
isDeviceToApRttSupported()4044     public boolean isDeviceToApRttSupported() {
4045         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
4046     }
4047 
4048     /**
4049      * @return true if this adapter supports offloaded connectivity scan
4050      */
isPreferredNetworkOffloadSupported()4051     public boolean isPreferredNetworkOffloadSupported() {
4052         return isFeatureSupported(WIFI_FEATURE_PNO);
4053     }
4054 
4055     /**
4056      * @return true if this adapter supports Tunnel Directed Link Setup
4057      */
isTdlsSupported()4058     public boolean isTdlsSupported() {
4059         return isFeatureSupported(WIFI_FEATURE_TDLS);
4060     }
4061 
4062     /**
4063      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
4064      * @hide
4065      */
isOffChannelTdlsSupported()4066     public boolean isOffChannelTdlsSupported() {
4067         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
4068     }
4069 
4070     /**
4071      * @return true if this adapter supports advanced power/performance counters
4072      */
isEnhancedPowerReportingSupported()4073     public boolean isEnhancedPowerReportingSupported() {
4074         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
4075     }
4076 
4077     /**
4078      * @return true if this device supports connected MAC randomization.
4079      * @hide
4080      */
4081     @SystemApi
isConnectedMacRandomizationSupported()4082     public boolean isConnectedMacRandomizationSupported() {
4083         return isFeatureSupported(WIFI_FEATURE_CONNECTED_RAND_MAC);
4084     }
4085 
4086     /**
4087      * @return true if this device supports AP MAC randomization.
4088      * @hide
4089      */
4090     @SystemApi
isApMacRandomizationSupported()4091     public boolean isApMacRandomizationSupported() {
4092         return isFeatureSupported(WIFI_FEATURE_AP_RAND_MAC);
4093     }
4094 
4095     /**
4096      * Check if the chipset supports 2.4GHz band.
4097      * @return {@code true} if supported, {@code false} otherwise.
4098      */
is24GHzBandSupported()4099     public boolean is24GHzBandSupported() {
4100         try {
4101             return mService.is24GHzBandSupported();
4102         } catch (RemoteException e) {
4103             throw e.rethrowFromSystemServer();
4104         }
4105     }
4106 
4107     /**
4108      * Check if the chipset supports 5GHz band.
4109      * @return {@code true} if supported, {@code false} otherwise.
4110      */
is5GHzBandSupported()4111     public boolean is5GHzBandSupported() {
4112         try {
4113             return mService.is5GHzBandSupported();
4114         } catch (RemoteException e) {
4115             throw e.rethrowFromSystemServer();
4116         }
4117     }
4118 
4119     /**
4120      * Check if the chipset supports the 60GHz frequency band.
4121      *
4122      * @return {@code true} if supported, {@code false} otherwise.
4123      */
4124     @RequiresApi(Build.VERSION_CODES.S)
is60GHzBandSupported()4125     public boolean is60GHzBandSupported() {
4126         try {
4127             return mService.is60GHzBandSupported();
4128         } catch (RemoteException e) {
4129             throw e.rethrowFromSystemServer();
4130         }
4131     }
4132 
4133     /**
4134      * Check if the chipset supports 6GHz band.
4135      * @return {@code true} if supported, {@code false} otherwise.
4136      */
is6GHzBandSupported()4137     public boolean is6GHzBandSupported() {
4138         try {
4139             return mService.is6GHzBandSupported();
4140         } catch (RemoteException e) {
4141             throw e.rethrowFromSystemServer();
4142         }
4143     }
4144 
4145     /**
4146      * Check if the chipset supports a certain Wi-Fi standard.
4147      * @param standard the IEEE 802.11 standard to check on.
4148      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
4149      * @return {@code true} if supported, {@code false} otherwise.
4150      */
isWifiStandardSupported(@ifiAnnotations.WifiStandard int standard)4151     public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
4152         try {
4153             return mService.isWifiStandardSupported(standard);
4154         } catch (RemoteException e) {
4155             throw e.rethrowFromSystemServer();
4156         }
4157     }
4158 
4159     /**
4160      * Query whether or not the device supports concurrency of Station (STA) + multiple access
4161      * points (AP) (where the APs bridged together).
4162      *
4163      * See {@link SoftApConfiguration.Builder#setBands(int[])}
4164      * or {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)} to configure
4165      * bridged AP when the bridged AP supported.
4166      *
4167      * @return true if this device supports concurrency of STA + multiple APs which are bridged
4168      *         together, false otherwise.
4169      */
isStaBridgedApConcurrencySupported()4170     public boolean isStaBridgedApConcurrencySupported() {
4171         return isFeatureSupported(WIFI_FEATURE_STA_BRIDGED_AP);
4172     }
4173 
4174     /**
4175      * Query whether or not the device supports multiple Access point (AP) which are bridged
4176      * together.
4177      *
4178      * See {@link SoftApConfiguration.Builder#setBands(int[])}
4179      * or {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)} to configure
4180      * bridged AP when the bridged AP supported.
4181      *
4182      * @return true if this device supports concurrency of multiple AP which bridged together,
4183      *         false otherwise.
4184      */
isBridgedApConcurrencySupported()4185     public boolean isBridgedApConcurrencySupported() {
4186         return isFeatureSupported(WIFI_FEATURE_BRIDGED_AP);
4187     }
4188 
4189     /**
4190      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
4191      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
4192      *
4193      * @hide
4194      */
4195     @SystemApi
4196     public interface OnWifiActivityEnergyInfoListener {
4197         /**
4198          * Called when Wi-Fi activity energy info is available.
4199          * Note: this listener is triggered at most once for each call to
4200          * {@link #getWifiActivityEnergyInfoAsync}.
4201          *
4202          * @param info the latest {@link WifiActivityEnergyInfo}, or null if unavailable.
4203          */
onWifiActivityEnergyInfo(@ullable WifiActivityEnergyInfo info)4204         void onWifiActivityEnergyInfo(@Nullable WifiActivityEnergyInfo info);
4205     }
4206 
4207     private static class OnWifiActivityEnergyInfoProxy
4208             extends IOnWifiActivityEnergyInfoListener.Stub {
4209         private final Object mLock = new Object();
4210         @Nullable @GuardedBy("mLock") private Executor mExecutor;
4211         @Nullable @GuardedBy("mLock") private OnWifiActivityEnergyInfoListener mListener;
4212 
OnWifiActivityEnergyInfoProxy(Executor executor, OnWifiActivityEnergyInfoListener listener)4213         OnWifiActivityEnergyInfoProxy(Executor executor,
4214                 OnWifiActivityEnergyInfoListener listener) {
4215             mExecutor = executor;
4216             mListener = listener;
4217         }
4218 
4219         @Override
onWifiActivityEnergyInfo(WifiActivityEnergyInfo info)4220         public void onWifiActivityEnergyInfo(WifiActivityEnergyInfo info) {
4221             Executor executor;
4222             OnWifiActivityEnergyInfoListener listener;
4223             synchronized (mLock) {
4224                 if (mExecutor == null || mListener == null) {
4225                     return;
4226                 }
4227                 executor = mExecutor;
4228                 listener = mListener;
4229                 // null out to allow garbage collection, prevent triggering listener more than once
4230                 mExecutor = null;
4231                 mListener = null;
4232             }
4233             Binder.clearCallingIdentity();
4234             executor.execute(() -> listener.onWifiActivityEnergyInfo(info));
4235         }
4236     }
4237 
4238     /**
4239      * Request to get the current {@link WifiActivityEnergyInfo} asynchronously.
4240      * Note: This method will return null if {@link #isEnhancedPowerReportingSupported()} returns
4241      * false.
4242      *
4243      * @param executor the executor that the listener will be invoked on
4244      * @param listener the listener that will receive the {@link WifiActivityEnergyInfo} object
4245      *                 when it becomes available. The listener will be triggered at most once for
4246      *                 each call to this method.
4247      *
4248      * @hide
4249      */
4250     @SystemApi
4251     @RequiresPermission(ACCESS_WIFI_STATE)
getWifiActivityEnergyInfoAsync( @onNull @allbackExecutor Executor executor, @NonNull OnWifiActivityEnergyInfoListener listener)4252     public void getWifiActivityEnergyInfoAsync(
4253             @NonNull @CallbackExecutor Executor executor,
4254             @NonNull OnWifiActivityEnergyInfoListener listener) {
4255         Objects.requireNonNull(executor, "executor cannot be null");
4256         Objects.requireNonNull(listener, "listener cannot be null");
4257         try {
4258             mService.getWifiActivityEnergyInfoAsync(
4259                     new OnWifiActivityEnergyInfoProxy(executor, listener));
4260         } catch (RemoteException e) {
4261             throw e.rethrowFromSystemServer();
4262         }
4263     }
4264 
4265     /**
4266      * Request a scan for access points. Returns immediately. The availability
4267      * of the results is made known later by means of an asynchronous event sent
4268      * on completion of the scan.
4269      * <p>
4270      * To initiate a Wi-Fi scan, declare the
4271      * {@link android.Manifest.permission#CHANGE_WIFI_STATE}
4272      * permission in the manifest, and perform these steps:
4273      * </p>
4274      * <ol style="1">
4275      * <li>Invoke the following method:
4276      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>
4277      * <li>
4278      * Register a BroadcastReceiver to listen to
4279      * {@code SCAN_RESULTS_AVAILABLE_ACTION}.</li>
4280      * <li>When a broadcast is received, call:
4281      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>
4282      * </ol>
4283      * @return {@code true} if the operation succeeded, i.e., the scan was initiated.
4284      * @deprecated The ability for apps to trigger scan requests will be removed in a future
4285      * release.
4286      */
4287     @Deprecated
startScan()4288     public boolean startScan() {
4289         return startScan(null);
4290     }
4291 
4292     /** @hide */
4293     @SystemApi
4294     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
startScan(WorkSource workSource)4295     public boolean startScan(WorkSource workSource) {
4296         try {
4297             String packageName = mContext.getOpPackageName();
4298             String attributionTag = mContext.getAttributionTag();
4299             return mService.startScan(packageName, attributionTag);
4300         } catch (RemoteException e) {
4301             throw e.rethrowFromSystemServer();
4302         }
4303     }
4304 
4305     /**
4306      * WPS has been deprecated from Client mode operation.
4307      *
4308      * @return null
4309      * @hide
4310      * @deprecated This API is deprecated
4311      */
getCurrentNetworkWpsNfcConfigurationToken()4312     public String getCurrentNetworkWpsNfcConfigurationToken() {
4313         return null;
4314     }
4315 
4316     /**
4317      * Return dynamic information about the current Wi-Fi connection, if any is active.
4318      * <p>
4319      *
4320      * @return the Wi-Fi information, contained in {@link WifiInfo}.
4321      *
4322      * @deprecated Starting with {@link Build.VERSION_CODES#S}, WifiInfo retrieval is moved to
4323      * {@link ConnectivityManager} API surface. WifiInfo is attached in
4324      * {@link NetworkCapabilities#getTransportInfo()} which is available via callback in
4325      * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} or on-demand from
4326      * {@link ConnectivityManager#getNetworkCapabilities(Network)}.
4327      *
4328      *</p>
4329      * Usage example:
4330      * <pre>
4331      * final NetworkRequest request =
4332      *      new NetworkRequest.Builder()
4333      *      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
4334      *      .build();
4335      * final ConnectivityManager connectivityManager =
4336      *      context.getSystemService(ConnectivityManager.class);
4337      * final NetworkCallback networkCallback = new NetworkCallback() {
4338      *      ...
4339      *      &#64;Override
4340      *      void onAvailable(Network network) {}
4341      *
4342      *      &#64;Override
4343      *      void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
4344      *          WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
4345      *      }
4346      *      // etc.
4347      * };
4348      * connectivityManager.requestNetwork(request, networkCallback); // For request
4349      * connectivityManager.registerNetworkCallback(request, networkCallback); // For listen
4350      * </pre>
4351      * <p>
4352      * <b>Compatibility Notes:</b>
4353      * <li>Apps can continue using this API, however newer features
4354      * such as ability to mask out location sensitive data in WifiInfo will not be supported
4355      * via this API. </li>
4356      * <li>On devices supporting concurrent connections (indicated via
4357      * {@link #isStaConcurrencyForLocalOnlyConnectionsSupported()}, etc) this API will return
4358      * the details of the internet providing connection (if any) to all apps, except for the apps
4359      * that triggered the creation of the concurrent connection. For such apps, this API will return
4360      * the details of the connection they created. e.g. apps using {@link WifiNetworkSpecifier} will
4361      * trigger a concurrent connection on supported devices and hence this API will provide
4362      * details of their peer to peer connection (not the internet providing connection). This
4363      * is to maintain backwards compatibility with behavior on single STA devices.</li>
4364      * </p>
4365      */
4366     @Deprecated
4367     @RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION}, conditional = true)
getConnectionInfo()4368     public WifiInfo getConnectionInfo() {
4369         try {
4370             return mService.getConnectionInfo(mContext.getOpPackageName(),
4371                     mContext.getAttributionTag());
4372         } catch (RemoteException e) {
4373             throw e.rethrowFromSystemServer();
4374         }
4375     }
4376 
4377     /**
4378      * Return the results of the latest access point scan.
4379      * @return the list of access points found in the most recent scan. An app must hold
4380      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
4381      * and {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission
4382      * in order to get valid results.
4383      */
4384     @RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION})
getScanResults()4385     public List<ScanResult> getScanResults() {
4386         try {
4387             return mService.getScanResults(mContext.getOpPackageName(),
4388                     mContext.getAttributionTag());
4389         } catch (RemoteException e) {
4390             throw e.rethrowFromSystemServer();
4391         }
4392     }
4393 
4394     /**
4395      * Get the filtered ScanResults which match the network configurations specified by the
4396      * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
4397      * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
4398      * use the matching rules of Hotspot 2.0.
4399      * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
4400      * These may or may not be suggestions which are installed on the device.
4401      * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
4402      * the Wi-Fi service will use the most recent scan results which the system has.
4403      * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
4404      * corresponding to networks which match them.
4405      * @hide
4406      */
4407     @SystemApi
4408     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
4409     @NonNull
getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestionsToMatch, @Nullable List<ScanResult> scanResults)4410     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
4411             @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
4412             @Nullable List<ScanResult> scanResults) {
4413         if (networkSuggestionsToMatch == null) {
4414             throw new IllegalArgumentException("networkSuggestions must not be null.");
4415         }
4416         try {
4417             return mService.getMatchingScanResults(
4418                     networkSuggestionsToMatch, scanResults,
4419                     mContext.getOpPackageName(), mContext.getAttributionTag());
4420         } catch (RemoteException e) {
4421             throw e.rethrowFromSystemServer();
4422         }
4423     }
4424 
4425     /**
4426      * Set if scanning is always available.
4427      *
4428      * If set to {@code true}, apps can issue {@link #startScan} and fetch scan results
4429      * even when Wi-Fi is turned off.
4430      *
4431      * @param isAvailable true to enable, false to disable.
4432      * @hide
4433      * @see #isScanAlwaysAvailable()
4434      */
4435     @SystemApi
4436     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanAlwaysAvailable(boolean isAvailable)4437     public void setScanAlwaysAvailable(boolean isAvailable) {
4438         try {
4439             mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName());
4440         } catch (RemoteException e) {
4441             throw e.rethrowFromSystemServer();
4442         }
4443     }
4444 
4445     /**
4446      * Check if scanning is always available.
4447      *
4448      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
4449      * even when Wi-Fi is turned off.
4450      *
4451      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
4452      * @deprecated The ability for apps to trigger scan requests will be removed in a future
4453      * release.
4454      */
4455     @Deprecated
isScanAlwaysAvailable()4456     public boolean isScanAlwaysAvailable() {
4457         try {
4458             return mService.isScanAlwaysAvailable();
4459         } catch (RemoteException e) {
4460             throw e.rethrowFromSystemServer();
4461         }
4462     }
4463 
4464     /**
4465      * Get channel data such as the number of APs found on each channel from the most recent scan.
4466      * App requires {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}
4467      *
4468      * @param executor        The executor on which callback will be invoked.
4469      * @param resultsCallback A callback that will return {@code List<Bundle>} containing channel
4470      *                       data such as the number of APs found on each channel.
4471      *                       {@link WifiManager#CHANNEL_DATA_KEY_FREQUENCY_MHZ} and
4472      *                       {@link WifiManager#CHANNEL_DATA_KEY_NUM_AP} are used to get
4473      *                       the frequency (Mhz) and number of APs.
4474      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
4475      * @throws SecurityException             if the caller does not have permission.
4476      * @throws NullPointerException          if the caller provided invalid inputs.
4477      */
4478     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4479     @RequiresPermission(NEARBY_WIFI_DEVICES)
getChannelData(@onNull @allbackExecutor Executor executor, @NonNull Consumer<List<Bundle>> resultsCallback)4480     public void getChannelData(@NonNull @CallbackExecutor Executor executor,
4481             @NonNull Consumer<List<Bundle>> resultsCallback) {
4482         Objects.requireNonNull(executor, "executor cannot be null");
4483         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
4484         try {
4485             Bundle extras = new Bundle();
4486             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
4487                     mContext.getAttributionSource());
4488             mService.getChannelData(new IListListener.Stub() {
4489                 @Override
4490                 public void onResult(List value) {
4491                     Binder.clearCallingIdentity();
4492                     executor.execute(() -> {
4493                         resultsCallback.accept(value);
4494                     });
4495                 }
4496             }, mContext.getOpPackageName(), extras);
4497         } catch (RemoteException e) {
4498             throw e.rethrowFromSystemServer();
4499         }
4500     }
4501 
4502     /**
4503      * Tell the device to persist the current list of configured networks.
4504      * <p>
4505      * Note: It is possible for this method to change the network IDs of
4506      * existing networks. You should assume the network IDs can be different
4507      * after calling this method.
4508      *
4509      * @return {@code false}.
4510      * @deprecated There is no need to call this method -
4511      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
4512      * and {@link #removeNetwork(int)} already persist the configurations automatically.
4513      */
4514     @Deprecated
saveConfiguration()4515     public boolean saveConfiguration() {
4516         return false;
4517     }
4518 
4519     /**
4520      * Helper class to support driver country code changed listener.
4521      */
4522     private static class OnDriverCountryCodeChangedProxy
4523             extends IOnWifiDriverCountryCodeChangedListener.Stub {
4524 
4525         @NonNull private Executor mExecutor;
4526         @NonNull private ActiveCountryCodeChangedCallback mCallback;
4527 
OnDriverCountryCodeChangedProxy(@onNull Executor executor, @NonNull ActiveCountryCodeChangedCallback callback)4528         OnDriverCountryCodeChangedProxy(@NonNull Executor executor,
4529                 @NonNull ActiveCountryCodeChangedCallback callback) {
4530             Objects.requireNonNull(executor);
4531             Objects.requireNonNull(callback);
4532             mExecutor = executor;
4533             mCallback = callback;
4534         }
4535 
4536         @Override
onDriverCountryCodeChanged(String countryCode)4537         public void onDriverCountryCodeChanged(String countryCode) {
4538             Log.i(TAG, "OnDriverCountryCodeChangedProxy: receive onDriverCountryCodeChanged: "
4539                     + countryCode);
4540             Binder.clearCallingIdentity();
4541             if (countryCode != null) {
4542                 mExecutor.execute(() -> mCallback.onActiveCountryCodeChanged(countryCode));
4543             } else {
4544                 mExecutor.execute(() -> mCallback.onCountryCodeInactive());
4545             }
4546         }
4547     }
4548 
4549     /**
4550      * Interface used to listen the active country code changed event.
4551      * @hide
4552      */
4553     @SystemApi
4554     public interface ActiveCountryCodeChangedCallback {
4555         /**
4556          * Called when the country code used by the Wi-Fi subsystem has changed.
4557          *
4558          * @param countryCode An ISO-3166-alpha2 country code which is 2-Character alphanumeric.
4559          */
onActiveCountryCodeChanged(@onNull String countryCode)4560         void onActiveCountryCodeChanged(@NonNull String countryCode);
4561 
4562         /**
4563          * Called when the Wi-Fi subsystem does not have an active country code.
4564          * This can happen when Wi-Fi is disabled.
4565          */
onCountryCodeInactive()4566         void onCountryCodeInactive();
4567     }
4568 
4569     /**
4570      * Add the provided callback for the active country code changed event.
4571      * Caller will receive either
4572      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}
4573      * or {@link WifiManager.ActiveCountryCodeChangedCallback#onCountryCodeInactive()}
4574      * on registration.
4575      *
4576      * Note: When the global location setting is off or the caller does not have runtime location
4577      * permission, caller will not receive the callback even if caller register callback succeeded.
4578      *
4579      *
4580      * Caller can remove a previously registered callback using
4581      * {@link WifiManager#unregisterActiveCountryCodeChangedCallback(
4582      * ActiveCountryCodeChangedCallback)}.
4583      *
4584      * <p>
4585      * Note:
4586      * The value provided by
4587      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}
4588      * may be different from the returned value from {@link WifiManager#getCountryCode()} even if
4589      * the Wi-Fi subsystem is active. See: {@link WifiManager#getCountryCode()} for details.
4590      * </p>
4591      *
4592      * @param executor The Executor on which to execute the callbacks.
4593      * @param callback callback for the driver country code changed events.
4594      * @hide
4595      */
4596     @SystemApi
4597     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4598     @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
registerActiveCountryCodeChangedCallback( @onNull @allbackExecutor Executor executor, @NonNull ActiveCountryCodeChangedCallback callback)4599     public void registerActiveCountryCodeChangedCallback(
4600             @NonNull @CallbackExecutor Executor executor,
4601             @NonNull ActiveCountryCodeChangedCallback callback) {
4602         if (!SdkLevel.isAtLeastT()) {
4603             throw new UnsupportedOperationException();
4604         }
4605         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
4606         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
4607         if (mVerboseLoggingEnabled) {
4608             Log.d(TAG, "registerActiveCountryCodeChangedCallback: callback=" + callback
4609                     + ", executor=" + executor);
4610         }
4611         final int callbackIdentifier = System.identityHashCode(callback);
4612         synchronized (sActiveCountryCodeChangedCallbackMap) {
4613             try {
4614                 IOnWifiDriverCountryCodeChangedListener.Stub binderListener =
4615                         new OnDriverCountryCodeChangedProxy(executor, callback);
4616                 sActiveCountryCodeChangedCallbackMap.put(callbackIdentifier,
4617                         binderListener);
4618                 mService.registerDriverCountryCodeChangedListener(binderListener,
4619                         mContext.getOpPackageName(), mContext.getAttributionTag());
4620             } catch (RemoteException e) {
4621                 sActiveCountryCodeChangedCallbackMap.remove(callbackIdentifier);
4622                 throw e.rethrowFromSystemServer();
4623             }
4624         }
4625     }
4626 
4627     /**
4628      * Allow callers to remove a previously registered listener. After calling this method,
4629      * applications will no longer receive the active country code changed events through that
4630      * callback.
4631      *
4632      * @param callback Callback to remove the active country code changed events.
4633      *
4634      * @hide
4635      */
4636     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4637     @SystemApi
unregisterActiveCountryCodeChangedCallback( @onNull ActiveCountryCodeChangedCallback callback)4638     public void unregisterActiveCountryCodeChangedCallback(
4639             @NonNull ActiveCountryCodeChangedCallback callback) {
4640         if (!SdkLevel.isAtLeastT()) {
4641             throw new UnsupportedOperationException();
4642         }
4643         if (callback == null) throw new IllegalArgumentException("Callback cannot be null");
4644         if (mVerboseLoggingEnabled) {
4645             Log.d(TAG, "unregisterActiveCountryCodeChangedCallback: callback=" + callback);
4646         }
4647         final int callbackIdentifier = System.identityHashCode(callback);
4648         synchronized (sActiveCountryCodeChangedCallbackMap) {
4649             try {
4650                 if (!sActiveCountryCodeChangedCallbackMap.contains(callbackIdentifier)) {
4651                     Log.w(TAG, "Unknown external listener " + callbackIdentifier);
4652                     return;
4653                 }
4654                 mService.unregisterDriverCountryCodeChangedListener(
4655                         sActiveCountryCodeChangedCallbackMap.get(callbackIdentifier));
4656             } catch (RemoteException e) {
4657                 throw e.rethrowFromSystemServer();
4658             } finally {
4659                 sActiveCountryCodeChangedCallbackMap.remove(callbackIdentifier);
4660             }
4661         }
4662     }
4663 
4664     /**
4665      * Interface used to listen to changes in current network state.
4666      * @hide
4667      */
4668     @SystemApi
4669     public interface WifiNetworkStateChangedListener {
4670         /** @hide */
4671         @Retention(RetentionPolicy.SOURCE)
4672         @IntDef(prefix = {"WIFI_ROLE_CLIENT_"}, value = {
4673                 WIFI_ROLE_CLIENT_PRIMARY,
4674                 WIFI_ROLE_CLIENT_SECONDARY_INTERNET,
4675                 WIFI_ROLE_CLIENT_SECONDARY_LOCAL_ONLY
4676         })
4677         @interface WifiClientModeRole {}
4678 
4679         /**
4680          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4681          * Represents the primary Client Mode Manager which is mostly used for internet, but could
4682          * also be used for other use-cases such as local only connections.
4683          **/
4684         int WIFI_ROLE_CLIENT_PRIMARY = 1;
4685         /**
4686          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4687          * Represents a Client Mode Manager dedicated for the secondary internet use-case.
4688          **/
4689         int WIFI_ROLE_CLIENT_SECONDARY_INTERNET = 2;
4690         /**
4691          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4692          * Represents a Client Mode Manager dedicated for the local only connection use-case.
4693          **/
4694         int WIFI_ROLE_CLIENT_SECONDARY_LOCAL_ONLY = 3;
4695 
4696         /** @hide */
4697         @Retention(RetentionPolicy.SOURCE)
4698         @IntDef(prefix = {"WIFI_NETWORK_STATUS_"}, value = {
4699                 WIFI_NETWORK_STATUS_IDLE,
4700                 WIFI_NETWORK_STATUS_SCANNING,
4701                 WIFI_NETWORK_STATUS_CONNECTING,
4702                 WIFI_NETWORK_STATUS_AUTHENTICATING,
4703                 WIFI_NETWORK_STATUS_OBTAINING_IPADDR,
4704                 WIFI_NETWORK_STATUS_CONNECTED,
4705                 WIFI_NETWORK_STATUS_DISCONNECTED,
4706                 WIFI_NETWORK_STATUS_FAILED
4707         })
4708         @interface WifiNetworkState {}
4709 
4710         /**
4711          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4712          * Supplicant is in uninitialized state.
4713          **/
4714         int WIFI_NETWORK_STATUS_IDLE = 1;
4715         /**
4716          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4717          * Supplicant is scanning.
4718          **/
4719         int WIFI_NETWORK_STATUS_SCANNING = 2;
4720         /**
4721          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4722          * L2 connection is in progress.
4723          **/
4724         int WIFI_NETWORK_STATUS_CONNECTING = 3;
4725         /**
4726          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4727          * L2 connection 4 way handshake.
4728          **/
4729         int WIFI_NETWORK_STATUS_AUTHENTICATING = 4;
4730         /**
4731          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4732          * L2 connection complete. Obtaining IP address.
4733          **/
4734         int WIFI_NETWORK_STATUS_OBTAINING_IPADDR = 5;
4735         /**
4736          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4737          * L3 connection is complete.
4738          **/
4739         int WIFI_NETWORK_STATUS_CONNECTED = 6;
4740         /**
4741          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4742          * Network disconnected.
4743          **/
4744         int WIFI_NETWORK_STATUS_DISCONNECTED = 7;
4745         /**
4746          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4747          * A pseudo-state that should normally never be seen.
4748          **/
4749         int WIFI_NETWORK_STATUS_FAILED = 8;
4750 
4751 
4752         /**
4753          * Provides network state changes per client mode role.
4754          * @param cmmRole the role of the wifi client mode manager having the state change.
4755          *                One of {@link WifiClientModeRole}.
4756          * @param state the wifi network state specified by one of {@link WifiNetworkState}.
4757          */
onWifiNetworkStateChanged(@ifiClientModeRole int cmmRole, @WifiNetworkState int state)4758         void onWifiNetworkStateChanged(@WifiClientModeRole int cmmRole,
4759                 @WifiNetworkState int state);
4760     }
4761 
4762     /**
4763      * Helper class to support wifi network state changed listener.
4764      */
4765     private static class OnWifiNetworkStateChangedProxy
4766             extends IWifiNetworkStateChangedListener.Stub {
4767 
4768         @NonNull private Executor mExecutor;
4769         @NonNull private WifiNetworkStateChangedListener mListener;
4770 
OnWifiNetworkStateChangedProxy(@onNull Executor executor, @NonNull WifiNetworkStateChangedListener listener)4771         OnWifiNetworkStateChangedProxy(@NonNull Executor executor,
4772                 @NonNull WifiNetworkStateChangedListener listener) {
4773             Objects.requireNonNull(executor);
4774             Objects.requireNonNull(listener);
4775             mExecutor = executor;
4776             mListener = listener;
4777         }
4778 
4779         @Override
onWifiNetworkStateChanged(int cmmRole, int state)4780         public void onWifiNetworkStateChanged(int cmmRole, int state) {
4781             Log.i(TAG, "OnWifiNetworkStateChangedProxy: onWifiNetworkStateChanged: "
4782                     + cmmRole + ", " + state);
4783             Binder.clearCallingIdentity();
4784             mExecutor.execute(() -> mListener.onWifiNetworkStateChanged(cmmRole, state));
4785         }
4786     }
4787 
4788     /**
4789      * Add a listener to listen to Wi-Fi network state changes on available client mode roles
4790      * specified in {@link WifiNetworkStateChangedListener.WifiClientModeRole}.
4791      * When wifi state changes such as connected/disconnect happens, results will be delivered via
4792      * {@link WifiNetworkStateChangedListener#onWifiNetworkStateChanged(int, int)}.
4793      *
4794      * @param executor The Executor on which to execute the callbacks.
4795      * @param listener listener for the network status updates.
4796      * @throws SecurityException if the caller is missing required permissions.
4797      * @throws IllegalArgumentException if incorrect input arguments are provided.
4798      * @hide
4799      */
4800     @SystemApi
4801     @RequiresPermission(Manifest.permission.NETWORK_SETTINGS)
addWifiNetworkStateChangedListener(@onNull @allbackExecutor Executor executor, @NonNull WifiNetworkStateChangedListener listener)4802     public void addWifiNetworkStateChangedListener(@NonNull @CallbackExecutor Executor executor,
4803             @NonNull WifiNetworkStateChangedListener listener) {
4804         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
4805         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
4806         if (mVerboseLoggingEnabled) {
4807             Log.d(TAG, "addWifiNetworkStateChangedListener: listener=" + listener
4808                     + ", executor=" + executor);
4809         }
4810         final int listenerIdentifier = System.identityHashCode(listener);
4811         synchronized (sOnWifiNetworkStateChangedListenerMap) {
4812             try {
4813                 IWifiNetworkStateChangedListener.Stub listenerProxy =
4814                         new OnWifiNetworkStateChangedProxy(executor, listener);
4815                 sOnWifiNetworkStateChangedListenerMap.put(listenerIdentifier,
4816                         listenerProxy);
4817                 mService.addWifiNetworkStateChangedListener(listenerProxy);
4818             } catch (RemoteException e) {
4819                 sOnWifiNetworkStateChangedListenerMap.remove(listenerIdentifier);
4820                 throw e.rethrowFromSystemServer();
4821             }
4822         }
4823     }
4824 
4825     /**
4826      * Remove a listener added using
4827      * {@link #addWifiNetworkStateChangedListener(Executor, WifiNetworkStateChangedListener)}.
4828      * @param listener the listener to be removed.
4829      * @throws IllegalArgumentException if incorrect input arguments are provided.
4830      * @hide
4831      */
4832     @SystemApi
4833     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
removeWifiNetworkStateChangedListener( @onNull WifiNetworkStateChangedListener listener)4834     public void removeWifiNetworkStateChangedListener(
4835             @NonNull WifiNetworkStateChangedListener listener) {
4836         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
4837         if (mVerboseLoggingEnabled) {
4838             Log.d(TAG, "removeWifiNetworkStateChangedListener: listener=" + listener);
4839         }
4840         final int listenerIdentifier = System.identityHashCode(listener);
4841         synchronized (sOnWifiNetworkStateChangedListenerMap) {
4842             try {
4843                 if (!sOnWifiNetworkStateChangedListenerMap.contains(listenerIdentifier)) {
4844                     Log.w(TAG, "Unknown external listener " + listenerIdentifier);
4845                     return;
4846                 }
4847                 mService.removeWifiNetworkStateChangedListener(
4848                         sOnWifiNetworkStateChangedListenerMap.get(listenerIdentifier));
4849             } catch (RemoteException e) {
4850                 throw e.rethrowFromSystemServer();
4851             } finally {
4852                 sOnWifiNetworkStateChangedListenerMap.remove(listenerIdentifier);
4853             }
4854         }
4855     }
4856 
4857     /**
4858      * Get the country code as resolved by the Wi-Fi framework.
4859      * The Wi-Fi framework uses multiple sources to resolve a country code
4860      * - in order of priority (high to low):
4861      * 1. Override country code set by {@link WifiManager#setOverrideCountryCode(String)}
4862      * and cleared by {@link WifiManager#clearOverrideCountryCode()}. Typically only used
4863      * for testing.
4864      * 2. Country code supplied by the telephony module. Typically provided from the
4865      * current network or from emergency cell information.
4866      * 3. Country code supplied by the wifi driver module. (802.11d)
4867      * 4. Default country code set either via {@code ro.boot.wificountrycode}
4868      * or the {@link WifiManager#setDefaultCountryCode(String)}.
4869      *
4870      * <p>
4871      * Note:
4872      * This method returns the Country Code value used by the framework - even if not currently
4873      * used by the Wi-Fi subsystem. I.e. the returned value from this API may be different from the
4874      * value provided by
4875      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}.
4876      * Such a difference may happen when there is an ongoing network connection (STA, AP, Direct,
4877      * or Aware) and the Wi-Fi subsystem does not support dynamic updates - at that point the
4878      * framework may defer setting the Country Code to the Wi-Fi subsystem.
4879      * </p>
4880      * @return the country code in ISO 3166 alpha-2 (2-letter) upper format,
4881      * or null if there is no country code configured.
4882      *
4883      * @hide
4884      */
4885     @Nullable
4886     @SystemApi
4887     @RequiresPermission(anyOf = {
4888             android.Manifest.permission.NETWORK_SETTINGS,
4889             android.Manifest.permission.ACCESS_COARSE_LOCATION
4890     })
getCountryCode()4891     public String getCountryCode() {
4892         try {
4893             return mService.getCountryCode(mContext.getOpPackageName(),
4894                     mContext.getAttributionTag());
4895         } catch (RemoteException e) {
4896             throw e.rethrowFromSystemServer();
4897         }
4898     }
4899 
4900     /**
4901      * Set the override country code - may be used for testing. See the country code resolution
4902      * order and format in {@link #getCountryCode()}.
4903      * @param country A 2-Character alphanumeric country code.
4904      * @see #getCountryCode().
4905      *
4906      * @hide
4907      */
4908     @RequiresApi(Build.VERSION_CODES.S)
4909     @SystemApi
4910     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
setOverrideCountryCode(@onNull String country)4911     public void setOverrideCountryCode(@NonNull String country) {
4912         try {
4913             mService.setOverrideCountryCode(country);
4914         } catch (RemoteException e) {
4915             throw e.rethrowFromSystemServer();
4916         }
4917     }
4918 
4919     /**
4920      * This clears the override country code which was previously set by
4921      * {@link WifiManager#setOverrideCountryCode(String)} method.
4922      * @see #getCountryCode().
4923      *
4924      * @hide
4925      */
4926     @RequiresApi(Build.VERSION_CODES.S)
4927     @SystemApi
4928     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
clearOverrideCountryCode()4929     public void clearOverrideCountryCode() {
4930         try {
4931             mService.clearOverrideCountryCode();
4932         } catch (RemoteException e) {
4933             throw e.rethrowFromSystemServer();
4934         }
4935     }
4936     /**
4937      * Used to configure the default country code. See {@link #getCountryCode()} for resolution
4938      * method of the country code.
4939      * @param country A 2-character alphanumeric country code.
4940      * @see #getCountryCode().
4941      *
4942      * @hide
4943      */
4944     @RequiresApi(Build.VERSION_CODES.S)
4945     @SystemApi
4946     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
setDefaultCountryCode(@onNull String country)4947     public void setDefaultCountryCode(@NonNull String country) {
4948         try {
4949             mService.setDefaultCountryCode(country);
4950         } catch (RemoteException e) {
4951             throw e.rethrowFromSystemServer();
4952         }
4953     }
4954 
4955     /**
4956      * Return the DHCP-assigned addresses from the last successful DHCP request,
4957      * if any.
4958      *
4959      * @return the DHCP information
4960      *
4961      * @deprecated Use the methods on {@link android.net.LinkProperties} which can be obtained
4962      * either via {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)} or
4963      * {@link ConnectivityManager#getLinkProperties(Network)}.
4964      *
4965      * <p>
4966      * <b>Compatibility Notes:</b>
4967      * <li>On devices supporting concurrent connections (indicated via
4968      * {@link #isStaConcurrencyForLocalOnlyConnectionsSupported()}, etc), this API will return
4969      * the details of the internet providing connection (if any) to all apps, except for the apps
4970      * that triggered the creation of the concurrent connection. For such apps, this API will return
4971      * the details of the connection they created. e.g. apps using {@link WifiNetworkSpecifier} will
4972      * trigger a concurrent connection on supported devices and hence this API will provide
4973      * details of their peer to peer connection (not the internet providing connection). This
4974      * is to maintain backwards compatibility with behavior on single STA devices.</li>
4975      * </p>
4976      */
4977     @Deprecated
getDhcpInfo()4978     public DhcpInfo getDhcpInfo() {
4979         try {
4980             return mService.getDhcpInfo(mContext.getOpPackageName());
4981         } catch (RemoteException e) {
4982             throw e.rethrowFromSystemServer();
4983         }
4984     }
4985 
4986     /**
4987      * Enable or disable Wi-Fi.
4988      * <p>
4989      * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
4990      * permission to toggle wifi.
4991      *
4992      * @param enabled {@code true} to enable, {@code false} to disable.
4993      * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
4994      *         either already in the requested state, or in progress toward the requested state.
4995      * @throws  SecurityException if the caller is missing required permissions.
4996      *
4997      * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
4998      * enable/disable Wi-Fi.
4999      * <b>Compatibility Note:</b> For applications targeting
5000      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
5001      * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
5002      * or below), they can continue to use this API.
5003      * <p>
5004      * Deprecation Exemptions:
5005      * <ul>
5006      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
5007      * </ul>
5008      *
5009      * Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, DO/COPE may set
5010      * a user restriction (DISALLOW_CHANGE_WIFI_STATE) to only allow DO/PO to use this API.
5011      */
5012     @Deprecated
setWifiEnabled(boolean enabled)5013     public boolean setWifiEnabled(boolean enabled) {
5014         try {
5015             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
5016         } catch (RemoteException e) {
5017             throw e.rethrowFromSystemServer();
5018         }
5019     }
5020 
5021     /**
5022      * Abstract callback class for applications to receive updates about the Wi-Fi subsystem
5023      * restarting. The Wi-Fi subsystem can restart due to internal recovery mechanisms or via user
5024      * action.
5025      */
5026     @RequiresApi(Build.VERSION_CODES.S)
5027     public abstract static class SubsystemRestartTrackingCallback {
5028         private final SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy mProxy;
5029 
SubsystemRestartTrackingCallback()5030         public SubsystemRestartTrackingCallback() {
5031             mProxy = new SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy();
5032         }
5033 
5034         /*package*/ @NonNull
getProxy()5035         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy getProxy() {
5036             return mProxy;
5037         }
5038 
5039         /**
5040          * Indicates that the Wi-Fi subsystem is about to restart.
5041          */
onSubsystemRestarting()5042         public abstract void onSubsystemRestarting();
5043 
5044         /**
5045          * Indicates that the Wi-Fi subsystem has restarted.
5046          */
onSubsystemRestarted()5047         public abstract void onSubsystemRestarted();
5048 
5049         private static class SubsystemRestartCallbackProxy extends ISubsystemRestartCallback.Stub {
5050             private final Object mLock = new Object();
5051             @Nullable
5052             @GuardedBy("mLock")
5053             private Executor mExecutor;
5054             @Nullable
5055             @GuardedBy("mLock")
5056             private SubsystemRestartTrackingCallback mCallback;
5057 
SubsystemRestartCallbackProxy()5058             SubsystemRestartCallbackProxy() {
5059                 mExecutor = null;
5060                 mCallback = null;
5061             }
5062 
initProxy(@onNull Executor executor, @NonNull SubsystemRestartTrackingCallback callback)5063             /*package*/ void initProxy(@NonNull Executor executor,
5064                     @NonNull SubsystemRestartTrackingCallback callback) {
5065                 synchronized (mLock) {
5066                     mExecutor = executor;
5067                     mCallback = callback;
5068                 }
5069             }
5070 
cleanUpProxy()5071             /*package*/ void cleanUpProxy() {
5072                 synchronized (mLock) {
5073                     mExecutor = null;
5074                     mCallback = null;
5075                 }
5076             }
5077 
5078             @Override
onSubsystemRestarting()5079             public void onSubsystemRestarting() {
5080                 Executor executor;
5081                 SubsystemRestartTrackingCallback callback;
5082                 synchronized (mLock) {
5083                     executor = mExecutor;
5084                     callback = mCallback;
5085                 }
5086                 if (executor == null || callback == null) {
5087                     return;
5088                 }
5089                 Binder.clearCallingIdentity();
5090                 executor.execute(callback::onSubsystemRestarting);
5091             }
5092 
5093             @Override
onSubsystemRestarted()5094             public void onSubsystemRestarted() {
5095                 Executor executor;
5096                 SubsystemRestartTrackingCallback callback;
5097                 synchronized (mLock) {
5098                     executor = mExecutor;
5099                     callback = mCallback;
5100                 }
5101                 if (executor == null || callback == null) {
5102                     return;
5103                 }
5104                 Binder.clearCallingIdentity();
5105                 executor.execute(callback::onSubsystemRestarted);
5106             }
5107         }
5108     }
5109 
5110     /**
5111      * Registers a {@link SubsystemRestartTrackingCallback} to listen to Wi-Fi subsystem restarts.
5112      * The subsystem may restart due to internal recovery mechanisms or via user action.
5113      *
5114      * @see #unregisterSubsystemRestartTrackingCallback(SubsystemRestartTrackingCallback)
5115      *
5116      * @param executor Executor to execute callback on
5117      * @param callback {@link SubsystemRestartTrackingCallback} to register
5118      */
5119     @RequiresApi(Build.VERSION_CODES.S)
5120     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
registerSubsystemRestartTrackingCallback( @onNull @allbackExecutor Executor executor, @NonNull SubsystemRestartTrackingCallback callback)5121     public void registerSubsystemRestartTrackingCallback(
5122             @NonNull @CallbackExecutor Executor executor,
5123             @NonNull SubsystemRestartTrackingCallback callback) {
5124         if (executor == null) throw new IllegalArgumentException("executor must not be null");
5125         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5126         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy proxy = callback.getProxy();
5127         proxy.initProxy(executor, callback);
5128         try {
5129             mService.registerSubsystemRestartCallback(proxy);
5130         } catch (RemoteException e) {
5131             proxy.cleanUpProxy();
5132             throw e.rethrowFromSystemServer();
5133         }
5134     }
5135 
5136     /**
5137      * Unregisters a {@link SubsystemRestartTrackingCallback} registered with
5138      * {@link #registerSubsystemRestartTrackingCallback(Executor, SubsystemRestartTrackingCallback)}
5139      *
5140      * @param callback {@link SubsystemRestartTrackingCallback} to unregister
5141      */
5142     @RequiresApi(Build.VERSION_CODES.S)
5143     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
unregisterSubsystemRestartTrackingCallback( @onNull SubsystemRestartTrackingCallback callback)5144     public void unregisterSubsystemRestartTrackingCallback(
5145             @NonNull SubsystemRestartTrackingCallback callback) {
5146         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5147         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy proxy = callback.getProxy();
5148         try {
5149             mService.unregisterSubsystemRestartCallback(proxy);
5150         } catch (RemoteException e) {
5151             throw e.rethrowFromSystemServer();
5152         } finally {
5153             proxy.cleanUpProxy();
5154         }
5155     }
5156 
5157     /**
5158      * Restart the Wi-Fi subsystem.
5159      *
5160      * Restarts the Wi-Fi subsystem - effectively disabling it and re-enabling it. All existing
5161      * Access Point (AP) associations are torn down, all Soft APs are disabled, Wi-Fi Direct and
5162      * Wi-Fi Aware are disabled.
5163      *
5164      * The state of the system after restart is not guaranteed to match its state before the API is
5165      * called - for instance the device may associate to a different Access Point (AP), and tethered
5166      * hotspots may or may not be restored.
5167      *
5168      * Use the
5169      * {@link #registerSubsystemRestartTrackingCallback(Executor, SubsystemRestartTrackingCallback)}
5170      * to track the operation.
5171      *
5172      * @hide
5173      */
5174     @RequiresApi(Build.VERSION_CODES.S)
5175     @SystemApi
5176     @RequiresPermission(android.Manifest.permission.RESTART_WIFI_SUBSYSTEM)
restartWifiSubsystem()5177     public void restartWifiSubsystem() {
5178         try {
5179             mService.restartWifiSubsystem();
5180         } catch (RemoteException e) {
5181             throw e.rethrowFromSystemServer();
5182         }
5183     }
5184 
5185     /**
5186      * Gets the Wi-Fi enabled state.
5187      * @return One of {@link #WIFI_STATE_DISABLED},
5188      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
5189      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
5190      * @see #isWifiEnabled()
5191      */
getWifiState()5192     public int getWifiState() {
5193         try {
5194             return mService.getWifiEnabledState();
5195         } catch (RemoteException e) {
5196             throw e.rethrowFromSystemServer();
5197         }
5198     }
5199 
5200     /**
5201      * Return whether Wi-Fi is enabled or disabled.
5202      * @return {@code true} if Wi-Fi is enabled
5203      * @see #getWifiState()
5204      */
isWifiEnabled()5205     public boolean isWifiEnabled() {
5206         return getWifiState() == WIFI_STATE_ENABLED;
5207     }
5208 
5209     /**
5210      * Calculates the level of the signal. This should be used any time a signal
5211      * is being shown.
5212      *
5213      * @param rssi The power of the signal measured in RSSI.
5214      * @param numLevels The number of levels to consider in the calculated level.
5215      * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive).
5216      * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the
5217      * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level
5218      * themselves using their own formula.
5219      */
5220     @Deprecated
calculateSignalLevel(int rssi, int numLevels)5221     public static int calculateSignalLevel(int rssi, int numLevels) {
5222         if (rssi <= MIN_RSSI) {
5223             return 0;
5224         } else if (rssi >= MAX_RSSI) {
5225             return numLevels - 1;
5226         } else {
5227             float inputRange = (MAX_RSSI - MIN_RSSI);
5228             float outputRange = (numLevels - 1);
5229             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
5230         }
5231     }
5232 
5233     /**
5234      * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI
5235      * quality rating thresholds.
5236      * @param rssi a raw RSSI value, in dBm, usually between -55 and -90
5237      * @return the RSSI signal quality rating, in the range
5238      * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
5239      * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
5240      */
5241     @IntRange(from = 0)
calculateSignalLevel(int rssi)5242     public int calculateSignalLevel(int rssi) {
5243         try {
5244             return mService.calculateSignalLevel(rssi);
5245         } catch (RemoteException e) {
5246             throw e.rethrowFromSystemServer();
5247         }
5248     }
5249 
5250     /**
5251      * Get the system default maximum signal level.
5252      * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
5253      */
5254     @IntRange(from = 0)
getMaxSignalLevel()5255     public int getMaxSignalLevel() {
5256         return calculateSignalLevel(Integer.MAX_VALUE);
5257     }
5258 
5259     /**
5260      * Compares two signal strengths.
5261      *
5262      * @param rssiA The power of the first signal measured in RSSI.
5263      * @param rssiB The power of the second signal measured in RSSI.
5264      * @return Returns <0 if the first signal is weaker than the second signal,
5265      *         0 if the two signals have the same strength, and >0 if the first
5266      *         signal is stronger than the second signal.
5267      */
compareSignalLevel(int rssiA, int rssiB)5268     public static int compareSignalLevel(int rssiA, int rssiB) {
5269         return rssiA - rssiB;
5270     }
5271 
5272     /**
5273      * Call allowing ConnectivityService to update WifiService with interface mode changes.
5274      *
5275      * @param ifaceName String name of the updated interface, or null to represent all interfaces
5276      * @param mode int representing the new mode, one of:
5277      *             {@link #IFACE_IP_MODE_TETHERED},
5278      *             {@link #IFACE_IP_MODE_LOCAL_ONLY},
5279      *             {@link #IFACE_IP_MODE_CONFIGURATION_ERROR},
5280      *             {@link #IFACE_IP_MODE_UNSPECIFIED}
5281      *
5282      * @hide
5283      */
5284     @SystemApi
5285     @RequiresPermission(anyOf = {
5286             android.Manifest.permission.NETWORK_STACK,
5287             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5288     })
updateInterfaceIpState(@ullable String ifaceName, @IfaceIpMode int mode)5289     public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
5290         try {
5291             mService.updateInterfaceIpState(ifaceName, mode);
5292         } catch (RemoteException e) {
5293             throw e.rethrowFromSystemServer();
5294         }
5295     }
5296 
5297     /* Wi-Fi/Cellular Coex */
5298 
5299     /**
5300      * Mandatory coex restriction flag for Wi-Fi Direct.
5301      *
5302      * @see #setCoexUnsafeChannels(List, int)
5303      *
5304      * @hide
5305      */
5306     @SystemApi
5307     @RequiresApi(Build.VERSION_CODES.S)
5308     public static final int COEX_RESTRICTION_WIFI_DIRECT = 0x1 << 0;
5309 
5310     /**
5311      * Mandatory coex restriction flag for SoftAP
5312      *
5313      * @see #setCoexUnsafeChannels(List, int)
5314      *
5315      * @hide
5316      */
5317     @SystemApi
5318     @RequiresApi(Build.VERSION_CODES.S)
5319     public static final int COEX_RESTRICTION_SOFTAP = 0x1 << 1;
5320 
5321     /**
5322      * Mandatory coex restriction flag for Wi-Fi Aware.
5323      *
5324      * @see #setCoexUnsafeChannels(List, int)
5325      *
5326      * @hide
5327      */
5328     @SystemApi
5329     @RequiresApi(Build.VERSION_CODES.S)
5330     public static final int COEX_RESTRICTION_WIFI_AWARE = 0x1 << 2;
5331 
5332     /** @hide */
5333     @RequiresApi(Build.VERSION_CODES.S)
5334     @Retention(RetentionPolicy.SOURCE)
5335     @IntDef(flag = true, prefix = {"COEX_RESTRICTION_"}, value = {
5336             COEX_RESTRICTION_WIFI_DIRECT,
5337             COEX_RESTRICTION_SOFTAP,
5338             COEX_RESTRICTION_WIFI_AWARE
5339     })
5340     public @interface CoexRestriction {}
5341 
5342     /**
5343      * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
5344      *
5345      * @hide
5346      */
isDefaultCoexAlgorithmEnabled()5347     public boolean isDefaultCoexAlgorithmEnabled() {
5348         try {
5349             return mService.isDefaultCoexAlgorithmEnabled();
5350         } catch (RemoteException e) {
5351             throw e.rethrowFromSystemServer();
5352         }
5353     }
5354 
5355     /**
5356      * Specify the list of {@link CoexUnsafeChannel} to propagate through the framework for
5357      * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
5358      * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
5359      *
5360      * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
5361      * @param restrictions Bitmap of {@code COEX_RESTRICTION_*} constants specifying the mode
5362      *                     restrictions on the specified channels. If any restrictions are set,
5363      *                     then the supplied CoexUnsafeChannels should be completely avoided for
5364      *                     the specified modes, rather than be avoided with best effort.
5365      *
5366      * @hide
5367      */
5368     @SystemApi
5369     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS)
5370     @RequiresApi(Build.VERSION_CODES.S)
setCoexUnsafeChannels( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5371     public void setCoexUnsafeChannels(
5372             @NonNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions) {
5373         if (unsafeChannels == null) {
5374             throw new IllegalArgumentException("unsafeChannels must not be null");
5375         }
5376         try {
5377             mService.setCoexUnsafeChannels(unsafeChannels, restrictions);
5378         } catch (RemoteException e) {
5379             throw e.rethrowFromSystemServer();
5380         }
5381     }
5382 
5383     /**
5384      * Registers a CoexCallback to listen on the current CoexUnsafeChannels and restrictions being
5385      * used for Wi-Fi/cellular coex channel avoidance. The callback method
5386      * {@link CoexCallback#onCoexUnsafeChannelsChanged(List, int)} will be called immediately after
5387      * registration to return the current values.
5388      *
5389      * @param executor Executor to execute listener callback on
5390      * @param callback CoexCallback to register
5391      *
5392      * @hide
5393      */
5394     @SystemApi
5395     @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
5396     @RequiresApi(Build.VERSION_CODES.S)
registerCoexCallback( @onNull @allbackExecutor Executor executor, @NonNull CoexCallback callback)5397     public void registerCoexCallback(
5398             @NonNull @CallbackExecutor Executor executor, @NonNull CoexCallback callback) {
5399         if (executor == null) throw new IllegalArgumentException("executor must not be null");
5400         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5401         CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
5402         proxy.initProxy(executor, callback);
5403         try {
5404             mService.registerCoexCallback(proxy);
5405         } catch (RemoteException e) {
5406             throw e.rethrowFromSystemServer();
5407         }
5408     }
5409 
5410     /**
5411      * Unregisters a CoexCallback from listening on the current CoexUnsafeChannels and restrictions
5412      * being used for Wi-Fi/cellular coex channel avoidance.
5413      * @param callback CoexCallback to unregister
5414      *
5415      * @hide
5416      */
5417     @SystemApi
5418     @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
5419     @RequiresApi(Build.VERSION_CODES.S)
unregisterCoexCallback(@onNull CoexCallback callback)5420     public void unregisterCoexCallback(@NonNull CoexCallback callback) {
5421         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5422         CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
5423         try {
5424             mService.unregisterCoexCallback(proxy);
5425         } catch (RemoteException e) {
5426             throw e.rethrowFromSystemServer();
5427         } finally {
5428             proxy.cleanUpProxy();
5429         }
5430     }
5431 
5432     /**
5433      * Abstract callback class for applications to receive updates about current CoexUnsafeChannels
5434      * for Wi-Fi/Cellular coex channel avoidance.
5435      *
5436      * @hide
5437      */
5438     @SystemApi
5439     @RequiresApi(Build.VERSION_CODES.S)
5440     public abstract static class CoexCallback {
5441         private final CoexCallbackProxy mCoexCallbackProxy;
5442 
CoexCallback()5443         public CoexCallback() {
5444             if (!SdkLevel.isAtLeastS()) {
5445                 throw new UnsupportedOperationException();
5446             }
5447             mCoexCallbackProxy = new CoexCallbackProxy();
5448         }
5449 
5450         /*package*/ @NonNull
getProxy()5451         CoexCallbackProxy getProxy() {
5452             return mCoexCallbackProxy;
5453         }
5454 
5455         /**
5456          * This indicates the current CoexUnsafeChannels and restrictions calculated by the default
5457          * coex algorithm if config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, the
5458          * values will match the ones supplied to {@link #setCoexUnsafeChannels(List, int)}.
5459          *
5460          * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
5461          * @param restrictions Bitmap of {@code COEX_RESTRICTION_*} constants specifying the mode
5462          *                     restrictions on the specified channels. If any restrictions are set,
5463          *                     then the supplied CoexUnsafeChannels should be completely avoided for
5464          *                     the specified modes, rather than be avoided with best effort.
5465          */
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5466         public abstract void onCoexUnsafeChannelsChanged(
5467                 @NonNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions);
5468 
5469         /**
5470          * Callback proxy for CoexCallback objects.
5471          */
5472         private static class CoexCallbackProxy extends ICoexCallback.Stub {
5473             private final Object mLock = new Object();
5474             @Nullable @GuardedBy("mLock") private Executor mExecutor;
5475             @Nullable @GuardedBy("mLock") private CoexCallback mCallback;
5476 
CoexCallbackProxy()5477             CoexCallbackProxy() {
5478                 mExecutor = null;
5479                 mCallback = null;
5480             }
5481 
initProxy(@onNull Executor executor, @NonNull CoexCallback callback)5482             /*package*/ void initProxy(@NonNull Executor executor,
5483                     @NonNull CoexCallback callback) {
5484                 synchronized (mLock) {
5485                     mExecutor = executor;
5486                     mCallback = callback;
5487                 }
5488             }
5489 
cleanUpProxy()5490             /*package*/ void cleanUpProxy() {
5491                 synchronized (mLock) {
5492                     mExecutor = null;
5493                     mCallback = null;
5494                 }
5495             }
5496 
5497             @Override
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5498             public void onCoexUnsafeChannelsChanged(
5499                     @NonNull List<CoexUnsafeChannel> unsafeChannels,
5500                     @CoexRestriction int restrictions) {
5501                 Executor executor;
5502                 CoexCallback callback;
5503                 synchronized (mLock) {
5504                     executor = mExecutor;
5505                     callback = mCallback;
5506                 }
5507                 if (executor == null || callback == null) {
5508                     return;
5509                 }
5510                 Binder.clearCallingIdentity();
5511                 executor.execute(() ->
5512                         callback.onCoexUnsafeChannelsChanged(unsafeChannels, restrictions));
5513             }
5514         }
5515     }
5516 
5517     /**
5518      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
5519      * Note that starting Soft AP mode may disable station mode operation if the device does not
5520      * support concurrency.
5521      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
5522      *                   use the persisted Soft AP configuration that was previously set using
5523      *                   {@link #setWifiApConfiguration(WifiConfiguration)}.
5524      * @return {@code true} if the operation succeeded, {@code false} otherwise
5525      *
5526      * @hide
5527      */
5528     @RequiresPermission(anyOf = {
5529             android.Manifest.permission.NETWORK_STACK,
5530             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5531     })
startSoftAp(@ullable WifiConfiguration wifiConfig)5532     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
5533         try {
5534             return mService.startSoftAp(wifiConfig, mContext.getOpPackageName());
5535         } catch (RemoteException e) {
5536             throw e.rethrowFromSystemServer();
5537         }
5538     }
5539 
5540     /**
5541      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
5542      * Note that starting Soft AP mode may disable station mode operation if the device does not
5543      * support concurrency.
5544      *
5545      * Note: Call {@link WifiManager#validateSoftApConfiguration(SoftApConfiguration)} to avoid
5546      * unexpected error due to invalid configuration.
5547      *
5548      * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP, or
5549      *                     null to use the persisted Soft AP configuration that was previously set
5550      *                     using {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}.
5551      * @return {@code true} if the operation succeeded, {@code false} otherwise
5552      *
5553      * @hide
5554      */
5555     @SystemApi
5556     @RequiresPermission(anyOf = {
5557             android.Manifest.permission.NETWORK_STACK,
5558             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5559     })
startTetheredHotspot(@ullable SoftApConfiguration softApConfig)5560     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
5561         try {
5562             return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
5563         } catch (RemoteException e) {
5564             throw e.rethrowFromSystemServer();
5565         }
5566     }
5567 
5568 
5569     /**
5570      * Stop SoftAp mode.
5571      * Note that stopping softap mode will restore the previous wifi mode.
5572      * @return {@code true} if the operation succeeds, {@code false} otherwise
5573      *
5574      * @hide
5575      */
5576     @SystemApi
5577     @RequiresPermission(anyOf = {
5578             android.Manifest.permission.NETWORK_STACK,
5579             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5580     })
stopSoftAp()5581     public boolean stopSoftAp() {
5582         try {
5583             return mService.stopSoftAp();
5584         } catch (RemoteException e) {
5585             throw e.rethrowFromSystemServer();
5586         }
5587     }
5588 
5589     /**
5590      * Check if input configuration is valid.
5591      *
5592      * @param config a configuration would like to be checked.
5593      * @return true if config is valid, otherwise false.
5594      */
validateSoftApConfiguration(@onNull SoftApConfiguration config)5595     public boolean validateSoftApConfiguration(@NonNull SoftApConfiguration config) {
5596         if (config == null) {
5597             throw new IllegalArgumentException(TAG + ": config can not be null");
5598         }
5599         try {
5600             return mService.validateSoftApConfiguration(config);
5601         } catch (RemoteException e) {
5602             throw e.rethrowFromSystemServer();
5603         }
5604     }
5605 
5606     /**
5607      * Request a local only hotspot that an application can use to communicate between co-located
5608      * devices connected to the created WiFi hotspot.  The network created by this method will not
5609      * have Internet access.  Each application can make a single request for the hotspot, but
5610      * multiple applications could be requesting the hotspot at the same time.  When multiple
5611      * applications have successfully registered concurrently, they will be sharing the underlying
5612      * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called
5613      * when the hotspot is ready for use by the application.
5614      * <p>
5615      * Each application can make a single active call to this method. The {@link
5616      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
5617      * requestor with a {@link LocalOnlyHotspotReservation} that contains a
5618      * {@link SoftApConfiguration} with the SSID, security type and credentials needed to connect
5619      * to the hotspot.  Communicating this information is up to the application.
5620      * <p>
5621      * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
5622      * method will be called. Example failures include errors bringing up the network or if
5623      * there is an incompatible operating mode.  For example, if the user is currently using Wifi
5624      * Tethering to provide an upstream to another device, LocalOnlyHotspot may not start due to
5625      * an incompatible mode. The possible error codes include:
5626      * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL},
5627      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC},
5628      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and
5629      * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}.
5630      * <p>
5631      * Internally, requests will be tracked to prevent the hotspot from being torn down while apps
5632      * are still using it.  The {@link LocalOnlyHotspotReservation} object passed in the  {@link
5633      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when
5634      * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}.
5635      * Since the hotspot may be shared among multiple applications, removing the final registered
5636      * application request will trigger the hotspot teardown.  This means that applications should
5637      * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after
5638      * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is
5639      * called, applications will not receive callbacks of any kind.
5640      * <p>
5641      * Applications should be aware that the user may also stop the LocalOnlyHotspot through the
5642      * Settings UI; it is not guaranteed to stay up as long as there is a requesting application.
5643      * The requestors will be notified of this case via
5644      * {@link LocalOnlyHotspotCallback#onStopped()}.  Other cases may arise where the hotspot is
5645      * torn down (Emergency mode, etc).  Application developers should be aware that it can stop
5646      * unexpectedly, but they will receive a notification if they have properly registered.
5647      * <p>
5648      * Applications should also be aware that this network will be shared with other applications.
5649      * Applications are responsible for protecting their data on this network (e.g. TLS).
5650      * <p>
5651      * Applications targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later need to have
5652      * the following permissions: {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
5653      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}.
5654      * Applications targeting {@link Build.VERSION_CODES#S} or prior SDK levels need to have the
5655      * following permissions: {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
5656      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
5657      * Callers without
5658      * the permissions will trigger a {@link java.lang.SecurityException}.
5659      * <p>
5660      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
5661      * operating status.
5662      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
5663      * main thread will be used.
5664      */
5665     @RequiresPermission(allOf = {CHANGE_WIFI_STATE, ACCESS_FINE_LOCATION, NEARBY_WIFI_DEVICES},
5666             conditional = true)
startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler)5667     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
5668             @Nullable Handler handler) {
5669         Executor executor = handler == null ? null : new HandlerExecutor(handler);
5670         startLocalOnlyHotspotInternal(null, executor, callback);
5671     }
5672 
5673     /**
5674      * Starts a local-only hotspot with a specific configuration applied. See
5675      * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
5676      *
5677      * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD},
5678      * {@link android.Manifest.permission#NETWORK_SETTINGS} or
5679      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} to call this method.
5680      *
5681      * Since custom configuration settings may be incompatible with each other, the hotspot started
5682      * through this method cannot coexist with another hotspot created through
5683      * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others
5684      * receive {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
5685      * {@link LocalOnlyHotspotCallback#onFailed}.
5686      *
5687      * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
5688      * @param executor Executor to run callback methods on, or null to use the main thread.
5689      * @param callback Callback object for updates about hotspot status, or null for no updates.
5690      * @hide
5691      */
5692     @SystemApi
5693     @RequiresPermission(anyOf = {
5694             android.Manifest.permission.NETWORK_SETTINGS,
5695             android.Manifest.permission.NETWORK_SETUP_WIZARD,
5696             NEARBY_WIFI_DEVICES})
startLocalOnlyHotspot(@onNull SoftApConfiguration config, @Nullable @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)5697     public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config,
5698             @Nullable @CallbackExecutor Executor executor,
5699             @Nullable LocalOnlyHotspotCallback callback) {
5700         Objects.requireNonNull(config);
5701         startLocalOnlyHotspotInternal(config, executor, callback);
5702     }
5703 
5704     /**
5705      * Common implementation of both configurable and non-configurable LOHS.
5706      *
5707      * @param config App-specified configuration, or null. When present, additional privileges are
5708      *               required, and the hotspot cannot be shared with other clients.
5709      * @param executor Executor to run callback methods on, or null to use the main thread.
5710      * @param callback Callback object for updates about hotspot status, or null for no updates.
5711      */
startLocalOnlyHotspotInternal( @ullable SoftApConfiguration config, @Nullable @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)5712     private void startLocalOnlyHotspotInternal(
5713             @Nullable SoftApConfiguration config,
5714             @Nullable @CallbackExecutor Executor executor,
5715             @Nullable LocalOnlyHotspotCallback callback) {
5716         if (executor == null) {
5717             executor = mContext.getMainExecutor();
5718         }
5719         synchronized (mLock) {
5720             LocalOnlyHotspotCallbackProxy proxy =
5721                     new LocalOnlyHotspotCallbackProxy(this, executor, callback);
5722             try {
5723                 String packageName = mContext.getOpPackageName();
5724                 String featureId = mContext.getAttributionTag();
5725                 Bundle extras = new Bundle();
5726                 if (SdkLevel.isAtLeastS()) {
5727                     extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
5728                             mContext.getAttributionSource());
5729                 }
5730                 int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
5731                         config, extras);
5732                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
5733                     // Send message to the proxy to make sure we call back on the correct thread
5734                     proxy.onHotspotFailed(returnCode);
5735                     return;
5736                 }
5737                 mLOHSCallbackProxy = proxy;
5738             } catch (RemoteException e) {
5739                 throw e.rethrowFromSystemServer();
5740             }
5741         }
5742     }
5743 
5744     /**
5745      * Cancels a pending local only hotspot request.  This can be used by the calling application to
5746      * cancel the existing request if the provided callback has not been triggered.  Calling this
5747      * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not
5748      * explicitly required.
5749      * <p>
5750      * When cancelling this request, application developers should be aware that there may still be
5751      * outstanding local only hotspot requests and the hotspot may still start, or continue running.
5752      * Additionally, if a callback was registered, it will no longer be triggered after calling
5753      * cancel.
5754      *
5755      * @hide
5756      */
5757     @UnsupportedAppUsage
cancelLocalOnlyHotspotRequest()5758     public void cancelLocalOnlyHotspotRequest() {
5759         synchronized (mLock) {
5760             stopLocalOnlyHotspot();
5761         }
5762     }
5763 
5764     /**
5765      *  Method used to inform WifiService that the LocalOnlyHotspot is no longer needed.  This
5766      *  method is used by WifiManager to release LocalOnlyHotspotReservations held by calling
5767      *  applications and removes the internal tracking for the hotspot request.  When all requesting
5768      *  applications are finished using the hotspot, it will be stopped and WiFi will return to the
5769      *  previous operational mode.
5770      *
5771      *  This method should not be called by applications.  Instead, they should call the close()
5772      *  method on their LocalOnlyHotspotReservation.
5773      */
stopLocalOnlyHotspot()5774     private void stopLocalOnlyHotspot() {
5775         synchronized (mLock) {
5776             if (mLOHSCallbackProxy == null) {
5777                 // nothing to do, the callback was already cleaned up.
5778                 return;
5779             }
5780             mLOHSCallbackProxy = null;
5781             try {
5782                 mService.stopLocalOnlyHotspot();
5783             } catch (RemoteException e) {
5784                 throw e.rethrowFromSystemServer();
5785             }
5786         }
5787     }
5788 
5789     /**
5790      * Registers a callback for local only hotspot. See {@link SoftApCallback}. Caller will receive
5791      * the following callbacks on registration:
5792      * <ul>
5793      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
5794      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
5795      * <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
5796      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
5797      * </ul>
5798      *
5799      * Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
5800      * if there are any clients connected to a specific bridged instance of this AP
5801      * (if bridged AP is enabled).
5802      *
5803      * Note: Caller will receive the callback
5804      * {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)}
5805      * on registration when there are clients connected to AP.
5806      *
5807      * These will be dispatched on registration to provide the caller with the current state
5808      * (and are not an indication of any current change). Note that receiving an immediate
5809      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
5810      * soft AP has failed. Caller can unregister a previously registered callback using
5811      * {@link #unregisterLocalOnlyHotspotSoftApCallback}
5812      * <p>
5813      *
5814      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
5815      *                 object.
5816      * @param callback Callback for local only hotspot events
5817      * @hide
5818      */
5819     @SystemApi
5820     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
5821     @RequiresPermission(NEARBY_WIFI_DEVICES)
registerLocalOnlyHotspotSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)5822     public void registerLocalOnlyHotspotSoftApCallback(@NonNull @CallbackExecutor Executor executor,
5823             @NonNull SoftApCallback callback) {
5824         if (!SdkLevel.isAtLeastT()) {
5825             throw new UnsupportedOperationException();
5826         }
5827         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5828         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5829         Log.v(TAG, "registerLocalOnlyHotspotSoftApCallback: callback=" + callback + ", executor="
5830                 + executor);
5831         try {
5832             synchronized (sLocalOnlyHotspotSoftApCallbackMap) {
5833                 ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
5834                         IFACE_IP_MODE_LOCAL_ONLY);
5835                 sLocalOnlyHotspotSoftApCallbackMap.put(System.identityHashCode(callback),
5836                         binderCallback);
5837                 Bundle extras = new Bundle();
5838                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
5839                         mContext.getAttributionSource());
5840                 mService.registerLocalOnlyHotspotSoftApCallback(binderCallback, extras);
5841             }
5842         } catch (RemoteException e) {
5843             throw e.rethrowFromSystemServer();
5844         }
5845     }
5846 
5847     /**
5848      * Allow callers to unregister a previously registered callback. After calling this method,
5849      * applications will no longer receive local only hotspot events.
5850      *
5851      * <p>
5852      *
5853      * @param callback Callback to unregister for soft AP events
5854      *
5855      * @hide
5856      */
5857     @SystemApi
5858     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
5859     @RequiresPermission(NEARBY_WIFI_DEVICES)
unregisterLocalOnlyHotspotSoftApCallback(@onNull SoftApCallback callback)5860     public void unregisterLocalOnlyHotspotSoftApCallback(@NonNull SoftApCallback callback) {
5861         if (!SdkLevel.isAtLeastT()) {
5862             throw new UnsupportedOperationException();
5863         }
5864         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5865         Log.v(TAG, "unregisterLocalOnlyHotspotSoftApCallback: callback=" + callback);
5866 
5867         try {
5868             synchronized (sLocalOnlyHotspotSoftApCallbackMap) {
5869                 int callbackIdentifier = System.identityHashCode(callback);
5870                 if (!sLocalOnlyHotspotSoftApCallbackMap.contains(callbackIdentifier)) {
5871                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
5872                     return;
5873                 }
5874                 Bundle extras = new Bundle();
5875                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
5876                         mContext.getAttributionSource());
5877                 mService.unregisterLocalOnlyHotspotSoftApCallback(
5878                         sLocalOnlyHotspotSoftApCallbackMap.get(callbackIdentifier), extras);
5879                 sLocalOnlyHotspotSoftApCallbackMap.remove(callbackIdentifier);
5880             }
5881         } catch (RemoteException e) {
5882             throw e.rethrowFromSystemServer();
5883         }
5884     }
5885 
5886     /**
5887      * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes.  Callers will
5888      * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
5889      * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
5890      * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(SoftApConfiguration)} and
5891      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
5892      * <p>
5893      * Applications should have the
5894      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
5895      * permission.  Callers without the permission will trigger a
5896      * {@link java.lang.SecurityException}.
5897      * <p>
5898      * @param observer LocalOnlyHotspotObserver callback.
5899      * @param handler Handler to use for callbacks
5900      *
5901      * @hide
5902      */
watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, @Nullable Handler handler)5903     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
5904             @Nullable Handler handler) {
5905         Executor executor = handler == null ? mContext.getMainExecutor()
5906                 : new HandlerExecutor(handler);
5907         synchronized (mLock) {
5908             mLOHSObserverProxy =
5909                     new LocalOnlyHotspotObserverProxy(this, executor, observer);
5910             try {
5911                 mService.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
5912                 mLOHSObserverProxy.registered();
5913             } catch (RemoteException e) {
5914                 mLOHSObserverProxy = null;
5915                 throw e.rethrowFromSystemServer();
5916             }
5917         }
5918     }
5919 
5920     /**
5921      * Allow callers to stop watching LocalOnlyHotspot state changes.  After calling this method,
5922      * applications will no longer receive callbacks.
5923      *
5924      * @hide
5925      */
unregisterLocalOnlyHotspotObserver()5926     public void unregisterLocalOnlyHotspotObserver() {
5927         synchronized (mLock) {
5928             if (mLOHSObserverProxy == null) {
5929                 // nothing to do, the callback was already cleaned up
5930                 return;
5931             }
5932             mLOHSObserverProxy = null;
5933             try {
5934                 mService.stopWatchLocalOnlyHotspot();
5935             } catch (RemoteException e) {
5936                 throw e.rethrowFromSystemServer();
5937             }
5938         }
5939     }
5940 
5941     /**
5942      * Gets the tethered Wi-Fi hotspot enabled state.
5943      * @return One of {@link #WIFI_AP_STATE_DISABLED},
5944      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
5945      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
5946      * @see #isWifiApEnabled()
5947      *
5948      * @hide
5949      */
5950     @SystemApi
5951     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getWifiApState()5952     public int getWifiApState() {
5953         try {
5954             return mService.getWifiApEnabledState();
5955         } catch (RemoteException e) {
5956             throw e.rethrowFromSystemServer();
5957         }
5958     }
5959 
5960     /**
5961      * Return whether tethered Wi-Fi AP is enabled or disabled.
5962      * @return {@code true} if tethered  Wi-Fi AP is enabled
5963      * @see #getWifiApState()
5964      *
5965      * @hide
5966      */
5967     @SystemApi
5968     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiApEnabled()5969     public boolean isWifiApEnabled() {
5970         return getWifiApState() == WIFI_AP_STATE_ENABLED;
5971     }
5972 
5973     /**
5974      * Gets the tethered Wi-Fi AP Configuration.
5975      * @return AP details in WifiConfiguration
5976      *
5977      * Note that AP detail may contain configuration which is cannot be represented
5978      * by the legacy WifiConfiguration, in such cases a null will be returned.
5979      *
5980      * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
5981      * @hide
5982      */
5983     @Nullable
5984     @SystemApi
5985     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
5986     @Deprecated
getWifiApConfiguration()5987     public WifiConfiguration getWifiApConfiguration() {
5988         try {
5989             return mService.getWifiApConfiguration();
5990         } catch (RemoteException e) {
5991             throw e.rethrowFromSystemServer();
5992         }
5993     }
5994 
5995     /**
5996      * Gets the Wi-Fi tethered AP Configuration.
5997      * @return AP details in {@link SoftApConfiguration}
5998      *
5999      * @hide
6000      */
6001     @NonNull
6002     @SystemApi
6003     @RequiresPermission(anyOf = {
6004             android.Manifest.permission.NETWORK_SETTINGS,
6005             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6006     })
getSoftApConfiguration()6007     public SoftApConfiguration getSoftApConfiguration() {
6008         try {
6009             return mService.getSoftApConfiguration();
6010         } catch (RemoteException e) {
6011             throw e.rethrowFromSystemServer();
6012         }
6013     }
6014 
6015     /**
6016      * Gets the last configured Wi-Fi tethered AP passphrase.
6017      *
6018      * Note: It may be null when there is no passphrase changed since
6019      * device boot.
6020      *
6021      * @param executor The executor on which callback will be invoked.
6022      * @param resultCallback An asynchronous callback that will return the last configured
6023      *                       Wi-Fi tethered AP passphrase.
6024      *
6025      * @throws SecurityException if the caller does not have permission.
6026      * @throws NullPointerException if the caller provided invalid inputs.
6027      *
6028      * @hide
6029      */
6030     @Nullable
6031     @SystemApi
6032     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
queryLastConfiguredTetheredApPassphraseSinceBoot( @onNull @allbackExecutor Executor executor, @NonNull Consumer<String> resultCallback)6033     public void queryLastConfiguredTetheredApPassphraseSinceBoot(
6034             @NonNull @CallbackExecutor Executor executor,
6035             @NonNull Consumer<String> resultCallback) {
6036         Objects.requireNonNull(executor, "executor cannot be null");
6037         Objects.requireNonNull(resultCallback, "resultsCallback cannot be null");
6038         try {
6039             mService.queryLastConfiguredTetheredApPassphraseSinceBoot(
6040                     new IStringListener.Stub() {
6041                         @Override
6042                         public void onResult(String value) {
6043                             Binder.clearCallingIdentity();
6044                             executor.execute(() -> {
6045                                 resultCallback.accept(value);
6046                             });
6047                         }
6048                     });
6049         } catch (RemoteException e) {
6050             throw e.rethrowFromSystemServer();
6051         }
6052     }
6053 
6054     /**
6055      * Sets the tethered Wi-Fi AP Configuration.
6056      * @return {@code true} if the operation succeeded, {@code false} otherwise
6057      *
6058      * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
6059      * instead.
6060      * @hide
6061      */
6062     @SystemApi
6063     @RequiresPermission(CHANGE_WIFI_STATE)
6064     @Deprecated
setWifiApConfiguration(WifiConfiguration wifiConfig)6065     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
6066         try {
6067             return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
6068         } catch (RemoteException e) {
6069             throw e.rethrowFromSystemServer();
6070         }
6071     }
6072 
6073     /**
6074      * Sets the tethered Wi-Fi AP Configuration.
6075      *
6076      * If the API is called while the tethered soft AP is enabled, the configuration will apply to
6077      * the current soft AP if the new configuration only includes
6078      * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
6079      * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
6080      * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
6081      * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
6082      * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
6083      * or {@link SoftApConfiguration.Builder#setAutoShutdownEnabled(boolean)}
6084      * or {@link SoftApConfiguration.Builder#setBridgedModeOpportunisticShutdownEnabled(boolean)}
6085      *
6086      * Otherwise, the configuration changes will be applied when the Soft AP is next started
6087      * (the framework will not stop/start the AP).
6088      *
6089      * Note: Call {@link WifiManager#validateSoftApConfiguration(SoftApConfiguration)} to avoid
6090      * unexpected error due to invalid configuration.
6091      *
6092      * @param softApConfig  A valid SoftApConfiguration specifying the configuration of the SAP.
6093      * @return {@code true} if the operation succeeded, {@code false} otherwise
6094      *
6095      * @hide
6096      */
6097     @SystemApi
6098     @RequiresPermission(anyOf = {
6099             android.Manifest.permission.NETWORK_SETTINGS,
6100             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6101     })
setSoftApConfiguration(@onNull SoftApConfiguration softApConfig)6102     public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
6103         try {
6104             return mService.setSoftApConfiguration(
6105                     softApConfig, mContext.getOpPackageName());
6106         } catch (RemoteException e) {
6107             throw e.rethrowFromSystemServer();
6108         }
6109     }
6110 
6111     /**
6112      * Enable/Disable TDLS on a specific local route.
6113      *
6114      * <p>
6115      * TDLS enables two wireless endpoints to talk to each other directly
6116      * without going through the access point that is managing the local
6117      * network. It saves bandwidth and improves quality of the link.
6118      * </p>
6119      * <p>
6120      * This API enables/disables the option of using TDLS. If enabled, the
6121      * underlying hardware is free to use TDLS or a hop through the access
6122      * point. If disabled, existing TDLS session is torn down and
6123      * hardware is restricted to use access point for transferring wireless
6124      * packets. Default value for all routes is 'disabled', meaning restricted
6125      * to use access point for transferring packets.
6126      * </p>
6127      *
6128      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
6129      * @param enable true = setup and false = tear down TDLS
6130      */
setTdlsEnabled(InetAddress remoteIPAddress, boolean enable)6131     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
6132         try {
6133             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
6134         } catch (RemoteException e) {
6135             throw e.rethrowFromSystemServer();
6136         }
6137     }
6138 
6139     /**
6140      * Enable/Disable TDLS on a specific local route.
6141      *
6142      * Similar to {@link #setTdlsEnabled(InetAddress, boolean)}, except
6143      * this version sends the result of the Enable/Disable request.
6144      *
6145      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
6146      * @param enable true = setup and false = tear down TDLS
6147      * @param executor The executor on which callback will be invoked.
6148      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6149      *                        whether TDLS was successfully enabled or disabled.
6150      *                        {@code true} for success, {@code false} for failure.
6151      *
6152      * @throws NullPointerException if the caller provided invalid inputs.
6153      */
setTdlsEnabled(@onNull InetAddress remoteIPAddress, boolean enable, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6154     public void setTdlsEnabled(@NonNull InetAddress remoteIPAddress, boolean enable,
6155             @NonNull @CallbackExecutor Executor executor,
6156             @NonNull Consumer<Boolean> resultsCallback) {
6157         Objects.requireNonNull(executor, "executor cannot be null");
6158         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6159         Objects.requireNonNull(remoteIPAddress, "remote IP address cannot be null");
6160         try {
6161             mService.enableTdlsWithRemoteIpAddress(remoteIPAddress.getHostAddress(), enable,
6162                     new IBooleanListener.Stub() {
6163                         @Override
6164                         public void onResult(boolean value) {
6165                             Binder.clearCallingIdentity();
6166                             executor.execute(() -> {
6167                                 resultsCallback.accept(value);
6168                             });
6169                         }
6170                     });
6171         } catch (RemoteException e) {
6172             throw e.rethrowFromSystemServer();
6173         }
6174     }
6175 
6176     /**
6177      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
6178      * this version allows you to specify remote endpoint with a MAC address.
6179      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
6180      * @param enable true = setup and false = tear down TDLS
6181      */
setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable)6182     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
6183         try {
6184             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
6185         } catch (RemoteException e) {
6186             throw e.rethrowFromSystemServer();
6187         }
6188     }
6189 
6190     /**
6191      * Enable/Disable TDLS with a specific peer Mac Address.
6192      *
6193      * Similar to {@link #setTdlsEnabledWithMacAddress(String, boolean)}, except
6194      * this version sends the result of the Enable/Disable request.
6195      *
6196      * @param remoteMacAddress Mac address of the endpoint to setup TDLS with
6197      * @param enable true = setup and false = tear down TDLS
6198      * @param executor The executor on which callback will be invoked.
6199      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6200      *                        whether TDLS was successfully enabled or disabled.
6201      *                        {@code true} for success, {@code false} for failure.
6202      *
6203      * @throws NullPointerException if the caller provided invalid inputs.
6204      */
setTdlsEnabledWithMacAddress(@onNull String remoteMacAddress, boolean enable, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6205     public void setTdlsEnabledWithMacAddress(@NonNull String remoteMacAddress, boolean enable,
6206             @NonNull @CallbackExecutor Executor executor,
6207             @NonNull Consumer<Boolean> resultsCallback) {
6208         Objects.requireNonNull(executor, "executor cannot be null");
6209         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6210         Objects.requireNonNull(remoteMacAddress, "remote Mac address cannot be null");
6211         try {
6212             mService.enableTdlsWithRemoteMacAddress(remoteMacAddress, enable,
6213                     new IBooleanListener.Stub() {
6214                         @Override
6215                         public void onResult(boolean value) {
6216                             Binder.clearCallingIdentity();
6217                             executor.execute(() -> {
6218                                 resultsCallback.accept(value);
6219                             });
6220                         }
6221                     });
6222         } catch (RemoteException e) {
6223             throw e.rethrowFromSystemServer();
6224         }
6225     }
6226 
6227     /**
6228      * Check if a TDLS session can be established at this time via
6229      * {@link #setTdlsEnabled(InetAddress, boolean)} or
6230      * {@link #setTdlsEnabledWithMacAddress(String, boolean)} or
6231      * {@link #setTdlsEnabled(InetAddress, boolean, Executor, Consumer)} or
6232      * {@link #setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
6233      *
6234      * Internally framework checks the STA connected state, device support for TDLS and
6235      * the number of TDLS sessions available in driver/firmware.
6236      *
6237      * @param executor The executor on which callback will be invoked.
6238      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6239      *                        whether a TDLS session can be established at this time.
6240      *                        {@code true} for available, {@code false} for not available.
6241      *
6242      * @throws NullPointerException if the caller provided invalid inputs.
6243      */
isTdlsOperationCurrentlyAvailable(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6244     public void isTdlsOperationCurrentlyAvailable(@NonNull @CallbackExecutor Executor executor,
6245             @NonNull Consumer<Boolean> resultsCallback) {
6246         Objects.requireNonNull(executor, "executor cannot be null");
6247         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6248         try {
6249             mService.isTdlsOperationCurrentlyAvailable(
6250                     new IBooleanListener.Stub() {
6251                         @Override
6252                         public void onResult(boolean value) {
6253                             Binder.clearCallingIdentity();
6254                             executor.execute(() -> {
6255                                 resultsCallback.accept(value);
6256                             });
6257                         }
6258                     });
6259         } catch (RemoteException e) {
6260             throw e.rethrowFromSystemServer();
6261         }
6262     }
6263 
6264     /**
6265      * Return the maximum number of concurrent TDLS sessions supported by the device.
6266      *
6267      * @param executor The executor on which callback will be invoked.
6268      * @param resultsCallback An asynchronous callback that will return the maximum number of
6269      *                        concurrent TDLS sessions supported by the device. Returns
6270      *                        {@code -1} if information is not available,
6271      *                        e.g. if the driver/firmware doesn't provide this information.
6272      *
6273      * @throws NullPointerException if the caller provided invalid inputs.
6274      * @throws UnsupportedOperationException if the feature is not available.
6275      */
6276     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
getMaxSupportedConcurrentTdlsSessions(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)6277     public void getMaxSupportedConcurrentTdlsSessions(@NonNull @CallbackExecutor Executor executor,
6278             @NonNull Consumer<Integer> resultsCallback) {
6279         Objects.requireNonNull(executor, "executor cannot be null");
6280         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6281         try {
6282             mService.getMaxSupportedConcurrentTdlsSessions(
6283                     new IIntegerListener.Stub() {
6284                         @Override
6285                         public void onResult(int value) {
6286                             Binder.clearCallingIdentity();
6287                             executor.execute(() -> {
6288                                 resultsCallback.accept(value);
6289                             });
6290                         }
6291                     });
6292         } catch (RemoteException e) {
6293             throw e.rethrowFromSystemServer();
6294         }
6295     }
6296 
6297     /**
6298      * Return the number of currently enabled TDLS sessions.
6299      *
6300      * Tracks the number of peers enabled for TDLS session via
6301      * {@link #setTdlsEnabled(InetAddress, boolean) },
6302      * {@link #setTdlsEnabledWithMacAddress(String, boolean) },
6303      * {@link #setTdlsEnabled(InetAddress, boolean, Executor, Consumer) } and
6304      * {@link #setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer) }
6305      *
6306      * @param executor The executor on which callback will be invoked.
6307      * @param resultsCallback An asynchronous callback that will return the number of Peer
6308      *                        Mac addresses configured in the driver for TDLS session.
6309      *
6310      * @throws NullPointerException if the caller provided invalid inputs.
6311      */
getNumberOfEnabledTdlsSessions(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)6312     public void getNumberOfEnabledTdlsSessions(@NonNull @CallbackExecutor Executor executor,
6313             @NonNull Consumer<Integer> resultsCallback) {
6314         Objects.requireNonNull(executor, "executor cannot be null");
6315         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6316         try {
6317             mService.getNumberOfEnabledTdlsSessions(
6318                     new IIntegerListener.Stub() {
6319                         @Override
6320                         public void onResult(int value) {
6321                             Binder.clearCallingIdentity();
6322                             executor.execute(() -> {
6323                                 resultsCallback.accept(value);
6324                             });
6325                         }
6326                     });
6327         } catch (RemoteException e) {
6328             throw e.rethrowFromSystemServer();
6329         }
6330     }
6331 
6332     /** @hide */
6333     @Retention(RetentionPolicy.SOURCE)
6334     @IntDef({ActionListener.FAILURE_INTERNAL_ERROR,
6335             ActionListener.FAILURE_IN_PROGRESS,
6336             ActionListener.FAILURE_BUSY,
6337             ActionListener.FAILURE_INVALID_ARGS,
6338             ActionListener.FAILURE_NOT_AUTHORIZED})
6339     public @interface ActionListenerFailureReason {}
6340 
6341     /* WPS specific errors */
6342     /** WPS overlap detected
6343      * @deprecated This is deprecated
6344      */
6345     public static final int WPS_OVERLAP_ERROR           = 3;
6346     /** WEP on WPS is prohibited
6347      * @deprecated This is deprecated
6348      */
6349     public static final int WPS_WEP_PROHIBITED          = 4;
6350     /** TKIP only prohibited
6351      * @deprecated This is deprecated
6352      */
6353     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
6354     /** Authentication failure on WPS
6355      * @deprecated This is deprecated
6356      */
6357     public static final int WPS_AUTH_FAILURE            = 6;
6358     /** WPS timed out
6359      * @deprecated This is deprecated
6360      */
6361     public static final int WPS_TIMED_OUT               = 7;
6362 
6363     /**
6364      * Interface for callback invocation on an application action.
6365      * @hide
6366      */
6367     @SystemApi
6368     public interface ActionListener {
6369         /**
6370          * Passed with {@link #onFailure}.
6371          * Indicates that the operation failed due to an internal error.
6372          */
6373         int FAILURE_INTERNAL_ERROR = 0;
6374 
6375         /**
6376          * Passed with {@link #onFailure}.
6377          * Indicates that the operation is already in progress.
6378          */
6379         int FAILURE_IN_PROGRESS = 1;
6380 
6381         /**
6382          * Passed with {@link #onFailure}.
6383          * Indicates that the operation failed because the framework is busy and is unable to
6384          * service the request.
6385          */
6386         int FAILURE_BUSY = 2;
6387 
6388         /**
6389          * Passed with {@link #onFailure}.
6390          * Indicates that the operation failed due to invalid inputs.
6391          */
6392         int FAILURE_INVALID_ARGS = 3;
6393 
6394         /**
6395          * Passed with {@link #onFailure}.
6396          * Indicates that the operation failed due to insufficient user permissions.
6397          */
6398         int FAILURE_NOT_AUTHORIZED = 4;
6399 
6400         /**
6401          * The operation succeeded.
6402          */
onSuccess()6403         void onSuccess();
6404         /**
6405          * The operation failed.
6406          * @param reason The reason for failure depends on the operation.
6407          */
onFailure(@ctionListenerFailureReason int reason)6408         void onFailure(@ActionListenerFailureReason int reason);
6409     }
6410 
6411     /** Interface for callback invocation on a start WPS action
6412      * @deprecated This is deprecated
6413      */
6414     public static abstract class WpsCallback {
6415 
6416         /** WPS start succeeded
6417          * @deprecated This API is deprecated
6418          */
onStarted(String pin)6419         public abstract void onStarted(String pin);
6420 
6421         /** WPS operation completed successfully
6422          * @deprecated This API is deprecated
6423          */
onSucceeded()6424         public abstract void onSucceeded();
6425 
6426         /**
6427          * WPS operation failed
6428          * @param reason The reason for failure could be one of
6429          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
6430          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
6431          * and some generic errors.
6432          * @deprecated This API is deprecated
6433          */
onFailed(int reason)6434         public abstract void onFailed(int reason);
6435     }
6436 
6437     /**
6438      * Base class for soft AP callback. Should be extended by applications and set when calling
6439      * {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
6440      *
6441      * @hide
6442      */
6443     @SystemApi
6444     public interface SoftApCallback {
6445         /**
6446          * Called when soft AP state changes.
6447          *
6448          * @param state         the new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
6449          *                      {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
6450          *                      {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
6451          * @param failureReason reason when in failed state. One of
6452          *                      {@link #SAP_START_FAILURE_GENERAL},
6453          *                      {@link #SAP_START_FAILURE_NO_CHANNEL},
6454          *                      {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION},
6455          *                      {@link #SAP_START_FAILURE_USER_REJECTED}
6456          */
onStateChanged(@ifiApState int state, @SapStartFailure int failureReason)6457         default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
6458 
6459         /**
6460          * Called when the connected clients to soft AP changes.
6461          *
6462          * @param clients the currently connected clients
6463          *
6464          * @deprecated This API is deprecated.
6465          * Use {@link #onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} instead.
6466          */
6467         @Deprecated
onConnectedClientsChanged(@onNull List<WifiClient> clients)6468         default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
6469 
6470 
6471         /**
6472          * Called when the connected clients for a soft AP instance change.
6473          *
6474          * When the Soft AP is configured in single AP mode, this callback is invoked
6475          * with the same {@link SoftApInfo} for all connected clients changes.
6476          * When the Soft AP is configured as multiple Soft AP instances (using
6477          * {@link SoftApConfiguration.Builder#setBands(int[])} or
6478          * {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)}), this
6479          * callback is invoked with the corresponding {@link SoftApInfo} for the instance in which
6480          * the connected clients changed.
6481          *
6482          * @param info The {@link SoftApInfo} of the AP.
6483          * @param clients The currently connected clients on the AP instance specified by
6484          *                {@code info}.
6485          */
onConnectedClientsChanged(@onNull SoftApInfo info, @NonNull List<WifiClient> clients)6486         default void onConnectedClientsChanged(@NonNull SoftApInfo info,
6487                 @NonNull List<WifiClient> clients) {}
6488 
6489         /**
6490          * Called when the Soft AP information changes.
6491          *
6492          * Note: this API remains valid only when the Soft AP is configured as a single AP -
6493          * not as multiple Soft APs (which are bridged to each other). When multiple Soft APs are
6494          * configured (using {@link SoftApConfiguration.Builder#setBands(int[])} or
6495          * {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)})
6496          * this callback will not be triggered -  use the
6497          * {@link #onInfoChanged(List<SoftApInfo>)} callback in that case.
6498          *
6499          * @param softApInfo is the Soft AP information. {@link SoftApInfo}
6500          *
6501          * @deprecated This API is deprecated. Use {@link #onInfoChanged(List<SoftApInfo>)}
6502          * instead.
6503          */
6504         @Deprecated
onInfoChanged(@onNull SoftApInfo softApInfo)6505         default void onInfoChanged(@NonNull SoftApInfo softApInfo) {
6506             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
6507         }
6508 
6509         /**
6510          * Called when the Soft AP information changes.
6511          *
6512          * Returns information on all configured Soft AP instances. The number of the elements in
6513          * the list depends on Soft AP configuration and state:
6514          * <ul>
6515          * <li>An empty list will be returned when the Soft AP is disabled.
6516          * <li>One information element will be returned in the list when the Soft AP is configured
6517          *     as a single AP or when a single Soft AP remains active.
6518          * <li>Two information elements will be returned in the list when the multiple Soft APs are
6519          *     configured and are active.
6520          *     (configured using {@link SoftApConfiguration.Builder#setBands(int[])} or
6521          *     {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)}).
6522          * </ul>
6523          *
6524          * Note: When multiple Soft AP instances are configured, one of the Soft APs may
6525          * be shut down independently of the other by the framework. This can happen if no devices
6526          * are connected to it for some duration. In that case, one information element will be
6527          * returned.
6528          *
6529          * See {@link #isBridgedApConcurrencySupported()} for support info of multiple (bridged) AP.
6530          *
6531          * @param softApInfoList is the list of the Soft AP information elements -
6532          *        {@link SoftApInfo}.
6533          */
onInfoChanged(@onNull List<SoftApInfo> softApInfoList)6534         default void onInfoChanged(@NonNull List<SoftApInfo> softApInfoList) {
6535             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
6536         }
6537 
6538         /**
6539          * Called when capability of Soft AP changes.
6540          *
6541          * @param softApCapability is the Soft AP capability. {@link SoftApCapability}
6542          */
onCapabilityChanged(@onNull SoftApCapability softApCapability)6543         default void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
6544             // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported
6545             // client number) to the UI.
6546         }
6547 
6548         /**
6549          * Called when client trying to connect but device blocked the client with specific reason.
6550          *
6551          * Can be used to ask user to update client to allowed list or blocked list
6552          * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or
6553          * indicate the block due to maximum supported client number limitation when reason is
6554          * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}.
6555          *
6556          * @param client the currently blocked client.
6557          * @param blockedReason one of blocked reason from {@link SapClientBlockedReason}
6558          */
onBlockedClientConnecting(@onNull WifiClient client, @SapClientBlockedReason int blockedReason)6559         default void onBlockedClientConnecting(@NonNull WifiClient client,
6560                 @SapClientBlockedReason int blockedReason) {
6561             // Do nothing: can be used to ask user to update client to allowed list or blocked list.
6562         }
6563     }
6564 
6565     /**
6566      * Callback proxy for SoftApCallback objects.
6567      *
6568      * @hide
6569      */
6570     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
6571         private final Executor mExecutor;
6572         private final SoftApCallback mCallback;
6573         // Either {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
6574         private final int mIpMode;
6575         private Map<String, List<WifiClient>> mCurrentClients = new HashMap<>();
6576         private Map<String, SoftApInfo> mCurrentInfos = new HashMap<>();
6577 
getConnectedClientList(Map<String, List<WifiClient>> clientsMap)6578         private List<WifiClient> getConnectedClientList(Map<String, List<WifiClient>> clientsMap) {
6579             List<WifiClient> connectedClientList = new ArrayList<>();
6580             for (List<WifiClient> it : clientsMap.values()) {
6581                 connectedClientList.addAll(it);
6582             }
6583             return connectedClientList;
6584         }
6585 
SoftApCallbackProxy(Executor executor, SoftApCallback callback, int mode)6586         SoftApCallbackProxy(Executor executor, SoftApCallback callback, int mode) {
6587             mExecutor = executor;
6588             mCallback = callback;
6589             mIpMode = mode;
6590         }
6591 
6592         @Override
onStateChanged(int state, int failureReason)6593         public void onStateChanged(int state, int failureReason) {
6594             if (mVerboseLoggingEnabled) {
6595                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode + ", onStateChanged: state="
6596                         + state + ", failureReason=" + failureReason);
6597             }
6598 
6599             Binder.clearCallingIdentity();
6600             mExecutor.execute(() -> {
6601                 mCallback.onStateChanged(state, failureReason);
6602             });
6603         }
6604 
6605         @Override
onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration)6606         public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
6607                 Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration) {
6608             if (mVerboseLoggingEnabled) {
6609                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6610                         + ", onConnectedClientsOrInfoChanged: clients: "
6611                         + clients + ", infos: " + infos + ", isBridged is " + isBridged
6612                         + ", isRegistration is " + isRegistration);
6613             }
6614 
6615             List<SoftApInfo> changedInfoList = new ArrayList<>(infos.values());
6616             Map<SoftApInfo, List<WifiClient>> changedInfoClients = new HashMap<>();
6617             // Some devices may not support infos callback, allow them to support client
6618             // connection changed callback.
6619             boolean areClientsChangedWithoutInfosChanged =
6620                     infos.size() == 0 && getConnectedClientList(clients).size()
6621                     != getConnectedClientList(mCurrentClients).size();
6622             boolean isInfoChanged = infos.size() != mCurrentInfos.size();
6623 
6624             if (isRegistration) {
6625                 // Check if there are clients connected, put it to changedInfoClients
6626                 for (SoftApInfo currentInfo : infos.values()) {
6627                     String instance = currentInfo.getApInstanceIdentifier();
6628                     if (clients.getOrDefault(instance, Collections.emptyList()).size() > 0) {
6629                         changedInfoClients.put(currentInfo, clients.get(instance));
6630                     }
6631                 }
6632             }
6633 
6634             // Check if old info removed or not (client changed case)
6635             for (SoftApInfo info : mCurrentInfos.values()) {
6636                 String changedInstance = info.getApInstanceIdentifier();
6637                 List<WifiClient> changedClientList = clients.getOrDefault(
6638                         changedInstance, Collections.emptyList());
6639                 if (!changedInfoList.contains(info)) {
6640                     isInfoChanged = true;
6641                     if (mCurrentClients.getOrDefault(changedInstance,
6642                               Collections.emptyList()).size() > 0) {
6643                         SoftApInfo changedInfo = infos.get(changedInstance);
6644                         if (changedInfo == null || changedInfo.getFrequency() == 0) {
6645                             Log.d(TAG, "SoftApCallbackProxy on mode " + mIpMode
6646                                     + ", info changed on client connected instance(AP disabled)");
6647                             // Send old info with empty client list for shutdown case
6648                             changedInfoClients.put(info, Collections.emptyList());
6649                         } else {
6650                             Log.d(TAG, "SoftApCallbackProxy on mode " + mIpMode
6651                                     + ", info changed on client connected instance");
6652                             changedInfoClients.put(changedInfo, changedClientList);
6653                         }
6654                     }
6655                 } else {
6656                     // info doesn't change, check client list
6657                     if (changedClientList.size()
6658                             != mCurrentClients
6659                             .getOrDefault(changedInstance, Collections.emptyList()).size()) {
6660                         // Here should notify client changed on new info(same as old info)
6661                         changedInfoClients.put(info, changedClientList);
6662                     }
6663                 }
6664             }
6665 
6666             mCurrentClients = clients;
6667             mCurrentInfos = infos;
6668             if (!isInfoChanged && changedInfoClients.isEmpty()
6669                     && !isRegistration && !areClientsChangedWithoutInfosChanged) {
6670                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6671                         + ", No changed & Not Registration don't need to notify the client");
6672                 return;
6673             }
6674             Binder.clearCallingIdentity();
6675             // Notify the clients changed first for old info shutdown case
6676             for (SoftApInfo changedInfo : changedInfoClients.keySet()) {
6677                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6678                         + ", send onConnectedClientsChanged, changedInfo is "
6679                         + changedInfo + " and clients are " + changedInfoClients.get(changedInfo));
6680                 mExecutor.execute(() -> {
6681                     mCallback.onConnectedClientsChanged(
6682                             changedInfo, changedInfoClients.get(changedInfo));
6683                 });
6684             }
6685 
6686             if (isInfoChanged || isRegistration) {
6687                 if (!isBridged) {
6688                     SoftApInfo newInfo = changedInfoList.isEmpty()
6689                             ? new SoftApInfo() : changedInfoList.get(0);
6690                     Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6691                             + ", send InfoChanged, newInfo: " + newInfo);
6692                     mExecutor.execute(() -> {
6693                         mCallback.onInfoChanged(newInfo);
6694                     });
6695                 }
6696                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6697                         + ", send InfoChanged, changedInfoList: " + changedInfoList);
6698                 mExecutor.execute(() -> {
6699                     mCallback.onInfoChanged(changedInfoList);
6700                 });
6701             }
6702 
6703             if (isRegistration || !changedInfoClients.isEmpty()
6704                     || areClientsChangedWithoutInfosChanged) {
6705                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6706                         + ", send onConnectedClientsChanged(clients): "
6707                         + getConnectedClientList(clients));
6708                 mExecutor.execute(() -> {
6709                     mCallback.onConnectedClientsChanged(getConnectedClientList(clients));
6710                 });
6711             }
6712         }
6713 
6714         @Override
onCapabilityChanged(SoftApCapability capability)6715         public void onCapabilityChanged(SoftApCapability capability) {
6716             if (mVerboseLoggingEnabled) {
6717                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6718                         + ",  onCapabilityChanged: SoftApCapability = " + capability);
6719             }
6720 
6721             Binder.clearCallingIdentity();
6722             mExecutor.execute(() -> {
6723                 mCallback.onCapabilityChanged(capability);
6724             });
6725         }
6726 
6727         @Override
onBlockedClientConnecting(@onNull WifiClient client, int blockedReason)6728         public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) {
6729             if (mVerboseLoggingEnabled) {
6730                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6731                         + ", onBlockedClientConnecting: client =" + client
6732                         + " with reason = " + blockedReason);
6733             }
6734 
6735             Binder.clearCallingIdentity();
6736             mExecutor.execute(() -> {
6737                 mCallback.onBlockedClientConnecting(client, blockedReason);
6738             });
6739         }
6740     }
6741 
6742     /**
6743      * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the
6744      * following callbacks on registration:
6745      * <ul>
6746      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
6747      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
6748      * <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
6749      * <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
6750      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
6751      * </ul>
6752      *
6753      * Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
6754      * if there are any clients connected to a specific bridged instance of this AP
6755      * (if bridged AP is enabled).
6756      *
6757      * Note: Caller will receive the callback
6758      * {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)}
6759      * on registration when there are clients connected to AP.
6760      *
6761      * These will be dispatched on registration to provide the caller with the current state
6762      * (and are not an indication of any current change). Note that receiving an immediate
6763      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
6764      * soft AP has failed. Caller can unregister a previously registered callback using
6765      * {@link #unregisterSoftApCallback}
6766      * <p>
6767      * Applications should have the
6768      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
6769      * without the permission will trigger a {@link java.lang.SecurityException}.
6770      * <p>
6771      *
6772      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
6773      *                 object.
6774      * @param callback Callback for soft AP events
6775      * @hide
6776      */
6777     @SystemApi
6778     @RequiresPermission(anyOf = {
6779             android.Manifest.permission.NETWORK_SETTINGS,
6780             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
6781             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6782     })
registerSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)6783     public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
6784             @NonNull SoftApCallback callback) {
6785         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
6786         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
6787         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
6788 
6789         try {
6790             synchronized (sSoftApCallbackMap) {
6791                 ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
6792                         IFACE_IP_MODE_TETHERED);
6793                 sSoftApCallbackMap.put(System.identityHashCode(callback), binderCallback);
6794                 mService.registerSoftApCallback(binderCallback);
6795             }
6796         } catch (RemoteException e) {
6797             throw e.rethrowFromSystemServer();
6798         }
6799     }
6800 
6801     /**
6802      * Allow callers to unregister a previously registered callback. After calling this method,
6803      * applications will no longer receive soft AP events.
6804      *
6805      * @param callback Callback to unregister for soft AP events
6806      *
6807      * @hide
6808      */
6809     @SystemApi
6810     @RequiresPermission(anyOf = {
6811             android.Manifest.permission.NETWORK_SETTINGS,
6812             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
6813             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6814     })
unregisterSoftApCallback(@onNull SoftApCallback callback)6815     public void unregisterSoftApCallback(@NonNull SoftApCallback callback) {
6816         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
6817         Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
6818 
6819         try {
6820             synchronized (sSoftApCallbackMap) {
6821                 int callbackIdentifier = System.identityHashCode(callback);
6822                 if (!sSoftApCallbackMap.contains(callbackIdentifier)) {
6823                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
6824                     return;
6825                 }
6826                 mService.unregisterSoftApCallback(sSoftApCallbackMap.get(callbackIdentifier));
6827                 sSoftApCallbackMap.remove(callbackIdentifier);
6828             }
6829         } catch (RemoteException e) {
6830             throw e.rethrowFromSystemServer();
6831         }
6832     }
6833 
6834     /**
6835      * LocalOnlyHotspotReservation that contains the {@link SoftApConfiguration} for the active
6836      * LocalOnlyHotspot request.
6837      * <p>
6838      * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
6839      * LocalOnlyHotspotReservation in the
6840      * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call.  This
6841      * reservation contains the relevant {@link SoftApConfiguration}.
6842      * When an application is done with the LocalOnlyHotspot, they should call {@link
6843      * LocalOnlyHotspotReservation#close()}.  Once this happens, the application will not receive
6844      * any further callbacks. If the LocalOnlyHotspot is stopped due to a
6845      * user triggered mode change, applications will be notified via the {@link
6846      * LocalOnlyHotspotCallback#onStopped()} callback.
6847      */
6848     public class LocalOnlyHotspotReservation implements AutoCloseable {
6849 
6850         private final CloseGuard mCloseGuard = new CloseGuard();
6851         private final SoftApConfiguration mSoftApConfig;
6852         private final WifiConfiguration mWifiConfig;
6853         private boolean mClosed = false;
6854 
6855         /** @hide */
6856         @VisibleForTesting
LocalOnlyHotspotReservation(SoftApConfiguration config)6857         public LocalOnlyHotspotReservation(SoftApConfiguration config) {
6858             mSoftApConfig = config;
6859             mWifiConfig = config.toWifiConfiguration();
6860             mCloseGuard.open("close");
6861         }
6862 
6863         /**
6864          * Returns the {@link WifiConfiguration} of the current Local Only Hotspot (LOHS).
6865          * May be null if hotspot enabled and security type is not
6866          * {@code WifiConfiguration.KeyMgmt.None} or {@code WifiConfiguration.KeyMgmt.WPA2_PSK}.
6867          *
6868          * @deprecated Use {@code WifiManager#getSoftApConfiguration()} to get the
6869          * LOHS configuration.
6870          */
6871         @Deprecated
6872         @Nullable
getWifiConfiguration()6873         public WifiConfiguration getWifiConfiguration() {
6874             return mWifiConfig;
6875         }
6876 
6877         /**
6878          * Returns the {@link SoftApConfiguration} of the current Local Only Hotspot (LOHS).
6879          */
6880         @NonNull
getSoftApConfiguration()6881         public SoftApConfiguration getSoftApConfiguration() {
6882             return mSoftApConfig;
6883         }
6884 
6885         @Override
close()6886         public void close() {
6887             try {
6888                 synchronized (mLock) {
6889                     if (!mClosed) {
6890                         mClosed = true;
6891                         stopLocalOnlyHotspot();
6892                         mCloseGuard.close();
6893                     }
6894                 }
6895             } catch (Exception e) {
6896                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
6897             } finally {
6898                 Reference.reachabilityFence(this);
6899             }
6900         }
6901 
6902         @Override
finalize()6903         protected void finalize() throws Throwable {
6904             try {
6905                 if (mCloseGuard != null) {
6906                     mCloseGuard.warnIfOpen();
6907                 }
6908                 close();
6909             } finally {
6910                 super.finalize();
6911             }
6912         }
6913     }
6914 
6915     /**
6916      * Callback class for applications to receive updates about the LocalOnlyHotspot status.
6917      */
6918     public static class LocalOnlyHotspotCallback {
6919         /** @hide */
6920         public static final int REQUEST_REGISTERED = 0;
6921 
6922         public static final int ERROR_NO_CHANNEL = 1;
6923         public static final int ERROR_GENERIC = 2;
6924         public static final int ERROR_INCOMPATIBLE_MODE = 3;
6925         public static final int ERROR_TETHERING_DISALLOWED = 4;
6926 
6927         /** LocalOnlyHotspot start succeeded. */
onStarted(LocalOnlyHotspotReservation reservation)6928         public void onStarted(LocalOnlyHotspotReservation reservation) {};
6929 
6930         /**
6931          * LocalOnlyHotspot stopped.
6932          * <p>
6933          * The LocalOnlyHotspot can be disabled at any time by the user.  When this happens,
6934          * applications will be notified that it was stopped. This will not be invoked when an
6935          * application calls {@link LocalOnlyHotspotReservation#close()}.
6936          */
onStopped()6937         public void onStopped() {};
6938 
6939         /**
6940          * LocalOnlyHotspot failed to start.
6941          * <p>
6942          * Applications can attempt to call
6943          * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at
6944          * a later time.
6945          * <p>
6946          * @param reason The reason for failure could be one of: {@link
6947          * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE},
6948          * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}.
6949          */
onFailed(int reason)6950         public void onFailed(int reason) { };
6951     }
6952 
6953     /**
6954      * Callback proxy for LocalOnlyHotspotCallback objects.
6955      */
6956     private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub {
6957         private final WeakReference<WifiManager> mWifiManager;
6958         private final Executor mExecutor;
6959         private final LocalOnlyHotspotCallback mCallback;
6960 
6961         /**
6962          * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor.  All
6963          * callbacks will run using the given executor.
6964          *
6965          * @param manager WifiManager
6966          * @param executor Executor for delivering callbacks.
6967          * @param callback LocalOnlyHotspotCallback to notify the calling application, or null.
6968          */
LocalOnlyHotspotCallbackProxy( @onNull WifiManager manager, @NonNull @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)6969         LocalOnlyHotspotCallbackProxy(
6970                 @NonNull WifiManager manager,
6971                 @NonNull @CallbackExecutor Executor executor,
6972                 @Nullable LocalOnlyHotspotCallback callback) {
6973             mWifiManager = new WeakReference<>(manager);
6974             mExecutor = executor;
6975             mCallback = callback;
6976         }
6977 
6978         @Override
onHotspotStarted(SoftApConfiguration config)6979         public void onHotspotStarted(SoftApConfiguration config) {
6980             WifiManager manager = mWifiManager.get();
6981             if (manager == null) return;
6982 
6983             if (config == null) {
6984                 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
6985                 onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
6986                 return;
6987             }
6988             final LocalOnlyHotspotReservation reservation =
6989                     manager.new LocalOnlyHotspotReservation(config);
6990             if (mCallback == null) return;
6991             mExecutor.execute(() -> mCallback.onStarted(reservation));
6992         }
6993 
6994         @Override
onHotspotStopped()6995         public void onHotspotStopped() {
6996             WifiManager manager = mWifiManager.get();
6997             if (manager == null) return;
6998 
6999             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
7000             if (mCallback == null) return;
7001             mExecutor.execute(() -> mCallback.onStopped());
7002         }
7003 
7004         @Override
onHotspotFailed(int reason)7005         public void onHotspotFailed(int reason) {
7006             WifiManager manager = mWifiManager.get();
7007             if (manager == null) return;
7008 
7009             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
7010                     + reason);
7011             if (mCallback == null) return;
7012             mExecutor.execute(() -> mCallback.onFailed(reason));
7013         }
7014     }
7015 
7016     /**
7017      * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications
7018      * watching for LocalOnlyHotspot changes.
7019      *
7020      * @hide
7021      */
7022     public class LocalOnlyHotspotSubscription implements AutoCloseable {
7023         private final CloseGuard mCloseGuard = new CloseGuard();
7024 
7025         /** @hide */
7026         @VisibleForTesting
LocalOnlyHotspotSubscription()7027         public LocalOnlyHotspotSubscription() {
7028             mCloseGuard.open("close");
7029         }
7030 
7031         @Override
close()7032         public void close() {
7033             try {
7034                 unregisterLocalOnlyHotspotObserver();
7035                 mCloseGuard.close();
7036             } catch (Exception e) {
7037                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
7038             } finally {
7039                 Reference.reachabilityFence(this);
7040             }
7041         }
7042 
7043         @Override
finalize()7044         protected void finalize() throws Throwable {
7045             try {
7046                 if (mCloseGuard != null) {
7047                     mCloseGuard.warnIfOpen();
7048                 }
7049                 close();
7050             } finally {
7051                 super.finalize();
7052             }
7053         }
7054     }
7055 
7056     /**
7057      * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates.
7058      *
7059      * @hide
7060      */
7061     public static class LocalOnlyHotspotObserver {
7062         /**
7063          * Confirm registration for LocalOnlyHotspotChanges by returning a
7064          * LocalOnlyHotspotSubscription.
7065          */
onRegistered(LocalOnlyHotspotSubscription subscription)7066         public void onRegistered(LocalOnlyHotspotSubscription subscription) {};
7067 
7068         /**
7069          * LocalOnlyHotspot started with the supplied config.
7070          */
onStarted(SoftApConfiguration config)7071         public void onStarted(SoftApConfiguration config) {};
7072 
7073         /**
7074          * LocalOnlyHotspot stopped.
7075          */
onStopped()7076         public void onStopped() {};
7077     }
7078 
7079     /**
7080      * Callback proxy for LocalOnlyHotspotObserver objects.
7081      */
7082     private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub {
7083         private final WeakReference<WifiManager> mWifiManager;
7084         private final Executor mExecutor;
7085         private final LocalOnlyHotspotObserver mObserver;
7086 
7087         /**
7088          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
7089          * All callbacks will be delivered on the thread of the specified looper.
7090          *
7091          * @param manager WifiManager
7092          * @param executor Executor for delivering callbacks
7093          * @param observer LocalOnlyHotspotObserver to notify the calling application.
7094          */
LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor, final LocalOnlyHotspotObserver observer)7095         LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor,
7096                 final LocalOnlyHotspotObserver observer) {
7097             mWifiManager = new WeakReference<>(manager);
7098             mExecutor = executor;
7099             mObserver = observer;
7100         }
7101 
registered()7102         public void registered() throws RemoteException {
7103             WifiManager manager = mWifiManager.get();
7104             if (manager == null) return;
7105 
7106             mExecutor.execute(() ->
7107                     mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription()));
7108         }
7109 
7110         @Override
onHotspotStarted(SoftApConfiguration config)7111         public void onHotspotStarted(SoftApConfiguration config) {
7112             WifiManager manager = mWifiManager.get();
7113             if (manager == null) return;
7114 
7115             if (config == null) {
7116                 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
7117                 return;
7118             }
7119             mExecutor.execute(() -> mObserver.onStarted(config));
7120         }
7121 
7122         @Override
onHotspotStopped()7123         public void onHotspotStopped() {
7124             WifiManager manager = mWifiManager.get();
7125             if (manager == null) return;
7126 
7127             mExecutor.execute(() -> mObserver.onStopped());
7128         }
7129 
7130         @Override
onHotspotFailed(int reason)7131         public void onHotspotFailed(int reason) {
7132             // do nothing
7133         }
7134     }
7135 
7136     /**
7137      * Callback proxy for ActionListener objects.
7138      */
7139     private class ActionListenerProxy extends IActionListener.Stub {
7140         private final String mActionTag;
7141         private final Handler mHandler;
7142         private final ActionListener mCallback;
7143 
ActionListenerProxy(String actionTag, Looper looper, ActionListener callback)7144         ActionListenerProxy(String actionTag, Looper looper, ActionListener callback) {
7145             mActionTag = actionTag;
7146             mHandler = new Handler(looper);
7147             mCallback = callback;
7148         }
7149 
7150         @Override
onSuccess()7151         public void onSuccess() {
7152             if (mVerboseLoggingEnabled) {
7153                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onSuccess");
7154             }
7155             mHandler.post(() -> {
7156                 mCallback.onSuccess();
7157             });
7158         }
7159 
7160         @Override
onFailure(@ctionListenerFailureReason int reason)7161         public void onFailure(@ActionListenerFailureReason int reason) {
7162             if (mVerboseLoggingEnabled) {
7163                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onFailure=" + reason);
7164             }
7165             mHandler.post(() -> {
7166                 mCallback.onFailure(reason);
7167             });
7168         }
7169     }
7170 
connectInternal(@ullable WifiConfiguration config, int networkId, @Nullable ActionListener listener)7171     private void connectInternal(@Nullable WifiConfiguration config, int networkId,
7172             @Nullable ActionListener listener) {
7173         ActionListenerProxy listenerProxy = null;
7174         if (listener != null) {
7175             listenerProxy = new ActionListenerProxy("connect", mLooper, listener);
7176         }
7177         try {
7178             mService.connect(config, networkId, listenerProxy, mContext.getOpPackageName());
7179         } catch (RemoteException e) {
7180             if (listenerProxy != null) {
7181                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7182             }
7183         } catch (SecurityException e) {
7184             if (listenerProxy != null) {
7185                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7186             }
7187         }
7188     }
7189 
7190     /**
7191      * Connect to a network with the given configuration. The network also
7192      * gets added to the list of configured networks for the foreground user.
7193      *
7194      * For a new network, this function is used instead of a
7195      * sequence of addNetwork(), enableNetwork(), and reconnect()
7196      *
7197      * @param config the set of variables that describe the configuration,
7198      *            contained in a {@link WifiConfiguration} object.
7199      * @param listener for callbacks on success or failure. Can be null.
7200      * @throws IllegalStateException if the WifiManager instance needs to be
7201      * initialized again
7202      *
7203      * @hide
7204      */
7205     @SystemApi
7206     @RequiresPermission(anyOf = {
7207             android.Manifest.permission.NETWORK_SETTINGS,
7208             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7209             android.Manifest.permission.NETWORK_STACK
7210     })
connect(@onNull WifiConfiguration config, @Nullable ActionListener listener)7211     public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
7212         if (config == null) throw new IllegalArgumentException("config cannot be null");
7213         connectInternal(config, WifiConfiguration.INVALID_NETWORK_ID, listener);
7214     }
7215 
7216     /**
7217      * Connect to a network with the given networkId.
7218      *
7219      * This function is used instead of a enableNetwork() and reconnect()
7220      *
7221      * <li> This API will cause reconnect if the credentials of the current active
7222      * connection has been changed.</li>
7223      * <li> This API will cause reconnect if the current active connection is marked metered.</li>
7224      *
7225      * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
7226      *        getConfiguredNetworks}.
7227      * @param listener for callbacks on success or failure. Can be null.
7228      * @throws IllegalStateException if the WifiManager instance needs to be
7229      * initialized again
7230      * @hide
7231      */
7232     @SystemApi
7233     @RequiresPermission(anyOf = {
7234             android.Manifest.permission.NETWORK_SETTINGS,
7235             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7236             android.Manifest.permission.NETWORK_STACK
7237     })
connect(int networkId, @Nullable ActionListener listener)7238     public void connect(int networkId, @Nullable ActionListener listener) {
7239         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7240         connectInternal(null, networkId, listener);
7241     }
7242 
7243     /**
7244      * Temporarily disable autojoin for all currently visible and provisioned (saved, suggested)
7245      * wifi networks except merged carrier networks from the provided subscription ID.
7246      *
7247      * Disabled networks will get automatically re-enabled when they are out of range for a period
7248      * of time, or after the maximum disable duration specified in the framework.
7249      *
7250      * Calling {@link #stopRestrictingAutoJoinToSubscriptionId()} will immediately re-enable
7251      * autojoin on all disabled networks.
7252      *
7253      * @param subscriptionId the subscription ID of the carrier whose merged wifi networks won't be
7254      *                       disabled {@link android.telephony.SubscriptionInfo#getSubscriptionId()}
7255      * @hide
7256      */
7257     @SystemApi
7258     @RequiresPermission(anyOf = {
7259             android.Manifest.permission.NETWORK_SETTINGS,
7260             android.Manifest.permission.NETWORK_SETUP_WIZARD})
7261     @RequiresApi(Build.VERSION_CODES.S)
startRestrictingAutoJoinToSubscriptionId(int subscriptionId)7262     public void startRestrictingAutoJoinToSubscriptionId(int subscriptionId) {
7263         try {
7264             mService.startRestrictingAutoJoinToSubscriptionId(subscriptionId);
7265         } catch (RemoteException e) {
7266             throw e.rethrowFromSystemServer();
7267         }
7268     }
7269 
7270     /**
7271      * Re-enable autojoin for all non carrier merged wifi networks temporarily disconnected by
7272      * {@link #startRestrictingAutoJoinToSubscriptionId(int)}.
7273      * @hide
7274      */
7275     @SystemApi
7276     @RequiresPermission(anyOf = {
7277             android.Manifest.permission.NETWORK_SETTINGS,
7278             android.Manifest.permission.NETWORK_SETUP_WIZARD})
7279     @RequiresApi(Build.VERSION_CODES.S)
stopRestrictingAutoJoinToSubscriptionId()7280     public void stopRestrictingAutoJoinToSubscriptionId() {
7281         try {
7282             mService.stopRestrictingAutoJoinToSubscriptionId();
7283         } catch (RemoteException e) {
7284             throw e.rethrowFromSystemServer();
7285         }
7286     }
7287 
7288     /**
7289      * Save the given network to the list of configured networks for the
7290      * foreground user. If the network already exists, the configuration
7291      * is updated. Any new network is enabled by default.
7292      *
7293      * For a new network, this function is used instead of a
7294      * sequence of addNetwork() and enableNetwork().
7295      *
7296      * For an existing network, it accomplishes the task of updateNetwork()
7297      *
7298      * <li> This API will cause reconnect if the credentials of the current active
7299      * connection has been changed.</li>
7300      * <li> This API will cause disconnect if the current active connection is marked metered.</li>
7301      *
7302      * @param config the set of variables that describe the configuration,
7303      *            contained in a {@link WifiConfiguration} object.
7304      * @param listener for callbacks on success or failure. Can be null.
7305      * @throws IllegalStateException if the WifiManager instance needs to be
7306      * initialized again
7307      * @hide
7308      */
7309     @SystemApi
7310     @RequiresPermission(anyOf = {
7311             android.Manifest.permission.NETWORK_SETTINGS,
7312             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7313             android.Manifest.permission.NETWORK_STACK
7314     })
save(@onNull WifiConfiguration config, @Nullable ActionListener listener)7315     public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
7316         if (config == null) throw new IllegalArgumentException("config cannot be null");
7317         ActionListenerProxy listenerProxy = null;
7318         if (listener != null) {
7319             listenerProxy = new ActionListenerProxy("save", mLooper, listener);
7320         }
7321         try {
7322             mService.save(config, listenerProxy, mContext.getOpPackageName());
7323         } catch (RemoteException e) {
7324             if (listenerProxy != null) {
7325                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7326             }
7327         } catch (SecurityException e) {
7328             if (listenerProxy != null) {
7329                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7330             }
7331         }
7332     }
7333 
7334     /**
7335      * Delete the network from the list of configured networks for the
7336      * foreground user.
7337      *
7338      * This function is used instead of a sequence of removeNetwork()
7339      *
7340      * @param config the set of variables that describe the configuration,
7341      *            contained in a {@link WifiConfiguration} object.
7342      * @param listener for callbacks on success or failure. Can be null.
7343      * @throws IllegalStateException if the WifiManager instance needs to be
7344      * initialized again
7345      * @hide
7346      */
7347     @SystemApi
7348     @RequiresPermission(anyOf = {
7349             android.Manifest.permission.NETWORK_SETTINGS,
7350             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7351             android.Manifest.permission.NETWORK_STACK
7352     })
forget(int netId, @Nullable ActionListener listener)7353     public void forget(int netId, @Nullable ActionListener listener) {
7354         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7355         ActionListenerProxy listenerProxy = null;
7356         if (listener != null) {
7357             listenerProxy = new ActionListenerProxy("forget", mLooper, listener);
7358         }
7359         try {
7360             mService.forget(netId, listenerProxy);
7361         } catch (RemoteException e) {
7362             if (listenerProxy != null) {
7363                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7364             }
7365         } catch (SecurityException e) {
7366             if (listenerProxy != null) {
7367                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7368             }
7369         }
7370     }
7371 
7372     /**
7373      * Disable network
7374      *
7375      * @param netId is the network Id
7376      * @param listener for callbacks on success or failure. Can be null.
7377      * @throws IllegalStateException if the WifiManager instance needs to be
7378      * initialized again
7379      * @deprecated This API is deprecated. Use {@link #disableNetwork(int)} instead.
7380      * @hide
7381      */
7382     @SystemApi
7383     @RequiresPermission(anyOf = {
7384             android.Manifest.permission.NETWORK_SETTINGS,
7385             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7386             android.Manifest.permission.NETWORK_STACK
7387     })
7388     @Deprecated
disable(int netId, @Nullable ActionListener listener)7389     public void disable(int netId, @Nullable ActionListener listener) {
7390         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7391         // Simple wrapper which forwards the call to disableNetwork. This is a temporary
7392         // implementation until we can remove this API completely.
7393         boolean status = disableNetwork(netId);
7394         if (listener != null) {
7395             if (status) {
7396                 listener.onSuccess();
7397             } else {
7398                 listener.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7399             }
7400         }
7401     }
7402 
7403     /**
7404      * Control whether the device will automatically search for and connect to Wi-Fi networks -
7405      * auto-join Wi-Fi networks. Disabling this option will not impact manual connections - i.e.
7406      * the user will still be able to manually select and connect to a Wi-Fi network. Disabling
7407      * this option significantly impacts the device connectivity and is a restricted operation
7408      * (see below for permissions). Note that disabling this operation will also disable
7409      * connectivity initiated scanning operations.
7410      * <p>
7411      * Disabling the auto-join configuration is a temporary operation (with the exception of a
7412      * DO/PO caller): it will be reset (to enabled) when the device reboots or the user toggles
7413      * Wi-Fi off/on. When the caller is a DO/PO then toggling Wi-Fi will not reset the
7414      * configuration. Additionally, if a DO/PO disables auto-join then it cannot be (re)enabled by
7415      * a non-DO/PO caller.
7416      *
7417      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
7418      *
7419      * Available for DO/PO apps.
7420      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
7421      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
7422      */
allowAutojoinGlobal(boolean allowAutojoin)7423     public void allowAutojoinGlobal(boolean allowAutojoin) {
7424         try {
7425             Bundle extras = new Bundle();
7426             if (SdkLevel.isAtLeastS()) {
7427                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
7428                         mContext.getAttributionSource());
7429             }
7430             mService.allowAutojoinGlobal(allowAutojoin, mContext.getOpPackageName(), extras);
7431         } catch (RemoteException e) {
7432             throw e.rethrowFromSystemServer();
7433         }
7434     }
7435 
7436     /**
7437      * Query whether or not auto-join global is enabled/disabled
7438      * @see #allowAutojoinGlobal(boolean)
7439      *
7440      * Available for DO/PO apps.
7441      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
7442      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
7443      *
7444      * @param executor The executor on which callback will be invoked.
7445      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
7446      *                        whether auto-join global is enabled/disabled.
7447      *
7448      * @throws SecurityException if the caller does not have permission.
7449      * @throws NullPointerException if the caller provided invalid inputs.
7450      */
queryAutojoinGlobal(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)7451     public void queryAutojoinGlobal(@NonNull @CallbackExecutor Executor executor,
7452             @NonNull Consumer<Boolean> resultsCallback) {
7453         Objects.requireNonNull(executor, "executor cannot be null");
7454         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
7455         try {
7456             mService.queryAutojoinGlobal(
7457                     new IBooleanListener.Stub() {
7458                         @Override
7459                         public void onResult(boolean value) {
7460                             Binder.clearCallingIdentity();
7461                             executor.execute(() -> {
7462                                 resultsCallback.accept(value);
7463                             });
7464                         }
7465                     });
7466         } catch (RemoteException e) {
7467             throw e.rethrowFromSystemServer();
7468         }
7469     }
7470 
7471     /**
7472      * Sets the user choice for allowing auto-join to a network.
7473      * The updated choice will be made available through the updated config supplied by the
7474      * CONFIGURED_NETWORKS_CHANGED broadcast.
7475      *
7476      * @param netId the id of the network to allow/disallow auto-join for.
7477      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
7478      * @hide
7479      */
7480     @SystemApi
7481     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoin(int netId, boolean allowAutojoin)7482     public void allowAutojoin(int netId, boolean allowAutojoin) {
7483         try {
7484             mService.allowAutojoin(netId, allowAutojoin);
7485         } catch (RemoteException e) {
7486             throw e.rethrowFromSystemServer();
7487         }
7488     }
7489 
7490     /**
7491      * Configure auto-join settings for a Passpoint profile.
7492      *
7493      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7494      * @param allowAutojoin true to enable auto-join, false to disable auto-join.
7495      * @hide
7496      */
7497     @SystemApi
7498     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoinPasspoint(@onNull String fqdn, boolean allowAutojoin)7499     public void allowAutojoinPasspoint(@NonNull String fqdn, boolean allowAutojoin) {
7500         try {
7501             mService.allowAutojoinPasspoint(fqdn, allowAutojoin);
7502         } catch (RemoteException e) {
7503             throw e.rethrowFromSystemServer();
7504         }
7505     }
7506 
7507     /**
7508      * Configure MAC randomization setting for a Passpoint profile.
7509      * MAC randomization is enabled by default.
7510      *
7511      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7512      * @param enable true to enable MAC randomization, false to disable MAC randomization.
7513      * @hide
7514      */
7515     @SystemApi
7516     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setMacRandomizationSettingPasspointEnabled(@onNull String fqdn, boolean enable)7517     public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
7518         try {
7519             mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
7520         } catch (RemoteException e) {
7521             throw e.rethrowFromSystemServer();
7522         }
7523     }
7524 
7525     /**
7526      * Sets the user's choice of metered override for a Passpoint profile.
7527      *
7528      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7529      * @param meteredOverride One of three values: {@link WifiConfiguration#METERED_OVERRIDE_NONE},
7530      *                        {@link WifiConfiguration#METERED_OVERRIDE_METERED},
7531      *                        {@link WifiConfiguration#METERED_OVERRIDE_NOT_METERED}
7532      * @hide
7533      */
7534     @SystemApi
7535     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setPasspointMeteredOverride(@onNull String fqdn, @WifiConfiguration.MeteredOverride int meteredOverride)7536     public void setPasspointMeteredOverride(@NonNull String fqdn,
7537             @WifiConfiguration.MeteredOverride int meteredOverride) {
7538         try {
7539             mService.setPasspointMeteredOverride(fqdn, meteredOverride);
7540         } catch (RemoteException e) {
7541             throw e.rethrowFromSystemServer();
7542         }
7543     }
7544 
7545     /**
7546      * Temporarily disable a network. Should always trigger with user disconnect network.
7547      *
7548      * @param network Input can be SSID or FQDN. And caller must ensure that the SSID passed thru
7549      *                this API matched the WifiConfiguration.SSID rules, and thus be surrounded by
7550      *                quotes.
7551      * @hide
7552      */
7553     @SystemApi
7554     @RequiresPermission(anyOf = {
7555             android.Manifest.permission.NETWORK_SETTINGS,
7556             android.Manifest.permission.NETWORK_STACK
7557     })
disableEphemeralNetwork(@onNull String network)7558     public void disableEphemeralNetwork(@NonNull String network) {
7559         if (TextUtils.isEmpty(network)) {
7560             throw new IllegalArgumentException("SSID cannot be null or empty!");
7561         }
7562         try {
7563             mService.disableEphemeralNetwork(network, mContext.getOpPackageName());
7564         } catch (RemoteException e) {
7565             throw e.rethrowFromSystemServer();
7566         }
7567     }
7568 
7569     /**
7570      * WPS suport has been deprecated from Client mode and this method will immediately trigger
7571      * {@link WpsCallback#onFailed(int)} with a generic error.
7572      *
7573      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
7574      * @param listener for callbacks on success or failure. Can be null.
7575      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
7576      * @deprecated This API is deprecated
7577      */
startWps(WpsInfo config, WpsCallback listener)7578     public void startWps(WpsInfo config, WpsCallback listener) {
7579         if (listener != null ) {
7580             listener.onFailed(ActionListener.FAILURE_INTERNAL_ERROR);
7581         }
7582     }
7583 
7584     /**
7585      * WPS support has been deprecated from Client mode and this method will immediately trigger
7586      * {@link WpsCallback#onFailed(int)} with a generic error.
7587      *
7588      * @param listener for callbacks on success or failure. Can be null.
7589      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
7590      * @deprecated This API is deprecated
7591      */
cancelWps(WpsCallback listener)7592     public void cancelWps(WpsCallback listener) {
7593         if (listener != null) {
7594             listener.onFailed(ActionListener.FAILURE_INTERNAL_ERROR);
7595         }
7596     }
7597 
7598     /**
7599      * Allows an application to keep the Wi-Fi radio awake.
7600      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
7601      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
7602      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
7603      * WifiLocks are held in any application.
7604      * <p>
7605      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
7606      * could function over a mobile network, if available.  A program that needs to download large
7607      * files should hold a WifiLock to ensure that the download will complete, but a program whose
7608      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
7609      * affecting battery life.
7610      * <p>
7611      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
7612      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
7613      * is idle.
7614      * <p>
7615      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
7616      * permission in an {@code <uses-permission>} element of the application's manifest.
7617      */
7618     public class WifiLock {
7619         private String mTag;
7620         private final IBinder mBinder;
7621         private int mRefCount;
7622         int mLockType;
7623         private boolean mRefCounted;
7624         private boolean mHeld;
7625         private WorkSource mWorkSource;
7626 
WifiLock(int lockType, String tag)7627         private WifiLock(int lockType, String tag) {
7628             mTag = tag;
7629             mLockType = lockType;
7630             mBinder = new Binder();
7631             mRefCount = 0;
7632             mRefCounted = true;
7633             mHeld = false;
7634         }
7635 
7636         /**
7637          * Locks the Wi-Fi radio on until {@link #release} is called.
7638          *
7639          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
7640          * reference count, and the radio will remain locked as long as the reference count is
7641          * above zero.
7642          *
7643          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
7644          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
7645          * will be required, regardless of the number of times that {@code acquire} is called.
7646          */
acquire()7647         public void acquire() {
7648             synchronized (mBinder) {
7649                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
7650                     try {
7651                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
7652                         synchronized (WifiManager.this) {
7653                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
7654                                 mService.releaseWifiLock(mBinder);
7655                                 throw new UnsupportedOperationException(
7656                                             "Exceeded maximum number of wifi locks");
7657                             }
7658                             mActiveLockCount++;
7659                         }
7660                     } catch (RemoteException e) {
7661                         throw e.rethrowFromSystemServer();
7662                     }
7663                     mHeld = true;
7664                 }
7665             }
7666         }
7667 
7668         /**
7669          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
7670          *
7671          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
7672          * reference count, and the radio will be unlocked only when the reference count reaches
7673          * zero.  If the reference count goes below zero (that is, if {@code release} is called
7674          * a greater number of times than {@link #acquire}), an exception is thrown.
7675          *
7676          * If this WifiLock is not reference-counted, the first call to {@code release} (after
7677          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
7678          * calls will be ignored.
7679          */
release()7680         public void release() {
7681             synchronized (mBinder) {
7682                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
7683                     try {
7684                         mService.releaseWifiLock(mBinder);
7685                         synchronized (WifiManager.this) {
7686                             mActiveLockCount--;
7687                         }
7688                     } catch (RemoteException e) {
7689                         throw e.rethrowFromSystemServer();
7690                     }
7691                     mHeld = false;
7692                 }
7693                 if (mRefCount < 0) {
7694                     throw new RuntimeException("WifiLock under-locked " + mTag);
7695                 }
7696             }
7697         }
7698 
7699         /**
7700          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
7701          *
7702          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
7703          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
7704          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
7705          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
7706          * radio whenever {@link #release} is called and it is locked.
7707          *
7708          * @param refCounted true if this WifiLock should keep a reference count
7709          */
setReferenceCounted(boolean refCounted)7710         public void setReferenceCounted(boolean refCounted) {
7711             mRefCounted = refCounted;
7712         }
7713 
7714         /**
7715          * Checks whether this WifiLock is currently held.
7716          *
7717          * @return true if this WifiLock is held, false otherwise
7718          */
isHeld()7719         public boolean isHeld() {
7720             synchronized (mBinder) {
7721                 return mHeld;
7722             }
7723         }
7724 
setWorkSource(WorkSource ws)7725         public void setWorkSource(WorkSource ws) {
7726             synchronized (mBinder) {
7727                 if (ws != null && ws.isEmpty()) {
7728                     ws = null;
7729                 }
7730                 boolean changed = true;
7731                 if (ws == null) {
7732                     mWorkSource = null;
7733                 } else {
7734                     ws = ws.withoutNames();
7735                     if (mWorkSource == null) {
7736                         changed = mWorkSource != null;
7737                         mWorkSource = new WorkSource(ws);
7738                     } else {
7739                         changed = !mWorkSource.equals(ws);
7740                         if (changed) {
7741                             mWorkSource.set(ws);
7742                         }
7743                     }
7744                 }
7745                 if (changed && mHeld) {
7746                     try {
7747                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
7748                     } catch (RemoteException e) {
7749                         throw e.rethrowFromSystemServer();
7750                     }
7751                 }
7752             }
7753         }
7754 
toString()7755         public String toString() {
7756             String s1, s2, s3;
7757             synchronized (mBinder) {
7758                 s1 = Integer.toHexString(System.identityHashCode(this));
7759                 s2 = mHeld ? "held; " : "";
7760                 if (mRefCounted) {
7761                     s3 = "refcounted: refcount = " + mRefCount;
7762                 } else {
7763                     s3 = "not refcounted";
7764                 }
7765                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
7766             }
7767         }
7768 
7769         @Override
finalize()7770         protected void finalize() throws Throwable {
7771             super.finalize();
7772             synchronized (mBinder) {
7773                 if (mHeld) {
7774                     try {
7775                         mService.releaseWifiLock(mBinder);
7776                         synchronized (WifiManager.this) {
7777                             mActiveLockCount--;
7778                         }
7779                     } catch (RemoteException e) {
7780                         throw e.rethrowFromSystemServer();
7781                     }
7782                 }
7783             }
7784         }
7785     }
7786 
7787     /**
7788      * Creates a new WifiLock.
7789      *
7790      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL_HIGH_PERF}
7791      * and {@link #WIFI_MODE_FULL_LOW_LATENCY} for descriptions of the types of Wi-Fi locks.
7792      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
7793      *            never shown to the user under normal conditions, but should be descriptive
7794      *            enough to identify your application and the specific WifiLock within it, if it
7795      *            holds multiple WifiLocks.
7796      *
7797      * @return a new, unacquired WifiLock with the given tag.
7798      *
7799      * @see WifiLock
7800      */
createWifiLock(int lockType, String tag)7801     public WifiLock createWifiLock(int lockType, String tag) {
7802         return new WifiLock(lockType, tag);
7803     }
7804 
7805     /**
7806      * Interface for low latency lock listener. Should be extended by application and
7807      * set when calling {@link WifiManager#addWifiLowLatencyLockListener(Executor,
7808      * WifiLowLatencyLockListener)}.
7809      *
7810      * @hide
7811      */
7812     public interface WifiLowLatencyLockListener {
7813         /**
7814          * Provides low latency mode is activated or not. Triggered when Wi-Fi chip enters into low
7815          * latency mode.
7816          *
7817          * Note: Always called with current state when a new listener gets registered.
7818          */
onActivatedStateChanged(boolean activated)7819         void onActivatedStateChanged(boolean activated);
7820 
7821         /**
7822          * Provides UIDs (lock owners) of the applications which currently acquired low latency
7823          * lock. Triggered when an application acquires or releases a lock.
7824          *
7825          * Note: Always called with UIDs of the current acquired locks when a new listener gets
7826          * registered.
7827          *
7828          * @param ownerUids An array of UIDs.
7829          */
onOwnershipChanged(@onNull int[] ownerUids)7830         default void onOwnershipChanged(@NonNull int[] ownerUids) {}
7831 
7832         /**
7833          * Provides UIDs of the applications which acquired the low latency lock and is currently
7834          * active. See {@link WifiManager#WIFI_MODE_FULL_LOW_LATENCY} for the conditions to be
7835          * met for low latency lock to be active. Triggered when application acquiring the lock
7836          * satisfies or does not satisfy low latency conditions when the low latency mode is
7837          * activated. Also gets triggered when the lock becomes active, immediately after the
7838          * {@link WifiLowLatencyLockListener#onActivatedStateChanged(boolean)} callback is
7839          * triggered.
7840          *
7841          * Note: Always called with UIDs of the current active locks when a new listener gets
7842          * registered if the Wi-Fi chip is in low latency mode.
7843          *
7844          * @param activeUids An array of UIDs.
7845          */
onActiveUsersChanged(@onNull int[] activeUids)7846         default void onActiveUsersChanged(@NonNull int[] activeUids) {}
7847     }
7848 
7849     /**
7850      * Helper class to support wifi low latency lock listener.
7851      */
7852     private static class OnWifiLowLatencyLockProxy extends IWifiLowLatencyLockListener.Stub {
7853         @NonNull
7854         private Executor mExecutor;
7855         @NonNull
7856         private WifiLowLatencyLockListener mListener;
7857 
OnWifiLowLatencyLockProxy(@onNull Executor executor, @NonNull WifiLowLatencyLockListener listener)7858         OnWifiLowLatencyLockProxy(@NonNull Executor executor,
7859                 @NonNull WifiLowLatencyLockListener listener) {
7860             Objects.requireNonNull(executor);
7861             Objects.requireNonNull(listener);
7862             mExecutor = executor;
7863             mListener = listener;
7864         }
7865 
7866         @Override
onActivatedStateChanged(boolean activated)7867         public void onActivatedStateChanged(boolean activated) {
7868             Binder.clearCallingIdentity();
7869             mExecutor.execute(() -> mListener.onActivatedStateChanged(activated));
7870 
7871         }
7872 
7873         @Override
onOwnershipChanged(@onNull int[] ownerUids)7874         public void onOwnershipChanged(@NonNull int[] ownerUids) {
7875             Binder.clearCallingIdentity();
7876             mExecutor.execute(() -> mListener.onOwnershipChanged(ownerUids));
7877 
7878         }
7879 
7880         @Override
onActiveUsersChanged(@onNull int[] activeUids)7881         public void onActiveUsersChanged(@NonNull int[] activeUids) {
7882             Binder.clearCallingIdentity();
7883             mExecutor.execute(() -> mListener.onActiveUsersChanged(activeUids));
7884         }
7885     }
7886 
7887     /**
7888      * Add a listener for monitoring the low latency lock. The caller can unregister a previously
7889      * registered listener using {@link WifiManager#removeWifiLowLatencyLockListener(
7890      * WifiLowLatencyLockListener)}.
7891      *
7892      * Applications should have the {@link android.Manifest.permission#NETWORK_SETTINGS} and
7893      * {@link android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission. Callers
7894      * without the permission will trigger a {@link java.lang.SecurityException}.
7895      *
7896      * @param executor The Executor on which to execute the callbacks.
7897      * @param listener The listener for the latency mode change.
7898      * @throws IllegalArgumentException if incorrect input arguments are provided.
7899      * @throws SecurityException if the caller is not allowed to call this API
7900      * @hide
7901      */
7902     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
7903     @RequiresPermission(anyOf = {android.Manifest.permission.NETWORK_SETTINGS,
7904             MANAGE_WIFI_NETWORK_SELECTION})
addWifiLowLatencyLockListener(@onNull @allbackExecutor Executor executor, @NonNull WifiLowLatencyLockListener listener)7905     public void addWifiLowLatencyLockListener(@NonNull @CallbackExecutor Executor executor,
7906             @NonNull WifiLowLatencyLockListener listener) {
7907         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
7908         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
7909         if (mVerboseLoggingEnabled) {
7910             Log.d(TAG, "addWifiLowLatencyLockListener: listener=" + listener + ", executor="
7911                     + executor);
7912         }
7913         final int listenerIdentifier = System.identityHashCode(listener);
7914         try {
7915             synchronized (sWifiLowLatencyLockListenerMap) {
7916                 IWifiLowLatencyLockListener.Stub listenerProxy = new OnWifiLowLatencyLockProxy(
7917                         executor,
7918                         listener);
7919                 sWifiLowLatencyLockListenerMap.put(listenerIdentifier, listenerProxy);
7920                 mService.addWifiLowLatencyLockListener(listenerProxy);
7921             }
7922         } catch (RemoteException e) {
7923             sWifiLowLatencyLockListenerMap.remove(listenerIdentifier);
7924             throw e.rethrowFromSystemServer();
7925         }
7926     }
7927 
7928     /**
7929      * Removes a listener added using {@link WifiManager#addWifiLowLatencyLockListener(Executor,
7930      * WifiLowLatencyLockListener)}. After calling this method, applications will no longer
7931      * receive low latency mode notifications.
7932      *
7933      * @param listener the listener to be removed.
7934      * @throws IllegalArgumentException if incorrect input arguments are provided.
7935      * @hide
7936      */
removeWifiLowLatencyLockListener(@onNull WifiLowLatencyLockListener listener)7937     public void removeWifiLowLatencyLockListener(@NonNull WifiLowLatencyLockListener listener) {
7938         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
7939         if (mVerboseLoggingEnabled) {
7940             Log.d(TAG, "removeWifiLowLatencyLockListener: listener=" + listener);
7941         }
7942         final int listenerIdentifier = System.identityHashCode(listener);
7943         synchronized (sWifiLowLatencyLockListenerMap) {
7944             try {
7945                 if (!sWifiLowLatencyLockListenerMap.contains(listenerIdentifier)) {
7946                     Log.w(TAG, "Unknown external listener " + listenerIdentifier);
7947                     return;
7948                 }
7949                 mService.removeWifiLowLatencyLockListener(
7950                         sWifiLowLatencyLockListenerMap.get(listenerIdentifier));
7951 
7952             } catch (RemoteException e) {
7953                 throw e.rethrowFromSystemServer();
7954             } finally {
7955                 sWifiLowLatencyLockListenerMap.remove(listenerIdentifier);
7956             }
7957         }
7958     }
7959 
7960     /**
7961      * Creates a new WifiLock.
7962      *
7963      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
7964      *            never shown to the user under normal conditions, but should be descriptive
7965      *            enough to identify your application and the specific WifiLock within it, if it
7966      *            holds multiple WifiLocks.
7967      *
7968      * @return a new, unacquired WifiLock with the given tag.
7969      *
7970      * @see WifiLock
7971      *
7972      * @deprecated This API is non-functional.
7973      */
7974     @Deprecated
createWifiLock(String tag)7975     public WifiLock createWifiLock(String tag) {
7976         return new WifiLock(WIFI_MODE_FULL, tag);
7977     }
7978 
7979     /**
7980      * Create a new MulticastLock
7981      *
7982      * @param tag a tag for the MulticastLock to identify it in debugging
7983      *            messages.  This string is never shown to the user under
7984      *            normal conditions, but should be descriptive enough to
7985      *            identify your application and the specific MulticastLock
7986      *            within it, if it holds multiple MulticastLocks.
7987      *
7988      * @return a new, unacquired MulticastLock with the given tag.
7989      *
7990      * @see MulticastLock
7991      */
createMulticastLock(String tag)7992     public MulticastLock createMulticastLock(String tag) {
7993         return new MulticastLock(tag);
7994     }
7995 
7996     /**
7997      * Allows an application to receive Wifi Multicast packets.
7998      * Normally the Wifi stack filters out packets not explicitly
7999      * addressed to this device.  Acquring a MulticastLock will
8000      * cause the stack to receive packets addressed to multicast
8001      * addresses.  Processing these extra packets can cause a noticeable
8002      * battery drain and should be disabled when not needed.
8003      */
8004     public class MulticastLock {
8005         private String mTag;
8006         private final IBinder mBinder;
8007         private int mRefCount;
8008         private boolean mRefCounted;
8009         private boolean mHeld;
8010 
MulticastLock(String tag)8011         private MulticastLock(String tag) {
8012             mTag = tag;
8013             mBinder = new Binder();
8014             mRefCount = 0;
8015             mRefCounted = true;
8016             mHeld = false;
8017         }
8018 
8019         /**
8020          * Locks Wifi Multicast on until {@link #release} is called.
8021          *
8022          * If this MulticastLock is reference-counted each call to
8023          * {@code acquire} will increment the reference count, and the
8024          * wifi interface will receive multicast packets as long as the
8025          * reference count is above zero.
8026          *
8027          * If this MulticastLock is not reference-counted, the first call to
8028          * {@code acquire} will turn on the multicast packets, but subsequent
8029          * calls will be ignored.  Only one call to {@link #release} will
8030          * be required, regardless of the number of times that {@code acquire}
8031          * is called.
8032          *
8033          * Note that other applications may also lock Wifi Multicast on.
8034          * Only they can relinquish their lock.
8035          *
8036          * Also note that applications cannot leave Multicast locked on.
8037          * When an app exits or crashes, any Multicast locks will be released.
8038          */
acquire()8039         public void acquire() {
8040             synchronized (mBinder) {
8041                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
8042                     try {
8043                         mService.acquireMulticastLock(mBinder, mTag);
8044                         synchronized (WifiManager.this) {
8045                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
8046                                 mService.releaseMulticastLock(mTag);
8047                                 throw new UnsupportedOperationException(
8048                                         "Exceeded maximum number of wifi locks");
8049                             }
8050                             mActiveLockCount++;
8051                         }
8052                     } catch (RemoteException e) {
8053                         throw e.rethrowFromSystemServer();
8054                     }
8055                     mHeld = true;
8056                 }
8057             }
8058         }
8059 
8060         /**
8061          * Unlocks Wifi Multicast, restoring the filter of packets
8062          * not addressed specifically to this device and saving power.
8063          *
8064          * If this MulticastLock is reference-counted, each call to
8065          * {@code release} will decrement the reference count, and the
8066          * multicast packets will only stop being received when the reference
8067          * count reaches zero.  If the reference count goes below zero (that
8068          * is, if {@code release} is called a greater number of times than
8069          * {@link #acquire}), an exception is thrown.
8070          *
8071          * If this MulticastLock is not reference-counted, the first call to
8072          * {@code release} (after the radio was multicast locked using
8073          * {@link #acquire}) will unlock the multicast, and subsequent calls
8074          * will be ignored.
8075          *
8076          * Note that if any other Wifi Multicast Locks are still outstanding
8077          * this {@code release} call will not have an immediate effect.  Only
8078          * when all applications have released all their Multicast Locks will
8079          * the Multicast filter be turned back on.
8080          *
8081          * Also note that when an app exits or crashes all of its Multicast
8082          * Locks will be automatically released.
8083          */
release()8084         public void release() {
8085             synchronized (mBinder) {
8086                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
8087                     try {
8088                         mService.releaseMulticastLock(mTag);
8089                         synchronized (WifiManager.this) {
8090                             mActiveLockCount--;
8091                         }
8092                     } catch (RemoteException e) {
8093                         throw e.rethrowFromSystemServer();
8094                     }
8095                     mHeld = false;
8096                 }
8097                 if (mRefCount < 0) {
8098                     throw new RuntimeException("MulticastLock under-locked "
8099                             + mTag);
8100                 }
8101             }
8102         }
8103 
8104         /**
8105          * Controls whether this is a reference-counted or non-reference-
8106          * counted MulticastLock.
8107          *
8108          * Reference-counted MulticastLocks keep track of the number of calls
8109          * to {@link #acquire} and {@link #release}, and only stop the
8110          * reception of multicast packets when every call to {@link #acquire}
8111          * has been balanced with a call to {@link #release}.  Non-reference-
8112          * counted MulticastLocks allow the reception of multicast packets
8113          * whenever {@link #acquire} is called and stop accepting multicast
8114          * packets whenever {@link #release} is called.
8115          *
8116          * @param refCounted true if this MulticastLock should keep a reference
8117          * count
8118          */
setReferenceCounted(boolean refCounted)8119         public void setReferenceCounted(boolean refCounted) {
8120             mRefCounted = refCounted;
8121         }
8122 
8123         /**
8124          * Checks whether this MulticastLock is currently held.
8125          *
8126          * @return true if this MulticastLock is held, false otherwise
8127          */
isHeld()8128         public boolean isHeld() {
8129             synchronized (mBinder) {
8130                 return mHeld;
8131             }
8132         }
8133 
toString()8134         public String toString() {
8135             String s1, s2, s3;
8136             synchronized (mBinder) {
8137                 s1 = Integer.toHexString(System.identityHashCode(this));
8138                 s2 = mHeld ? "held; " : "";
8139                 if (mRefCounted) {
8140                     s3 = "refcounted: refcount = " + mRefCount;
8141                 } else {
8142                     s3 = "not refcounted";
8143                 }
8144                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
8145             }
8146         }
8147 
8148         @Override
finalize()8149         protected void finalize() throws Throwable {
8150             super.finalize();
8151             setReferenceCounted(false);
8152             release();
8153         }
8154     }
8155 
8156     /**
8157      * Check multicast filter status.
8158      *
8159      * @return true if multicast packets are allowed.
8160      *
8161      * @hide pending API council approval
8162      */
isMulticastEnabled()8163     public boolean isMulticastEnabled() {
8164         try {
8165             return mService.isMulticastEnabled();
8166         } catch (RemoteException e) {
8167             throw e.rethrowFromSystemServer();
8168         }
8169     }
8170 
8171     /**
8172      * Initialize the multicast filtering to 'on'
8173      * @hide no intent to publish
8174      */
8175     @UnsupportedAppUsage
initializeMulticastFiltering()8176     public boolean initializeMulticastFiltering() {
8177         try {
8178             mService.initializeMulticastFiltering();
8179             return true;
8180         } catch (RemoteException e) {
8181             throw e.rethrowFromSystemServer();
8182         }
8183     }
8184 
8185     /**
8186      * Set Wi-Fi verbose logging level from developer settings.
8187      *
8188      * @param enable true to enable verbose logging, false to disable.
8189      *
8190      * @hide
8191      */
8192     @SystemApi
8193     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setVerboseLoggingEnabled(boolean enable)8194     public void setVerboseLoggingEnabled(boolean enable) {
8195         enableVerboseLogging(enable ? VERBOSE_LOGGING_LEVEL_ENABLED
8196                 : VERBOSE_LOGGING_LEVEL_DISABLED);
8197     }
8198 
8199     /**
8200      * Set Wi-Fi verbose logging level from developer settings.
8201      *
8202      * @param verbose the verbose logging mode which could be
8203      * {@link #VERBOSE_LOGGING_LEVEL_DISABLED}, {@link #VERBOSE_LOGGING_LEVEL_ENABLED}, or
8204      * {@link #VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY}.
8205      *
8206      * @hide
8207      */
8208     @SystemApi
8209     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setVerboseLoggingLevel(@erboseLoggingLevel int verbose)8210     public void setVerboseLoggingLevel(@VerboseLoggingLevel int verbose) {
8211         enableVerboseLogging(verbose);
8212     }
8213 
8214     /** @hide */
8215     @UnsupportedAppUsage(
8216             maxTargetSdk = Build.VERSION_CODES.Q,
8217             publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead."
8218     )
8219     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
enableVerboseLogging(@erboseLoggingLevel int verbose)8220     public void enableVerboseLogging(@VerboseLoggingLevel int verbose) {
8221         try {
8222             mService.enableVerboseLogging(verbose);
8223             mVerboseLoggingEnabled = verbose == VERBOSE_LOGGING_LEVEL_ENABLED;
8224         } catch (RemoteException e) {
8225             throw e.rethrowFromSystemServer();
8226         }
8227     }
8228 
8229     /**
8230      * Get the persisted Wi-Fi verbose logging level, set by
8231      * {@link #setVerboseLoggingEnabled(boolean)} or {@link #setVerboseLoggingLevel(int)}.
8232      * No permissions are required to call this method.
8233      *
8234      * @return true to indicate that verbose logging is enabled, false to indicate that verbose
8235      * logging is disabled.
8236      *
8237      * @hide
8238      */
8239     @SystemApi
isVerboseLoggingEnabled()8240     public boolean isVerboseLoggingEnabled() {
8241         return getVerboseLoggingLevel() > 0;
8242     }
8243 
8244     /**
8245      * Get the persisted Wi-Fi verbose logging level, set by
8246      * {@link #setVerboseLoggingEnabled(boolean)} or {@link #setVerboseLoggingLevel(int)}.
8247      * No permissions are required to call this method.
8248      *
8249      * @return one of {@link #VERBOSE_LOGGING_LEVEL_DISABLED},
8250      *         {@link #VERBOSE_LOGGING_LEVEL_ENABLED},
8251      *         or {@link #VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY}.
8252      *
8253      * @hide
8254      */
8255     @SystemApi
getVerboseLoggingLevel()8256     public @VerboseLoggingLevel int getVerboseLoggingLevel() {
8257         try {
8258             return mService.getVerboseLoggingLevel();
8259         } catch (RemoteException e) {
8260             throw e.rethrowFromSystemServer();
8261         }
8262     }
8263 
8264     /**
8265      * Removes all saved Wi-Fi networks, Passpoint configurations, ephemeral networks, Network
8266      * Requests, and Network Suggestions.
8267      *
8268      * @hide
8269      */
8270     @SystemApi
8271     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
factoryReset()8272     public void factoryReset() {
8273         try {
8274             mService.factoryReset(mContext.getOpPackageName());
8275         } catch (RemoteException e) {
8276             throw e.rethrowFromSystemServer();
8277         }
8278     }
8279 
8280     /**
8281      * Get {@link Network} object of current wifi network, or null if not connected.
8282      * @hide
8283      */
8284     @Nullable
8285     @SystemApi
8286     @RequiresPermission(anyOf = {
8287             android.Manifest.permission.NETWORK_SETTINGS,
8288             android.Manifest.permission.NETWORK_SETUP_WIZARD
8289     })
getCurrentNetwork()8290     public Network getCurrentNetwork() {
8291         try {
8292             return mService.getCurrentNetwork();
8293         } catch (RemoteException e) {
8294             throw e.rethrowFromSystemServer();
8295         }
8296     }
8297 
8298     /**
8299      * Deprecated
8300      * returns false
8301      * @hide
8302      * @deprecated
8303      */
setEnableAutoJoinWhenAssociated(boolean enabled)8304     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
8305         return false;
8306     }
8307 
8308     /**
8309      * Deprecated
8310      * returns false
8311      * @hide
8312      * @deprecated
8313      */
getEnableAutoJoinWhenAssociated()8314     public boolean getEnableAutoJoinWhenAssociated() {
8315         return false;
8316     }
8317 
8318     /**
8319      * Returns a byte stream representing the data that needs to be backed up to save the
8320      * current Wifi state.
8321      * This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}.
8322      * @hide
8323      */
8324     @NonNull
8325     @SystemApi
8326     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveBackupData()8327     public byte[] retrieveBackupData() {
8328         try {
8329             return mService.retrieveBackupData();
8330         } catch (RemoteException e) {
8331             throw e.rethrowFromSystemServer();
8332         }
8333     }
8334 
8335     /**
8336      * Restore state from the backed up data.
8337      * @param data byte stream in the same format produced by {@link #retrieveBackupData()}
8338      * @hide
8339      */
8340     @SystemApi
8341     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreBackupData(@onNull byte[] data)8342     public void restoreBackupData(@NonNull byte[] data) {
8343         try {
8344             mService.restoreBackupData(data);
8345         } catch (RemoteException e) {
8346             throw e.rethrowFromSystemServer();
8347         }
8348     }
8349 
8350     /**
8351      * Returns a byte stream representing the data that needs to be backed up to save the
8352      * current soft ap config data.
8353      *
8354      * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
8355      * @hide
8356      */
8357     @NonNull
8358     @SystemApi
8359     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveSoftApBackupData()8360     public byte[] retrieveSoftApBackupData() {
8361         try {
8362             return mService.retrieveSoftApBackupData();
8363         } catch (RemoteException e) {
8364             throw e.rethrowFromSystemServer();
8365         }
8366     }
8367 
8368     /**
8369      * Returns soft ap config from the backed up data or null if data is invalid.
8370      * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
8371      *
8372      * @hide
8373      */
8374     @Nullable
8375     @SystemApi
8376     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSoftApBackupData(@onNull byte[] data)8377     public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
8378         try {
8379             return mService.restoreSoftApBackupData(data);
8380         } catch (RemoteException e) {
8381             throw e.rethrowFromSystemServer();
8382         }
8383     }
8384 
8385     /**
8386      * Restore state from the older version of back up data.
8387      * The old backup data was essentially a backup of wpa_supplicant.conf
8388      * and ipconfig.txt file.
8389      * @param supplicantData bytes representing wpa_supplicant.conf
8390      * @param ipConfigData bytes representing ipconfig.txt
8391      * @hide
8392      */
8393     @SystemApi
8394     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSupplicantBackupData( @onNull byte[] supplicantData, @NonNull byte[] ipConfigData)8395     public void restoreSupplicantBackupData(
8396             @NonNull byte[] supplicantData, @NonNull byte[] ipConfigData) {
8397         try {
8398             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
8399         } catch (RemoteException e) {
8400             throw e.rethrowFromSystemServer();
8401         }
8402     }
8403 
8404     /**
8405      * Start subscription provisioning flow
8406      *
8407      * @param provider {@link OsuProvider} to provision with
8408      * @param executor the Executor on which to run the callback.
8409      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
8410      * @hide
8411      */
8412     @SystemApi
8413     @RequiresPermission(anyOf = {
8414             android.Manifest.permission.NETWORK_SETTINGS,
8415             android.Manifest.permission.NETWORK_SETUP_WIZARD
8416     })
startSubscriptionProvisioning(@onNull OsuProvider provider, @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback)8417     public void startSubscriptionProvisioning(@NonNull OsuProvider provider,
8418             @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback) {
8419         // Verify arguments
8420         if (executor == null) {
8421             throw new IllegalArgumentException("executor must not be null");
8422         }
8423         if (callback == null) {
8424             throw new IllegalArgumentException("callback must not be null");
8425         }
8426         try {
8427             mService.startSubscriptionProvisioning(provider,
8428                     new ProvisioningCallbackProxy(executor, callback));
8429         } catch (RemoteException e) {
8430             throw e.rethrowFromSystemServer();
8431         }
8432     }
8433 
8434     /**
8435      * Helper class to support OSU Provisioning callbacks
8436      */
8437     private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
8438         private final Executor mExecutor;
8439         private final ProvisioningCallback mCallback;
8440 
ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback)8441         ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback) {
8442             mExecutor = executor;
8443             mCallback = callback;
8444         }
8445 
8446         @Override
onProvisioningStatus(int status)8447         public void onProvisioningStatus(int status) {
8448             mExecutor.execute(() -> mCallback.onProvisioningStatus(status));
8449         }
8450 
8451         @Override
onProvisioningFailure(int status)8452         public void onProvisioningFailure(int status) {
8453             mExecutor.execute(() -> mCallback.onProvisioningFailure(status));
8454         }
8455 
8456         @Override
onProvisioningComplete()8457         public void onProvisioningComplete() {
8458             mExecutor.execute(() -> mCallback.onProvisioningComplete());
8459         }
8460     }
8461 
8462     /**
8463      * Interface for Traffic state callback. Should be extended by applications and set when
8464      * calling {@link #registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}.
8465      * @hide
8466      */
8467     @SystemApi
8468     public interface TrafficStateCallback {
8469         /** @hide */
8470         @Retention(RetentionPolicy.SOURCE)
8471         @IntDef(prefix = {"DATA_ACTIVITY_"}, value = {
8472                 DATA_ACTIVITY_NONE,
8473                 DATA_ACTIVITY_IN,
8474                 DATA_ACTIVITY_OUT,
8475                 DATA_ACTIVITY_INOUT})
8476         @interface DataActivity {}
8477 
8478         // Lowest bit indicates data reception and the second lowest bit indicates data transmitted
8479         /** No data in or out */
8480         int DATA_ACTIVITY_NONE         = 0x00;
8481         /** Data in, no data out */
8482         int DATA_ACTIVITY_IN           = 0x01;
8483         /** Data out, no data in */
8484         int DATA_ACTIVITY_OUT          = 0x02;
8485         /** Data in and out */
8486         int DATA_ACTIVITY_INOUT        = 0x03;
8487 
8488         /**
8489          * Callback invoked to inform clients about the current traffic state.
8490          *
8491          * @param state One of the values: {@link #DATA_ACTIVITY_NONE}, {@link #DATA_ACTIVITY_IN},
8492          * {@link #DATA_ACTIVITY_OUT} & {@link #DATA_ACTIVITY_INOUT}.
8493          */
onStateChanged(@ataActivity int state)8494         void onStateChanged(@DataActivity int state);
8495     }
8496 
8497     /**
8498      * Callback proxy for TrafficStateCallback objects.
8499      *
8500      * @hide
8501      */
8502     private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub {
8503         private final Executor mExecutor;
8504         private final TrafficStateCallback mCallback;
8505 
TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback)8506         TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback) {
8507             mExecutor = executor;
8508             mCallback = callback;
8509         }
8510 
8511         @Override
onStateChanged(int state)8512         public void onStateChanged(int state) {
8513             if (mVerboseLoggingEnabled) {
8514                 Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state);
8515             }
8516             Binder.clearCallingIdentity();
8517             mExecutor.execute(() -> {
8518                 mCallback.onStateChanged(state);
8519             });
8520         }
8521     }
8522 
8523     /**
8524      * Registers a callback for monitoring traffic state. See {@link TrafficStateCallback}. These
8525      * callbacks will be invoked periodically by platform to inform clients about the current
8526      * traffic state. Caller can unregister a previously registered callback using
8527      * {@link #unregisterTrafficStateCallback(TrafficStateCallback)}
8528      * <p>
8529      * Applications should have the
8530      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
8531      * without the permission will trigger a {@link java.lang.SecurityException}.
8532      * <p>
8533      *
8534      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
8535      *                 object.
8536      * @param callback Callback for traffic state events
8537      * @hide
8538      */
8539     @SystemApi
8540     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerTrafficStateCallback(@onNull @allbackExecutor Executor executor, @NonNull TrafficStateCallback callback)8541     public void registerTrafficStateCallback(@NonNull @CallbackExecutor Executor executor,
8542                                              @NonNull TrafficStateCallback callback) {
8543         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
8544         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
8545         Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", executor=" + executor);
8546 
8547         try {
8548             synchronized (sTrafficStateCallbackMap) {
8549                 ITrafficStateCallback.Stub binderCallback = new TrafficStateCallbackProxy(executor,
8550                         callback);
8551                 sTrafficStateCallbackMap.put(System.identityHashCode(callback), binderCallback);
8552                 mService.registerTrafficStateCallback(binderCallback);
8553             }
8554         } catch (RemoteException e) {
8555             throw e.rethrowFromSystemServer();
8556         }
8557     }
8558 
8559     /**
8560      * Allow callers to unregister a previously registered callback. After calling this method,
8561      * applications will no longer receive traffic state notifications.
8562      *
8563      * @param callback Callback to unregister for traffic state events
8564      * @hide
8565      */
8566     @SystemApi
8567     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterTrafficStateCallback(@onNull TrafficStateCallback callback)8568     public void unregisterTrafficStateCallback(@NonNull TrafficStateCallback callback) {
8569         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
8570         Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
8571 
8572         try {
8573             synchronized (sTrafficStateCallbackMap) {
8574                 int callbackIdentifier = System.identityHashCode(callback);
8575                 if (!sTrafficStateCallbackMap.contains(callbackIdentifier)) {
8576                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
8577                     return;
8578                 }
8579                 mService.unregisterTrafficStateCallback(
8580                         sTrafficStateCallbackMap.get(callbackIdentifier));
8581                 sTrafficStateCallbackMap.remove(callbackIdentifier);
8582             }
8583         } catch (RemoteException e) {
8584             throw e.rethrowFromSystemServer();
8585         }
8586     }
8587 
8588     /**
8589      * Helper method to update the local verbose logging flag based on the verbose logging
8590      * level from wifi service.
8591      */
updateVerboseLoggingEnabledFromService()8592     private void updateVerboseLoggingEnabledFromService() {
8593         mVerboseLoggingEnabled = isVerboseLoggingEnabled();
8594     }
8595 
8596     /**
8597      * @return true if this device supports WPA3-Personal SAE
8598      */
isWpa3SaeSupported()8599     public boolean isWpa3SaeSupported() {
8600         return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
8601     }
8602 
8603     /**
8604      * @return true if this device supports WPA3-Enterprise Suite-B-192
8605      */
isWpa3SuiteBSupported()8606     public boolean isWpa3SuiteBSupported() {
8607         return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
8608     }
8609 
8610     /**
8611      * @return true if this device supports Wi-Fi Enhanced Open (OWE)
8612      */
isEnhancedOpenSupported()8613     public boolean isEnhancedOpenSupported() {
8614         return isFeatureSupported(WIFI_FEATURE_OWE);
8615     }
8616 
8617     /**
8618      * Wi-Fi Easy Connect (DPP) introduces standardized mechanisms to simplify the provisioning and
8619      * configuration of Wi-Fi devices.
8620      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
8621      * search for "Easy Connect" or "Device Provisioning Protocol specification".
8622      *
8623      * @return true if this device supports Wi-Fi Easy-connect (Device Provisioning Protocol)
8624      */
isEasyConnectSupported()8625     public boolean isEasyConnectSupported() {
8626         return isFeatureSupported(WIFI_FEATURE_DPP);
8627     }
8628 
8629     /**
8630      * @return true if this device supports Wi-Fi Easy Connect (DPP) Enrollee Responder mode.
8631      */
isEasyConnectEnrolleeResponderModeSupported()8632     public boolean isEasyConnectEnrolleeResponderModeSupported() {
8633         return isFeatureSupported(WIFI_FEATURE_DPP_ENROLLEE_RESPONDER);
8634     }
8635 
8636     /**
8637      * @return true if this device supports WAPI.
8638      */
isWapiSupported()8639     public boolean isWapiSupported() {
8640         return isFeatureSupported(WIFI_FEATURE_WAPI);
8641     }
8642 
8643     /**
8644      * @return true if this device supports WPA3 SAE Public Key.
8645      */
isWpa3SaePublicKeySupported()8646     public boolean isWpa3SaePublicKeySupported() {
8647         // This feature is not fully implemented in the framework yet.
8648         // After the feature complete, it returns whether WIFI_FEATURE_SAE_PK
8649         // is supported or not directly.
8650         return false;
8651     }
8652 
8653     /**
8654      * @return true if this device supports Wi-Fi Passpoint Terms and Conditions feature.
8655      */
isPasspointTermsAndConditionsSupported()8656     public boolean isPasspointTermsAndConditionsSupported() {
8657         return isFeatureSupported(WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS);
8658     }
8659 
8660     /**
8661      * @return true if this device supports WPA3 SAE Hash-to-Element.
8662      */
isWpa3SaeH2eSupported()8663     public boolean isWpa3SaeH2eSupported() {
8664         return isFeatureSupported(WIFI_FEATURE_SAE_H2E);
8665     }
8666 
8667     /**
8668      * @return true if this device supports Wi-Fi Display R2.
8669      */
isWifiDisplayR2Supported()8670     public boolean isWifiDisplayR2Supported() {
8671         return isFeatureSupported(WIFI_FEATURE_WFD_R2);
8672     }
8673 
8674     /**
8675      * @return true if this device supports RFC 7542 decorated identity.
8676      */
isDecoratedIdentitySupported()8677     public boolean isDecoratedIdentitySupported() {
8678         return isFeatureSupported(WIFI_FEATURE_DECORATED_IDENTITY);
8679     }
8680 
8681     /**
8682      * @return true if this device supports Trust On First Use (TOFU).
8683      */
isTrustOnFirstUseSupported()8684     public boolean isTrustOnFirstUseSupported() {
8685         return isFeatureSupported(WIFI_FEATURE_TRUST_ON_FIRST_USE);
8686     }
8687 
8688     /**
8689      * Wi-Fi Easy Connect DPP AKM enables provisioning and configuration of Wi-Fi devices without
8690      * the need of using the device PSK passphrase.
8691      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
8692      * search for "Easy Connect" or "Device Provisioning Protocol specification".
8693      *
8694      * @return true if this device supports Wi-Fi Easy-connect DPP (Device Provisioning Protocol)
8695      * AKM, false otherwise.
8696      */
isEasyConnectDppAkmSupported()8697     public boolean isEasyConnectDppAkmSupported() {
8698         return isFeatureSupported(WIFI_FEATURE_DPP_AKM);
8699     }
8700 
8701     /**
8702      * Indicate that whether or not settings required TLS minimum version is supported.
8703      *
8704      * If the device doesn't support this capability, the minimum accepted TLS version is 1.0.
8705      *
8706      * @return true if this device supports setting TLS minimum version.
8707      */
isTlsMinimumVersionSupported()8708     public boolean isTlsMinimumVersionSupported() {
8709         return isFeatureSupported(WIFI_FEATURE_SET_TLS_MINIMUM_VERSION);
8710     }
8711 
8712     /**
8713      * Indicate that whether or not TLS v1.3 is supported.
8714      *
8715      * If requested minimum is not supported, it will default to the maximum supported version.
8716      *
8717      * @return true if this device supports TLS v1.3.
8718      */
isTlsV13Supported()8719     public boolean isTlsV13Supported() {
8720         return isFeatureSupported(WIFI_FEATURE_TLS_V1_3);
8721     }
8722 
8723     /**
8724      * @return true if this device supports Dual Band Simultaneous (DBS) operation.
8725      */
isDualBandSimultaneousSupported()8726     public boolean isDualBandSimultaneousSupported() {
8727         return isFeatureSupported(WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS);
8728     }
8729 
8730     /**
8731      * @return true if this device supports TID-To-Link Mapping Negotiation.
8732      */
isTidToLinkMappingNegotiationSupported()8733     public boolean isTidToLinkMappingNegotiationSupported() {
8734         return isFeatureSupported(WIFI_FEATURE_T2LM_NEGOTIATION);
8735     }
8736 
8737     /**
8738      * Gets the factory Wi-Fi MAC addresses.
8739      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
8740      * if failed.
8741      * @hide
8742      */
8743     @NonNull
8744     @SystemApi
8745     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getFactoryMacAddresses()8746     public String[] getFactoryMacAddresses() {
8747         try {
8748             return mService.getFactoryMacAddresses();
8749         } catch (RemoteException e) {
8750             throw e.rethrowFromSystemServer();
8751         }
8752     }
8753 
8754     /** @hide */
8755     @Retention(RetentionPolicy.SOURCE)
8756     @IntDef(prefix = {"DEVICE_MOBILITY_STATE_"}, value = {
8757             DEVICE_MOBILITY_STATE_UNKNOWN,
8758             DEVICE_MOBILITY_STATE_HIGH_MVMT,
8759             DEVICE_MOBILITY_STATE_LOW_MVMT,
8760             DEVICE_MOBILITY_STATE_STATIONARY})
8761     public @interface DeviceMobilityState {}
8762 
8763     /**
8764      * Unknown device mobility state
8765      *
8766      * @see #setDeviceMobilityState(int)
8767      *
8768      * @hide
8769      */
8770     @SystemApi
8771     public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0;
8772 
8773     /**
8774      * High movement device mobility state.
8775      * e.g. on a bike, in a motor vehicle
8776      *
8777      * @see #setDeviceMobilityState(int)
8778      *
8779      * @hide
8780      */
8781     @SystemApi
8782     public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1;
8783 
8784     /**
8785      * Low movement device mobility state.
8786      * e.g. walking, running
8787      *
8788      * @see #setDeviceMobilityState(int)
8789      *
8790      * @hide
8791      */
8792     @SystemApi
8793     public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2;
8794 
8795     /**
8796      * Stationary device mobility state
8797      *
8798      * @see #setDeviceMobilityState(int)
8799      *
8800      * @hide
8801      */
8802     @SystemApi
8803     public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3;
8804 
8805     /**
8806      * Updates the device mobility state. Wifi uses this information to adjust the interval between
8807      * Wifi scans in order to balance power consumption with scan accuracy.
8808      * The default mobility state when the device boots is {@link #DEVICE_MOBILITY_STATE_UNKNOWN}.
8809      * This API should be called whenever there is a change in the mobility state.
8810      * @param state the updated device mobility state
8811      * @hide
8812      */
8813     @SystemApi
8814     @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
setDeviceMobilityState(@eviceMobilityState int state)8815     public void setDeviceMobilityState(@DeviceMobilityState int state) {
8816         try {
8817             mService.setDeviceMobilityState(state);
8818         } catch (RemoteException e) {
8819             throw e.rethrowFromSystemServer();
8820         }
8821     }
8822 
8823     /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
8824 
8825     /**
8826      * Easy Connect Network role: Station.
8827      *
8828      * @hide
8829      */
8830     @SystemApi
8831     public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
8832 
8833     /**
8834      * Easy Connect Network role: Access Point.
8835      *
8836      * @hide
8837      */
8838     @SystemApi
8839     public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
8840 
8841     /** @hide */
8842     @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
8843             EASY_CONNECT_NETWORK_ROLE_STA,
8844             EASY_CONNECT_NETWORK_ROLE_AP,
8845     })
8846     @Retention(RetentionPolicy.SOURCE)
8847     public @interface EasyConnectNetworkRole {
8848     }
8849 
8850     /** Easy Connect Device information maximum allowed length */
8851     private static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40;
8852 
8853     /**
8854      * Easy Connect Cryptography Curve name: prime256v1
8855      *
8856      * @hide
8857      */
8858     @SystemApi
8859     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0;
8860 
8861     /**
8862      * Easy Connect Cryptography Curve name: secp384r1
8863      *
8864      * @hide
8865      */
8866     @SystemApi
8867     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1;
8868 
8869     /**
8870      * Easy Connect Cryptography Curve name: secp521r1
8871      *
8872      * @hide
8873      */
8874     @SystemApi
8875     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2;
8876 
8877 
8878     /**
8879      * Easy Connect Cryptography Curve name: brainpoolP256r1
8880      *
8881      * @hide
8882      */
8883     @SystemApi
8884     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3;
8885 
8886 
8887     /**
8888      * Easy Connect Cryptography Curve name: brainpoolP384r1
8889      *
8890      * @hide
8891      */
8892     @SystemApi
8893     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4;
8894 
8895 
8896     /**
8897      * Easy Connect Cryptography Curve name: brainpoolP512r1
8898      *
8899      * @hide
8900      */
8901     @SystemApi
8902     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5;
8903 
8904     /** @hide */
8905     @IntDef(prefix = {"EASY_CONNECT_CRYPTOGRAPHY_CURVE_"}, value = {
8906             EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1,
8907             EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1,
8908             EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1,
8909             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1,
8910             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1,
8911             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1,
8912     })
8913     @Retention(RetentionPolicy.SOURCE)
8914     public @interface EasyConnectCryptographyCurve {
8915     }
8916 
8917     /**
8918      * Verbose logging mode: DISABLED.
8919      * @hide
8920      */
8921     @SystemApi
8922     public static final int VERBOSE_LOGGING_LEVEL_DISABLED = 0;
8923 
8924     /**
8925      * Verbose logging mode: ENABLED.
8926      * @hide
8927      */
8928     @SystemApi
8929     public static final int VERBOSE_LOGGING_LEVEL_ENABLED = 1;
8930 
8931     /**
8932      * Verbose logging mode: ENABLED_SHOW_KEY.
8933      * This mode causes the Wi-Fi password and encryption keys to be output to the logcat.
8934      * This is security sensitive information useful for debugging.
8935      * This configuration is enabled for 30 seconds and then falls back to
8936      * the regular verbose mode (i.e. to {@link VERBOSE_LOGGING_LEVEL_ENABLED}).
8937      * Show key mode is not persistent, i.e. rebooting the device would fallback to
8938      * the regular verbose mode.
8939      * @hide
8940      */
8941     @SystemApi
8942     public static final int VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY = 2;
8943 
8944     /** @hide */
8945     @IntDef(prefix = {"VERBOSE_LOGGING_LEVEL_"}, value = {
8946             VERBOSE_LOGGING_LEVEL_DISABLED,
8947             VERBOSE_LOGGING_LEVEL_ENABLED,
8948             VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY,
8949     })
8950     @Retention(RetentionPolicy.SOURCE)
8951     public @interface VerboseLoggingLevel {
8952     }
8953 
8954     /**
8955      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
8956      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
8957      * the specified network using the Easy Connect protocol on an encrypted link.
8958      *
8959      * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
8960      * @param selectedNetworkId   Selected network ID to be sent to the peer
8961      * @param enrolleeNetworkRole The network role of the enrollee
8962      * @param callback            Callback for status updates
8963      * @param executor            The Executor on which to run the callback.
8964      * @hide
8965      */
8966     @SystemApi
8967     @RequiresPermission(anyOf = {
8968             android.Manifest.permission.NETWORK_SETTINGS,
8969             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsConfiguratorInitiator(@onNull String enrolleeUri, int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)8970     public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
8971             int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
8972             @NonNull @CallbackExecutor Executor executor,
8973             @NonNull EasyConnectStatusCallback callback) {
8974         Binder binder = new Binder();
8975         try {
8976             mService.startDppAsConfiguratorInitiator(binder, mContext.getOpPackageName(),
8977                     enrolleeUri, selectedNetworkId, enrolleeNetworkRole,
8978                     new EasyConnectCallbackProxy(executor, callback));
8979         } catch (RemoteException e) {
8980             throw e.rethrowFromSystemServer();
8981         }
8982     }
8983 
8984     /**
8985      * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
8986      * Connect bootstrapping with a peer, and receive the SSID and password from the peer
8987      * configurator.
8988      *
8989      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
8990      * @param callback        Callback for status updates
8991      * @param executor        The Executor on which to run the callback.
8992      * @hide
8993      */
8994     @SystemApi
8995     @RequiresPermission(anyOf = {
8996             android.Manifest.permission.NETWORK_SETTINGS,
8997             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsEnrolleeInitiator(@onNull String configuratorUri, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)8998     public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
8999             @NonNull @CallbackExecutor Executor executor,
9000             @NonNull EasyConnectStatusCallback callback) {
9001         Binder binder = new Binder();
9002         try {
9003             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
9004                     new EasyConnectCallbackProxy(executor, callback));
9005         } catch (RemoteException e) {
9006             throw e.rethrowFromSystemServer();
9007         }
9008     }
9009 
9010     /**
9011      * Start Easy Connect (DPP) in Enrollee-Responder role.
9012      * The device will:
9013      * 1. Generate a DPP bootstrap URI and return it using the
9014      * {@link EasyConnectStatusCallback#onBootstrapUriGenerated(Uri)} method.
9015      * 2. Start DPP as a Responder, waiting for an Initiator device to start the DPP
9016      * authentication process.
9017      * The caller should use the URI provided in step #1, for instance display it as a QR code
9018      * or communicate it in some other way to the initiator device.
9019      *
9020      * @param deviceInfo      Device specific information to add to the DPP URI. This field allows
9021      *                        the users of the configurators to identify the device.
9022      *                        Optional - if not provided or in case of an empty string,
9023      *                        Info field (I:) will be skipped in the generated DPP URI.
9024      *                        Allowed Range of ASCII characters in deviceInfo - %x20-7E.
9025      *                        semicolon and space are not allowed. Due to the limitation of maximum
9026      *                        allowed characters in QR code, framework adds a limit to maximum
9027      *                        characters in deviceInfo. Users must call
9028      *                        {@link WifiManager#getEasyConnectMaxAllowedResponderDeviceInfoLength()
9029      *                        } method to know max allowed length. Violation of these rules will
9030      *                        result in an exception.
9031      * @param curve           Elliptic curve cryptography used to generate DPP
9032      *                        public/private key pair. If application is not interested in a
9033      *                        specific curve, use specification mandated NIST P-256 elliptic curve,
9034      *                        {@link WifiManager#EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1}.
9035      * @param callback        Callback for status updates
9036      * @param executor        The Executor on which to run the callback.
9037      * @hide
9038      */
9039     @SystemApi
9040     @RequiresPermission(anyOf = {
9041             android.Manifest.permission.NETWORK_SETTINGS,
9042             android.Manifest.permission.NETWORK_SETUP_WIZARD})
9043     @RequiresApi(Build.VERSION_CODES.S)
startEasyConnectAsEnrolleeResponder(@ullable String deviceInfo, @EasyConnectCryptographyCurve int curve, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)9044     public void startEasyConnectAsEnrolleeResponder(@Nullable String deviceInfo,
9045             @EasyConnectCryptographyCurve int curve,
9046             @NonNull @CallbackExecutor Executor executor,
9047             @NonNull EasyConnectStatusCallback callback) {
9048         Binder binder = new Binder();
9049         try {
9050             mService.startDppAsEnrolleeResponder(binder, deviceInfo, curve,
9051                     new EasyConnectCallbackProxy(executor, callback));
9052         } catch (RemoteException e) {
9053             throw e.rethrowFromSystemServer();
9054         }
9055     }
9056 
9057     /**
9058      * Maximum allowed length of Device specific information that can be added to the URI of
9059      * Easy Connect responder device.
9060      * @see #startEasyConnectAsEnrolleeResponder(String, int, Executor, EasyConnectStatusCallback)}
9061      *
9062      * @hide
9063      */
9064     @SystemApi
getEasyConnectMaxAllowedResponderDeviceInfoLength()9065     public static int getEasyConnectMaxAllowedResponderDeviceInfoLength() {
9066         return EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH;
9067     }
9068 
9069     /**
9070      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
9071      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
9072      * expect any callbacks once this call is made. However, due to the asynchronous nature of
9073      * this call, a callback may be fired if it was already pending in the queue.
9074      *
9075      * @hide
9076      */
9077     @SystemApi
9078     @RequiresPermission(anyOf = {
9079             android.Manifest.permission.NETWORK_SETTINGS,
9080             android.Manifest.permission.NETWORK_SETUP_WIZARD})
stopEasyConnectSession()9081     public void stopEasyConnectSession() {
9082         try {
9083             /* Request lower layers to stop/abort and clear resources */
9084             mService.stopDppSession();
9085         } catch (RemoteException e) {
9086             throw e.rethrowFromSystemServer();
9087         }
9088     }
9089 
9090     /**
9091      * Helper class to support Easy Connect (DPP) callbacks
9092      *
9093      * @hide
9094      */
9095     private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
9096         private final Executor mExecutor;
9097         private final EasyConnectStatusCallback mEasyConnectStatusCallback;
9098 
EasyConnectCallbackProxy(Executor executor, EasyConnectStatusCallback easyConnectStatusCallback)9099         EasyConnectCallbackProxy(Executor executor,
9100                 EasyConnectStatusCallback easyConnectStatusCallback) {
9101             mExecutor = executor;
9102             mEasyConnectStatusCallback = easyConnectStatusCallback;
9103         }
9104 
9105         @Override
onSuccessConfigReceived(int newNetworkId)9106         public void onSuccessConfigReceived(int newNetworkId) {
9107             Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
9108             Binder.clearCallingIdentity();
9109             mExecutor.execute(() -> {
9110                 mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
9111             });
9112         }
9113 
9114         @Override
onSuccess(int status)9115         public void onSuccess(int status) {
9116             Log.d(TAG, "Easy Connect onSuccess callback");
9117             Binder.clearCallingIdentity();
9118             mExecutor.execute(() -> {
9119                 mEasyConnectStatusCallback.onConfiguratorSuccess(status);
9120             });
9121         }
9122 
9123         @Override
onFailure(int status, String ssid, String channelList, int[] operatingClassArray)9124         public void onFailure(int status, String ssid, String channelList,
9125                 int[] operatingClassArray) {
9126             Log.d(TAG, "Easy Connect onFailure callback");
9127             Binder.clearCallingIdentity();
9128             mExecutor.execute(() -> {
9129                 SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
9130                 mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
9131                         operatingClassArray);
9132             });
9133         }
9134 
9135         @Override
onProgress(int status)9136         public void onProgress(int status) {
9137             Log.d(TAG, "Easy Connect onProgress callback");
9138             Binder.clearCallingIdentity();
9139             mExecutor.execute(() -> {
9140                 mEasyConnectStatusCallback.onProgress(status);
9141             });
9142         }
9143 
9144         @Override
onBootstrapUriGenerated(@onNull String uri)9145         public void onBootstrapUriGenerated(@NonNull String uri) {
9146             Log.d(TAG, "Easy Connect onBootstrapUriGenerated callback");
9147             if (!SdkLevel.isAtLeastS()) {
9148                 Log.e(TAG, "Easy Connect bootstrap URI callback supported only on S+");
9149                 return;
9150             }
9151             Binder.clearCallingIdentity();
9152             mExecutor.execute(() -> {
9153                 mEasyConnectStatusCallback.onBootstrapUriGenerated(Uri.parse(uri));
9154             });
9155         }
9156     }
9157 
9158     /**
9159      * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
9160      * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor,
9161      * OnWifiUsabilityStatsListener)}.
9162      *
9163      * @hide
9164      */
9165     @SystemApi
9166     public interface OnWifiUsabilityStatsListener {
9167         /**
9168          * Called when Wi-Fi usability statistics is updated.
9169          *
9170          * @param seqNum The sequence number of statistics, used to derive the timing of updated
9171          *               Wi-Fi usability statistics, set by framework and incremented by one after
9172          *               each update.
9173          * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
9174          *                           network stays the same or not relative to the last update of
9175          *                           Wi-Fi usability stats.
9176          * @param stats The updated Wi-Fi usability statistics.
9177          */
onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, @NonNull WifiUsabilityStatsEntry stats)9178         void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
9179                 @NonNull WifiUsabilityStatsEntry stats);
9180     }
9181 
9182     /**
9183      * Interface for Wi-Fi verbose logging status listener. Should be implemented by applications
9184      * and set when calling {@link WifiManager#addWifiVerboseLoggingStatusListener(Executor,
9185      * WifiVerboseLoggingStatusListener)}.
9186      *
9187      * @hide
9188      */
9189     @SystemApi
9190     public interface WifiVerboseLoggingStatusChangedListener {
9191         /**
9192          * Called when Wi-Fi verbose logging setting is updated.
9193          *
9194          * @param enabled true if verbose logging is enabled, false if verbose logging is disabled.
9195          */
onWifiVerboseLoggingStatusChanged(boolean enabled)9196         void onWifiVerboseLoggingStatusChanged(boolean enabled);
9197     }
9198 
9199     /**
9200      * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}.
9201      * Multiple listeners can be added. Callers will be invoked periodically by framework to
9202      * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
9203      * added listener using
9204      * {@link #removeOnWifiUsabilityStatsListener(OnWifiUsabilityStatsListener)}.
9205      *
9206      * @param executor The executor on which callback will be invoked.
9207      * @param listener Listener for Wifi usability statistics.
9208      *
9209      * @hide
9210      */
9211     @SystemApi
9212     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
addOnWifiUsabilityStatsListener(@onNull @allbackExecutor Executor executor, @NonNull OnWifiUsabilityStatsListener listener)9213     public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
9214             @NonNull OnWifiUsabilityStatsListener listener) {
9215         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
9216         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
9217         if (mVerboseLoggingEnabled) {
9218             Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
9219         }
9220         try {
9221             synchronized (sOnWifiUsabilityStatsListenerMap) {
9222                 IOnWifiUsabilityStatsListener.Stub binderCallback =
9223                         new IOnWifiUsabilityStatsListener.Stub() {
9224                             @Override
9225                             public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
9226                                     WifiUsabilityStatsEntry stats) {
9227                                 if (mVerboseLoggingEnabled) {
9228                                     Log.v(TAG, "OnWifiUsabilityStatsListener: "
9229                                             + "onWifiUsabilityStats: seqNum=" + seqNum);
9230                                 }
9231                                 Binder.clearCallingIdentity();
9232                                 executor.execute(() -> listener.onWifiUsabilityStats(
9233                                         seqNum, isSameBssidAndFreq, stats));
9234                             }
9235                         };
9236                 sOnWifiUsabilityStatsListenerMap.put(System.identityHashCode(listener),
9237                         binderCallback);
9238                 mService.addOnWifiUsabilityStatsListener(binderCallback);
9239             }
9240         } catch (RemoteException e) {
9241             throw e.rethrowFromSystemServer();
9242         }
9243     }
9244 
9245     /**
9246      * Allow callers to remove a previously registered listener. After calling this method,
9247      * applications will no longer receive Wi-Fi usability statistics.
9248      *
9249      * @param listener Listener to remove the Wi-Fi usability statistics.
9250      *
9251      * @hide
9252      */
9253     @SystemApi
9254     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
removeOnWifiUsabilityStatsListener(@onNull OnWifiUsabilityStatsListener listener)9255     public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) {
9256         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
9257         if (mVerboseLoggingEnabled) {
9258             Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
9259         }
9260         try {
9261             synchronized (sOnWifiUsabilityStatsListenerMap) {
9262                 int listenerIdentifier = System.identityHashCode(listener);
9263                 if (!sOnWifiUsabilityStatsListenerMap.contains(listenerIdentifier)) {
9264                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9265                     return;
9266                 }
9267                 mService.removeOnWifiUsabilityStatsListener(
9268                         sOnWifiUsabilityStatsListenerMap.get(listenerIdentifier));
9269                 sOnWifiUsabilityStatsListenerMap.remove(listenerIdentifier);
9270             }
9271         } catch (RemoteException e) {
9272             throw e.rethrowFromSystemServer();
9273         }
9274     }
9275 
9276     /**
9277      * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
9278      * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
9279      * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
9280      * is used to quantify whether Wi-Fi is usable in a future time.
9281      *
9282      * @param seqNum Sequence number of the Wi-Fi usability score.
9283      * @param score The Wi-Fi usability score, expected range: [0, 100].
9284      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
9285      *                             expected range: [0, 30].
9286      *
9287      * @hide
9288      */
9289     @SystemApi
9290     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)9291     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
9292         try {
9293             mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
9294         } catch (RemoteException e) {
9295             throw e.rethrowFromSystemServer();
9296         }
9297     }
9298 
9299     /**
9300      * Abstract class for scan results callback. Should be extended by applications and set when
9301      * calling {@link WifiManager#registerScanResultsCallback(Executor, ScanResultsCallback)}.
9302      */
9303     public abstract static class ScanResultsCallback {
9304         private final ScanResultsCallbackProxy mScanResultsCallbackProxy;
9305 
ScanResultsCallback()9306         public ScanResultsCallback() {
9307             mScanResultsCallbackProxy = new ScanResultsCallbackProxy();
9308         }
9309 
9310         /**
9311          * Called when new scan results are available.
9312          * Clients should use {@link WifiManager#getScanResults()} to get the scan results.
9313          */
onScanResultsAvailable()9314         public abstract void onScanResultsAvailable();
9315 
getProxy()9316         /*package*/ @NonNull ScanResultsCallbackProxy getProxy() {
9317             return mScanResultsCallbackProxy;
9318         }
9319 
9320         private static class ScanResultsCallbackProxy extends IScanResultsCallback.Stub {
9321             private final Object mLock = new Object();
9322             @Nullable @GuardedBy("mLock") private Executor mExecutor;
9323             @Nullable @GuardedBy("mLock") private ScanResultsCallback mCallback;
9324 
ScanResultsCallbackProxy()9325             ScanResultsCallbackProxy() {
9326                 mCallback = null;
9327                 mExecutor = null;
9328             }
9329 
initProxy(@onNull Executor executor, @NonNull ScanResultsCallback callback)9330             /*package*/ void initProxy(@NonNull Executor executor,
9331                     @NonNull ScanResultsCallback callback) {
9332                 synchronized (mLock) {
9333                     mExecutor = executor;
9334                     mCallback = callback;
9335                 }
9336             }
9337 
cleanUpProxy()9338             /*package*/ void cleanUpProxy() {
9339                 synchronized (mLock) {
9340                     mExecutor = null;
9341                     mCallback = null;
9342                 }
9343             }
9344 
9345             @Override
onScanResultsAvailable()9346             public void onScanResultsAvailable() {
9347                 ScanResultsCallback callback;
9348                 Executor executor;
9349                 synchronized (mLock) {
9350                     executor = mExecutor;
9351                     callback = mCallback;
9352                 }
9353                 if (callback == null || executor == null) {
9354                     return;
9355                 }
9356                 Binder.clearCallingIdentity();
9357                 executor.execute(callback::onScanResultsAvailable);
9358             }
9359         }
9360     }
9361 
9362     /**
9363      * Register a callback for Scan Results. See {@link ScanResultsCallback}.
9364      * Caller will receive the event when scan results are available.
9365      * Caller should use {@link WifiManager#getScanResults()} requires
9366      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results.
9367      * Caller can remove a previously registered callback using
9368      * {@link WifiManager#unregisterScanResultsCallback(ScanResultsCallback)}
9369      * Same caller can add multiple listeners.
9370      * <p>
9371      * Applications should have the
9372      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers
9373      * without the permission will trigger a {@link java.lang.SecurityException}.
9374      * <p>
9375      *
9376      * @param executor The executor to execute the callback of the {@code callback} object.
9377      * @param callback callback for Scan Results events
9378      */
9379 
9380     @RequiresPermission(ACCESS_WIFI_STATE)
registerScanResultsCallback(@onNull @allbackExecutor Executor executor, @NonNull ScanResultsCallback callback)9381     public void registerScanResultsCallback(@NonNull @CallbackExecutor Executor executor,
9382             @NonNull ScanResultsCallback callback) {
9383         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
9384         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9385 
9386         Log.v(TAG, "registerScanResultsCallback: callback=" + callback
9387                 + ", executor=" + executor);
9388         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
9389         proxy.initProxy(executor, callback);
9390         try {
9391             mService.registerScanResultsCallback(proxy);
9392         } catch (RemoteException e) {
9393             throw e.rethrowFromSystemServer();
9394         }
9395     }
9396 
9397     /**
9398      * Allow callers to unregister a previously registered callback. After calling this method,
9399      * applications will no longer receive Scan Results events.
9400      *
9401      * @param callback callback to unregister for Scan Results events
9402      */
9403     @RequiresPermission(ACCESS_WIFI_STATE)
unregisterScanResultsCallback(@onNull ScanResultsCallback callback)9404     public void unregisterScanResultsCallback(@NonNull ScanResultsCallback callback) {
9405         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9406         Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback);
9407         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
9408         try {
9409             mService.unregisterScanResultsCallback(proxy);
9410         } catch (RemoteException e) {
9411             throw e.rethrowFromSystemServer();
9412         } finally {
9413             proxy.cleanUpProxy();
9414         }
9415     }
9416 
9417     /**
9418      * Interface for suggestion connection status listener.
9419      * Should be implemented by applications and set when calling
9420      * {@link WifiManager#addSuggestionConnectionStatusListener(
9421      * Executor, SuggestionConnectionStatusListener)}.
9422      */
9423     public interface SuggestionConnectionStatusListener {
9424 
9425         /**
9426          * Called when the framework attempted to connect to a suggestion provided by the
9427          * registering app, but the connection to the suggestion failed.
9428          * @param wifiNetworkSuggestion The suggestion which failed to connect.
9429          * @param failureReason the connection failure reason code.
9430          */
onConnectionStatus( @onNull WifiNetworkSuggestion wifiNetworkSuggestion, @SuggestionConnectionStatusCode int failureReason)9431         void onConnectionStatus(
9432                 @NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
9433                 @SuggestionConnectionStatusCode int failureReason);
9434     }
9435 
9436     private class SuggestionConnectionStatusListenerProxy extends
9437             ISuggestionConnectionStatusListener.Stub {
9438         private final Executor mExecutor;
9439         private final SuggestionConnectionStatusListener mListener;
9440 
SuggestionConnectionStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionConnectionStatusListener listener)9441         SuggestionConnectionStatusListenerProxy(@NonNull Executor executor,
9442                 @NonNull SuggestionConnectionStatusListener listener) {
9443             mExecutor = executor;
9444             mListener = listener;
9445         }
9446 
9447         @Override
onConnectionStatus(@onNull WifiNetworkSuggestion wifiNetworkSuggestion, int failureReason)9448         public void onConnectionStatus(@NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
9449                 int failureReason) {
9450             Binder.clearCallingIdentity();
9451             mExecutor.execute(() ->
9452                     mListener.onConnectionStatus(wifiNetworkSuggestion, failureReason));
9453         }
9454 
9455     }
9456 
9457     /**
9458      * Interface for local-only connection failure listener.
9459      * Should be implemented by applications and set when calling
9460      * {@link WifiManager#addLocalOnlyConnectionFailureListener(Executor, LocalOnlyConnectionFailureListener)}
9461      */
9462     public interface LocalOnlyConnectionFailureListener {
9463 
9464         /**
9465          * Called when the framework attempted to connect to a local-only network requested by the
9466          * registering app, but the connection to the network failed.
9467          * @param wifiNetworkSpecifier The {@link WifiNetworkSpecifier} which failed to connect.
9468          * @param failureReason the connection failure reason code.
9469          */
onConnectionFailed( @onNull WifiNetworkSpecifier wifiNetworkSpecifier, @LocalOnlyConnectionStatusCode int failureReason)9470         void onConnectionFailed(
9471                 @NonNull WifiNetworkSpecifier wifiNetworkSpecifier,
9472                 @LocalOnlyConnectionStatusCode int failureReason);
9473     }
9474 
9475     private static class LocalOnlyConnectionStatusListenerProxy extends
9476             ILocalOnlyConnectionStatusListener.Stub {
9477         private final Executor mExecutor;
9478         private final LocalOnlyConnectionFailureListener mListener;
9479 
LocalOnlyConnectionStatusListenerProxy(@onNull Executor executor, @NonNull LocalOnlyConnectionFailureListener listener)9480         LocalOnlyConnectionStatusListenerProxy(@NonNull Executor executor,
9481                 @NonNull LocalOnlyConnectionFailureListener listener) {
9482             mExecutor = executor;
9483             mListener = listener;
9484         }
9485 
9486         @Override
onConnectionStatus(@onNull WifiNetworkSpecifier networkSpecifier, int failureReason)9487         public void onConnectionStatus(@NonNull WifiNetworkSpecifier networkSpecifier,
9488                 int failureReason) {
9489             Binder.clearCallingIdentity();
9490             mExecutor.execute(() ->
9491                     mListener.onConnectionFailed(networkSpecifier, failureReason));
9492         }
9493 
9494     }
9495 
9496     /**
9497      * Add a listener listening to wifi verbose logging changes.
9498      * See {@link WifiVerboseLoggingStatusChangedListener}.
9499      * Caller can remove a previously registered listener using
9500      * {@link WifiManager#removeWifiVerboseLoggingStatusChangedListener(
9501      * WifiVerboseLoggingStatusChangedListener)}
9502      * Same caller can add multiple listeners to monitor the event.
9503      * <p>
9504      * Applications should have the
9505      * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
9506      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
9507      * <p>
9508      * @param executor The executor to execute the listener of the {@code listener} object.
9509      * @param listener listener for changes in wifi verbose logging.
9510      *
9511      * @hide
9512      */
9513     @SystemApi
9514     @RequiresPermission(ACCESS_WIFI_STATE)
addWifiVerboseLoggingStatusChangedListener( @onNull @allbackExecutor Executor executor, @NonNull WifiVerboseLoggingStatusChangedListener listener)9515     public void addWifiVerboseLoggingStatusChangedListener(
9516             @NonNull @CallbackExecutor Executor executor,
9517             @NonNull WifiVerboseLoggingStatusChangedListener listener) {
9518         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9519         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
9520         if (mVerboseLoggingEnabled) {
9521             Log.v(TAG, "addWifiVerboseLoggingStatusChangedListener listener=" + listener
9522                     + ", executor=" + executor);
9523         }
9524         try {
9525             synchronized (sWifiVerboseLoggingStatusChangedListenerMap) {
9526                 IWifiVerboseLoggingStatusChangedListener.Stub binderCallback =
9527                         new IWifiVerboseLoggingStatusChangedListener.Stub() {
9528                             @Override
9529                             public void onStatusChanged(boolean enabled) {
9530                                 if (mVerboseLoggingEnabled) {
9531                                     Log.v(TAG, "WifiVerboseLoggingStatusListener: "
9532                                             + "onVerboseLoggingStatusChanged: enabled=" + enabled);
9533                                 }
9534                                 Binder.clearCallingIdentity();
9535                                 executor.execute(() -> listener.onWifiVerboseLoggingStatusChanged(
9536                                         enabled));
9537                             }
9538                         };
9539                 sWifiVerboseLoggingStatusChangedListenerMap.put(System.identityHashCode(listener),
9540                         binderCallback);
9541                 mService.addWifiVerboseLoggingStatusChangedListener(binderCallback);
9542             }
9543         } catch (RemoteException e) {
9544             throw e.rethrowFromSystemServer();
9545         }
9546     }
9547 
9548     /**
9549      * Allow callers to remove a previously registered listener.
9550      * <p>
9551      * Applications should have the
9552      * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
9553      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
9554      * <p>
9555      * @param listener listener to remove.
9556      *
9557      * @hide
9558      */
9559     @SystemApi
9560     @RequiresPermission(ACCESS_WIFI_STATE)
removeWifiVerboseLoggingStatusChangedListener( @onNull WifiVerboseLoggingStatusChangedListener listener)9561     public void removeWifiVerboseLoggingStatusChangedListener(
9562             @NonNull WifiVerboseLoggingStatusChangedListener listener) {
9563         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9564         Log.v(TAG, "removeWifiVerboseLoggingStatusChangedListener: listener=" + listener);
9565         try {
9566             synchronized (sWifiVerboseLoggingStatusChangedListenerMap) {
9567                 int listenerIdentifier = System.identityHashCode(listener);
9568                 if (!sWifiVerboseLoggingStatusChangedListenerMap.contains(listenerIdentifier)) {
9569                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9570                     return;
9571                 }
9572                 mService.removeWifiVerboseLoggingStatusChangedListener(
9573                         sWifiVerboseLoggingStatusChangedListenerMap.get(listenerIdentifier));
9574                 sWifiVerboseLoggingStatusChangedListenerMap.remove(listenerIdentifier);
9575             }
9576         } catch (RemoteException e) {
9577             throw e.rethrowFromSystemServer();
9578         }
9579     }
9580 
9581     /**
9582      * Add a listener for suggestion networks. See {@link SuggestionConnectionStatusListener}.
9583      * Caller will receive the event when suggested network have connection failure.
9584      * Caller can remove a previously registered listener using
9585      * {@link WifiManager#removeSuggestionConnectionStatusListener(
9586      * SuggestionConnectionStatusListener)}
9587      * Same caller can add multiple listeners to monitor the event.
9588      * <p>
9589      * Applications should have the
9590      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
9591      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permissions.
9592      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
9593      * <p>
9594      *
9595      * @param executor The executor to execute the listener of the {@code listener} object.
9596      * @param listener listener for suggestion network connection failure.
9597      */
9598     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
addSuggestionConnectionStatusListener(@onNull @allbackExecutor Executor executor, @NonNull SuggestionConnectionStatusListener listener)9599     public void addSuggestionConnectionStatusListener(@NonNull @CallbackExecutor Executor executor,
9600             @NonNull SuggestionConnectionStatusListener listener) {
9601         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9602         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
9603         Log.v(TAG, "addSuggestionConnectionStatusListener listener=" + listener
9604                 + ", executor=" + executor);
9605         try {
9606             synchronized (sSuggestionConnectionStatusListenerMap) {
9607                 ISuggestionConnectionStatusListener.Stub binderCallback =
9608                         new SuggestionConnectionStatusListenerProxy(executor, listener);
9609                 sSuggestionConnectionStatusListenerMap.put(System.identityHashCode(listener),
9610                         binderCallback);
9611                 mService.registerSuggestionConnectionStatusListener(binderCallback,
9612                         mContext.getOpPackageName(), mContext.getAttributionTag());
9613             }
9614         } catch (RemoteException e) {
9615             throw e.rethrowFromSystemServer();
9616         }
9617 
9618     }
9619 
9620     /**
9621      * Allow callers to remove a previously registered listener. After calling this method,
9622      * applications will no longer receive suggestion connection events through that listener.
9623      *
9624      * @param listener listener to remove.
9625      */
9626     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionConnectionStatusListener( @onNull SuggestionConnectionStatusListener listener)9627     public void removeSuggestionConnectionStatusListener(
9628             @NonNull SuggestionConnectionStatusListener listener) {
9629         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9630         Log.v(TAG, "removeSuggestionConnectionStatusListener: listener=" + listener);
9631         try {
9632             synchronized (sSuggestionConnectionStatusListenerMap) {
9633                 int listenerIdentifier = System.identityHashCode(listener);
9634                 if (!sSuggestionConnectionStatusListenerMap.contains(listenerIdentifier)) {
9635                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9636                     return;
9637                 }
9638                 mService.unregisterSuggestionConnectionStatusListener(
9639                         sSuggestionConnectionStatusListenerMap.get(listenerIdentifier),
9640                         mContext.getOpPackageName());
9641                 sSuggestionConnectionStatusListenerMap.remove(listenerIdentifier);
9642             }
9643         } catch (RemoteException e) {
9644             throw e.rethrowFromSystemServer();
9645         }
9646     }
9647 
9648     /**
9649      * Add a listener for local-only networks. See {@link WifiNetworkSpecifier}.
9650      * Specify the caller will only get connection failures for networks they requested.
9651      * Caller can remove a previously registered listener using
9652      * {@link WifiManager#removeLocalOnlyConnectionFailureListener(LocalOnlyConnectionFailureListener)}
9653      * Same caller can add multiple listeners to monitor the event.
9654      * <p>
9655      * Applications should have the {@link android.Manifest.permission#ACCESS_WIFI_STATE}
9656      * permissions.
9657      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
9658      * <p>
9659      *
9660      * @param executor The executor to execute the listener of the {@code listener} object.
9661      * @param listener listener for local-only network connection failure.
9662      */
9663     @RequiresPermission(ACCESS_WIFI_STATE)
addLocalOnlyConnectionFailureListener(@onNull @allbackExecutor Executor executor, @NonNull LocalOnlyConnectionFailureListener listener)9664     public void addLocalOnlyConnectionFailureListener(@NonNull @CallbackExecutor Executor executor,
9665             @NonNull LocalOnlyConnectionFailureListener listener) {
9666         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9667         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
9668         try {
9669             synchronized (sLocalOnlyConnectionStatusListenerMap) {
9670                 if (sLocalOnlyConnectionStatusListenerMap
9671                         .contains(System.identityHashCode(listener))) {
9672                     Log.w(TAG, "Same listener already registered");
9673                     return;
9674                 }
9675                 ILocalOnlyConnectionStatusListener.Stub binderCallback =
9676                         new LocalOnlyConnectionStatusListenerProxy(executor, listener);
9677                 sLocalOnlyConnectionStatusListenerMap.put(System.identityHashCode(listener),
9678                         binderCallback);
9679                 mService.addLocalOnlyConnectionStatusListener(binderCallback,
9680                         mContext.getOpPackageName(), mContext.getAttributionTag());
9681             }
9682         } catch (RemoteException e) {
9683             throw e.rethrowFromSystemServer();
9684         }
9685     }
9686 
9687     /**
9688      * Allow callers to remove a previously registered listener. After calling this method,
9689      * applications will no longer receive local-only connection events through that listener.
9690      *
9691      * @param listener listener to remove.
9692      */
9693     @RequiresPermission(ACCESS_WIFI_STATE)
removeLocalOnlyConnectionFailureListener( @onNull LocalOnlyConnectionFailureListener listener)9694     public void removeLocalOnlyConnectionFailureListener(
9695             @NonNull LocalOnlyConnectionFailureListener listener) {
9696         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9697         try {
9698             synchronized (sLocalOnlyConnectionStatusListenerMap) {
9699                 int listenerIdentifier = System.identityHashCode(listener);
9700                 if (!sLocalOnlyConnectionStatusListenerMap.contains(listenerIdentifier)) {
9701                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9702                     return;
9703                 }
9704                 mService.removeLocalOnlyConnectionStatusListener(
9705                         sLocalOnlyConnectionStatusListenerMap.get(listenerIdentifier),
9706                         mContext.getOpPackageName());
9707                 sLocalOnlyConnectionStatusListenerMap.remove(listenerIdentifier);
9708             }
9709         } catch (RemoteException e) {
9710             throw e.rethrowFromSystemServer();
9711         }
9712     }
9713 
9714     /**
9715      * Parse the list of channels the DPP enrollee reports when it fails to find an AP.
9716      *
9717      * @param channelList List of channels in the format defined in the DPP specification.
9718      * @return A parsed sparse array, where the operating class is the key.
9719      * @hide
9720      */
9721     @VisibleForTesting
parseDppChannelList(String channelList)9722     public static SparseArray<int[]> parseDppChannelList(String channelList) {
9723         SparseArray<int[]> channelListArray = new SparseArray<>();
9724 
9725         if (TextUtils.isEmpty(channelList)) {
9726             return channelListArray;
9727         }
9728         StringTokenizer str = new StringTokenizer(channelList, ",");
9729         String classStr = null;
9730         List<Integer> channelsInClass = new ArrayList<>();
9731 
9732         try {
9733             while (str.hasMoreElements()) {
9734                 String cur = str.nextToken();
9735 
9736                 /**
9737                  * Example for a channel list:
9738                  *
9739                  * 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,
9740                  * 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
9741                  *
9742                  * Detect operating class by the delimiter of '/' and use a string tokenizer with
9743                  * ',' as a delimiter.
9744                  */
9745                 int classDelim = cur.indexOf('/');
9746                 if (classDelim != -1) {
9747                     if (classStr != null) {
9748                         // Store the last channel array in the sparse array, where the operating
9749                         // class is the key (as an integer).
9750                         int[] channelsArray = new int[channelsInClass.size()];
9751                         for (int i = 0; i < channelsInClass.size(); i++) {
9752                             channelsArray[i] = channelsInClass.get(i);
9753                         }
9754                         channelListArray.append(Integer.parseInt(classStr), channelsArray);
9755                         channelsInClass = new ArrayList<>();
9756                     }
9757 
9758                     // Init a new operating class and store the first channel
9759                     classStr = cur.substring(0, classDelim);
9760                     String channelStr = cur.substring(classDelim + 1);
9761                     channelsInClass.add(Integer.parseInt(channelStr));
9762                 } else {
9763                     if (classStr == null) {
9764                         // Invalid format
9765                         Log.e(TAG, "Cannot parse DPP channel list");
9766                         return new SparseArray<>();
9767                     }
9768                     channelsInClass.add(Integer.parseInt(cur));
9769                 }
9770             }
9771 
9772             // Store the last array
9773             if (classStr != null) {
9774                 int[] channelsArray = new int[channelsInClass.size()];
9775                 for (int i = 0; i < channelsInClass.size(); i++) {
9776                     channelsArray[i] = channelsInClass.get(i);
9777                 }
9778                 channelListArray.append(Integer.parseInt(classStr), channelsArray);
9779             }
9780             return channelListArray;
9781         } catch (NumberFormatException e) {
9782             Log.e(TAG, "Cannot parse DPP channel list");
9783             return new SparseArray<>();
9784         }
9785     }
9786 
9787     /**
9788      * Callback interface for framework to receive network status updates and trigger of updating
9789      * {@link WifiUsabilityStatsEntry}.
9790      *
9791      * @hide
9792      */
9793     @SystemApi
9794     public interface ScoreUpdateObserver {
9795         /**
9796          * Called by applications to indicate network status. For applications targeting
9797          * {@link android.os.Build.VERSION_CODES#S} or above: The score is not used to take action
9798          * on network selection but for the purpose of Wifi metric collection only; Network
9799          * selection is influenced by inputs from
9800          * {@link ScoreUpdateObserver#notifyStatusUpdate(int, boolean)},
9801          * {@link ScoreUpdateObserver#requestNudOperation(int, boolean)}, and
9802          * {@link ScoreUpdateObserver#blocklistCurrentBssid(int)}.
9803          *
9804          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9805          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9806          * @param score The score representing link quality of current Wi-Fi network connection.
9807          *              Populated by connected network scorer in applications..
9808          */
notifyScoreUpdate(int sessionId, int score)9809         void notifyScoreUpdate(int sessionId, int score);
9810 
9811         /**
9812          * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
9813          * To receive update applications need to add WifiUsabilityStatsEntry listener. See
9814          * {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
9815          *
9816          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9817          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9818          */
triggerUpdateOfWifiUsabilityStats(int sessionId)9819         void triggerUpdateOfWifiUsabilityStats(int sessionId);
9820 
9821         /**
9822          * Called by applications to indicate whether current Wi-Fi network is usable or not.
9823          *
9824          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9825          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9826          * @param isUsable The boolean representing whether current Wi-Fi network is usable, and it
9827          *                 may be sent to ConnectivityService and used for setting default network.
9828          *                 Populated by connected network scorer in applications.
9829          */
9830         @RequiresApi(Build.VERSION_CODES.S)
notifyStatusUpdate(int sessionId, boolean isUsable)9831         default void notifyStatusUpdate(int sessionId, boolean isUsable) {}
9832 
9833         /**
9834          * Called by applications to start a NUD (Neighbor Unreachability Detection) operation. The
9835          * framework throttles NUD operations to no more frequently than every five seconds
9836          * (see {@link WifiScoreReport#NUD_THROTTLE_MILLIS}). The framework keeps track of requests
9837          * and executes them as soon as possible based on the throttling criteria.
9838          *
9839          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9840          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9841          */
9842         @RequiresApi(Build.VERSION_CODES.S)
requestNudOperation(int sessionId)9843         default void requestNudOperation(int sessionId) {}
9844 
9845         /**
9846          * Called by applications to blocklist currently connected BSSID. No blocklisting operation
9847          * if called after disconnection.
9848          *
9849          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9850          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9851          */
9852         @RequiresApi(Build.VERSION_CODES.S)
blocklistCurrentBssid(int sessionId)9853         default void blocklistCurrentBssid(int sessionId) {}
9854     }
9855 
9856     /**
9857      * Callback proxy for {@link ScoreUpdateObserver} objects.
9858      *
9859      * @hide
9860      */
9861     private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
9862         private final IScoreUpdateObserver mScoreUpdateObserver;
9863 
ScoreUpdateObserverProxy(IScoreUpdateObserver observer)9864         private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
9865             mScoreUpdateObserver = observer;
9866         }
9867 
9868         @Override
notifyScoreUpdate(int sessionId, int score)9869         public void notifyScoreUpdate(int sessionId, int score) {
9870             try {
9871                 mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
9872             } catch (RemoteException e) {
9873                 throw e.rethrowFromSystemServer();
9874             }
9875         }
9876 
9877         @Override
triggerUpdateOfWifiUsabilityStats(int sessionId)9878         public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
9879             try {
9880                 mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
9881             } catch (RemoteException e) {
9882                 throw e.rethrowFromSystemServer();
9883             }
9884         }
9885 
9886         @Override
notifyStatusUpdate(int sessionId, boolean isUsable)9887         public void notifyStatusUpdate(int sessionId, boolean isUsable) {
9888             if (!SdkLevel.isAtLeastS()) {
9889                 throw new UnsupportedOperationException();
9890             }
9891             try {
9892                 mScoreUpdateObserver.notifyStatusUpdate(sessionId, isUsable);
9893             } catch (RemoteException e) {
9894                 throw e.rethrowFromSystemServer();
9895             }
9896         }
9897 
9898         @Override
requestNudOperation(int sessionId)9899         public void requestNudOperation(int sessionId) {
9900             if (!SdkLevel.isAtLeastS()) {
9901                 throw new UnsupportedOperationException();
9902             }
9903             try {
9904                 mScoreUpdateObserver.requestNudOperation(sessionId);
9905             } catch (RemoteException e) {
9906                 throw e.rethrowFromSystemServer();
9907             }
9908         }
9909 
9910         @Override
blocklistCurrentBssid(int sessionId)9911         public void blocklistCurrentBssid(int sessionId) {
9912             if (!SdkLevel.isAtLeastS()) {
9913                 throw new UnsupportedOperationException();
9914             }
9915             try {
9916                 mScoreUpdateObserver.blocklistCurrentBssid(sessionId);
9917             } catch (RemoteException e) {
9918                 throw e.rethrowFromSystemServer();
9919             }
9920         }
9921     }
9922 
9923     /**
9924      * Interface for Wi-Fi connected network scorer. Should be implemented by applications and set
9925      * when calling
9926      * {@link WifiManager#setWifiConnectedNetworkScorer(Executor, WifiConnectedNetworkScorer)}.
9927      *
9928      * @hide
9929      */
9930     @SystemApi
9931     public interface WifiConnectedNetworkScorer {
9932         /**
9933          * Called by framework to indicate the start of a network connection.
9934          * @param sessionId The ID to indicate current Wi-Fi network connection.
9935          * @deprecated This API is deprecated.  Please use
9936          *             {@link WifiConnectedNetworkScorer#onStart(WifiConnectedSessionInfo)}.
9937          */
9938         @Deprecated
onStart(int sessionId)9939         default void onStart(int sessionId) {}
9940 
9941         /**
9942          * Called by framework to indicate the start of a network connection.
9943          * @param sessionInfo The session information to indicate current Wi-Fi network connection.
9944          *                    See {@link WifiConnectedSessionInfo}.
9945          */
onStart(@onNull WifiConnectedSessionInfo sessionInfo)9946         default void onStart(@NonNull WifiConnectedSessionInfo sessionInfo) {
9947             onStart(sessionInfo.getSessionId());
9948         }
9949 
9950         /**
9951          * Called by framework to indicate the end of a network connection.
9952          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9953          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9954          */
onStop(int sessionId)9955         void onStop(int sessionId);
9956 
9957         /**
9958          * Framework sets callback for score change events after application sets its scorer.
9959          * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
9960          * implemented and instantiated by framework.
9961          */
onSetScoreUpdateObserver(@onNull ScoreUpdateObserver observerImpl)9962         void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
9963 
9964         /**
9965          * Called by framework to indicate the user accepted a dialog to switch to a new network.
9966          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9967          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9968          * @param targetNetworkId Network ID of the target network.
9969          * @param targetBssid BSSID of the target network.
9970          */
onNetworkSwitchAccepted( int sessionId, int targetNetworkId, @NonNull String targetBssid)9971         default void onNetworkSwitchAccepted(
9972                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
9973             // No-op.
9974         }
9975 
9976         /**
9977          * Called by framework to indicate the user rejected a dialog to switch to new network.
9978          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
9979          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
9980          * @param targetNetworkId Network ID of the target network.
9981          * @param targetBssid BSSID of the target network.
9982          */
onNetworkSwitchRejected( int sessionId, int targetNetworkId, @NonNull String targetBssid)9983         default void onNetworkSwitchRejected(
9984                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
9985             // No-op.
9986         }
9987     }
9988 
9989 
9990     /**
9991      * Callback registered with {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
9992      * PnoScanResultsCallback)}. Returns status and result information on offloaded external PNO
9993      * requests.
9994      * @hide
9995      */
9996     @SystemApi
9997     public interface PnoScanResultsCallback {
9998         /**
9999          * A status code returned by {@link #onRegisterFailed(int)}.
10000          * Unknown failure.
10001          */
10002         int REGISTER_PNO_CALLBACK_UNKNOWN = 0;
10003 
10004         /**
10005          * A status code returned by {@link #onRegisterFailed(int)}.
10006          * A callback has already been registered by the caller.
10007          */
10008         int REGISTER_PNO_CALLBACK_ALREADY_REGISTERED = 1;
10009 
10010         /**
10011          * A status code returned by {@link #onRegisterFailed(int)}.
10012          * The platform is unable to serve this request because another app has a PNO scan request
10013          * active.
10014          */
10015         int REGISTER_PNO_CALLBACK_RESOURCE_BUSY = 2;
10016 
10017         /**
10018          * A status code returned by {@link #onRegisterFailed(int)}.
10019          * PNO scans are not supported on this device.
10020          */
10021         int REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED = 3;
10022 
10023         /** @hide */
10024         @IntDef(prefix = { "REGISTER_PNO_CALLBACK_" }, value = {
10025                 REGISTER_PNO_CALLBACK_UNKNOWN,
10026                 REGISTER_PNO_CALLBACK_ALREADY_REGISTERED,
10027                 REGISTER_PNO_CALLBACK_RESOURCE_BUSY,
10028                 REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED
10029         })
10030         @Retention(RetentionPolicy.SOURCE)
10031         public @interface RegisterFailureReason {}
10032 
10033         /**
10034          * A status code returned by {@link #onRemoved(int)}.
10035          * Unknown reason.
10036          */
10037         int REMOVE_PNO_CALLBACK_UNKNOWN = 0;
10038 
10039         /**
10040          * A status code returned by {@link #onRemoved(int)}.
10041          * This Callback is automatically removed after results ScanResults are delivered.
10042          */
10043         int REMOVE_PNO_CALLBACK_RESULTS_DELIVERED = 1;
10044 
10045         /**
10046          * A status code returned by {@link #onRemoved(int)}.
10047          * This callback has been unregistered via {@link WifiManager#clearExternalPnoScanRequest()}
10048          */
10049         int REMOVE_PNO_CALLBACK_UNREGISTERED = 2;
10050 
10051         /** @hide */
10052         @IntDef(prefix = { "REMOVE_PNO_CALLBACK_" }, value = {
10053                 REMOVE_PNO_CALLBACK_UNKNOWN,
10054                 REMOVE_PNO_CALLBACK_RESULTS_DELIVERED,
10055                 REMOVE_PNO_CALLBACK_UNREGISTERED
10056         })
10057         @Retention(RetentionPolicy.SOURCE)
10058         public @interface RemovalReason {}
10059 
10060         /**
10061          * Called when PNO scan finds one of the requested SSIDs. This is a one time callback.
10062          * After results are reported the callback will be automatically unregistered.
10063          */
onScanResultsAvailable(@onNull List<ScanResult> scanResults)10064         void onScanResultsAvailable(@NonNull List<ScanResult> scanResults);
10065 
10066         /**
10067          * Called when this callback has been successfully registered.
10068          */
onRegisterSuccess()10069         void onRegisterSuccess();
10070 
10071         /**
10072          * Called when this callback failed to register with the failure reason.
10073          * See {@link RegisterFailureReason} for details.
10074          */
onRegisterFailed(@egisterFailureReason int reason)10075         void onRegisterFailed(@RegisterFailureReason int reason);
10076 
10077         /**
10078          * Called when this callback has been unregistered from the Wi-Fi subsystem.
10079          * See {@link RemovalReason} for details.
10080          */
onRemoved(@emovalReason int reason)10081         void onRemoved(@RemovalReason int reason);
10082     }
10083 
10084 
10085     private class PnoScanResultsCallbackProxy extends IPnoScanResultsCallback.Stub {
10086         private Executor mExecutor;
10087         private PnoScanResultsCallback mCallback;
10088 
PnoScanResultsCallbackProxy(@onNull Executor executor, @NonNull PnoScanResultsCallback callback)10089         PnoScanResultsCallbackProxy(@NonNull Executor executor,
10090                 @NonNull PnoScanResultsCallback callback) {
10091             mExecutor = executor;
10092             mCallback = callback;
10093         }
10094 
10095         @Override
onScanResultsAvailable(List<ScanResult> scanResults)10096         public void onScanResultsAvailable(List<ScanResult> scanResults) {
10097             if (mVerboseLoggingEnabled) {
10098                 Log.v(TAG, "PnoScanResultsCallback: " + "onScanResultsAvailable");
10099             }
10100             Binder.clearCallingIdentity();
10101             mExecutor.execute(() -> mCallback.onScanResultsAvailable(scanResults));
10102         }
10103 
10104         @Override
onRegisterSuccess()10105         public void onRegisterSuccess() {
10106             if (mVerboseLoggingEnabled) {
10107                 Log.v(TAG, "PnoScanResultsCallback: " + "onRegisterSuccess");
10108             }
10109             Binder.clearCallingIdentity();
10110             mExecutor.execute(() -> mCallback.onRegisterSuccess());
10111         }
10112 
10113         @Override
onRegisterFailed(int reason)10114         public void onRegisterFailed(int reason) {
10115             if (mVerboseLoggingEnabled) {
10116                 Log.v(TAG, "PnoScanResultsCallback: " + "onRegisterFailed " + reason);
10117             }
10118             Binder.clearCallingIdentity();
10119             mExecutor.execute(() -> mCallback.onRegisterFailed(reason));
10120         }
10121 
10122         @Override
onRemoved(int reason)10123         public void onRemoved(int reason) {
10124             if (mVerboseLoggingEnabled) {
10125                 Log.v(TAG, "PnoScanResultsCallback: " + "onRemoved");
10126             }
10127             Binder.clearCallingIdentity();
10128             mExecutor.execute(() -> mCallback.onRemoved(reason));
10129         }
10130     }
10131 
10132     /**
10133      * Callback proxy for {@link WifiConnectedNetworkScorer} objects.
10134      *
10135      * @hide
10136      */
10137     private class WifiConnectedNetworkScorerProxy extends IWifiConnectedNetworkScorer.Stub {
10138         private Executor mExecutor;
10139         private WifiConnectedNetworkScorer mScorer;
10140 
WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer)10141         WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer) {
10142             mExecutor = executor;
10143             mScorer = scorer;
10144         }
10145 
10146         @Override
onStart(@onNull WifiConnectedSessionInfo sessionInfo)10147         public void onStart(@NonNull WifiConnectedSessionInfo sessionInfo) {
10148             if (mVerboseLoggingEnabled) {
10149                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionInfo=" + sessionInfo);
10150             }
10151             Binder.clearCallingIdentity();
10152             mExecutor.execute(() -> mScorer.onStart(sessionInfo));
10153         }
10154 
10155         @Override
onStop(int sessionId)10156         public void onStop(int sessionId) {
10157             if (mVerboseLoggingEnabled) {
10158                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
10159             }
10160             Binder.clearCallingIdentity();
10161             mExecutor.execute(() -> mScorer.onStop(sessionId));
10162         }
10163 
10164         @Override
onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl)10165         public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
10166             if (mVerboseLoggingEnabled) {
10167                 Log.v(TAG, "WifiConnectedNetworkScorer: "
10168                         + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
10169             }
10170             Binder.clearCallingIdentity();
10171             mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
10172                     new ScoreUpdateObserverProxy(observerImpl)));
10173         }
10174 
10175         @Override
onNetworkSwitchAccepted( int sessionId, int targetNetworkId, @NonNull String targetBssid)10176         public void onNetworkSwitchAccepted(
10177                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10178             if (mVerboseLoggingEnabled) {
10179                 Log.v(TAG, "WifiConnectedNetworkScorer: onNetworkSwitchAccepted:"
10180                         + " sessionId=" + sessionId
10181                         + " targetNetworkId=" + targetNetworkId
10182                         + " targetBssid=" + targetBssid);
10183             }
10184             Binder.clearCallingIdentity();
10185             mExecutor.execute(() -> mScorer.onNetworkSwitchAccepted(
10186                     sessionId, targetNetworkId, targetBssid));
10187         }
10188         @Override
onNetworkSwitchRejected( int sessionId, int targetNetworkId, @NonNull String targetBssid)10189         public void onNetworkSwitchRejected(
10190                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10191             if (mVerboseLoggingEnabled) {
10192                 Log.v(TAG, "WifiConnectedNetworkScorer: onNetworkSwitchRejected:"
10193                                 + " sessionId=" + sessionId
10194                                 + " targetNetworkId=" + targetNetworkId
10195                                 + " targetBssid=" + targetBssid);
10196             }
10197             Binder.clearCallingIdentity();
10198             mExecutor.execute(() -> mScorer.onNetworkSwitchRejected(
10199                     sessionId, targetNetworkId, targetBssid));
10200         }
10201     }
10202 
10203     /**
10204      * This API allows the caller to program up to 2 SSIDs for PNO scans. PNO scans are offloaded
10205      * to the Wi-Fi chip when the device is inactive (typically screen-off).
10206      * If the screen is currently off when this API is called, then a PNO scan including the
10207      * requested SSIDs will immediately get started. If the screen is on when this API is called,
10208      * the requested SSIDs will get included for PNO scans the next time the screen turns off.
10209      * <p>
10210      * Note, due to PNO being a limited resource, only one external PNO request is supported, and
10211      * calling this API will fail if an external PNO scan request is already registered by another
10212      * caller. If the caller that has already registered a callback calls this API again, the new
10213      * callback will override the previous one.
10214      * <p>
10215      * After this API is called, {@link PnoScanResultsCallback#onRegisterSuccess()} will be invoked
10216      * if the operation is successful, or {@link PnoScanResultsCallback#onRegisterFailed(int)} will
10217      * be invoked if the operation failed.
10218      * <p>
10219      * {@link PnoScanResultsCallback#onRemoved(int)} will be invoked to notify the caller when the
10220      * external PNO scan request is removed, which will happen when one of the following events
10221      * happen:
10222      * </p>
10223      * <ul>
10224      * <li>Upon finding any of the requested SSIDs through either a connectivity scan or PNO scan,
10225      * the matching ScanResults will be returned
10226      * via {@link PnoScanResultsCallback#onScanResultsAvailable(List)}, and the registered PNO
10227      * scan request will get automatically removed.</li>
10228      * <li>The external PNO scan request is removed by a call to
10229      * {@link #clearExternalPnoScanRequest()}</li>
10230      * </ul>
10231      *
10232      * @param ssids The list of SSIDs to request for PNO scan.
10233      * @param frequencies Provide as hint a list of up to 10 frequencies to be used for PNO scan.
10234      *                    Each frequency should be in MHz. For example 2412 and 5180 are valid
10235      *                    frequencies. {@link WifiInfo#getFrequency()} is a location where this
10236      *                    information could be obtained. If a null or empty array is provided, the
10237      *                    Wi-Fi framework will automatically decide the list of frequencies to scan.
10238      * @param executor The executor on which callback will be invoked.
10239      * @param callback For the calling application to receive results and status updates.
10240      *
10241      * @throws SecurityException if the caller does not have permission.
10242      * @throws IllegalArgumentException if the caller provided invalid inputs.
10243      * @throws UnsupportedOperationException if this API is not supported on this SDK version.
10244      * @hide
10245      */
10246     @SystemApi
10247     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION,
10248             REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION})
10249     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setExternalPnoScanRequest(@onNull List<WifiSsid> ssids, @Nullable int[] frequencies, @NonNull @CallbackExecutor Executor executor, @NonNull PnoScanResultsCallback callback)10250     public void setExternalPnoScanRequest(@NonNull List<WifiSsid> ssids,
10251             @Nullable int[] frequencies, @NonNull @CallbackExecutor Executor executor,
10252             @NonNull PnoScanResultsCallback callback) {
10253         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
10254         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
10255         try {
10256             mService.setExternalPnoScanRequest(new Binder(),
10257                     new PnoScanResultsCallbackProxy(executor, callback),
10258                     ssids, frequencies == null ? new int[0] : frequencies,
10259                     mContext.getOpPackageName(), mContext.getAttributionTag());
10260         } catch (RemoteException e) {
10261             throw e.rethrowFromSystemServer();
10262         }
10263     }
10264 
10265     /**
10266      * Clear the current PNO scan request that's been set by the calling UID. Note, the call will
10267      * be no-op if the current PNO scan request is set by a different UID.
10268      *
10269      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
10270      * @hide
10271      */
10272     @SystemApi
10273     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
clearExternalPnoScanRequest()10274     public void clearExternalPnoScanRequest() {
10275         try {
10276             mService.clearExternalPnoScanRequest();
10277         } catch (RemoteException e) {
10278             throw e.rethrowFromSystemServer();
10279         }
10280     }
10281 
10282     /**
10283      * Returns information about the last caller of an API.
10284      *
10285      * @param apiType The type of API to request information for the last caller.
10286      * @param executor The executor on which callback will be invoked.
10287      * @param resultsCallback An asynchronous callback that will return 2 arguments.
10288      *                        {@code String} the name of the package that performed the last API
10289      *                        call. {@code Boolean} the value associated with the last API call.
10290      *
10291      * @throws SecurityException if the caller does not have permission.
10292      * @throws IllegalArgumentException if the caller provided invalid inputs.
10293      * @hide
10294      */
10295     @SystemApi
10296     @RequiresPermission(anyOf = {
10297             android.Manifest.permission.NETWORK_SETTINGS,
10298             android.Manifest.permission.NETWORK_STACK,
10299             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
getLastCallerInfoForApi(@piType int apiType, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<String, Boolean> resultsCallback)10300     public void getLastCallerInfoForApi(@ApiType int apiType,
10301             @NonNull @CallbackExecutor Executor executor,
10302             @NonNull BiConsumer<String, Boolean> resultsCallback) {
10303         if (executor == null) {
10304             throw new IllegalArgumentException("executor can't be null");
10305         }
10306         if (resultsCallback == null) {
10307             throw new IllegalArgumentException("resultsCallback can't be null");
10308         }
10309         try {
10310             mService.getLastCallerInfoForApi(apiType,
10311                     new ILastCallerListener.Stub() {
10312                         @Override
10313                         public void onResult(String packageName, boolean enabled) {
10314                             Binder.clearCallingIdentity();
10315                             executor.execute(() -> {
10316                                 resultsCallback.accept(packageName, enabled);
10317                             });
10318                         }
10319                     });
10320         } catch (RemoteException e) {
10321             throw e.rethrowFromSystemServer();
10322         }
10323     }
10324 
10325     /**
10326      * Set a callback for Wi-Fi connected network scorer.  See {@link WifiConnectedNetworkScorer}.
10327      * Only a single scorer can be set. Caller will be invoked periodically by framework to inform
10328      * client about start and stop of Wi-Fi connection. Caller can clear a previously set scorer
10329      * using {@link clearWifiConnectedNetworkScorer()}.
10330      *
10331      * @param executor The executor on which callback will be invoked.
10332      * @param scorer Scorer for Wi-Fi network implemented by application.
10333      * @return true Scorer is set successfully.
10334      *
10335      * @hide
10336      */
10337     @SystemApi
10338     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
setWifiConnectedNetworkScorer(@onNull @allbackExecutor Executor executor, @NonNull WifiConnectedNetworkScorer scorer)10339     public boolean setWifiConnectedNetworkScorer(@NonNull @CallbackExecutor Executor executor,
10340             @NonNull WifiConnectedNetworkScorer scorer) {
10341         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
10342         if (scorer == null) throw new IllegalArgumentException("scorer cannot be null");
10343         if (mVerboseLoggingEnabled) {
10344             Log.v(TAG, "setWifiConnectedNetworkScorer: scorer=" + scorer);
10345         }
10346         try {
10347             return mService.setWifiConnectedNetworkScorer(new Binder(),
10348                     new WifiConnectedNetworkScorerProxy(executor, scorer));
10349         } catch (RemoteException e) {
10350             throw e.rethrowFromSystemServer();
10351         }
10352     }
10353 
10354     /**
10355      * Allow caller to clear a previously set scorer. After calling this method,
10356      * client will no longer receive information about start and stop of Wi-Fi connection.
10357      *
10358      * @hide
10359      */
10360     @SystemApi
10361     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
clearWifiConnectedNetworkScorer()10362     public void clearWifiConnectedNetworkScorer() {
10363         if (mVerboseLoggingEnabled) {
10364             Log.v(TAG, "clearWifiConnectedNetworkScorer");
10365         }
10366         try {
10367             mService.clearWifiConnectedNetworkScorer();
10368         } catch (RemoteException e) {
10369             throw e.rethrowFromSystemServer();
10370         }
10371     }
10372 
10373     /**
10374      * Enable/disable wifi scan throttling from 3rd party apps.
10375      *
10376      * <p>
10377      * The throttling limits for apps are described in
10378      * <a href="Wi-Fi Scan Throttling">
10379      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
10380      * </p>
10381      *
10382      * @param enable true to allow scan throttling, false to disallow scan throttling.
10383      * @hide
10384      */
10385     @SystemApi
10386     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanThrottleEnabled(boolean enable)10387     public void setScanThrottleEnabled(boolean enable) {
10388         try {
10389             mService.setScanThrottleEnabled(enable);
10390         } catch (RemoteException e) {
10391             throw e.rethrowFromSystemServer();
10392         }
10393     }
10394 
10395     /**
10396      * Get the persisted Wi-Fi scan throttle state. Defaults to true, unless changed by the user via
10397      * Developer options.
10398      *
10399      * <p>
10400      * The throttling limits for apps are described in
10401      * <a href="Wi-Fi Scan Throttling">
10402      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
10403      * </p>
10404      *
10405      * @return true to indicate that scan throttling is enabled, false to indicate that scan
10406      * throttling is disabled.
10407      */
10408     @RequiresPermission(ACCESS_WIFI_STATE)
isScanThrottleEnabled()10409     public boolean isScanThrottleEnabled() {
10410         try {
10411             return mService.isScanThrottleEnabled();
10412         } catch (RemoteException e) {
10413             throw e.rethrowFromSystemServer();
10414         }
10415     }
10416 
10417     /**
10418      * Enable/disable wifi auto wakeup feature.
10419      *
10420      * <p>
10421      * The feature is described in
10422      * <a href="Wi-Fi Turn on automatically">
10423      * https://source.android.com/devices/tech/connect/wifi-infrastructure
10424      * #turn_on_wi-fi_automatically
10425      * </a>
10426      *
10427      * @param enable true to enable, false to disable.
10428      * @hide
10429      */
10430     @SystemApi
10431     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setAutoWakeupEnabled(boolean enable)10432     public void setAutoWakeupEnabled(boolean enable) {
10433         try {
10434             mService.setAutoWakeupEnabled(enable);
10435         } catch (RemoteException e) {
10436             throw e.rethrowFromSystemServer();
10437         }
10438     }
10439 
10440     /**
10441      * Get the persisted Wi-Fi auto wakeup feature state. Defaults to false, unless changed by the
10442      * user via Settings.
10443      *
10444      * <p>
10445      * The feature is described in
10446      * <a href="Wi-Fi Turn on automatically">
10447      * https://source.android.com/devices/tech/connect/wifi-infrastructure
10448      * #turn_on_wi-fi_automatically
10449      * </a>
10450      *
10451      * @return true to indicate that wakeup feature is enabled, false to indicate that wakeup
10452      * feature is disabled.
10453      */
10454     @RequiresPermission(ACCESS_WIFI_STATE)
isAutoWakeupEnabled()10455     public boolean isAutoWakeupEnabled() {
10456         try {
10457             return mService.isAutoWakeupEnabled();
10458         } catch (RemoteException e) {
10459             throw e.rethrowFromSystemServer();
10460         }
10461     }
10462 
10463     /**
10464      * Sets the state of carrier offload on merged or unmerged networks for specified subscription.
10465      *
10466      * <p>
10467      * When a subscription's carrier network offload is disabled, all network suggestions related to
10468      * this subscription will not be considered for auto join.
10469      * <p>
10470      * If calling app want disable all carrier network offload from a specified subscription, should
10471      * call this API twice to disable both merged and unmerged carrier network suggestions.
10472      *
10473      * @param subscriptionId See {@link SubscriptionInfo#getSubscriptionId()}.
10474      * @param merged True for carrier merged network, false otherwise.
10475      *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
10476      * @param enabled True for enable carrier network offload, false otherwise.
10477      * @see #isCarrierNetworkOffloadEnabled(int, boolean)
10478      * @hide
10479      */
10480     @SystemApi
10481     @RequiresPermission(anyOf = {
10482             android.Manifest.permission.NETWORK_SETTINGS,
10483             android.Manifest.permission.NETWORK_SETUP_WIZARD})
setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged, boolean enabled)10484     public void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged,
10485             boolean enabled) {
10486         try {
10487             mService.setCarrierNetworkOffloadEnabled(subscriptionId, merged, enabled);
10488         } catch (RemoteException e) {
10489             throw e.rethrowFromSystemServer();
10490         }
10491     }
10492 
10493     /**
10494      * Get the carrier network offload state for merged or unmerged networks for specified
10495      * subscription.
10496      * @param subscriptionId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
10497      * @param merged True for carrier merged network, false otherwise.
10498      *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
10499      * @return True to indicate that carrier network offload is enabled, false otherwise.
10500      */
10501     @RequiresPermission(ACCESS_WIFI_STATE)
isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged)10502     public boolean isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged) {
10503         try {
10504             return mService.isCarrierNetworkOffloadEnabled(subscriptionId, merged);
10505         } catch (RemoteException e) {
10506             throw e.rethrowFromSystemServer();
10507         }
10508     }
10509 
10510     /**
10511      * Interface for network suggestion user approval status change listener.
10512      * Should be implemented by applications and registered using
10513      * {@link #addSuggestionUserApprovalStatusListener(Executor,
10514      * SuggestionUserApprovalStatusListener)} (
10515      */
10516     public interface SuggestionUserApprovalStatusListener {
10517 
10518         /**
10519          * Called when the user approval status of the App has changed.
10520          * @param status The current status code for the user approval. One of the
10521          *               {@code STATUS_SUGGESTION_APPROVAL_} values.
10522          */
onUserApprovalStatusChange(@uggestionUserApprovalStatus int status)10523         void onUserApprovalStatusChange(@SuggestionUserApprovalStatus int status);
10524     }
10525 
10526     private class SuggestionUserApprovalStatusListenerProxy extends
10527             ISuggestionUserApprovalStatusListener.Stub {
10528         private final Executor mExecutor;
10529         private final SuggestionUserApprovalStatusListener mListener;
10530 
SuggestionUserApprovalStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionUserApprovalStatusListener listener)10531         SuggestionUserApprovalStatusListenerProxy(@NonNull Executor executor,
10532                 @NonNull SuggestionUserApprovalStatusListener listener) {
10533             mExecutor = executor;
10534             mListener = listener;
10535         }
10536 
10537         @Override
onUserApprovalStatusChange(int status)10538         public void onUserApprovalStatusChange(int status) {
10539             mExecutor.execute(() -> mListener.onUserApprovalStatusChange(status));
10540         }
10541 
10542     }
10543 
10544     /**
10545      * Add a listener for Wi-Fi network suggestion user approval status.
10546      * See {@link SuggestionUserApprovalStatusListener}.
10547      * Caller will receive a callback immediately after adding a listener and when the user approval
10548      * status of the caller has changed.
10549      * Caller can remove a previously registered listener using
10550      * {@link WifiManager#removeSuggestionUserApprovalStatusListener(
10551      * SuggestionUserApprovalStatusListener)}
10552      * A caller can add multiple listeners to monitor the event.
10553      * @param executor The executor to execute the listener of the {@code listener} object.
10554      * @param listener listener for suggestion user approval status changes.
10555      */
10556     @RequiresPermission(ACCESS_WIFI_STATE)
addSuggestionUserApprovalStatusListener( @onNull @allbackExecutor Executor executor, @NonNull SuggestionUserApprovalStatusListener listener)10557     public void addSuggestionUserApprovalStatusListener(
10558             @NonNull @CallbackExecutor Executor executor,
10559             @NonNull SuggestionUserApprovalStatusListener listener) {
10560         if (listener == null) throw new NullPointerException("Listener cannot be null");
10561         if (executor == null) throw new NullPointerException("Executor cannot be null");
10562         Log.v(TAG, "addSuggestionUserApprovalStatusListener listener=" + listener
10563                 + ", executor=" + executor);
10564         try {
10565             synchronized (sSuggestionUserApprovalStatusListenerMap) {
10566                 ISuggestionUserApprovalStatusListener.Stub binderCallback =
10567                         new SuggestionUserApprovalStatusListenerProxy(executor, listener);
10568                 sSuggestionUserApprovalStatusListenerMap.put(System.identityHashCode(listener),
10569                         binderCallback);
10570                 mService.addSuggestionUserApprovalStatusListener(binderCallback,
10571                         mContext.getOpPackageName());
10572             }
10573         } catch (RemoteException e) {
10574             throw e.rethrowFromSystemServer();
10575         }
10576 
10577     }
10578 
10579     /**
10580      * Allow callers to remove a previously registered listener using
10581      * {@link #addSuggestionUserApprovalStatusListener(Executor,
10582      * SuggestionUserApprovalStatusListener)}. After calling this method,
10583      * applications will no longer receive network suggestion user approval status change through
10584      * that listener.
10585      */
10586     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionUserApprovalStatusListener( @onNull SuggestionUserApprovalStatusListener listener)10587     public void removeSuggestionUserApprovalStatusListener(
10588             @NonNull SuggestionUserApprovalStatusListener listener) {
10589         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10590         Log.v(TAG, "removeSuggestionUserApprovalStatusListener: listener=" + listener);
10591         try {
10592             synchronized (sSuggestionUserApprovalStatusListenerMap) {
10593                 int listenerIdentifier = System.identityHashCode(listener);
10594                 if (!sSuggestionUserApprovalStatusListenerMap.contains(listenerIdentifier)) {
10595                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
10596                     return;
10597                 }
10598                 mService.removeSuggestionUserApprovalStatusListener(
10599                         sSuggestionUserApprovalStatusListenerMap.get(listenerIdentifier),
10600                         mContext.getOpPackageName());
10601                 sSuggestionUserApprovalStatusListenerMap.remove(listenerIdentifier);
10602             }
10603         } catch (RemoteException e) {
10604             throw e.rethrowFromSystemServer();
10605         }
10606     }
10607 
10608     /**
10609      * Indicates the start/end of an emergency scan request being processed by {@link WifiScanner}.
10610      * The wifi stack should ensure that the wifi chip remains on for the duration of the scan.
10611      * WifiScanner detects emergency scan requests via
10612      * {@link WifiScanner.ScanSettings#ignoreLocationSettings} flag.
10613      *
10614      * If the wifi stack is off (because location & wifi toggles are off) when this indication is
10615      * received, the wifi stack will temporarily move to a scan only mode. Since location toggle
10616      * is off, only scan with
10617      * {@link WifiScanner.ScanSettings#ignoreLocationSettings} flag set will be
10618      * allowed to be processed for this duration.
10619      *
10620      * @hide
10621      */
10622     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
setEmergencyScanRequestInProgress(boolean inProgress)10623     public void setEmergencyScanRequestInProgress(boolean inProgress) {
10624         try {
10625             mService.setEmergencyScanRequestInProgress(inProgress);
10626         } catch (RemoteException e) {
10627             throw e.rethrowFromSystemServer();
10628         }
10629     }
10630 
10631     /**
10632      * Enable or disable Wi-Fi scoring.  Wi-Fi network status is evaluated by Wi-Fi scoring
10633      * {@link WifiScoreReport}. This API enables/disables Wi-Fi scoring to take action on network
10634      * selection.
10635      *
10636      * @param enabled {@code true} to enable, {@code false} to disable.
10637      * @return true The status of Wifi scoring is set successfully.
10638      * @hide
10639      */
10640     @SystemApi
10641     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setWifiScoringEnabled(boolean enabled)10642     public boolean setWifiScoringEnabled(boolean enabled) {
10643         if (mVerboseLoggingEnabled) {
10644             Log.v(TAG, "setWifiScoringEnabled: " + enabled);
10645         }
10646         try {
10647             return mService.setWifiScoringEnabled(enabled);
10648         } catch (RemoteException e) {
10649             throw e.rethrowFromSystemServer();
10650         }
10651     }
10652 
10653     /**
10654      * Flush Passpoint ANQP cache, and clear pending ANQP requests. Allows the caller to reset the
10655      * Passpoint ANQP state, if required.
10656      *
10657      * Notes:
10658      * 1. Flushing the ANQP cache may cause delays in discovering and connecting to Passpoint
10659      * networks.
10660      * 2. Intended to be used by Device Owner (DO), Profile Owner (PO), Settings and provisioning
10661      * apps.
10662      */
10663     @RequiresPermission(anyOf = {
10664             android.Manifest.permission.NETWORK_SETTINGS,
10665             android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
10666             android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
10667             }, conditional = true)
flushPasspointAnqpCache()10668     public void flushPasspointAnqpCache() {
10669         try {
10670             mService.flushPasspointAnqpCache(mContext.getOpPackageName());
10671         } catch (RemoteException e) {
10672             throw e.rethrowFromSystemServer();
10673         }
10674     }
10675 
10676     /**
10677      * Returns a list of {@link WifiAvailableChannel} for the specified band and operational
10678      * mode(s), that is allowed for the current regulatory domain. An empty list implies that there
10679      * are no available channels for use.
10680      *
10681      * Note: the {@code band} parameter which is specified as a {@code WifiScanner#WIFI_BAND_*}
10682      * constant is limited to one of the band values specified below. Specifically, if the 5GHz
10683      * band is included then it must include the DFS channels - an exception will be thrown
10684      * otherwise. The caller should not make any assumptions about whether DFS channels are allowed.
10685      * This API will indicate whether DFS channels are allowed for the specified operation mode(s)
10686      * per device policy.
10687      *
10688      * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
10689      *             constants.
10690      *             1. {@code WifiScanner#WIFI_BAND_UNSPECIFIED}=0 - no band specified; Looks for the
10691      *                channels in all the available bands - 2.4 GHz, 5 GHz, 6 GHz and 60 GHz
10692      *             2. {@code WifiScanner#WIFI_BAND_24_GHZ}=1
10693      *             3. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}=6
10694      *             4. {@code WifiScanner#WIFI_BAND_BOTH_WITH_DFS}=7
10695      *             5. {@code WifiScanner#WIFI_BAND_6_GHZ}=8
10696      *             6. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_GHZ}=15
10697      *             7. {@code WifiScanner#WIFI_BAND_60_GHZ}=16
10698      *             8. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_60_GHZ}=31
10699      * @param mode Bitwise OR of {@code WifiAvailableChannel#OP_MODE_*} constants
10700      *        e.g. {@link WifiAvailableChannel#OP_MODE_WIFI_AWARE}
10701      * @return a list of {@link WifiAvailableChannel}
10702      *
10703      * @throws UnsupportedOperationException - if this API is not supported on this device
10704      *         or IllegalArgumentException - if the band specified is not one among the list
10705      *         of bands mentioned above.
10706      */
10707     @RequiresApi(Build.VERSION_CODES.S)
10708     @NonNull
10709     @RequiresPermission(NEARBY_WIFI_DEVICES)
getAllowedChannels( int band, @WifiAvailableChannel.OpMode int mode)10710     public List<WifiAvailableChannel> getAllowedChannels(
10711             int band,
10712             @WifiAvailableChannel.OpMode int mode) {
10713         if (!SdkLevel.isAtLeastS()) {
10714             throw new UnsupportedOperationException();
10715         }
10716         try {
10717             Bundle extras = new Bundle();
10718             if (SdkLevel.isAtLeastS()) {
10719                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
10720                         mContext.getAttributionSource());
10721             }
10722             return mService.getUsableChannels(band, mode,
10723                     WifiAvailableChannel.FILTER_REGULATORY, mContext.getOpPackageName(), extras);
10724         } catch (RemoteException e) {
10725             throw e.rethrowFromSystemServer();
10726         }
10727     }
10728 
10729     /**
10730      * Returns a list of {@link WifiAvailableChannel} for the specified band and operational
10731      * mode(s) per the current regulatory domain and device-specific constraints such as concurrency
10732      * state and interference due to other radios. An empty list implies that there are no available
10733      * channels for use.
10734      *
10735      * Note: the {@code band} parameter which is specified as a {@code WifiScanner#WIFI_BAND_*}
10736      * constant is limited to one of the band values specified below. Specifically, if the 5GHz
10737      * band is included then it must include the DFS channels - an exception will be thrown
10738      * otherwise. The caller should not make any assumptions about whether DFS channels are allowed.
10739      * This API will indicate whether DFS channels are allowed for the specified operation mode(s)
10740      * per device policy.
10741      *
10742      * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
10743      *             constants.
10744      *             1. {@code WifiScanner#WIFI_BAND_UNSPECIFIED}=0 - no band specified; Looks for the
10745      *                channels in all the available bands - 2.4 GHz, 5 GHz, 6 GHz and 60 GHz
10746      *             2. {@code WifiScanner#WIFI_BAND_24_GHZ}=1
10747      *             3. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}=6
10748      *             4. {@code WifiScanner#WIFI_BAND_BOTH_WITH_DFS}=7
10749      *             5. {@code WifiScanner#WIFI_BAND_6_GHZ}=8
10750      *             6. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_GHZ}=15
10751      *             7. {@code WifiScanner#WIFI_BAND_60_GHZ}=16
10752      *             8. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_60_GHZ}=31
10753      * @param mode Bitwise OR of {@code WifiAvailableChannel#OP_MODE_*} constants
10754      *        e.g. {@link WifiAvailableChannel#OP_MODE_WIFI_AWARE}
10755      * @return a list of {@link WifiAvailableChannel}
10756      *
10757      * @throws UnsupportedOperationException - if this API is not supported on this device
10758      *         or IllegalArgumentException - if the band specified is not one among the list
10759      *         of bands mentioned above.
10760      */
10761     @RequiresApi(Build.VERSION_CODES.S)
10762     @NonNull
10763     @RequiresPermission(NEARBY_WIFI_DEVICES)
getUsableChannels( int band, @WifiAvailableChannel.OpMode int mode)10764     public List<WifiAvailableChannel> getUsableChannels(
10765             int band,
10766             @WifiAvailableChannel.OpMode int mode) {
10767         if (!SdkLevel.isAtLeastS()) {
10768             throw new UnsupportedOperationException();
10769         }
10770         try {
10771             Bundle extras = new Bundle();
10772             if (SdkLevel.isAtLeastS()) {
10773                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
10774                         mContext.getAttributionSource());
10775             }
10776             return mService.getUsableChannels(band, mode,
10777                     WifiAvailableChannel.getUsableFilter(), mContext.getOpPackageName(), extras);
10778         } catch (RemoteException e) {
10779             throw e.rethrowFromSystemServer();
10780         }
10781     }
10782 
10783     /**
10784      * If the device supports Wi-Fi Passpoint, the user can explicitly enable or disable it.
10785      * That status can be queried using this method.
10786      * @return {@code true} if Wi-Fi Passpoint is enabled
10787      *
10788      */
10789     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiPasspointEnabled()10790     public boolean isWifiPasspointEnabled() {
10791         try {
10792             return mService.isWifiPasspointEnabled();
10793         } catch (RemoteException e) {
10794             throw e.rethrowFromSystemServer();
10795         }
10796     }
10797 
10798     /**
10799      * Explicitly enable or disable Wi-Fi Passpoint as a global switch.
10800      * The global Passpoint enabling/disabling overrides individual configuration
10801      * enabling/disabling.
10802      * Passpoint global status can be queried by {@link WifiManager#isWifiPasspointEnabled }.
10803      *
10804      * @param enabled {@code true} to enable, {@code false} to disable.
10805      * @hide
10806      */
10807     @SystemApi
10808     @RequiresPermission(anyOf = {
10809             android.Manifest.permission.NETWORK_SETTINGS,
10810             android.Manifest.permission.NETWORK_SETUP_WIZARD
10811     })
setWifiPasspointEnabled(boolean enabled)10812     public void setWifiPasspointEnabled(boolean enabled) {
10813         if (mVerboseLoggingEnabled) {
10814             Log.v(TAG, "setWifiPasspointEnabled: " + enabled);
10815         }
10816         try {
10817             mService.setWifiPasspointEnabled(enabled);
10818         } catch (RemoteException e) {
10819             throw e.rethrowFromSystemServer();
10820         }
10821     }
10822 
10823     /**
10824      * The device may support concurrent connections to multiple internet-providing Wi-Fi
10825      * networks (APs) - that is indicated by
10826      * {@link WifiManager#isStaConcurrencyForMultiInternetSupported()}.
10827      * This method indicates whether or not the feature is currently enabled.
10828      * A value of {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DISABLED} indicates that the feature
10829      * is disabled, a value of {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DBS_AP} or
10830      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_MULTI_AP} indicates that the feature is enabled.
10831      *
10832      * The app can register to receive the corresponding Wi-Fi networks using the
10833      * {@link ConnectivityManager#registerNetworkCallback(NetworkRequest, NetworkCallback)} API with
10834      * a {@link WifiNetworkSpecifier} configured using the
10835      * {@link WifiNetworkSpecifier.Builder#setBand(int)} method.
10836      */
10837     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
10838     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getStaConcurrencyForMultiInternetMode()10839     public @WifiMultiInternetMode int getStaConcurrencyForMultiInternetMode() {
10840         try {
10841             return mService.getStaConcurrencyForMultiInternetMode();
10842         } catch (RemoteException e) {
10843             throw e.rethrowFromSystemServer();
10844         }
10845     }
10846 
10847     /**
10848      * Check if the currently connected network meets the minimum required Wi-Fi security level set.
10849      * If not, the current network will be disconnected.
10850      *
10851      * @throws SecurityException if the caller does not have permission.
10852      * @hide
10853      */
10854     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
10855     @SystemApi
10856     @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
notifyMinimumRequiredWifiSecurityLevelChanged(int level)10857     public void notifyMinimumRequiredWifiSecurityLevelChanged(int level) {
10858         if (mVerboseLoggingEnabled) {
10859             Log.v(TAG, "notifyMinimumRequiredWifiSecurityLevelChanged");
10860         }
10861         try {
10862             mService.notifyMinimumRequiredWifiSecurityLevelChanged(level);
10863         } catch (RemoteException e) {
10864             throw e.rethrowFromSystemServer();
10865         }
10866     }
10867 
10868     /**
10869      * Check if the currently connected network meets the Wi-Fi SSID policy set.
10870      * If not, the current network will be disconnected.
10871      *
10872      * @throws SecurityException if the caller does not have permission.
10873      * @hide
10874      */
10875     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
10876     @SystemApi
10877     @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
notifyWifiSsidPolicyChanged(@onNull WifiSsidPolicy policy)10878     public void notifyWifiSsidPolicyChanged(@NonNull WifiSsidPolicy policy) {
10879         if (mVerboseLoggingEnabled) {
10880             Log.v(TAG, "notifyWifiSsidPolicyChanged");
10881         }
10882         try {
10883             if (policy != null) {
10884                 mService.notifyWifiSsidPolicyChanged(
10885                         policy.getPolicyType(), new ArrayList<>(policy.getSsids()));
10886             }
10887         } catch (RemoteException e) {
10888             throw e.rethrowFromSystemServer();
10889         }
10890     }
10891 
10892     /**
10893      * Configure whether or not concurrent multiple connections to internet-providing Wi-Fi
10894      * networks (AP) is enabled.
10895      * Use {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DISABLED} to disable, and either
10896      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DBS_AP} or
10897      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_MULTI_AP} to enable in different modes.
10898      * The {@link WifiManager#getStaConcurrencyForMultiInternetMode() } can be used to retrieve
10899      * the current mode.
10900      *
10901      * @param mode Multi internet mode.
10902      * @return true when the mode is set successfully, false when failed.
10903      * @hide
10904      */
10905     @SystemApi
10906     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
10907     @RequiresPermission(anyOf = {
10908             android.Manifest.permission.NETWORK_SETTINGS,
10909             android.Manifest.permission.NETWORK_SETUP_WIZARD
10910     })
setStaConcurrencyForMultiInternetMode(@ifiMultiInternetMode int mode)10911     public boolean setStaConcurrencyForMultiInternetMode(@WifiMultiInternetMode int mode) {
10912         if (mVerboseLoggingEnabled) {
10913             Log.v(TAG, "setStaConcurrencyForMultiInternetMode: " + mode);
10914         }
10915         try {
10916             return mService.setStaConcurrencyForMultiInternetMode(mode);
10917         } catch (RemoteException e) {
10918             throw e.rethrowFromSystemServer();
10919         }
10920     }
10921 
10922     /**
10923      * Intent action to launch a dialog from the WifiDialog app.
10924      * Must include EXTRA_DIALOG_ID, EXTRA_DIALOG_TYPE, and appropriate extras for the dialog type.
10925      * @hide
10926      */
10927     public static final String ACTION_LAUNCH_DIALOG =
10928             "android.net.wifi.action.LAUNCH_DIALOG";
10929 
10930     /**
10931      * Intent action to dismiss an existing dialog from the WifiDialog app.
10932      * Must include EXTRA_DIALOG_ID.
10933      * @hide
10934      */
10935     public static final String ACTION_DISMISS_DIALOG =
10936             "android.net.wifi.action.DISMISS_DIALOG";
10937 
10938     /**
10939      * Unknown DialogType.
10940      * @hide
10941      */
10942     public static final int DIALOG_TYPE_UNKNOWN = 0;
10943 
10944     /**
10945      * DialogType for a simple dialog.
10946      * @see {@link com.android.server.wifi.WifiDialogManager#createSimpleDialog}
10947      * @hide
10948      */
10949     public static final int DIALOG_TYPE_SIMPLE = 1;
10950 
10951     /**
10952      * DialogType for a P2P Invitation Sent dialog.
10953      * @see {@link com.android.server.wifi.WifiDialogManager#createP2pInvitationSentDialog}
10954      * @hide
10955      */
10956     public static final int DIALOG_TYPE_P2P_INVITATION_SENT = 2;
10957 
10958     /**
10959      * DialogType for a P2P Invitation Received dialog.
10960      * @see {@link com.android.server.wifi.WifiDialogManager#createP2pInvitationReceivedDialog}
10961      * @hide
10962      */
10963     public static final int DIALOG_TYPE_P2P_INVITATION_RECEIVED = 3;
10964 
10965     /** @hide */
10966     @IntDef(prefix = { "DIALOG_TYPE_" }, value = {
10967             DIALOG_TYPE_UNKNOWN,
10968             DIALOG_TYPE_SIMPLE,
10969             DIALOG_TYPE_P2P_INVITATION_SENT,
10970             DIALOG_TYPE_P2P_INVITATION_RECEIVED,
10971     })
10972     @Retention(RetentionPolicy.SOURCE)
10973     public @interface DialogType {}
10974 
10975     /**
10976      * Dialog positive button was clicked.
10977      * @hide
10978      */
10979     public static final int DIALOG_REPLY_POSITIVE = 0;
10980 
10981     /**
10982      * Dialog negative button was clicked.
10983      * @hide
10984      */
10985     public static final int DIALOG_REPLY_NEGATIVE = 1;
10986 
10987     /**
10988      * Dialog neutral button was clicked.
10989      * @hide
10990      */
10991     public static final int DIALOG_REPLY_NEUTRAL = 2;
10992 
10993     /**
10994      * Dialog was cancelled.
10995      * @hide
10996      */
10997     public static final int DIALOG_REPLY_CANCELLED = 3;
10998 
10999     /**
11000      * Indication of a reply to a dialog.
11001      * See {@link WifiManager#replyToSimpleDialog(int, int)}
11002      * @hide
11003      */
11004     @IntDef(prefix = { "DIALOG_TYPE_" }, value = {
11005             DIALOG_REPLY_POSITIVE,
11006             DIALOG_REPLY_NEGATIVE,
11007             DIALOG_REPLY_NEUTRAL,
11008             DIALOG_REPLY_CANCELLED,
11009     })
11010     @Retention(RetentionPolicy.SOURCE)
11011     public @interface DialogReply {}
11012 
11013     /**
11014      * Invalid dialog id for dialogs that are not currently active.
11015      * @hide
11016      */
11017     public static final int INVALID_DIALOG_ID = -1;
11018 
11019     /**
11020      * Extra int indicating the type of dialog to display.
11021      * @hide
11022      */
11023     public static final String EXTRA_DIALOG_TYPE = "android.net.wifi.extra.DIALOG_TYPE";
11024 
11025     /**
11026      * Extra int indicating the ID of a dialog. The value must not be {@link #INVALID_DIALOG_ID}.
11027      * @hide
11028      */
11029     public static final String EXTRA_DIALOG_ID = "android.net.wifi.extra.DIALOG_ID";
11030 
11031     /**
11032      * Extra String indicating the title of a simple dialog.
11033      * @hide
11034      */
11035     public static final String EXTRA_DIALOG_TITLE = "android.net.wifi.extra.DIALOG_TITLE";
11036 
11037     /**
11038      * Extra String indicating the message of a simple dialog.
11039      * @hide
11040      */
11041     public static final String EXTRA_DIALOG_MESSAGE = "android.net.wifi.extra.DIALOG_MESSAGE";
11042 
11043     /**
11044      * Extra String indicating the message URL of a simple dialog.
11045      * @hide
11046      */
11047     public static final String EXTRA_DIALOG_MESSAGE_URL =
11048             "android.net.wifi.extra.DIALOG_MESSAGE_URL";
11049 
11050     /**
11051      * Extra String indicating the start index of a message URL span of a simple dialog.
11052      * @hide
11053      */
11054     public static final String EXTRA_DIALOG_MESSAGE_URL_START =
11055             "android.net.wifi.extra.DIALOG_MESSAGE_URL_START";
11056 
11057     /**
11058      * Extra String indicating the end index of a message URL span of a simple dialog.
11059      * @hide
11060      */
11061     public static final String EXTRA_DIALOG_MESSAGE_URL_END =
11062             "android.net.wifi.extra.DIALOG_MESSAGE_URL_END";
11063 
11064     /**
11065      * Extra String indicating the positive button text of a simple dialog.
11066      * @hide
11067      */
11068     public static final String EXTRA_DIALOG_POSITIVE_BUTTON_TEXT =
11069             "android.net.wifi.extra.DIALOG_POSITIVE_BUTTON_TEXT";
11070 
11071     /**
11072      * Extra String indicating the negative button text of a simple dialog.
11073      * @hide
11074      */
11075     public static final String EXTRA_DIALOG_NEGATIVE_BUTTON_TEXT =
11076             "android.net.wifi.extra.DIALOG_NEGATIVE_BUTTON_TEXT";
11077 
11078     /**
11079      * Extra String indicating the neutral button text of a simple dialog.
11080      * @hide
11081      */
11082     public static final String EXTRA_DIALOG_NEUTRAL_BUTTON_TEXT =
11083             "android.net.wifi.extra.DIALOG_NEUTRAL_BUTTON_TEXT";
11084 
11085     /**
11086      * Extra long indicating the timeout in milliseconds of a dialog.
11087      * @hide
11088      */
11089     public static final String EXTRA_DIALOG_TIMEOUT_MS = "android.net.wifi.extra.DIALOG_TIMEOUT_MS";
11090 
11091     /**
11092      * Extra String indicating a P2P device name for a P2P Invitation Sent/Received dialog.
11093      * @hide
11094      */
11095     public static final String EXTRA_P2P_DEVICE_NAME = "android.net.wifi.extra.P2P_DEVICE_NAME";
11096 
11097     /**
11098      * Extra boolean indicating that a PIN is requested for a P2P Invitation Received dialog.
11099      * @hide
11100      */
11101     public static final String EXTRA_P2P_PIN_REQUESTED = "android.net.wifi.extra.P2P_PIN_REQUESTED";
11102 
11103     /**
11104      * Extra String indicating the PIN to be displayed for a P2P Invitation Sent/Received dialog.
11105      * @hide
11106      */
11107     public static final String EXTRA_P2P_DISPLAY_PIN = "android.net.wifi.extra.P2P_DISPLAY_PIN";
11108 
11109     /**
11110      * Extra boolean indicating ACTION_CLOSE_SYSTEM_DIALOGS should not close the Wi-Fi dialogs.
11111      * @hide
11112      */
11113     public static final String EXTRA_CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI =
11114             "android.net.wifi.extra.CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI";
11115 
11116     /**
11117      * Returns a set of packages that aren't DO or PO but should be able to manage WiFi networks.
11118      * @hide
11119      */
11120     @SystemApi
11121     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
11122     @NonNull
getOemPrivilegedWifiAdminPackages()11123     public Set<String> getOemPrivilegedWifiAdminPackages() {
11124         try {
11125             return new ArraySet<>(mService.getOemPrivilegedWifiAdminPackages());
11126         } catch (RemoteException e) {
11127             throw e.rethrowFromSystemServer();
11128         }
11129     }
11130 
11131     /**
11132      * Method for WifiDialog to notify the framework of a reply to a simple dialog.
11133      * @param dialogId id of the replying dialog.
11134      * @param reply reply of the dialog.
11135      * @hide
11136      */
replyToSimpleDialog(int dialogId, @DialogReply int reply)11137     public void replyToSimpleDialog(int dialogId, @DialogReply int reply) {
11138         if (mVerboseLoggingEnabled) {
11139             Log.v(TAG, "replyToWifiEnableRequestDialog: dialogId=" + dialogId
11140                     + " reply=" + reply);
11141         }
11142         try {
11143             mService.replyToSimpleDialog(dialogId, reply);
11144         } catch (RemoteException e) {
11145             throw e.rethrowFromSystemServer();
11146         }
11147     }
11148 
11149     /**
11150      * Method for WifiDialog to notify the framework of a reply to a P2P Invitation Received dialog.
11151      * @param dialogId id of the replying dialog.
11152      * @param accepted Whether the invitation was accepted.
11153      * @param optionalPin PIN of the reply, or {@code null} if none was supplied.
11154      * @hide
11155      */
replyToP2pInvitationReceivedDialog( int dialogId, boolean accepted, @Nullable String optionalPin)11156     public void replyToP2pInvitationReceivedDialog(
11157             int dialogId, boolean accepted, @Nullable String optionalPin) {
11158         if (mVerboseLoggingEnabled) {
11159             Log.v(TAG, "replyToP2pInvitationReceivedDialog: "
11160                     + "dialogId=" + dialogId
11161                     + ", accepted=" + accepted
11162                     + ", pin=" + optionalPin);
11163         }
11164         try {
11165             mService.replyToP2pInvitationReceivedDialog(dialogId, accepted, optionalPin);
11166         } catch (RemoteException e) {
11167             throw e.rethrowFromSystemServer();
11168         }
11169     }
11170 
11171     /**
11172      * Specify a list of DHCP options to use for any network whose SSID is specified and which
11173      * transmits vendor-specific information elements (VSIEs) using the specified Organizationally
11174      * Unique Identifier (OUI). If the AP transmits VSIEs for multiple specified OUIs then all
11175      * matching DHCP options will be used. The allowlist for DHCP options in
11176      * {@link android.net.ip.IpClient} gates whether the DHCP options will actually be used.
11177      * When DHCP options are used: if the option value {@link android.net.DhcpOption#getValue()}
11178      * is null, the option type {@link android.net.DhcpOption#getType()} will be put in the
11179      * Parameter Request List in the DHCP packets; otherwise, the option will be included in the
11180      * options section in the DHCP packets. Use {@link #removeCustomDhcpOptions(Object, Object)}
11181      * to remove the specified DHCP options.
11182      *
11183      * @param ssid the network SSID.
11184      * @param oui the 3-byte OUI.
11185      * @param options the list of {@link android.net.DhcpOption}.
11186      *
11187      * @hide
11188      */
11189     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
11190     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11191     @RequiresPermission(anyOf = {
11192             android.Manifest.permission.NETWORK_SETTINGS,
11193             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
11194     })
addCustomDhcpOptions(@onNull WifiSsid ssid, @NonNull byte[] oui, @NonNull List<DhcpOption> options)11195     public void addCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui,
11196             @NonNull List<DhcpOption> options) {
11197         if (mVerboseLoggingEnabled) {
11198             Log.v(TAG, "addCustomDhcpOptions: ssid="
11199                     + ssid + ", oui=" + Arrays.toString(oui) + ", options=" + options);
11200         }
11201         try {
11202             mService.addCustomDhcpOptions(ssid, oui, options);
11203         } catch (RemoteException e) {
11204             throw e.rethrowFromSystemServer();
11205         }
11206     }
11207 
11208     /**
11209      * Remove custom DHCP options specified by {@link #addCustomDhcpOptions(Object, Object, List)}.
11210      *
11211      * @param ssid the network SSID.
11212      * @param oui the 3-byte OUI.
11213      *
11214      * @hide
11215      */
11216     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
11217     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11218     @RequiresPermission(anyOf = {
11219             android.Manifest.permission.NETWORK_SETTINGS,
11220             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
11221     })
removeCustomDhcpOptions(@onNull WifiSsid ssid, @NonNull byte[] oui)11222     public void removeCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui) {
11223         if (mVerboseLoggingEnabled) {
11224             Log.v(TAG, "removeCustomDhcpOptions: ssid=" + ssid + ", oui=" + Arrays.toString(oui));
11225         }
11226         try {
11227             mService.removeCustomDhcpOptions(ssid, oui);
11228         } catch (RemoteException e) {
11229             throw e.rethrowFromSystemServer();
11230         }
11231     }
11232 
11233     /**
11234      * Wi-Fi interface of type STA (station/client Wi-Fi infrastructure device).
11235      */
11236     public static final int WIFI_INTERFACE_TYPE_STA = 0;
11237 
11238     /**
11239      * Wi-Fi interface of type AP (access point Wi-Fi infrastructure device).
11240      */
11241     public static final int WIFI_INTERFACE_TYPE_AP = 1;
11242 
11243     /**
11244      * Wi-Fi interface of type Wi-Fi Aware (aka NAN).
11245      */
11246     public static final int WIFI_INTERFACE_TYPE_AWARE = 2;
11247 
11248     /**
11249      * Wi-Fi interface of type Wi-Fi Direct (aka P2P).
11250      */
11251     public static final int WIFI_INTERFACE_TYPE_DIRECT = 3;
11252 
11253     /** @hide */
11254     @IntDef(prefix = { "WIFI_INTERFACE_TYPE_" }, value = {
11255             WIFI_INTERFACE_TYPE_STA,
11256             WIFI_INTERFACE_TYPE_AP,
11257             WIFI_INTERFACE_TYPE_AWARE,
11258             WIFI_INTERFACE_TYPE_DIRECT,
11259     })
11260     @Retention(RetentionPolicy.SOURCE)
11261     public @interface WifiInterfaceType {}
11262 
11263     /**
11264      * Class describing an impact of interface creation - returned by
11265      * {@link #reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)}. Due to Wi-Fi
11266      * concurrency limitations certain interfaces may have to be torn down. Each of these
11267      * interfaces was requested by a set of applications who could potentially be impacted.
11268      *
11269      * This class contain the information for a single interface: the interface type with
11270      * {@link InterfaceCreationImpact#getInterfaceType()} and the set of impacted packages
11271      * with {@link InterfaceCreationImpact#getPackages()}.
11272      */
11273     public static class InterfaceCreationImpact {
11274         private final int mInterfaceType;
11275         private final Set<String> mPackages;
11276 
InterfaceCreationImpact(@ifiInterfaceType int interfaceType, @NonNull Set<String> packages)11277         public InterfaceCreationImpact(@WifiInterfaceType int interfaceType,
11278                 @NonNull Set<String> packages) {
11279             mInterfaceType = interfaceType;
11280             mPackages = packages;
11281         }
11282 
11283         /**
11284          * @return The interface type which will be torn down to make room for the interface
11285          * requested in {@link #reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)}.
11286          */
getInterfaceType()11287         public @WifiInterfaceType int getInterfaceType() {
11288             return mInterfaceType;
11289         }
11290 
11291         /**
11292          * @return The list of potentially impacted packages due to tearing down the interface
11293          * specified in {@link #getInterfaceType()}.
11294          */
getPackages()11295         public @NonNull Set<String> getPackages() {
11296             return mPackages;
11297         }
11298 
11299         @Override
hashCode()11300         public int hashCode() {
11301             return Objects.hash(mInterfaceType, mPackages);
11302         }
11303 
11304         @Override
equals(Object that)11305         public boolean equals(Object that) {
11306             if (this == that) return true;
11307             if (!(that instanceof InterfaceCreationImpact)) return false;
11308             InterfaceCreationImpact thatInterfaceCreationImpact = (InterfaceCreationImpact) that;
11309 
11310             return this.mInterfaceType == thatInterfaceCreationImpact.mInterfaceType
11311                     && Objects.equals(this.mPackages, thatInterfaceCreationImpact.mPackages);
11312         }
11313     }
11314 
11315     /**
11316      * Queries the framework to determine whether the specified interface can be created, and if
11317      * so - what other interfaces would be torn down by the framework to allow this creation if
11318      * it were requested. The result is returned via the specified {@link BiConsumer} callback
11319      * which returns two arguments:
11320      * <li>First argument: a {@code boolean} - indicating whether or not the interface can be
11321      * created.</li>
11322      * <li>Second argument: a {@code Set<InterfaceCreationImpact>} - if the interface can be
11323      * created (first argument is {@code true} then this is the set of interface types which
11324      * will be removed and the packages which requested them. Possibly an empty set. If the
11325      * first argument is {@code false}, then an empty set will be returned here.</li>
11326      * <p>
11327      * Interfaces, input and output, are specified using the {@code WIFI_INTERFACE_*} constants:
11328      * {@link #WIFI_INTERFACE_TYPE_STA}, {@link #WIFI_INTERFACE_TYPE_AP},
11329      * {@link #WIFI_INTERFACE_TYPE_AWARE}, or {@link #WIFI_INTERFACE_TYPE_DIRECT}.
11330      * <p>
11331      * This method does not actually create the interface. That operation is handled by the
11332      * framework when a particular service method is called. E.g. a Wi-Fi Direct interface may be
11333      * created when various methods of {@link android.net.wifi.p2p.WifiP2pManager} are called,
11334      * similarly for Wi-Fi Aware and {@link android.net.wifi.aware.WifiAwareManager}.
11335      * <p>
11336      * Note: the information returned via this method is the current snapshot of the system. It may
11337      * change due to actions of the framework or other apps.
11338      *
11339      * @param interfaceType The interface type whose possible creation is being queried.
11340      * @param requireNewInterface Indicates that the query is for a new interface of the specified
11341      *                             type - an existing interface won't meet the query. Some
11342      *                             operations (such as Wi-Fi Direct and Wi-Fi Aware are a shared
11343      *                             resource and so may not need a new interface).
11344      * @param executor An {@link Executor} on which to return the result.
11345      * @param resultCallback The asynchronous callback which will return two argument: a
11346      * {@code boolean} (whether the interface can be created), and a
11347      * {@code Set<InterfaceCreationImpact>} (a set of {@link InterfaceCreationImpact}:
11348      *                       interfaces which will be destroyed when the interface is created
11349      *                       and the packages which requested them and thus may be impacted).
11350      */
11351     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11352     @RequiresPermission(allOf = {android.Manifest.permission.MANAGE_WIFI_INTERFACES,
11353             ACCESS_WIFI_STATE})
reportCreateInterfaceImpact(@ifiInterfaceType int interfaceType, boolean requireNewInterface, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<Boolean, Set<InterfaceCreationImpact>> resultCallback)11354     public void reportCreateInterfaceImpact(@WifiInterfaceType int interfaceType,
11355             boolean requireNewInterface,
11356             @NonNull @CallbackExecutor Executor executor,
11357             @NonNull BiConsumer<Boolean, Set<InterfaceCreationImpact>> resultCallback) {
11358         Objects.requireNonNull(executor, "Non-null executor required");
11359         Objects.requireNonNull(resultCallback, "Non-null resultCallback required");
11360         try {
11361             mService.reportCreateInterfaceImpact(mContext.getOpPackageName(), interfaceType,
11362                     requireNewInterface, new IInterfaceCreationInfoCallback.Stub() {
11363                         @Override
11364                         public void onResults(boolean canCreate, int[] interfacesToDelete,
11365                                 String[] packagesForInterfaces) {
11366                             Binder.clearCallingIdentity();
11367                             if ((interfacesToDelete == null && packagesForInterfaces != null)
11368                                     || (interfacesToDelete != null
11369                                     && packagesForInterfaces == null) || (canCreate && (
11370                                     interfacesToDelete == null || interfacesToDelete.length
11371                                             != packagesForInterfaces.length))) {
11372                                 Log.e(TAG,
11373                                         "reportImpactToCreateIfaceRequest: Invalid callback "
11374                                                 + "parameters - canCreate="
11375                                                 + canCreate + ", interfacesToDelete="
11376                                                 + Arrays.toString(interfacesToDelete)
11377                                                 + ", worksourcesForInterfaces="
11378                                                 + Arrays.toString(packagesForInterfaces));
11379                                 return;
11380                             }
11381 
11382                             final Set<InterfaceCreationImpact> finalSet =
11383                                     (canCreate && interfacesToDelete.length > 0) ? new ArraySet<>()
11384                                             : Collections.emptySet();
11385                             if (canCreate) {
11386                                 for (int i = 0; i < interfacesToDelete.length; ++i) {
11387                                     finalSet.add(
11388                                             new InterfaceCreationImpact(interfacesToDelete[i],
11389                                                     packagesForInterfaces[i] == null
11390                                                             ? Collections.emptySet()
11391                                                             : new ArraySet<>(
11392                                                                     packagesForInterfaces[i]
11393                                                                             .split(","))));
11394                                 }
11395                             }
11396                             executor.execute(() -> resultCallback.accept(canCreate, finalSet));
11397                         }
11398                     });
11399         } catch (RemoteException e) {
11400             throw e.rethrowFromSystemServer();
11401         }
11402     }
11403 
11404     /**
11405      * Returns the max number of channels that is allowed to be set on a
11406      * {@link WifiNetworkSpecifier}.
11407      * @see WifiNetworkSpecifier.Builder#setPreferredChannelsFrequenciesMhz(int[])
11408      *
11409      * @return The max number of channels can be set on a request.
11410      */
11411 
getMaxNumberOfChannelsPerNetworkSpecifierRequest()11412     public int getMaxNumberOfChannelsPerNetworkSpecifierRequest() {
11413         try {
11414             return mService.getMaxNumberOfChannelsPerRequest();
11415         } catch (RemoteException e) {
11416             throw e.rethrowFromSystemServer();
11417         }
11418     }
11419 
11420     /**
11421      * Add a list of new application-initiated QoS policies.
11422      *
11423      * Note: Policies are managed using a policy ID, which can be retrieved using
11424      *       {@link QosPolicyParams#getPolicyId()}. This ID can be used when removing a policy via
11425      *       {@link #removeQosPolicies(int[])}. The caller is in charge of assigning and managing
11426      *       the policy IDs for any requested policies.
11427      *
11428      * Note: Policies with duplicate IDs are not allowed. To update an existing policy, first
11429      *       remove it using {@link #removeQosPolicies(int[])}, and then re-add it using this API.
11430      *
11431      * Note: All policies in a single request must have the same {@link QosPolicyParams.Direction}.
11432      *
11433      * Note: Currently, only the {@link QosPolicyParams#DIRECTION_DOWNLINK} direction is supported.
11434      *
11435      * @param policyParamsList List of {@link QosPolicyParams} objects describing the requested
11436      *                         policies. Must have a maximum length of
11437      *                         {@link #getMaxNumberOfPoliciesPerQosRequest()}.
11438      * @param executor The executor on which callback will be invoked.
11439      * @param resultsCallback An asynchronous callback that will return a list of integer status
11440      *                        codes from {@link QosRequestStatus}. Result list will be the same
11441      *                        length as the input list, and each status code will correspond to
11442      *                        the policy at that index in the input list.
11443      *
11444      * @throws SecurityException if caller does not have the required permissions.
11445      * @throws NullPointerException if the caller provided a null input.
11446      * @throws UnsupportedOperationException if the feature is not enabled.
11447      * @throws IllegalArgumentException if the input list is invalid.
11448      * @hide
11449      */
11450     @SystemApi
11451     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11452     @RequiresPermission(anyOf = {
11453             android.Manifest.permission.NETWORK_SETTINGS,
11454             MANAGE_WIFI_NETWORK_SELECTION
11455     })
addQosPolicies(@onNull List<QosPolicyParams> policyParamsList, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<List<Integer>> resultsCallback)11456     public void addQosPolicies(@NonNull List<QosPolicyParams> policyParamsList,
11457             @NonNull @CallbackExecutor Executor executor,
11458             @NonNull Consumer<List<Integer>> resultsCallback) {
11459         Objects.requireNonNull(policyParamsList, "policyParamsList cannot be null");
11460         Objects.requireNonNull(executor, "executor cannot be null");
11461         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11462         try {
11463             mService.addQosPolicies(policyParamsList, new Binder(), mContext.getOpPackageName(),
11464                     new IListListener.Stub() {
11465                         @Override
11466                         public void onResult(List value) {
11467                             Binder.clearCallingIdentity();
11468                             executor.execute(() -> {
11469                                 resultsCallback.accept(value);
11470                             });
11471                         }
11472                     });
11473         } catch (RemoteException e) {
11474             throw e.rethrowFromSystemServer();
11475         }
11476     }
11477 
11478     /**
11479      * Remove a list of existing application-initiated QoS policies, previously added via
11480      * {@link #addQosPolicies(List, Executor, Consumer)}.
11481      *
11482      * Note: Policies are identified by their policy IDs, which are assigned by the caller. The ID
11483      *       for a given policy can be retrieved using {@link QosPolicyParams#getPolicyId()}.
11484      *
11485      * @param policyIdList List of policy IDs corresponding to the policies to remove. Must have
11486      *                     a maximum length of {@link #getMaxNumberOfPoliciesPerQosRequest()}.
11487      * @throws SecurityException if caller does not have the required permissions.
11488      * @throws NullPointerException if the caller provided a null input.
11489      * @throws IllegalArgumentException if the input list is invalid.
11490      * @hide
11491      */
11492     @SystemApi
11493     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11494     @RequiresPermission(anyOf = {
11495             android.Manifest.permission.NETWORK_SETTINGS,
11496             MANAGE_WIFI_NETWORK_SELECTION
11497     })
removeQosPolicies(@onNull int[] policyIdList)11498     public void removeQosPolicies(@NonNull int[] policyIdList) {
11499         Objects.requireNonNull(policyIdList, "policyIdList cannot be null");
11500         try {
11501             mService.removeQosPolicies(policyIdList, mContext.getOpPackageName());
11502         } catch (RemoteException e) {
11503             throw e.rethrowFromSystemServer();
11504         }
11505     }
11506 
11507     /**
11508      * Remove all application-initiated QoS policies requested by this caller,
11509      * previously added via {@link #addQosPolicies(List, Executor, Consumer)}.
11510      *
11511      * @throws SecurityException if caller does not have the required permissions.
11512      * @hide
11513      */
11514     @SystemApi
11515     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11516     @RequiresPermission(anyOf = {
11517             android.Manifest.permission.NETWORK_SETTINGS,
11518             MANAGE_WIFI_NETWORK_SELECTION
11519     })
removeAllQosPolicies()11520     public void removeAllQosPolicies() {
11521         try {
11522             mService.removeAllQosPolicies(mContext.getOpPackageName());
11523         } catch (RemoteException e) {
11524             throw e.rethrowFromSystemServer();
11525         }
11526     }
11527 
11528     /**
11529      * Set the link layer stats polling interval, in milliseconds.
11530      *
11531      * @param intervalMs a non-negative integer, for the link layer stats polling interval
11532      *                   in milliseconds.
11533      *                   To set a fixed interval, use a positive value.
11534      *                   For automatic handling of the interval, use value 0
11535      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
11536      * @throws SecurityException if the caller does not have permission.
11537      * @throws IllegalArgumentException if input is invalid.
11538      * @hide
11539      */
11540     @SystemApi
11541     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11542     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
setLinkLayerStatsPollingInterval(@ntRange from = 0) int intervalMs)11543     public void setLinkLayerStatsPollingInterval(@IntRange (from = 0) int intervalMs) {
11544         try {
11545             mService.setLinkLayerStatsPollingInterval(intervalMs);
11546         } catch (RemoteException e) {
11547             throw e.rethrowFromSystemServer();
11548         }
11549     }
11550 
11551     /**
11552      * Get the link layer stats polling interval, in milliseconds.
11553      *
11554      * @param executor The executor on which callback will be invoked.
11555      * @param resultsCallback An asynchronous callback that will return current
11556      *                        link layer stats polling interval in milliseconds.
11557      *
11558      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
11559      * @throws SecurityException if the caller does not have permission.
11560      * @throws NullPointerException if the caller provided invalid inputs.
11561      * @hide
11562      */
11563     @SystemApi
11564     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11565     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
getLinkLayerStatsPollingInterval(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)11566     public void getLinkLayerStatsPollingInterval(@NonNull @CallbackExecutor Executor executor,
11567             @NonNull Consumer<Integer> resultsCallback) {
11568         Objects.requireNonNull(executor, "executor cannot be null");
11569         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11570         try {
11571             mService.getLinkLayerStatsPollingInterval(
11572                     new IIntegerListener.Stub() {
11573                         @Override
11574                         public void onResult(int value) {
11575                             Binder.clearCallingIdentity();
11576                             executor.execute(() -> {
11577                                 resultsCallback.accept(value);
11578                             });
11579                         }
11580                     });
11581         } catch (RemoteException e) {
11582             throw e.rethrowFromSystemServer();
11583         }
11584     }
11585 
11586     /**
11587      * This API allows a privileged application to set Multi-Link Operation mode.
11588      *
11589      * Multi-link operation (MLO) will allow Wi-Fi devices to operate on multiple links at the same
11590      * time through a single connection, aiming to support applications that require lower latency,
11591      * and higher capacity. Chip vendors have algorithms that run on the chip to use available links
11592      * based on incoming traffic and various inputs. This API allows system application to give a
11593      * suggestion to such algorithms on its preference using {@link MloMode}.
11594      *
11595      *
11596      * @param mode Refer {@link MloMode} for supported modes.
11597      * @param executor The executor on which callback will be invoked.
11598      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
11599      *                        whether the MLO mode is successfully set or not.
11600      * @throws IllegalArgumentException if mode value is not in {@link MloMode}.
11601      * @throws NullPointerException if the caller provided a null input.
11602      * @throws SecurityException if caller does not have the required permissions.
11603      * @throws UnsupportedOperationException if the set operation is not supported on this SDK.
11604      * @hide
11605      */
11606     @SystemApi
11607     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11608     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
setMloMode(@loMode int mode, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)11609     public void setMloMode(@MloMode int mode, @NonNull @CallbackExecutor Executor executor,
11610             @NonNull Consumer<Boolean> resultsCallback) {
11611 
11612         if (mode < MLO_MODE_DEFAULT || mode > MLO_MODE_LOW_POWER) {
11613             throw new IllegalArgumentException("invalid mode: " + mode);
11614         }
11615         Objects.requireNonNull(executor, "executor cannot be null");
11616         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11617         try {
11618             mService.setMloMode(mode, new IBooleanListener.Stub() {
11619                 @Override
11620                 public void onResult(boolean value) {
11621                     Binder.clearCallingIdentity();
11622                     executor.execute(() -> {
11623                         resultsCallback.accept(value);
11624                     });
11625                 }
11626             });
11627         } catch (RemoteException e) {
11628             throw e.rethrowFromSystemServer();
11629         }
11630     }
11631 
11632     /**
11633      * This API allows a privileged application to get Multi-Link Operation mode. Refer
11634      * {@link WifiManager#setMloMode(int, Executor, Consumer)}  for more details.
11635      *
11636      * @param executor The executor on which callback will be invoked.
11637      * @param resultsCallback An asynchronous callback that will return current MLO mode. Returns
11638      *                        {@link MloMode#MLO_MODE_DEFAULT} if information is not available,
11639      *                        e.g. if the driver/firmware doesn't provide this information.
11640      * @throws NullPointerException if the caller provided a null input.
11641      * @throws SecurityException if caller does not have the required permissions.
11642      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
11643      * @hide
11644      */
11645     @SystemApi
11646     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11647     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMloMode(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)11648     public void getMloMode(@NonNull @CallbackExecutor Executor executor,
11649             @NonNull Consumer<Integer> resultsCallback) {
11650         Objects.requireNonNull(executor, "executor cannot be null");
11651         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11652         try {
11653             mService.getMloMode(new IIntegerListener.Stub() {
11654                 @Override
11655                 public void onResult(int value) {
11656                     Binder.clearCallingIdentity();
11657                     executor.execute(() -> {
11658                         resultsCallback.accept(value);
11659                     });
11660                 }
11661             });
11662         } catch (RemoteException e) {
11663             throw e.rethrowFromSystemServer();
11664         }
11665     }
11666 
11667     /**
11668      * Get the maximum number of links supported by the chip for MLO association. e.g. if the Wi-Fi
11669      * chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous Transmit and
11670      * Receive) with following capabilities,
11671      * - Max MLO assoc link count = 3.
11672      * - Max MLO STR link count   = 2. See
11673      * {@link WifiManager#getMaxMloStrLinkCount(Executor, Consumer)}
11674      * One of the possible configuration is - STR (2.4 GHz , eMLSR(5 GHz, 6 GHz)), provided the
11675      * radio combination of the chip supports it.
11676      *
11677      * @param executor        The executor on which callback will be invoked.
11678      * @param resultsCallback An asynchronous callback that will return maximum MLO association link
11679      *                        count supported by the chip or -1 if error or not available.
11680      * @throws NullPointerException          if the caller provided a null input.
11681      * @throws SecurityException             if caller does not have the required permissions.
11682      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
11683      * @hide
11684      */
11685     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11686     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMaxMloAssociationLinkCount(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)11687     public void getMaxMloAssociationLinkCount(@NonNull @CallbackExecutor Executor executor,
11688             @NonNull Consumer<Integer> resultsCallback) {
11689         Objects.requireNonNull(executor, "executor cannot be null");
11690         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11691         try {
11692             Bundle extras = new Bundle();
11693             if (SdkLevel.isAtLeastS()) {
11694                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
11695                         mContext.getAttributionSource());
11696             }
11697             mService.getMaxMloAssociationLinkCount(new IIntegerListener.Stub() {
11698                 @Override
11699                 public void onResult(int value) {
11700                     Binder.clearCallingIdentity();
11701                     executor.execute(() -> {
11702                         resultsCallback.accept(value);
11703                     });
11704                 }
11705             }, extras);
11706         } catch (RemoteException e) {
11707             throw e.rethrowFromSystemServer();
11708         }
11709     }
11710 
11711     /**
11712      * Get the maximum number of STR links used in Multi-Link Operation. The maximum number of STR
11713      * links used for MLO can be different from the number of radios supported by the chip. e.g. if
11714      * the Wi-Fi chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous
11715      * Transmit and Receive) with following capabilities,
11716      * - Max MLO assoc link count = 3. See
11717      *   {@link WifiManager#getMaxMloAssociationLinkCount(Executor, Consumer)}.
11718      * - Max MLO STR link count   = 2.
11719      * One of the possible configuration is - STR (2.4 GHz, eMLSR(5 GHz, 6 GHz)), provided the radio
11720      * combination of the chip supports it.
11721      *
11722      * @param executor The executor on which callback will be invoked.
11723      * @param resultsCallback An asynchronous callback that will return maximum STR link count
11724      *                       supported by the chip in MLO mode or -1 if error or not available.
11725      * @throws NullPointerException if the caller provided a null input.
11726      * @throws SecurityException if caller does not have the required permissions.
11727      * @throws UnsupportedOperationException if the get operation is not supported on this SDK
11728      * @hide
11729      */
11730     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11731     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMaxMloStrLinkCount(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)11732     public void getMaxMloStrLinkCount(@NonNull @CallbackExecutor Executor executor,
11733             @NonNull Consumer<Integer> resultsCallback) {
11734         Objects.requireNonNull(executor, "executor cannot be null");
11735         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11736         try {
11737             Bundle extras = new Bundle();
11738             if (SdkLevel.isAtLeastS()) {
11739                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
11740                         mContext.getAttributionSource());
11741             }
11742             mService.getMaxMloStrLinkCount(new IIntegerListener.Stub() {
11743                 @Override
11744                 public void onResult(int value) {
11745                     Binder.clearCallingIdentity();
11746                     executor.execute(() -> {
11747                         resultsCallback.accept(value);
11748                     });
11749                 }
11750             }, extras);
11751         } catch (RemoteException e) {
11752             throw e.rethrowFromSystemServer();
11753         }
11754     }
11755 
11756     /**
11757      * Get the set of band combinations supported simultaneously by the Wi-Fi Chip.
11758      *
11759      * Note: This method returns simultaneous band operation combination and not multichannel
11760      * concurrent operation (MCC) combination.
11761      *
11762      * @param executor The executor on which callback will be invoked.
11763      * @param resultsCallback An asynchronous callback that will return a list of possible
11764      *                        simultaneous band combinations supported by the chip or empty list if
11765      *                        not available. Band value is defined in {@link WifiScanner.WifiBand}.
11766      * @throws NullPointerException if the caller provided a null input.
11767      * @throws SecurityException if caller does not have the required permissions.
11768      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
11769      * @hide
11770      */
11771     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11772     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getSupportedSimultaneousBandCombinations( @onNull @allbackExecutor Executor executor, @NonNull Consumer<List<int[]>> resultsCallback)11773     public void getSupportedSimultaneousBandCombinations(
11774             @NonNull @CallbackExecutor Executor executor,
11775             @NonNull Consumer<List<int[]>> resultsCallback) {
11776         Objects.requireNonNull(executor, "executor cannot be null");
11777         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11778         try {
11779             Bundle extras = new Bundle();
11780             if (SdkLevel.isAtLeastS()) {
11781                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
11782                         mContext.getAttributionSource());
11783             }
11784             mService.getSupportedSimultaneousBandCombinations(new IWifiBandsListener.Stub() {
11785                 @Override
11786                 public void onResult(WifiBands[] supportedBands) {
11787                     Binder.clearCallingIdentity();
11788                     List<int[]> bandCombinations = new ArrayList<>();
11789                     for (WifiBands wifiBands : supportedBands) {
11790                         bandCombinations.add(wifiBands.bands);
11791                     }
11792                     executor.execute(() -> {
11793                         resultsCallback.accept(bandCombinations);
11794                     });
11795                 }
11796             }, extras);
11797         } catch (RemoteException e) {
11798             throw e.rethrowFromSystemServer();
11799         }
11800     }
11801 }