• 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.NETWORK_SETTINGS;
25 import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
26 import static android.Manifest.permission.READ_WIFI_CREDENTIAL;
27 import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
28 
29 import android.Manifest;
30 import android.annotation.CallbackExecutor;
31 import android.annotation.FlaggedApi;
32 import android.annotation.IntDef;
33 import android.annotation.IntRange;
34 import android.annotation.NonNull;
35 import android.annotation.Nullable;
36 import android.annotation.RequiresPermission;
37 import android.annotation.SdkConstant;
38 import android.annotation.SdkConstant.SdkConstantType;
39 import android.annotation.StringDef;
40 import android.annotation.SuppressLint;
41 import android.annotation.SystemApi;
42 import android.annotation.SystemService;
43 import android.app.ActivityManager;
44 import android.app.admin.WifiSsidPolicy;
45 import android.compat.annotation.ChangeId;
46 import android.compat.annotation.EnabledAfter;
47 import android.compat.annotation.UnsupportedAppUsage;
48 import android.content.Context;
49 import android.content.pm.PackageManager;
50 import android.net.ConnectivityManager;
51 import android.net.ConnectivityManager.NetworkCallback;
52 import android.net.DhcpInfo;
53 import android.net.DhcpOption;
54 import android.net.LinkProperties;
55 import android.net.MacAddress;
56 import android.net.Network;
57 import android.net.NetworkCapabilities;
58 import android.net.NetworkRequest;
59 import android.net.NetworkStack;
60 import android.net.TetheringManager;
61 import android.net.Uri;
62 import android.net.wifi.hotspot2.IProvisioningCallback;
63 import android.net.wifi.hotspot2.OsuProvider;
64 import android.net.wifi.hotspot2.PasspointConfiguration;
65 import android.net.wifi.hotspot2.ProvisioningCallback;
66 import android.net.wifi.p2p.WifiP2pConfig;
67 import android.net.wifi.p2p.WifiP2pDiscoveryConfig;
68 import android.net.wifi.p2p.WifiP2pManager;
69 import android.net.wifi.twt.TwtRequest;
70 import android.net.wifi.twt.TwtSession;
71 import android.net.wifi.twt.TwtSessionCallback;
72 import android.net.wifi.util.Environment;
73 import android.os.Binder;
74 import android.os.Build;
75 import android.os.Bundle;
76 import android.os.Handler;
77 import android.os.IBinder;
78 import android.os.Looper;
79 import android.os.Parcel;
80 import android.os.Parcelable;
81 import android.os.RemoteException;
82 import android.os.WorkSource;
83 import android.os.connectivity.WifiActivityEnergyInfo;
84 import android.security.advancedprotection.AdvancedProtectionFeature;
85 import android.security.advancedprotection.AdvancedProtectionManager;
86 import android.telephony.SubscriptionInfo;
87 import android.text.TextUtils;
88 import android.util.ArraySet;
89 import android.util.CloseGuard;
90 import android.util.Log;
91 import android.util.Pair;
92 import android.util.SparseArray;
93 
94 import androidx.annotation.RequiresApi;
95 
96 import com.android.internal.annotations.GuardedBy;
97 import com.android.internal.annotations.VisibleForTesting;
98 import com.android.modules.utils.HandlerExecutor;
99 import com.android.modules.utils.ParceledListSlice;
100 import com.android.modules.utils.StringParceledListSlice;
101 import com.android.modules.utils.build.SdkLevel;
102 import com.android.wifi.flags.Flags;
103 
104 import java.lang.annotation.Retention;
105 import java.lang.annotation.RetentionPolicy;
106 import java.lang.ref.Reference;
107 import java.lang.ref.WeakReference;
108 import java.net.InetAddress;
109 import java.time.Duration;
110 import java.util.ArrayList;
111 import java.util.Arrays;
112 import java.util.Collections;
113 import java.util.HashMap;
114 import java.util.List;
115 import java.util.Map;
116 import java.util.Objects;
117 import java.util.Set;
118 import java.util.StringTokenizer;
119 import java.util.concurrent.Executor;
120 import java.util.function.BiConsumer;
121 import java.util.function.Consumer;
122 import java.util.function.IntConsumer;
123 
124 /**
125  * This class provides the primary API for managing all aspects of Wi-Fi
126  * connectivity.
127  * <p>
128  * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
129  * should only be obtained from an {@linkplain Context#getApplicationContext()
130  * application context}, and not from any other derived context to avoid memory
131  * leaks within the calling process.
132  * <p>
133  * It deals with several categories of items:
134  * </p>
135  * <ul>
136  * <li>The list of configured networks. The list can be viewed and updated, and
137  * attributes of individual entries can be modified.</li>
138  * <li>The currently active Wi-Fi network, if any. Connectivity can be
139  * established or torn down, and dynamic information about the state of the
140  * network can be queried.</li>
141  * <li>Results of access point scans, containing enough information to make
142  * decisions about what access point to connect to.</li>
143  * <li>It defines the names of various Intent actions that are broadcast upon
144  * any sort of change in Wi-Fi state.
145  * </ul>
146  * <p>
147  * This is the API to use when performing Wi-Fi specific operations. To perform
148  * operations that pertain to network connectivity at an abstract level, use
149  * {@link android.net.ConnectivityManager}.
150  * </p>
151  */
152 @SystemService(Context.WIFI_SERVICE)
153 public class WifiManager {
154 
155     private static final String TAG = "WifiManager";
156 
157     /**
158      * Local networks should not be modified by B&R since the user may have
159      * updated it with the latest configurations.
160      * @hide
161      */
162     @ChangeId
163     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
164     public static final long NOT_OVERRIDE_EXISTING_NETWORKS_ON_RESTORE = 234793325L;
165 
166     // Supplicant error codes:
167     /**
168      * The error code if there was a problem authenticating.
169      * @deprecated This is no longer supported.
170      */
171     @Deprecated
172     public static final int ERROR_AUTHENTICATING = 1;
173 
174     /**
175      * The reason code if there is no error during authentication.
176      * It could also imply that there no authentication in progress,
177      * this reason code also serves as a reset value.
178      * @deprecated This is no longer supported.
179      * @hide
180      */
181     @Deprecated
182     public static final int ERROR_AUTH_FAILURE_NONE = 0;
183 
184     /**
185      * The reason code if there was a timeout authenticating.
186      * @deprecated This is no longer supported.
187      * @hide
188      */
189     @Deprecated
190     public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
191 
192     /**
193      * The reason code if there was a wrong password while
194      * authenticating.
195      * @deprecated This is no longer supported.
196      * @hide
197      */
198     @Deprecated
199     public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
200 
201     /**
202      * The reason code if there was EAP failure while
203      * authenticating.
204      * @deprecated This is no longer supported.
205      * @hide
206      */
207     @Deprecated
208     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
209 
210     /** @hide */
211     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM = 256;
212 
213     /** @hide */
214     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM = 1024;
215 
216     /**
217      * Reason code if all of the network suggestions were successfully added or removed.
218      */
219     public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0;
220 
221     /**
222      * Reason code if there was an internal error in the platform while processing the addition or
223      * removal of suggestions.
224      */
225     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1;
226 
227     /**
228      * Reason code if the user has disallowed "android:change_wifi_state" app-ops from the app.
229      * @see android.app.AppOpsManager#unsafeCheckOp(String, int, String).
230      */
231     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2;
232 
233     /**
234      * Reason code if one or more of the network suggestions added already exists in platform's
235      * database.
236      * Note: this code will not be returned with Android 11 as in-place modification is allowed,
237      * please check {@link #addNetworkSuggestions(List)}.
238      * @see WifiNetworkSuggestion#equals(Object)
239      */
240     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
241 
242     /**
243      * Reason code if the number of network suggestions provided by the app crosses the max
244      * threshold set per app.
245      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} if
246      * the total size exceeds the limit.
247      * @see #getMaxNumberOfNetworkSuggestionsPerApp()
248      */
249     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
250 
251     /**
252      * Reason code if one or more of the network suggestions removed does not exist in platform's
253      * database.
254      * The framework won't remove any suggestions if one or more of suggestions provided
255      * by {@link #removeNetworkSuggestions(List)} does not exist in database.
256      * @see WifiNetworkSuggestion#equals(Object)
257      */
258     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
259 
260     /**
261      * Reason code if one or more of the network suggestions added is not allowed.
262      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
263      * if one or more of them is not allowed.
264      * This error may be caused by suggestion is using SIM-based encryption method, but calling app
265      * is not carrier privileged.
266      */
267     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6;
268 
269     /**
270      * Reason code if one or more of the network suggestions added is invalid. Framework will reject
271      * all the suggestions in the list.
272      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
273      * if one or more of them is invalid.
274      * Please use {@link WifiNetworkSuggestion.Builder} to create network suggestions.
275      */
276     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7;
277 
278     /**
279      * Reason code if {@link android.os.UserManager#DISALLOW_ADD_WIFI_CONFIG} user restriction
280      * is set and calling app is restricted by device admin.
281      */
282     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_RESTRICTED_BY_ADMIN = 8;
283 
284     /** @hide */
285     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
286             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
287             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
288             STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED,
289             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
290             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
291             STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
292             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED,
293             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
294             STATUS_NETWORK_SUGGESTIONS_ERROR_RESTRICTED_BY_ADMIN,
295     })
296     @Retention(RetentionPolicy.SOURCE)
297     public @interface NetworkSuggestionsStatusCode {}
298 
299     /**
300      * Reason code if suggested network connection attempt failed with an unknown failure.
301      */
302     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN = 0;
303     /**
304      * Reason code if suggested network connection attempt failed with association failure.
305      */
306     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1;
307     /**
308      * Reason code if suggested network connection attempt failed with an authentication failure.
309      */
310     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2;
311     /**
312      * Reason code if suggested network connection attempt failed with an IP provision failure.
313      */
314     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3;
315 
316     /** @hide */
317     @IntDef(prefix = {"STATUS_SUGGESTION_CONNECTION_FAILURE_"},
318             value = {STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN,
319                     STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION,
320                     STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION,
321                     STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING
322     })
323     @Retention(RetentionPolicy.SOURCE)
324     public @interface SuggestionConnectionStatusCode {}
325 
326     /**
327      * Reason code if local-only network connection attempt failed with an unknown failure.
328      */
329     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_UNKNOWN = 0;
330     /**
331      * Reason code if local-only network connection attempt failed with association failure.
332      */
333     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_ASSOCIATION = 1;
334     /**
335      * Reason code if local-only network connection attempt failed with an authentication failure.
336      */
337     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION = 2;
338     /**
339      * Reason code if local-only network connection attempt failed with an IP provisioning failure.
340      */
341     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_IP_PROVISIONING = 3;
342     /**
343      * Reason code if local-only network connection attempt failed with AP not in range.
344      */
345     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NOT_FOUND = 4;
346     /**
347      * Reason code if local-only network connection attempt failed with AP not responding.
348      */
349     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NO_RESPONSE = 5;
350     /**
351      * Reason code if local-only network request rejected by the user.
352      */
353     @FlaggedApi(Flags.FLAG_LOCAL_ONLY_CONNECTION_OPTIMIZATION)
354     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_USER_REJECT = 6;
355 
356     /** @hide */
357     @IntDef(prefix = {"STATUS_LOCAL_ONLY_CONNECTION_FAILURE_"},
358             value = {STATUS_LOCAL_ONLY_CONNECTION_FAILURE_UNKNOWN,
359                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_ASSOCIATION,
360                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION,
361                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_IP_PROVISIONING,
362                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NOT_FOUND,
363                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NO_RESPONSE,
364                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_USER_REJECT
365             })
366     @Retention(RetentionPolicy.SOURCE)
367     public @interface LocalOnlyConnectionStatusCode {}
368 
369     /**
370      * Status code if suggestion approval status is unknown, an App which hasn't made any
371      * suggestions will get this code.
372      */
373     public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0;
374 
375     /**
376      * Status code if the calling app is still pending user approval for suggestions.
377      */
378     public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1;
379 
380     /**
381      * Status code if the calling app got the user approval for suggestions.
382      */
383     public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2;
384 
385     /**
386      * Status code if the calling app suggestions were rejected by the user.
387      */
388     public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3;
389 
390     /**
391      * Status code if the calling app was approved by virtue of being a carrier privileged app.
392      *
393      * @see android.telephony.TelephonyManager#hasCarrierPrivileges()
394      */
395     public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4;
396 
397     /** @hide */
398     @IntDef(prefix = {"STATUS_SUGGESTION_APPROVAL_"},
399             value = {STATUS_SUGGESTION_APPROVAL_UNKNOWN,
400                     STATUS_SUGGESTION_APPROVAL_PENDING,
401                     STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
402                     STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER,
403                     STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE
404             })
405     @Retention(RetentionPolicy.SOURCE)
406     public @interface SuggestionUserApprovalStatus {}
407 
408     /**
409      * Disable PNO scan until device reboot.
410      * @hide
411      */
412     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
413     @SystemApi
414     public static final int PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT = 0;
415 
416     /**
417      * Disable PNO scan until device reboot or Wi-Fi is toggled.
418      * @hide
419      */
420     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
421     @SystemApi
422     public static final int PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE = 1;
423 
424     /**
425      * Enable PNO scan.
426      * @hide
427      */
428     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
429     @SystemApi
430     public static final int PNO_SCAN_STATE_ENABLED = 2;
431 
432     /** @hide */
433     @IntDef(prefix = {"PNO_SCAN_STATE_"},
434             value = {PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT,
435                     PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE,
436                     PNO_SCAN_STATE_ENABLED
437             })
438     @Retention(RetentionPolicy.SOURCE)
439     public @interface PnoScanState {}
440 
441     /**
442      * If one of the removed suggestions is currently connected, that network will be disconnected
443      * after a short delay as opposed to immediately (which will be done by
444      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT}). The {@link ConnectivityManager} may call the
445      * {@link NetworkCallback#onLosing(Network, int)} on such networks.
446      */
447     public static final int ACTION_REMOVE_SUGGESTION_LINGER = 1;
448 
449     /**
450      * If one of the removed suggestions is currently connected, trigger an immediate disconnect
451      * after suggestions removal
452      */
453     public static final int ACTION_REMOVE_SUGGESTION_DISCONNECT = 2;
454 
455     /** @hide */
456     @IntDef(prefix = {"ACTION_REMOVE_SUGGESTION_"},
457             value = {ACTION_REMOVE_SUGGESTION_LINGER,
458                     ACTION_REMOVE_SUGGESTION_DISCONNECT
459             })
460     @Retention(RetentionPolicy.SOURCE)
461     public @interface ActionAfterRemovingSuggestion {}
462 
463     /**
464      * Only available on Android S or later.
465      * @hide
466      **/
467     public static final String EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE =
468             "EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE";
469 
470     /**
471      * Broadcast intent action indicating whether Wi-Fi scanning is currently available.
472      * Available extras:
473      * - {@link #EXTRA_SCAN_AVAILABLE}
474      */
475     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
476     public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED =
477             "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
478 
479     /**
480      * A boolean extra indicating whether scanning is currently available.
481      * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABILITY_CHANGED}.
482      * Its value is true if scanning is currently available, false otherwise.
483      */
484     public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
485 
486     /**
487      * Broadcast intent action indicating that the credential of a Wi-Fi network
488      * has been changed. One extra provides the ssid of the network. Another
489      * extra provides the event type, whether the credential is saved or forgot.
490      * @hide
491      */
492     @SystemApi
493     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
494             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
495     /** @hide */
496     @SystemApi
497     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
498     /** @hide */
499     @SystemApi
500     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
501     /** @hide */
502     @SystemApi
503     public static final int WIFI_CREDENTIAL_SAVED = 0;
504     /** @hide */
505     @SystemApi
506     public static final int WIFI_CREDENTIAL_FORGOT = 1;
507 
508     /** @hide */
509     @SystemApi
510     public static final int PASSPOINT_HOME_NETWORK = 0;
511 
512     /** @hide */
513     @SystemApi
514     public static final int PASSPOINT_ROAMING_NETWORK = 1;
515 
516     /** @hide */
517     @Retention(RetentionPolicy.SOURCE)
518     @IntDef(value = {
519             API_SCANNING_ENABLED,
520             API_WIFI_ENABLED,
521             API_SOFT_AP,
522             API_TETHERED_HOTSPOT,
523             API_AUTOJOIN_GLOBAL,
524             API_SET_SCAN_SCHEDULE,
525             API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY,
526             API_SET_NETWORK_SELECTION_CONFIG,
527             API_SET_THIRD_PARTY_APPS_ENABLING_WIFI_CONFIRMATION_DIALOG,
528             API_ADD_NETWORK,
529             API_UPDATE_NETWORK,
530             API_ALLOW_AUTOJOIN,
531             API_CONNECT_CONFIG,
532             API_CONNECT_NETWORK_ID,
533             API_DISABLE_NETWORK,
534             API_ENABLE_NETWORK,
535             API_FORGET,
536             API_SAVE,
537             API_START_SCAN,
538             API_START_LOCAL_ONLY_HOTSPOT,
539             API_P2P_DISCOVER_PEERS,
540             API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS,
541             API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY,
542             API_P2P_STOP_PEER_DISCOVERY,
543             API_P2P_CONNECT,
544             API_P2P_CANCEL_CONNECT,
545             API_P2P_CREATE_GROUP,
546             API_P2P_CREATE_GROUP_P2P_CONFIG,
547             API_P2P_REMOVE_GROUP,
548             API_P2P_START_LISTENING,
549             API_P2P_STOP_LISTENING,
550             API_P2P_SET_CHANNELS,
551             API_WIFI_SCANNER_START_SCAN,
552             API_SET_TDLS_ENABLED,
553             API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS,
554             API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS
555     })
556     public @interface ApiType {}
557 
558     /**
559      * A constant used in
560      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
561      * Tracks usage of {@link WifiScanner#setScanningEnabled(boolean)}
562      * @hide
563      */
564     @SystemApi
565     public static final int API_SCANNING_ENABLED = 1;
566     /**
567      * A constant used in
568      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
569      * Tracks usage of {@link WifiManager#setWifiEnabled(boolean)} .
570      * @hide
571      */
572     @SystemApi
573     public static final int API_WIFI_ENABLED = 2;
574     /**
575      * A constant used in
576      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
577      * Tracks usage of {@link WifiManager#startSoftAp(WifiConfiguration)} and
578      * {@link WifiManager#stopSoftAp()}.
579      * @hide
580      */
581     @SystemApi
582     public static final int API_SOFT_AP = 3;
583     /**
584      * A constant used in
585      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
586      * Tracks usage of {@link WifiManager#startTetheredHotspot(SoftApConfiguration)}.
587      * @hide
588      */
589     @SystemApi
590     public static final int API_TETHERED_HOTSPOT = 4;
591     /**
592      * A constant used in
593      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
594      * Tracks usage of {@link WifiManager#allowAutojoinGlobal(boolean)}.
595      * @hide
596      */
597     @SystemApi
598     public static final int API_AUTOJOIN_GLOBAL = 5;
599     /**
600      * A constant used in
601      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
602      * Tracks usage of {@link WifiManager#setScreenOnScanSchedule(List)}.
603      * @hide
604      */
605     @SystemApi
606     public static final int API_SET_SCAN_SCHEDULE = 6;
607 
608     /**
609      * A constant used in
610      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
611      * Tracks usage of {@link WifiManager#setOneShotScreenOnConnectivityScanDelayMillis(int)}.
612      * @hide
613      */
614     @SystemApi
615     public static final int API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY = 7;
616 
617     /**
618      * A constant used in
619      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
620      * Tracks usage of
621      * {@link WifiManager#setNetworkSelectionConfig(WifiNetworkSelectionConfig)}
622      * @hide
623      */
624     @SystemApi
625     public static final int API_SET_NETWORK_SELECTION_CONFIG = 8;
626 
627     /**
628      * A constant used in
629      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
630      * Tracks usage of
631      * {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)}
632      * @hide
633      */
634     @SystemApi
635     public static final int API_SET_THIRD_PARTY_APPS_ENABLING_WIFI_CONFIRMATION_DIALOG = 9;
636 
637     /**
638      * A constant used in
639      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
640      * Tracks usage of
641      * {@link WifiManager#addNetwork(WifiConfiguration)}
642      * @hide
643      */
644     @SystemApi
645     public static final int API_ADD_NETWORK = 10;
646 
647     /**
648      * A constant used in
649      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
650      * Tracks usage of
651      * {@link WifiManager#updateNetwork(WifiConfiguration)}
652      * @hide
653      */
654     @SystemApi
655     public static final int API_UPDATE_NETWORK = 11;
656 
657     /**
658      * A constant used in
659      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
660      * Tracks usage of
661      * {@link WifiManager#allowAutojoin(int, boolean)}
662      * @hide
663      */
664     @SystemApi
665     public static final int API_ALLOW_AUTOJOIN = 12;
666 
667     /**
668      * A constant used in
669      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
670      * Tracks usage of
671      * {@link WifiManager#connect(WifiConfiguration, ActionListener)}
672      * @hide
673      */
674     @SystemApi
675     public static final int API_CONNECT_CONFIG = 13;
676 
677     /**
678      * A constant used in
679      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
680      * Tracks usage of
681      * {@link WifiManager#connect(int, ActionListener)}
682      * @hide
683      */
684     @SystemApi
685     public static final int API_CONNECT_NETWORK_ID = 14;
686 
687     /**
688      * A constant used in
689      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
690      * Tracks usage of
691      * {@link WifiManager#disableNetwork(int)}
692      * @hide
693      */
694     @SystemApi
695     public static final int API_DISABLE_NETWORK = 15;
696 
697     /**
698      * A constant used in
699      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
700      * Tracks usage of
701      * {@link WifiManager#enableNetwork(int, boolean)}
702      * @hide
703      */
704     @SystemApi
705     public static final int API_ENABLE_NETWORK = 16;
706 
707     /**
708      * A constant used in
709      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
710      * Tracks usage of
711      * {@link WifiManager#forget(int, ActionListener)}
712      * @hide
713      */
714     @SystemApi
715     public static final int API_FORGET = 17;
716 
717     /**
718      * A constant used in
719      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
720      * Tracks usage of
721      * {@link WifiManager#save(WifiConfiguration, ActionListener)}
722      * @hide
723      */
724     @SystemApi
725     public static final int API_SAVE = 18;
726 
727     /**
728      * A constant used in
729      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
730      * Tracks usage of
731      * {@link WifiManager#startScan()}
732      * @hide
733      */
734     @SystemApi
735     public static final int API_START_SCAN = 19;
736 
737     /**
738      * A constant used in
739      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
740      * Tracks usage of
741      * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}
742      * @hide
743      */
744     @SystemApi
745     public static final int API_START_LOCAL_ONLY_HOTSPOT = 20;
746 
747     /**
748      * A constant used in
749      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
750      * Tracks usage of
751      * {@link WifiP2pManager#discoverPeers(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
752      * @hide
753      */
754     @SystemApi
755     public static final int API_P2P_DISCOVER_PEERS = 21;
756 
757     /**
758      * A constant used in
759      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
760      * Tracks usage of
761      * {@link WifiP2pManager#discoverPeersOnSocialChannels(WifiP2pManager.Channel,
762      * WifiP2pManager.ActionListener)}
763      * @hide
764      */
765     @SystemApi
766     public static final int API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS = 22;
767 
768     /**
769      * A constant used in
770      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
771      * Tracks usage of
772      * {@link WifiP2pManager#discoverPeersOnSpecificFrequency(WifiP2pManager.Channel, int,
773      * WifiP2pManager.ActionListener)}
774      * @hide
775      */
776     @SystemApi
777     public static final int API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY = 23;
778 
779     /**
780      * A constant used in
781      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
782      * Tracks usage of
783      * {@link WifiP2pManager#stopPeerDiscovery(WifiP2pManager.Channel,
784      * WifiP2pManager.ActionListener)}
785      * @hide
786      */
787     @SystemApi
788     public static final int API_P2P_STOP_PEER_DISCOVERY = 24;
789 
790     /**
791      * A constant used in
792      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
793      * Tracks usage of
794      * {@link WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
795      * WifiP2pManager.ActionListener)}
796      * @hide
797      */
798     @SystemApi
799     public static final int API_P2P_CONNECT = 25;
800 
801     /**
802      * A constant used in
803      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
804      * Tracks usage of
805      * {@link WifiP2pManager#cancelConnect(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
806      * @hide
807      */
808     @SystemApi
809     public static final int API_P2P_CANCEL_CONNECT = 26;
810 
811     /**
812      * A constant used in
813      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
814      * Tracks usage of
815      * {@link WifiP2pManager#createGroup(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
816      * @hide
817      */
818     @SystemApi
819     public static final int API_P2P_CREATE_GROUP = 27;
820 
821     /**
822      * A constant used in
823      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
824      * Tracks usage of
825      * {@link WifiP2pManager#createGroup(WifiP2pManager.Channel, WifiP2pConfig,
826      * WifiP2pManager.ActionListener)}
827      * @hide
828      */
829     @SystemApi
830     public static final int API_P2P_CREATE_GROUP_P2P_CONFIG = 28;
831 
832     /**
833      * A constant used in
834      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
835      * Tracks usage of
836      * {@link WifiP2pManager#removeGroup(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
837      * @hide
838      */
839     @SystemApi
840     public static final int API_P2P_REMOVE_GROUP = 29;
841 
842     /**
843      * A constant used in
844      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
845      * Tracks usage of
846      * {@link WifiP2pManager#startListening(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
847      * @hide
848      */
849     @SystemApi
850     public static final int API_P2P_START_LISTENING = 30;
851 
852     /**
853      * A constant used in
854      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
855      * Tracks usage of
856      * {@link WifiP2pManager#stopListening(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
857      * @hide
858      */
859     @SystemApi
860     public static final int API_P2P_STOP_LISTENING = 31;
861 
862     /**
863      * A constant used in
864      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
865      * Tracks usage of
866      * {@link WifiP2pManager#setWifiP2pChannels(WifiP2pManager.Channel, int, int,
867      * WifiP2pManager.ActionListener)}
868      * @hide
869      */
870     @SystemApi
871     public static final int API_P2P_SET_CHANNELS = 32;
872 
873     /**
874      * A constant used in
875      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
876      * Tracks usage of
877      * {@link WifiScanner#startScan(WifiScanner.ScanSettings, WifiScanner.ScanListener)}
878      * @hide
879      */
880     @SystemApi
881     public static final int API_WIFI_SCANNER_START_SCAN = 33;
882 
883     /**
884      * A constant used in
885      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
886      * Tracks usage of
887      * {@link WifiManager#setTdlsEnabled(InetAddress, boolean)} and
888      * {@link WifiManager#setTdlsEnabled(InetAddress, boolean, Executor, Consumer)}
889      * @hide
890      */
891     @SystemApi
892     public static final int API_SET_TDLS_ENABLED = 34;
893 
894     /**
895      * A constant used in
896      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
897      * Tracks usage of
898      * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean)} and
899      * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
900      * @hide
901      */
902     @SystemApi
903     public static final int API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS = 35;
904 
905     /**
906      * A constant used in {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
907      * Tracks usage of {@link WifiManager#setPnoScanState(int)}
908      *
909      * @hide
910      */
911     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
912     @SystemApi
913     public static final int API_SET_PNO_SCAN_ENABLED = 36;
914 
915     /**
916      * A constant used in {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
917      * Tracks usage of {@link WifiP2pManager#discoverPeersWithConfigParams(
918      * WifiP2pManager.Channel, WifiP2pDiscoveryConfig, WifiP2pManager.ActionListener)}
919      *
920      * @hide
921      */
922     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
923     @SystemApi
924     public static final int API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS = 37;
925 
926     /**
927      * Used internally to keep track of boundary.
928      * @hide
929      */
930     public static final int API_MAX = 38;
931 
932     /**
933      * Broadcast intent action indicating that a Passpoint provider icon has been received.
934      *
935      * Included extras:
936      * {@link #EXTRA_BSSID_LONG}
937      * {@link #EXTRA_FILENAME}
938      * {@link #EXTRA_ICON}
939      *
940      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
941      *
942      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
943      * components will be launched.
944      *
945      * @hide
946      */
947     public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
948     /**
949      * BSSID of an AP in long representation.  The {@link #EXTRA_BSSID} contains BSSID in
950      * String representation.
951      *
952      * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}.
953      *
954      * @hide
955      */
956     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
957     /**
958      * Icon data.
959      *
960      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
961      * {@link android.graphics.drawable.Icon}.
962      *
963      * @hide
964      */
965     public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
966     /**
967      * Name of a file.
968      *
969      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
970      *
971      * @hide
972      */
973     public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
974 
975     /**
976      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
977      *
978      * Included extras:
979      * {@link #EXTRA_BSSID_LONG}
980      * {@link #EXTRA_ANQP_ELEMENT_DATA}
981      *
982      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
983      *
984      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
985      * components will be launched.
986      *
987      * @hide
988      */
989     public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
990             "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
991     /**
992      * Raw binary data of an ANQP (Access Network Query Protocol) element.
993      *
994      * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}.
995      *
996      * @hide
997      */
998     public static final String EXTRA_ANQP_ELEMENT_DATA =
999             "android.net.wifi.extra.ANQP_ELEMENT_DATA";
1000 
1001     /**
1002      * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
1003      *
1004      * Included extras:
1005      * {@link #EXTRA_BSSID_LONG}
1006      * {@link #EXTRA_ESS}
1007      * {@link #EXTRA_DELAY}
1008      * {@link #EXTRA_URL}
1009      *
1010      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1011      *
1012      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
1013      * components will be launched.
1014      *
1015      * @hide
1016      */
1017     public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
1018             "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
1019     /**
1020      * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to
1021      * {@code true} for ESS.
1022      *
1023      * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}.
1024      *
1025      * @hide
1026      */
1027     public static final String EXTRA_ESS = "android.net.wifi.extra.ESS";
1028     /**
1029      * Delay in seconds.
1030      *
1031      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
1032      *
1033      * @hide
1034      */
1035     public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
1036 
1037     /**
1038      * Broadcast intent action indicating a Passpoint subscription remediation frame has been
1039      * received.
1040      *
1041      * Included extras:
1042      * {@link #EXTRA_BSSID_LONG}
1043      * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD}
1044      * {@link #EXTRA_URL}
1045      *
1046      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1047      *
1048      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
1049      * components will be launched.
1050      *
1051      * @hide
1052      */
1053     public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
1054             "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
1055     /**
1056      * The protocol supported by the subscription remediation server. The possible values are:
1057      * 0 - OMA DM
1058      * 1 - SOAP XML SPP
1059      *
1060      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
1061      *
1062      * @hide
1063      */
1064     public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD =
1065             "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
1066 
1067     /**
1068      * Activity Action: Receiver should launch Passpoint OSU (Online Sign Up) view.
1069      * Included extras:
1070      *
1071      * {@link #EXTRA_OSU_NETWORK}: {@link Network} instance associated with OSU AP.
1072      * {@link #EXTRA_URL}: String representation of a server URL used for OSU process.
1073      *
1074      * @hide
1075      */
1076     @SystemApi
1077     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1078     public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW =
1079             "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
1080 
1081     /**
1082      * The lookup key for a {@link android.net.Network} associated with a Passpoint OSU server.
1083      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
1084      *
1085      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1086      *
1087      * @hide
1088      */
1089     @SystemApi
1090     public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
1091 
1092     /**
1093      * String representation of an URL for Passpoint OSU.
1094      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
1095      *
1096      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
1097      *
1098      * @hide
1099      */
1100     @SystemApi
1101     public static final String EXTRA_URL = "android.net.wifi.extra.URL";
1102 
1103     /**
1104      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
1105      * enabling, disabling, or unknown. One extra provides this state as an int.
1106      * Another extra provides the previous state, if available.  No network-related
1107      * permissions are required to subscribe to this broadcast.
1108      *
1109      * <p class="note">This broadcast is not delivered to manifest receivers in
1110      * applications that target API version 26 or later.
1111      *
1112      * @see #EXTRA_WIFI_STATE
1113      * @see #EXTRA_PREVIOUS_WIFI_STATE
1114      */
1115     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1116     public static final String WIFI_STATE_CHANGED_ACTION =
1117         "android.net.wifi.WIFI_STATE_CHANGED";
1118     /**
1119      * The lookup key for an int that indicates whether Wi-Fi is enabled,
1120      * disabled, enabling, disabling, or unknown.  Retrieve it with
1121      * {@link android.content.Intent#getIntExtra(String,int)}.
1122      *
1123      * @see #WIFI_STATE_DISABLED
1124      * @see #WIFI_STATE_DISABLING
1125      * @see #WIFI_STATE_ENABLED
1126      * @see #WIFI_STATE_ENABLING
1127      * @see #WIFI_STATE_UNKNOWN
1128      */
1129     public static final String EXTRA_WIFI_STATE = "wifi_state";
1130     /**
1131      * The previous Wi-Fi state.
1132      *
1133      * @see #EXTRA_WIFI_STATE
1134      */
1135     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
1136 
1137     /** @hide */
1138     @IntDef(flag = false, prefix = { "WIFI_STATE_" }, value = {
1139             WIFI_STATE_DISABLING,
1140             WIFI_STATE_DISABLED,
1141             WIFI_STATE_ENABLING,
1142             WIFI_STATE_ENABLED,
1143             WIFI_STATE_UNKNOWN,
1144     })
1145     @Retention(RetentionPolicy.SOURCE)
1146     public @interface WifiState {}
1147 
1148     /**
1149      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
1150      * it finishes successfully.
1151      *
1152      * @see #WIFI_STATE_CHANGED_ACTION
1153      * @see #getWifiState()
1154      */
1155     public static final int WIFI_STATE_DISABLING = 0;
1156     /**
1157      * Wi-Fi is disabled.
1158      *
1159      * @see #WIFI_STATE_CHANGED_ACTION
1160      * @see #getWifiState()
1161      */
1162     public static final int WIFI_STATE_DISABLED = 1;
1163     /**
1164      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
1165      * it finishes successfully.
1166      *
1167      * @see #WIFI_STATE_CHANGED_ACTION
1168      * @see #getWifiState()
1169      */
1170     public static final int WIFI_STATE_ENABLING = 2;
1171     /**
1172      * Wi-Fi is enabled.
1173      *
1174      * @see #WIFI_STATE_CHANGED_ACTION
1175      * @see #getWifiState()
1176      */
1177     public static final int WIFI_STATE_ENABLED = 3;
1178     /**
1179      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
1180      * or disabling.
1181      *
1182      * @see #WIFI_STATE_CHANGED_ACTION
1183      * @see #getWifiState()
1184      */
1185     public static final int WIFI_STATE_UNKNOWN = 4;
1186 
1187     /**
1188      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
1189      * enabling, disabling, or failed.
1190      *
1191      * @hide
1192      */
1193     @SystemApi
1194     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
1195     public static final String WIFI_AP_STATE_CHANGED_ACTION =
1196         "android.net.wifi.WIFI_AP_STATE_CHANGED";
1197 
1198     /**
1199      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
1200      * disabled, enabling, disabling, or failed.  Retrieve it with
1201      * {@link android.content.Intent#getIntExtra(String,int)}.
1202      *
1203      * @see #WIFI_AP_STATE_DISABLED
1204      * @see #WIFI_AP_STATE_DISABLING
1205      * @see #WIFI_AP_STATE_ENABLED
1206      * @see #WIFI_AP_STATE_ENABLING
1207      * @see #WIFI_AP_STATE_FAILED
1208      *
1209      * @hide
1210      */
1211     @SystemApi
1212     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
1213 
1214     /**
1215      * An extra containing the int error code for Soft AP start failure.
1216      * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
1217      * {@link android.content.Intent#getIntExtra}.
1218      * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
1219      * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
1220      *
1221      * The error code will be one of:
1222      * {@link #SAP_START_FAILURE_GENERAL},
1223      * {@link #SAP_START_FAILURE_NO_CHANNEL},
1224      * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
1225      * {@link #SAP_START_FAILURE_USER_REJECTED}
1226      *
1227      * @hide
1228      */
1229     @SystemApi
1230     public static final String EXTRA_WIFI_AP_FAILURE_REASON =
1231             "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
1232     /**
1233      * The previous Wi-Fi state.
1234      *
1235      * @see #EXTRA_WIFI_AP_STATE
1236      *
1237      * @hide
1238      */
1239     @SystemApi
1240     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
1241     /**
1242      * The lookup key for a String extra that stores the interface name used for the Soft AP.
1243      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
1244      * Retrieve its value with {@link android.content.Intent#getStringExtra(String)}.
1245      *
1246      * @hide
1247      */
1248     @SystemApi
1249     public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
1250             "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
1251     /**
1252      * The lookup key for an int extra that stores the intended IP mode for this Soft AP.
1253      * One of {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
1254      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
1255      * Retrieve its value with {@link android.content.Intent#getIntExtra(String, int)}.
1256      *
1257      * @hide
1258      */
1259     @SystemApi
1260     public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
1261 
1262     /** @hide */
1263     @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
1264         WIFI_AP_STATE_DISABLING,
1265         WIFI_AP_STATE_DISABLED,
1266         WIFI_AP_STATE_ENABLING,
1267         WIFI_AP_STATE_ENABLED,
1268         WIFI_AP_STATE_FAILED,
1269     })
1270     @Retention(RetentionPolicy.SOURCE)
1271     public @interface WifiApState {}
1272 
1273     /**
1274      * Wi-Fi AP is currently being disabled. The state will change to
1275      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
1276      *
1277      * @see #WIFI_AP_STATE_CHANGED_ACTION
1278      * @see #getWifiApState()
1279      *
1280      * @hide
1281      */
1282     @SystemApi
1283     public static final int WIFI_AP_STATE_DISABLING = 10;
1284     /**
1285      * Wi-Fi AP is disabled.
1286      *
1287      * @see #WIFI_AP_STATE_CHANGED_ACTION
1288      * @see #getWifiState()
1289      *
1290      * @hide
1291      */
1292     @SystemApi
1293     public static final int WIFI_AP_STATE_DISABLED = 11;
1294     /**
1295      * Wi-Fi AP is currently being enabled. The state will change to
1296      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
1297      *
1298      * @see #WIFI_AP_STATE_CHANGED_ACTION
1299      * @see #getWifiApState()
1300      *
1301      * @hide
1302      */
1303     @SystemApi
1304     public static final int WIFI_AP_STATE_ENABLING = 12;
1305     /**
1306      * Wi-Fi AP is enabled.
1307      *
1308      * @see #WIFI_AP_STATE_CHANGED_ACTION
1309      * @see #getWifiApState()
1310      *
1311      * @hide
1312      */
1313     @SystemApi
1314     public static final int WIFI_AP_STATE_ENABLED = 13;
1315     /**
1316      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
1317      * enabling or disabling
1318      *
1319      * @see #WIFI_AP_STATE_CHANGED_ACTION
1320      * @see #getWifiApState()
1321      *
1322      * @hide
1323      */
1324     @SystemApi
1325     public static final int WIFI_AP_STATE_FAILED = 14;
1326 
1327     /** @hide */
1328     @IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = {
1329         SAP_START_FAILURE_GENERAL,
1330         SAP_START_FAILURE_NO_CHANNEL,
1331         SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION,
1332         SAP_START_FAILURE_USER_REJECTED,
1333     })
1334     @Retention(RetentionPolicy.SOURCE)
1335     public @interface SapStartFailure {}
1336 
1337     /**
1338      *  All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL},
1339      *  {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}, and
1340      *  {@link #SAP_START_FAILURE_USER_REJECTED}.
1341      *
1342      *  @hide
1343      */
1344     @SystemApi
1345     public static final int SAP_START_FAILURE_GENERAL= 0;
1346 
1347     /**
1348      *  If Wi-Fi AP start failed, this reason code means that no legal channel exists on user
1349      *  selected band due to regulatory constraints.
1350      *
1351      *  @hide
1352      */
1353     @SystemApi
1354     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
1355 
1356     /**
1357      *  If Wi-Fi AP start failed, this reason code means that the specified configuration
1358      *  is not supported by the current HAL version.
1359      *
1360      *  @hide
1361      */
1362     @SystemApi
1363     public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2;
1364 
1365     /**
1366      *  If Wi-Fi AP start failed, this reason code means that the user was asked for confirmation to
1367      *  create the AP and the user declined.
1368      *
1369      *  @hide
1370      */
1371     @SystemApi
1372     public static final int SAP_START_FAILURE_USER_REJECTED = 3;
1373 
1374     /** @hide */
1375     @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = {
1376         SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER,
1377         SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS,
1378     })
1379     @Retention(RetentionPolicy.SOURCE)
1380     public @interface SapClientBlockedReason {}
1381 
1382     /**
1383      *  If Soft Ap client is blocked, this reason code means that client doesn't exist in the
1384      *  specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
1385      *  and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
1386      *  and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
1387      *  is configured as well.
1388      *  @hide
1389      */
1390     @SystemApi
1391     public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0;
1392 
1393     /**
1394      *  If Soft Ap client is blocked, this reason code means that no more clients can be
1395      *  associated to this AP since it reached maximum capacity. The maximum capacity is
1396      *  the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and
1397      *  {@link SoftApCapability#getMaxSupportedClients} which get from
1398      *  {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}.
1399      *
1400      *  @hide
1401      */
1402     @SystemApi
1403     public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1;
1404 
1405     /**
1406      * Client disconnected for unspecified reason. This could for example be because the AP is being
1407      * shut down.
1408      * @hide
1409      */
1410     public static final int SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED = 2;
1411 
1412     /** @hide */
1413     @Retention(RetentionPolicy.SOURCE)
1414     @IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
1415             IFACE_IP_MODE_UNSPECIFIED,
1416             IFACE_IP_MODE_CONFIGURATION_ERROR,
1417             IFACE_IP_MODE_TETHERED,
1418             IFACE_IP_MODE_LOCAL_ONLY})
1419     public @interface IfaceIpMode {}
1420 
1421     /**
1422      * Interface IP mode unspecified.
1423      *
1424      * @see #updateInterfaceIpState(String, int)
1425      *
1426      * @hide
1427      */
1428     @SystemApi
1429     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
1430 
1431     /**
1432      * Interface IP mode for configuration error.
1433      *
1434      * @see #updateInterfaceIpState(String, int)
1435      *
1436      * @hide
1437      */
1438     @SystemApi
1439     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
1440 
1441     /**
1442      * Interface IP mode for tethering.
1443      *
1444      * @see #updateInterfaceIpState(String, int)
1445      *
1446      * @hide
1447      */
1448     @SystemApi
1449     public static final int IFACE_IP_MODE_TETHERED = 1;
1450 
1451     /**
1452      * Interface IP mode for Local Only Hotspot.
1453      *
1454      * @see #updateInterfaceIpState(String, int)
1455      *
1456      * @hide
1457      */
1458     @SystemApi
1459     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
1460 
1461     /**
1462      * Broadcast intent action indicating that the wifi network settings
1463      * had been reset.
1464      *
1465      * Note: This intent is sent as a directed broadcast to each manifest registered receiver.
1466      * Intent will not be received by dynamically registered receivers.
1467      * @hide
1468      */
1469     @SystemApi
1470     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
1471     public static final String ACTION_NETWORK_SETTINGS_RESET =
1472             "android.net.wifi.action.NETWORK_SETTINGS_RESET";
1473 
1474     /**
1475      * Broadcast intent action indicating that the wifi network profiles provisioned
1476      * may need refresh.
1477      *
1478      * Note: This intent is sent as a directed broadcast to each manifest registered receiver;
1479      * And restricted to those apps which have the NETWORK_CARRIER_PROVISIONING permission.
1480      * Intent will not be received by dynamically registered receivers.
1481      * @hide
1482      */
1483     @SystemApi
1484     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
1485     public static final String ACTION_REFRESH_USER_PROVISIONING =
1486             "android.net.wifi.action.REFRESH_USER_PROVISIONING";
1487 
1488     /**
1489      * Broadcast intent action indicating that a connection to the supplicant has
1490      * been established (and it is now possible
1491      * to perform Wi-Fi operations) or the connection to the supplicant has been
1492      * lost. One extra provides the connection state as a boolean, where {@code true}
1493      * means CONNECTED.
1494      * @deprecated This is no longer supported.
1495      * @see #EXTRA_SUPPLICANT_CONNECTED
1496      */
1497     @Deprecated
1498     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1499     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
1500         "android.net.wifi.supplicant.CONNECTION_CHANGE";
1501     /**
1502      * The lookup key for a boolean that indicates whether a connection to
1503      * the supplicant daemon has been gained or lost. {@code true} means
1504      * a connection now exists.
1505      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
1506      * @deprecated This is no longer supported.
1507      */
1508     @Deprecated
1509     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
1510     /**
1511      * Broadcast intent action indicating that the state of Wi-Fi connectivity
1512      * has changed. An extra provides the new state
1513      * in the form of a {@link android.net.NetworkInfo} object.  No network-related
1514      * permissions are required to subscribe to this broadcast.
1515      *
1516      * <p class="note">This broadcast is not delivered to manifest receivers in
1517      * applications that target API version 26 or later.
1518      * @see #EXTRA_NETWORK_INFO
1519      */
1520     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1521     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
1522     /**
1523      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
1524      * Wi-Fi network. Retrieve with
1525      * {@link android.content.Intent#getParcelableExtra(String)}.
1526      */
1527     public static final String EXTRA_NETWORK_INFO = "networkInfo";
1528     /**
1529      * The lookup key for a String giving the BSSID of the access point to which
1530      * we are connected. No longer used.
1531      */
1532     @Deprecated
1533     public static final String EXTRA_BSSID = "bssid";
1534     /**
1535      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
1536      * information about the access point to which we are connected.
1537      * No longer used.
1538      */
1539     @Deprecated
1540     public static final String EXTRA_WIFI_INFO = "wifiInfo";
1541     /**
1542      * Broadcast intent action indicating that the state of establishing a connection to
1543      * an access point has changed.One extra provides the new
1544      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
1545      * is not generally the most useful thing to look at if you are just interested in
1546      * the overall state of connectivity.
1547      * @see #EXTRA_NEW_STATE
1548      * @see #EXTRA_SUPPLICANT_ERROR
1549      * @deprecated This is no longer supported.
1550      */
1551     @Deprecated
1552     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1553     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
1554         "android.net.wifi.supplicant.STATE_CHANGE";
1555     /**
1556      * The lookup key for a {@link SupplicantState} describing the new state
1557      * Retrieve with
1558      * {@link android.content.Intent#getParcelableExtra(String)}.
1559      * @deprecated This is no longer supported.
1560      */
1561     @Deprecated
1562     public static final String EXTRA_NEW_STATE = "newState";
1563 
1564     /**
1565      * The lookup key for a {@link SupplicantState} describing the supplicant
1566      * error code if any
1567      * Retrieve with
1568      * {@link android.content.Intent#getIntExtra(String, int)}.
1569      * @see #ERROR_AUTHENTICATING
1570      * @deprecated This is no longer supported.
1571      */
1572     @Deprecated
1573     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
1574 
1575     /**
1576      * The lookup key for a {@link SupplicantState} describing the supplicant
1577      * error reason if any
1578      * Retrieve with
1579      * {@link android.content.Intent#getIntExtra(String, int)}.
1580      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
1581      * @deprecated This is no longer supported.
1582      * @hide
1583      */
1584     @Deprecated
1585     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
1586 
1587     /**
1588      * Broadcast intent action indicating that the configured networks changed.
1589      * This can be as a result of adding/updating/deleting a network.
1590      * <br />
1591      * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
1592      * {@link #EXTRA_WIFI_CONFIGURATION} is never set beginning in
1593      * {@link android.os.Build.VERSION_CODES#R}.
1594      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
1595      * its value is always true beginning in {@link android.os.Build.VERSION_CODES#R}, even if only
1596      * a single network changed.
1597      * <br />
1598      * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
1599      * required to receive this broadcast.
1600      *
1601      * @hide
1602      */
1603     @SystemApi
1604     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
1605         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
1606     /**
1607      * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
1608      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
1609      * broadcast is sent.
1610      * @deprecated This extra is never set beginning in {@link android.os.Build.VERSION_CODES#R},
1611      * regardless of the target SDK version. Use {@link #getConfiguredNetworks} to get the full list
1612      * of configured networks.
1613      * @hide
1614      */
1615     @Deprecated
1616     @SystemApi
1617     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
1618     /**
1619      * Multiple network configurations have changed.
1620      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
1621      * @deprecated This extra's value is always true beginning in
1622      * {@link android.os.Build.VERSION_CODES#R}, regardless of the target SDK version.
1623      * @hide
1624      */
1625     @Deprecated
1626     @SystemApi
1627     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
1628     /**
1629      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
1630      * has changed. One of {@link #CHANGE_REASON_ADDED}, {@link #CHANGE_REASON_REMOVED},
1631      * {@link #CHANGE_REASON_CONFIG_CHANGE}.
1632      *
1633      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
1634      * @hide
1635      */
1636     @SystemApi
1637     public static final String EXTRA_CHANGE_REASON = "changeReason";
1638     /**
1639      * The configuration is new and was added.
1640      * @hide
1641      */
1642     @SystemApi
1643     public static final int CHANGE_REASON_ADDED = 0;
1644     /**
1645      * The configuration was removed and is no longer present in the system's list of
1646      * configured networks.
1647      * @hide
1648      */
1649     @SystemApi
1650     public static final int CHANGE_REASON_REMOVED = 1;
1651     /**
1652      * The configuration has changed as a result of explicit action or because the system
1653      * took an automated action such as disabling a malfunctioning configuration.
1654      * @hide
1655      */
1656     @SystemApi
1657     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
1658     /**
1659      * An access point scan has completed, and results are available.
1660      * Call {@link #getScanResults()} to obtain the results.
1661      * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
1662      * and a {@code boolean} value indicating if the scan was successful.
1663      */
1664     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1665     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
1666 
1667     /**
1668      * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
1669      * representing if the scan was successful or not.
1670      * Scans may fail for multiple reasons, these may include:
1671      * <ol>
1672      * <li>An app requested too many scans in a certain period of time.
1673      * This may lead to additional scan request rejections via "scan throttling" for both
1674      * foreground and background apps.
1675      * Note: Apps holding android.Manifest.permission.NETWORK_SETTINGS permission are
1676      * exempted from scan throttling.
1677      * </li>
1678      * <li>The device is idle and scanning is disabled.</li>
1679      * <li>Wifi hardware reported a scan failure.</li>
1680      * </ol>
1681      * @return true scan was successful, results are updated
1682      * @return false scan was not successful, results haven't been updated since previous scan
1683      */
1684     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
1685 
1686     /**
1687      * A batch of access point scans has been completed and the results areavailable.
1688      * Call {@link #getBatchedScanResults()} to obtain the results.
1689      * @deprecated This API is nolonger supported.
1690      * Use {@link WifiScanner} API
1691      * @hide
1692      */
1693     @Deprecated
1694     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1695     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
1696             "android.net.wifi.BATCHED_RESULTS";
1697 
1698     /**
1699      * The RSSI (signal strength) has changed.
1700      *
1701      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1702      * @see #EXTRA_NEW_RSSI
1703      */
1704     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1705     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
1706     /**
1707      * The lookup key for an {@code int} giving the new RSSI in dBm.
1708      */
1709     public static final String EXTRA_NEW_RSSI = "newRssi";
1710 
1711     /**
1712      * @see #ACTION_LINK_CONFIGURATION_CHANGED
1713      * @hide
1714      */
1715     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1716     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
1717             "android.net.wifi.LINK_CONFIGURATION_CHANGED";
1718 
1719     /**
1720      * Broadcast intent action indicating that the link configuration changed on wifi.
1721      * <br /> No permissions are required to listen to this broadcast.
1722      * @hide
1723      */
1724     @SystemApi
1725     public static final String ACTION_LINK_CONFIGURATION_CHANGED =
1726             // should be android.net.wifi.action.LINK_CONFIGURATION_CHANGED, but due to
1727             // @UnsupportedAppUsage leaving it as android.net.wifi.LINK_CONFIGURATION_CHANGED.
1728             LINK_CONFIGURATION_CHANGED_ACTION;
1729 
1730     /**
1731      * The lookup key for a {@link android.net.LinkProperties} object associated with the
1732      * Wi-Fi network.
1733      * Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
1734      *
1735      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1736      *
1737      * @deprecated this extra is no longer populated.
1738      *
1739      * @hide
1740      */
1741     @Deprecated
1742     @SystemApi
1743     public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
1744 
1745     /**
1746      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
1747      * Wi-Fi network. Retrieve with
1748      * {@link android.content.Intent#getParcelableExtra(String)}.
1749      * @hide
1750      */
1751     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
1752 
1753     /**
1754      * The network IDs of the configured networks could have changed.
1755      */
1756     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1757     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
1758 
1759     /**
1760      * Activity Action: Show a system activity that allows the user to enable
1761      * scans to be available even with Wi-Fi turned off.
1762      *
1763      * <p>Notification of the result of this activity is posted using the
1764      * {@link android.app.Activity#onActivityResult} callback. The
1765      * <code>resultCode</code>
1766      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
1767      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
1768      * has rejected the request or an error has occurred.
1769      */
1770     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1771     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
1772             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
1773 
1774     /**
1775      * Activity Action: Pick a Wi-Fi network to connect to.
1776      * <p>Input: Nothing.
1777      * <p>Output: Nothing.
1778      */
1779     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1780     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
1781 
1782     /**
1783      * Activity Action: Receiver should show UI to get user approval to enable WiFi.
1784      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1785      *           the name of the app requesting the action.
1786      * <p>Output: Nothing.
1787      * <p>No permissions are required to send this action.
1788      * @hide
1789      */
1790     @SystemApi
1791     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1792     public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
1793 
1794     /**
1795      * Activity Action: Receiver should show UI to get user approval to disable WiFi.
1796      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1797      *           the name of the app requesting the action.
1798      * <p>Output: Nothing.
1799      * <p>No permissions are required to send this action.
1800      * @hide
1801      */
1802     @SystemApi
1803     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1804     public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
1805 
1806     /**
1807      * Directed broadcast intent action indicating that the device has connected to one of the
1808      * network suggestions provided by the app. This will be sent post connection to a network
1809      * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
1810      * boolean)}
1811      * flag set.
1812      * <p>
1813      * Note: The broadcast is sent to the app only if it holds
1814      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
1815      *
1816      * @see #EXTRA_NETWORK_SUGGESTION
1817      */
1818     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1819     public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION =
1820             "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
1821     /**
1822      * Sent as as a part of {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} that holds
1823      * an instance of {@link WifiNetworkSuggestion} corresponding to the connected network.
1824      */
1825     public static final String EXTRA_NETWORK_SUGGESTION =
1826             "android.net.wifi.extra.NETWORK_SUGGESTION";
1827 
1828     /**
1829      * Internally used Wi-Fi lock mode representing the case were no locks are held.
1830      * @hide
1831      */
1832     public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
1833 
1834     /**
1835      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1836      * and will behave normally, i.e., it will attempt to automatically
1837      * establish a connection to a remembered access point that is
1838      * within range, and will do periodic scans if there are remembered
1839      * access points but none are in range.
1840      *
1841      * @deprecated This API is non-functional and will have no impact.
1842      */
1843     @Deprecated
1844     public static final int WIFI_MODE_FULL = 1;
1845 
1846     /**
1847      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1848      * but the only operation that will be supported is initiation of
1849      * scans, and the subsequent reporting of scan results. No attempts
1850      * will be made to automatically connect to remembered access points,
1851      * nor will periodic scans be automatically performed looking for
1852      * remembered access points. Scans must be explicitly requested by
1853      * an application in this mode.
1854      *
1855      * @deprecated This API is non-functional and will have no impact.
1856      */
1857     @Deprecated
1858     public static final int WIFI_MODE_SCAN_ONLY = 2;
1859 
1860     /**
1861      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
1862      * This results in operating with low packet latency.
1863      * The lock is only active when the device is connected to an access point.
1864      * The lock is active even when the device screen is off or the acquiring application is
1865      * running in the background.
1866      * This mode will consume more power and hence should be used only
1867      * when there is a need for this tradeoff.
1868      * <p>
1869      * An example use case is when a voice connection needs to be
1870      * kept active even after the device screen goes off.
1871      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
1872      * duration of the voice call may improve the call quality.
1873      * <p>
1874      * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
1875      * lock will have no impact.
1876      *
1877      * @deprecated The {@code WIFI_MODE_FULL_HIGH_PERF} is deprecated and is automatically replaced
1878      * with {@link #WIFI_MODE_FULL_LOW_LATENCY} with all the restrictions documented on that lock.
1879      * I.e. any request to the {@code WIFI_MODE_FULL_HIGH_PERF} will now obtain a
1880      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock instead.
1881      * Deprecation is due to the impact of {@code WIFI_MODE_FULL_HIGH_PERF} on power dissipation.
1882      * The {@link #WIFI_MODE_FULL_LOW_LATENCY} provides much of the same desired functionality with
1883      * less impact on power dissipation.
1884      */
1885     @Deprecated
1886     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
1887 
1888     /**
1889      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
1890      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock has the following limitations:
1891      * <ol>
1892      * <li>The lock is only active when the device is connected to an access point.</li>
1893      * <li>The lock is only active when the screen is on.</li>
1894      * <li>The lock is only active when the acquiring app is running in the foreground.</li>
1895      * </ol>
1896      * Low latency mode optimizes for reduced packet latency,
1897      * and as a result other performance measures may suffer when there are trade-offs to make:
1898      * <ol>
1899      * <li>Battery life may be reduced.</li>
1900      * <li>Throughput may be reduced.</li>
1901      * <li>Frequency of Wi-Fi scanning may be reduced. This may result in: </li>
1902      * <ul>
1903      * <li>The device may not roam or switch to the AP with highest signal quality.</li>
1904      * <li>Location accuracy may be reduced.</li>
1905      * </ul>
1906      * </ol>
1907      * <p>
1908      * Example use cases are real time gaming or virtual reality applications where
1909      * low latency is a key factor for user experience.
1910      * <p>
1911      * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and
1912      * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY}
1913      * lock will be effective when app is running in foreground and screen is on,
1914      * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
1915      */
1916     public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
1917 
1918 
1919     /** Anything worse than or equal to this will show 0 bars. */
1920     @UnsupportedAppUsage
1921     private static final int MIN_RSSI = -100;
1922 
1923     /** Anything better than or equal to this will show the max bars. */
1924     @UnsupportedAppUsage
1925     private static final int MAX_RSSI = -55;
1926 
1927     /**
1928      * Number of RSSI levels used in the framework to initiate {@link #RSSI_CHANGED_ACTION}
1929      * broadcast, where each level corresponds to a range of RSSI values.
1930      * The {@link #RSSI_CHANGED_ACTION} broadcast will only fire if the RSSI
1931      * change is significant enough to change the RSSI signal level.
1932      * @hide
1933      */
1934     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1935     public static final int RSSI_LEVELS = 5;
1936 
1937     //TODO (b/146346676): This needs to be removed, not used in the code.
1938     /**
1939      * Auto settings in the driver. The driver could choose to operate on both
1940      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
1941      * @hide
1942      */
1943     @UnsupportedAppUsage
1944     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
1945 
1946     /**
1947      * Operation on 5 GHz alone
1948      * @hide
1949      */
1950     @UnsupportedAppUsage
1951     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
1952 
1953     /**
1954      * Operation on 2.4 GHz alone
1955      * @hide
1956      */
1957     @UnsupportedAppUsage
1958     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
1959 
1960     /** @hide */
1961     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
1962 
1963     /**
1964      * Maximum number of active locks we allow.
1965      * This limit was added to prevent apps from creating a ridiculous number
1966      * of locks and crashing the system by overflowing the global ref table.
1967      */
1968     private static final int MAX_ACTIVE_LOCKS = 50;
1969 
1970     /** Indicates an invalid SSID. */
1971     public static final String UNKNOWN_SSID = "<unknown ssid>";
1972 
1973     /** @hide */
1974     public static final MacAddress ALL_ZEROS_MAC_ADDRESS =
1975             MacAddress.fromString("00:00:00:00:00:00");
1976 
1977     /** @hide */
1978     @IntDef(flag = false, prefix = { "WIFI_MULTI_INTERNET_MODE_" }, value = {
1979         WIFI_MULTI_INTERNET_MODE_DISABLED,
1980         WIFI_MULTI_INTERNET_MODE_DBS_AP,
1981         WIFI_MULTI_INTERNET_MODE_MULTI_AP,
1982     })
1983     @Retention(RetentionPolicy.SOURCE)
1984     public @interface WifiMultiInternetMode {}
1985 
1986     /**
1987      * Wi-Fi simultaneous connection to multiple internet-providing Wi-Fi networks (APs) is
1988      * disabled.
1989      *
1990      * @see #getStaConcurrencyForMultiInternetMode()
1991      *
1992      */
1993     public static final int WIFI_MULTI_INTERNET_MODE_DISABLED = 0;
1994     /**
1995      * Wi-Fi simultaneous connection to multiple internet-providing Wi-FI networks (APs) is enabled
1996      * and restricted to a single network on different bands (e.g. a DBS AP).
1997      *
1998      * @see #getStaConcurrencyForMultiInternetMode()
1999      *
2000      */
2001     public static final int WIFI_MULTI_INTERNET_MODE_DBS_AP = 1;
2002     /**
2003      * Wi-Fi simultaneous connection to multiple internet-providing Wi-Fi networks (APs) is enabled.
2004      * The device can connect to any networks/APs - it is just restricted to using different bands
2005      * for individual connections.
2006      *
2007      * @see #getStaConcurrencyForMultiInternetMode()
2008      *
2009      */
2010     public static final int WIFI_MULTI_INTERNET_MODE_MULTI_AP = 2;
2011 
2012     /**
2013      * The bundle key string for the channel frequency in MHz.
2014      * See {@link #getChannelData(Executor, Consumer)}
2015      */
2016     public static final String CHANNEL_DATA_KEY_FREQUENCY_MHZ = "CHANNEL_DATA_KEY_FREQUENCY_MHZ";
2017     /**
2018      * The bundle key for the number of APs found on the corresponding channel specified by
2019      * {@link WifiManager#CHANNEL_DATA_KEY_FREQUENCY_MHZ}.
2020      * See {@link #getChannelData(Executor, Consumer)}
2021      */
2022     public static final String CHANNEL_DATA_KEY_NUM_AP = "CHANNEL_DATA_KEY_NUM_AP";
2023 
2024     /**
2025      * This policy is being tracked by the Wifi service.
2026      * Indicates success for {@link #addQosPolicies(List, Executor, Consumer)}.
2027      * @hide
2028      */
2029     @SystemApi
2030     public static final int QOS_REQUEST_STATUS_TRACKING = 0;
2031 
2032     /**
2033      * A policy with the same policy ID is already being tracked.
2034      * @hide
2035      */
2036     @SystemApi
2037     public static final int QOS_REQUEST_STATUS_ALREADY_ACTIVE = 1;
2038 
2039     /**
2040      * There are insufficient resources to handle this request at this time.
2041      * @hide
2042      */
2043     @SystemApi
2044     public static final int QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES = 2;
2045 
2046     /**
2047      * The parameters in the policy request are invalid.
2048      * @hide
2049      */
2050     @SystemApi
2051     public static final int QOS_REQUEST_STATUS_INVALID_PARAMETERS = 3;
2052 
2053     /**
2054      * An unspecified failure occurred while processing this request.
2055      * @hide
2056      */
2057     @SystemApi
2058     public static final int QOS_REQUEST_STATUS_FAILURE_UNKNOWN = 4;
2059 
2060     /** @hide */
2061     @Retention(RetentionPolicy.SOURCE)
2062     @IntDef(prefix = {"QOS_REQUEST_STATUS_"}, value = {
2063             QOS_REQUEST_STATUS_TRACKING,
2064             QOS_REQUEST_STATUS_ALREADY_ACTIVE,
2065             QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES,
2066             QOS_REQUEST_STATUS_INVALID_PARAMETERS,
2067             QOS_REQUEST_STATUS_FAILURE_UNKNOWN})
2068     public @interface QosRequestStatus {}
2069 
2070     /**
2071      * Maximum number of policies that can be included in a QoS add/remove request.
2072      */
2073     private static final int MAX_POLICIES_PER_QOS_REQUEST = 16;
2074 
2075     /**
2076      * Get the maximum number of policies that can be included in a request to
2077      * {@link #addQosPolicies(List, Executor, Consumer)} or {@link #removeQosPolicies(int[])}.
2078      * @hide
2079      */
2080     @SystemApi
getMaxNumberOfPoliciesPerQosRequest()2081     public static int getMaxNumberOfPoliciesPerQosRequest() {
2082         return MAX_POLICIES_PER_QOS_REQUEST;
2083     }
2084 
2085     /* Number of currently active WifiLocks and MulticastLocks */
2086     @UnsupportedAppUsage
2087     private int mActiveLockCount;
2088 
2089     private Context mContext;
2090     @UnsupportedAppUsage
2091     IWifiManager mService;
2092     private final int mTargetSdkVersion;
2093 
2094     private Looper mLooper;
2095     private boolean mVerboseLoggingEnabled = false;
2096 
2097     private final Object mLock = new Object(); // lock guarding access to the following vars
2098     @GuardedBy("mLock")
2099     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
2100     @GuardedBy("mLock")
2101     private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
2102 
2103     private static final SparseArray<IOnWifiUsabilityStatsListener>
2104             sOnWifiUsabilityStatsListenerMap = new SparseArray();
2105     private static final SparseArray<ISuggestionConnectionStatusListener>
2106             sSuggestionConnectionStatusListenerMap = new SparseArray();
2107     private static final SparseArray<ISuggestionUserApprovalStatusListener>
2108             sSuggestionUserApprovalStatusListenerMap = new SparseArray();
2109     private static final SparseArray<IWifiVerboseLoggingStatusChangedListener>
2110             sWifiVerboseLoggingStatusChangedListenerMap = new SparseArray();
2111     private static final SparseArray<INetworkRequestMatchCallback>
2112             sNetworkRequestMatchCallbackMap = new SparseArray();
2113     private static final SparseArray<ITrafficStateCallback>
2114             sTrafficStateCallbackMap = new SparseArray();
2115     private static final SparseArray<ISoftApCallback> sSoftApCallbackMap = new SparseArray();
2116     private static final SparseArray<IOnWifiDriverCountryCodeChangedListener>
2117             sActiveCountryCodeChangedCallbackMap = new SparseArray();
2118     private static final SparseArray<ISoftApCallback>
2119             sLocalOnlyHotspotSoftApCallbackMap = new SparseArray();
2120     private static final SparseArray<ILocalOnlyConnectionStatusListener>
2121             sLocalOnlyConnectionStatusListenerMap = new SparseArray();
2122     private static final SparseArray<IWifiNetworkStateChangedListener>
2123             sOnWifiNetworkStateChangedListenerMap = new SparseArray<>();
2124     private static final SparseArray<IWifiLowLatencyLockListener>
2125             sWifiLowLatencyLockListenerMap = new SparseArray<>();
2126     private static final SparseArray<IWifiStateChangedListener>
2127             sWifiStateChangedListenerMap = new SparseArray<>();
2128 
2129     /**
2130      * Multi-link operation (MLO) will allow Wi-Fi devices to operate on multiple links at the same
2131      * time through a single connection, aiming to support applications that require lower latency,
2132      * and higher capacity. Chip vendors have algorithms that run on the chip to use available links
2133      * based on incoming traffic and various inputs. Below is a list of Multi-Link Operation modes
2134      * that applications can suggest to be accommodated in the algorithm.
2135      *
2136      * The default MLO mode is for chip vendors to use algorithms to select the optimum links to
2137      * operate on, without any guidance from the calling app.
2138      *
2139      * @hide
2140      */
2141     @SystemApi
2142     public static final int MLO_MODE_DEFAULT = 0;
2143 
2144     /**
2145      * Low latency mode for Multi-link operation. In this mode, the chip vendor's algorithm
2146      * should select MLO links that will achieve low latency.
2147      *
2148      * @hide
2149      */
2150     @SystemApi
2151     public static final int MLO_MODE_LOW_LATENCY = 1;
2152 
2153     /**
2154      * High throughput mode for Multi-link operation. In this mode, the chip vendor's algorithm
2155      * should select MLO links that will achieve higher throughput.
2156      *
2157      * @hide
2158      */
2159     @SystemApi
2160     public static final int MLO_MODE_HIGH_THROUGHPUT = 2;
2161 
2162     /**
2163      * Low power mode for Multi-link operation. In this mode, the chip vendor's algorithm
2164      * should select MLO links that will achieve low power.
2165      *
2166      * @hide
2167      */
2168     @SystemApi
2169     public static final int MLO_MODE_LOW_POWER = 3;
2170 
2171     /** @hide */
2172     @Retention(RetentionPolicy.SOURCE)
2173     @IntDef(prefix = {"MLO_MODE_"}, value = {
2174             MLO_MODE_DEFAULT,
2175             MLO_MODE_LOW_LATENCY,
2176             MLO_MODE_HIGH_THROUGHPUT,
2177             MLO_MODE_LOW_POWER})
2178     public @interface MloMode {
2179     }
2180 
2181     /**
2182      * Roaming is disabled.
2183      */
2184     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
2185     public static final int ROAMING_MODE_NONE = 0;
2186 
2187     /**
2188      * Chipset has roaming trigger capability based on the score calculated
2189      * using multiple parameters. If device is configured to this mode then it
2190      * will be using chipset's normal (default) roaming.
2191      */
2192     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
2193     public static final int ROAMING_MODE_NORMAL = 1;
2194 
2195     /**
2196      * Allows the device to roam more quickly than the normal roaming mode.
2197      * Used in cases such as where APs are installed in a high density.
2198      */
2199     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
2200     public static final int ROAMING_MODE_AGGRESSIVE = 2;
2201 
2202     /**
2203      * @hide
2204      */
2205     @Retention(RetentionPolicy.SOURCE)
2206     @IntDef(prefix = {"ROAMING_MODE_"}, value = {
2207             ROAMING_MODE_NONE,
2208             ROAMING_MODE_NORMAL,
2209             ROAMING_MODE_AGGRESSIVE})
2210     public @interface RoamingMode {
2211     }
2212 
2213     /**
2214      * Create a new WifiManager instance.
2215      * Applications will almost always want to use
2216      * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve
2217      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
2218      *
2219      * @param context the application context
2220      * @param service the Binder interface
2221      * @hide - hide this because it takes in a parameter of type IWifiManager, which
2222      * is a system private class.
2223      */
WifiManager(@onNull Context context, @NonNull IWifiManager service)2224     public WifiManager(@NonNull Context context, @NonNull IWifiManager service) {
2225         mContext = context;
2226         mService = service;
2227         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
2228         updateVerboseLoggingEnabledFromService();
2229     }
2230 
2231     /**
2232      * Return a list of all the networks configured for the current foreground
2233      * user.
2234      *
2235      * Not all fields of WifiConfiguration are returned. Only the following
2236      * fields are filled in:
2237      * <ul>
2238      * <li>networkId</li>
2239      * <li>SSID</li>
2240      * <li>BSSID</li>
2241      * <li>priority</li>
2242      * <li>allowedProtocols</li>
2243      * <li>allowedKeyManagement</li>
2244      * <li>allowedAuthAlgorithms</li>
2245      * <li>allowedPairwiseCiphers</li>
2246      * <li>allowedGroupCiphers</li>
2247      * <li>status</li>
2248      * </ul>
2249      * @return a list of network configurations in the form of a list
2250      * of {@link WifiConfiguration} objects.
2251      *
2252      * @deprecated
2253      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2254      * mechanism to trigger connection to a Wi-Fi network.
2255      * b) See {@link #addNetworkSuggestions(List)},
2256      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2257      * when auto-connecting to wifi.
2258      * <b>Compatibility Note:</b> For applications targeting
2259      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return an
2260      * empty list.
2261      * <p>
2262      * Deprecation Exemptions:
2263      * <ul>
2264      * <li>Device Owner (DO), Profile Owner (PO) and system apps will have access to the full list.
2265      * <li>Callers with Carrier privilege will receive a restricted list only containing
2266      * configurations which they created.
2267      * </ul>
2268      */
2269     @Deprecated
2270     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
getConfiguredNetworks()2271     public List<WifiConfiguration> getConfiguredNetworks() {
2272         try {
2273             ParceledListSlice<WifiConfiguration> parceledList =
2274                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
2275                             mContext.getAttributionTag(), false);
2276             if (parceledList == null) {
2277                 return Collections.emptyList();
2278             }
2279             return parceledList.getList();
2280         } catch (RemoteException e) {
2281             throw e.rethrowFromSystemServer();
2282         }
2283     }
2284 
2285     /**
2286      * Return a list of all the networks previously configured by the calling app. Can
2287      * be called by Device Owner (DO), Profile Owner (PO), Callers with Carrier privilege and
2288      * system apps.
2289      *
2290      * @return a list of network configurations in the form of a list
2291      * of {@link WifiConfiguration} objects.
2292      * @throws SecurityException if the caller is not allowed to call this API
2293      */
2294     @RequiresPermission(ACCESS_WIFI_STATE)
2295     @NonNull
getCallerConfiguredNetworks()2296     public List<WifiConfiguration> getCallerConfiguredNetworks() {
2297         try {
2298             ParceledListSlice<WifiConfiguration> parceledList =
2299                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
2300                             mContext.getAttributionTag(), true);
2301             if (parceledList == null) {
2302                 return Collections.emptyList();
2303             }
2304             return parceledList.getList();
2305         } catch (RemoteException e) {
2306             throw e.rethrowFromSystemServer();
2307         }
2308     }
2309 
2310 
2311     /**
2312      * Applications targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later need to have
2313      * the following permissions: {@link android.Manifest.permission#NEARBY_WIFI_DEVICES},
2314      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
2315      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2316      * Applications targeting {@link Build.VERSION_CODES#S} or prior SDK levels need to have the
2317      * following permissions: {@link android.Manifest.permission#ACCESS_FINE_LOCATION},
2318      * {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
2319      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2320      * <p> See {@link #getPrivilegedConnectedNetwork()} to get the WifiConfiguration for only the
2321      * connected network that's providing internet by default.
2322      *
2323      * @hide
2324      **/
2325     @SystemApi
2326     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, NEARBY_WIFI_DEVICES, ACCESS_WIFI_STATE,
2327             READ_WIFI_CREDENTIAL},
2328             conditional = true)
getPrivilegedConfiguredNetworks()2329     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
2330         try {
2331             Bundle extras = new Bundle();
2332             if (SdkLevel.isAtLeastS()) {
2333                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
2334                         mContext.getAttributionSource());
2335             }
2336             ParceledListSlice<WifiConfiguration> parceledList =
2337                     mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
2338                             mContext.getAttributionTag(), extras);
2339             if (parceledList == null) {
2340                 return Collections.emptyList();
2341             }
2342             return parceledList.getList();
2343         } catch (RemoteException e) {
2344             throw e.rethrowFromSystemServer();
2345         }
2346     }
2347 
2348     /**
2349      * Gets the {@link WifiConfiguration} with credentials of the connected wifi network
2350      * that's providing internet by default.
2351      * <p>
2352      * On {@link android.os.Build.VERSION_CODES#TIRAMISU} or later SDKs, the caller need to have
2353      * the following permissions: {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2354      * android:usesPermissionFlags="neverForLocation",
2355      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
2356      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}. If the app does not have
2357      * android:usesPermissionFlags="neverForLocation", then it must also have
2358      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2359      * <p>
2360      * On {@link Build.VERSION_CODES#S} or prior SDKs, the caller need to have the
2361      * following permissions: {@link android.Manifest.permission#ACCESS_FINE_LOCATION},
2362      * {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
2363      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2364      *
2365      * @return The WifiConfiguration representation of the connected wifi network providing
2366      * internet, or null if wifi is not connected.
2367      *
2368      * @throws SecurityException if caller does not have the required permissions
2369      * @hide
2370      **/
2371     @SystemApi
2372     @RequiresPermission(allOf = {NEARBY_WIFI_DEVICES, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL},
2373             conditional = true)
2374     @Nullable
getPrivilegedConnectedNetwork()2375     public WifiConfiguration getPrivilegedConnectedNetwork() {
2376         try {
2377             Bundle extras = new Bundle();
2378             if (SdkLevel.isAtLeastS()) {
2379                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
2380                         mContext.getAttributionSource());
2381             }
2382             return mService.getPrivilegedConnectedNetwork(mContext.getOpPackageName(),
2383                     mContext.getAttributionTag(), extras);
2384         } catch (RemoteException e) {
2385             throw e.rethrowFromSystemServer();
2386         }
2387     }
2388 
2389     /**
2390      * Returns a list of all matching WifiConfigurations of PasspointConfiguration for a given list
2391      * of ScanResult.
2392      *
2393      * An empty list will be returned when no PasspointConfiguration are installed or if no
2394      * PasspointConfiguration match the ScanResult.
2395      *
2396      * @param scanResults a list of scanResult that represents the BSSID
2397      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
2398      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
2399      * @hide
2400      */
2401     @SystemApi
2402     @RequiresPermission(anyOf = {
2403             android.Manifest.permission.NETWORK_SETTINGS,
2404             android.Manifest.permission.NETWORK_SETUP_WIZARD
2405     })
2406     @NonNull
getAllMatchingWifiConfigs( @onNull List<ScanResult> scanResults)2407     public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
2408             @NonNull List<ScanResult> scanResults) {
2409         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
2410         try {
2411             Map<String, Map<Integer, List<ScanResult>>> results =
2412                     mService.getAllMatchingPasspointProfilesForScanResults(
2413                             new ParceledListSlice<>(scanResults));
2414             if (results.isEmpty()) {
2415                 return configs;
2416             }
2417             List<WifiConfiguration> wifiConfigurations =
2418                     mService.getWifiConfigsForPasspointProfiles(
2419                             new StringParceledListSlice(new ArrayList<>(results.keySet())))
2420                             .getList();
2421             for (WifiConfiguration configuration : wifiConfigurations) {
2422                 Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
2423                         results.get(configuration.getProfileKey());
2424                 if (scanResultsPerNetworkType != null) {
2425                     configs.add(Pair.create(configuration, scanResultsPerNetworkType));
2426                 }
2427             }
2428         } catch (RemoteException e) {
2429             throw e.rethrowFromSystemServer();
2430         }
2431 
2432         return configs;
2433     }
2434 
2435     /**
2436      * To be used with setScreenOnScanSchedule.
2437      * @hide
2438      */
2439     @SystemApi
2440     public static class ScreenOnScanSchedule {
2441         private final Duration mScanInterval;
2442         private final int mScanType;
2443 
2444         /**
2445          * Creates a ScreenOnScanSchedule.
2446          * @param scanInterval Interval between framework-initiated connectivity scans.
2447          * @param scanType One of the {@code WifiScanner.SCAN_TYPE_} values.
2448          */
ScreenOnScanSchedule(@onNull Duration scanInterval, @WifiAnnotations.ScanType int scanType)2449         public ScreenOnScanSchedule(@NonNull Duration scanInterval,
2450                 @WifiAnnotations.ScanType int scanType) {
2451             if (scanInterval == null) {
2452                 throw new IllegalArgumentException("scanInterval can't be null");
2453             }
2454             mScanInterval = scanInterval;
2455             mScanType = scanType;
2456         }
2457 
2458         /**
2459          * Gets the interval between framework-initiated connectivity scans.
2460          */
getScanInterval()2461         public @NonNull Duration getScanInterval() {
2462             return mScanInterval;
2463         }
2464 
2465         /**
2466          * Gets the type of scan to be used. One of the {@code WifiScanner.SCAN_TYPE_} values.
2467          */
getScanType()2468         public @WifiAnnotations.ScanType int getScanType() {
2469             return mScanType;
2470         }
2471     }
2472 
2473     /**
2474      * This API allows a privileged app to customize the wifi framework's network selection logic.
2475      * To revert to default behavior, call this API with a {@link WifiNetworkSelectionConfig}
2476      * created from a default {@link WifiNetworkSelectionConfig.Builder}.
2477      *
2478      * Use {@link WifiManager#getNetworkSelectionConfig(Executor, Consumer)} to get the current
2479      * network selection configuration.
2480      * <P>
2481      * @param nsConfig an Object representing the network selection configuration being programmed.
2482      *                 This should be created with a {@link WifiNetworkSelectionConfig.Builder}.
2483      *
2484      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2485      * @throws IllegalArgumentException if input is invalid.
2486      * @throws SecurityException if the caller does not have permission.
2487      * @hide
2488      */
2489     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2490     @RequiresPermission(anyOf = {
2491             android.Manifest.permission.NETWORK_SETTINGS,
2492             MANAGE_WIFI_NETWORK_SELECTION
2493     })
2494     @SystemApi
setNetworkSelectionConfig(@onNull WifiNetworkSelectionConfig nsConfig)2495     public void setNetworkSelectionConfig(@NonNull WifiNetworkSelectionConfig nsConfig) {
2496         try {
2497             if (nsConfig == null) {
2498                 throw new IllegalArgumentException("nsConfig can not be null");
2499             }
2500             mService.setNetworkSelectionConfig(nsConfig);
2501         } catch (RemoteException e) {
2502             throw e.rethrowFromSystemServer();
2503         }
2504     }
2505 
2506     /**
2507      * This API allows a privileged app to retrieve the {@link WifiNetworkSelectionConfig}
2508      * currently being used by the network selector.
2509      *
2510      * Use {@link WifiManager#setNetworkSelectionConfig(WifiNetworkSelectionConfig)} to set a
2511      * new network selection configuration.
2512      * <P>
2513      * @param executor The executor on which callback will be invoked.
2514      * @param resultsCallback An asynchronous callback that will return
2515      *                        {@link WifiNetworkSelectionConfig}
2516      *
2517      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2518      * @throws SecurityException if the caller does not have permission.
2519      * @throws NullPointerException if the caller provided invalid inputs.
2520      * @hide
2521      */
2522     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2523     @RequiresPermission(anyOf = {
2524             android.Manifest.permission.NETWORK_SETTINGS,
2525             MANAGE_WIFI_NETWORK_SELECTION
2526     })
2527     @SystemApi
getNetworkSelectionConfig(@onNull @allbackExecutor Executor executor, @NonNull Consumer<WifiNetworkSelectionConfig> resultsCallback)2528     public void getNetworkSelectionConfig(@NonNull @CallbackExecutor Executor executor,
2529             @NonNull Consumer<WifiNetworkSelectionConfig> resultsCallback) {
2530         Objects.requireNonNull(executor, "executor cannot be null");
2531         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
2532         try {
2533             mService.getNetworkSelectionConfig(
2534                     new IWifiNetworkSelectionConfigListener.Stub() {
2535                         @Override
2536                         public void onResult(WifiNetworkSelectionConfig value) {
2537                             Binder.clearCallingIdentity();
2538                             executor.execute(() -> {
2539                                 resultsCallback.accept(value);
2540                             });
2541                         }
2542                     });
2543         } catch (RemoteException e) {
2544             throw e.rethrowFromSystemServer();
2545         }
2546     }
2547 
2548     /**
2549      * Allows a privileged app to enable/disable whether a confirmation dialog should be displayed
2550      * when third-party apps attempt to turn on WiFi.
2551      *
2552      * Use {@link #isThirdPartyAppEnablingWifiConfirmationDialogEnabled()} to get the
2553      * currently configured value.
2554      *
2555      * Note: Only affects behavior for apps with targetSDK < Q, since third party apps are not
2556      * allowed to enable wifi on targetSDK >= Q.
2557      *
2558      * This overrides the overlay value |config_showConfirmationDialogForThirdPartyAppsEnablingWifi|
2559      * <P>
2560      * @param enable true to enable the confirmation dialog, false otherwise
2561      *
2562      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2563      * @throws SecurityException if the caller does not have permission.
2564      * @hide
2565      */
2566     @RequiresPermission(anyOf = {
2567             android.Manifest.permission.NETWORK_SETTINGS,
2568             android.Manifest.permission.NETWORK_SETUP_WIZARD
2569     })
2570     @SystemApi
setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable)2571     public void setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable) {
2572         try {
2573             mService.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(enable);
2574         } catch (RemoteException e) {
2575             throw e.rethrowFromSystemServer();
2576         }
2577     }
2578 
2579     /**
2580      * Check whether the wifi configuration indicates that a confirmation dialog should be displayed
2581      * when third-party apps attempt to turn on WiFi.
2582      *
2583      * Use {@link #setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)} to set this
2584      * value.
2585      *
2586      * Note: This setting only affects behavior for apps with targetSDK < Q, since third party apps
2587      *       are not allowed to enable wifi on targetSDK >= Q.
2588      *
2589      * <P>
2590      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2591      * @throws SecurityException if the caller does not have permission.
2592      * @return true if dialog should be displayed, false otherwise.
2593      * @hide
2594      */
2595     @RequiresPermission(anyOf = {
2596             android.Manifest.permission.NETWORK_SETTINGS,
2597             android.Manifest.permission.NETWORK_SETUP_WIZARD
2598     })
2599     @SystemApi
isThirdPartyAppEnablingWifiConfirmationDialogEnabled()2600     public boolean isThirdPartyAppEnablingWifiConfirmationDialogEnabled() {
2601         try {
2602             return mService.isThirdPartyAppEnablingWifiConfirmationDialogEnabled();
2603         } catch (RemoteException e) {
2604             throw e.rethrowFromSystemServer();
2605         }
2606     }
2607 
2608     /**
2609      * Allows a privileged app to customize the screen-on scan behavior. When a non-null schedule
2610      * is set via this API, it will always get used instead of the scan schedules defined in the
2611      * overlay. When a null schedule is set via this API, the wifi subsystem will go back to using
2612      * the scan schedules defined in the overlay. Also note, the scan schedule will be truncated
2613      * (rounded down) to the nearest whole second.
2614      * <p>
2615      * Example usage:
2616      * The following call specifies that first scheduled scan should be in 20 seconds using
2617      * {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, and all
2618      * scheduled scans later should happen every 40 seconds using
2619      * {@link WifiScanner#SCAN_TYPE_LOW_POWER}.
2620      * <pre>
2621      * List<ScreenOnScanSchedule> schedule = new ArrayList<>();
2622      * schedule.add(new ScreenOnScanSchedule(Duration.ofSeconds(20),
2623      *         WifiScanner.SCAN_TYPE_HIGH_ACCURACY));
2624      * schedule.add(new ScreenOnScanSchedule(Duration.ofSeconds(40),
2625      *         WifiScanner.SCAN_TYPE_LOW_POWER));
2626      * wifiManager.setScreenOnScanSchedule(schedule);
2627      * </pre>
2628      * @param screenOnScanSchedule defines the screen-on scan schedule and the corresponding
2629      *                             scan type. Set to null to clear any previously set value.
2630      *
2631      * @throws IllegalStateException if input is invalid
2632      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2633      * @throws SecurityException if the caller does not have permission.
2634      * @hide
2635      */
2636     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2637     @RequiresPermission(anyOf = {
2638             android.Manifest.permission.NETWORK_SETTINGS,
2639             MANAGE_WIFI_NETWORK_SELECTION
2640     })
2641     @SystemApi
setScreenOnScanSchedule(@ullable List<ScreenOnScanSchedule> screenOnScanSchedule)2642     public void setScreenOnScanSchedule(@Nullable List<ScreenOnScanSchedule> screenOnScanSchedule) {
2643         try {
2644             if (screenOnScanSchedule == null) {
2645                 mService.setScreenOnScanSchedule(null, null);
2646                 return;
2647             }
2648             if (screenOnScanSchedule.isEmpty()) {
2649                 throw new IllegalArgumentException("The input should either be null or a non-empty"
2650                         + " list");
2651             }
2652             int[] scanSchedule = new int[screenOnScanSchedule.size()];
2653             int[] scanType = new int[screenOnScanSchedule.size()];
2654             for (int i = 0; i < screenOnScanSchedule.size(); i++) {
2655                 scanSchedule[i] = (int) screenOnScanSchedule.get(i).getScanInterval().toSeconds();
2656                 scanType[i] = screenOnScanSchedule.get(i).getScanType();
2657             }
2658             mService.setScreenOnScanSchedule(scanSchedule, scanType);
2659         } catch (RemoteException e) {
2660             throw e.rethrowFromSystemServer();
2661         }
2662     }
2663 
2664     /**
2665      * The Wi-Fi framework may trigger connectivity scans in response to the screen turning on for
2666      * network selection purposes. This API allows a privileged app to set a delay to the next
2667      * connectivity scan triggered by the Wi-Fi framework in response to the next screen-on event.
2668      * This gives a window for the privileged app to issue their own custom scans to influence Wi-Fi
2669      * network selection. The expected usage is the privileged app monitor for the screen turning
2670      * off, and then call this API if it believes delaying the next screen-on connectivity scan is
2671      * needed.
2672      * <p>
2673      * Note that this API will only delay screen-on connectivity scans once. This API will need to
2674      * be called again if further screen-on scan delays are needed after it resolves.
2675      * @param delayMs defines the time in milliseconds to delay the next screen-on connectivity
2676      *                scan. Setting this to 0 will remove the delay.
2677      *
2678      * @throws IllegalStateException if input is invalid
2679      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2680      * @throws SecurityException if the caller does not have permission.
2681      * @hide
2682      */
2683     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2684     @RequiresPermission(anyOf = {
2685             android.Manifest.permission.NETWORK_SETTINGS,
2686             MANAGE_WIFI_NETWORK_SELECTION
2687     })
2688     @SystemApi
setOneShotScreenOnConnectivityScanDelayMillis(@ntRangefrom = 0) int delayMs)2689     public void setOneShotScreenOnConnectivityScanDelayMillis(@IntRange(from = 0) int delayMs) {
2690         try {
2691             mService.setOneShotScreenOnConnectivityScanDelayMillis(delayMs);
2692         } catch (RemoteException e) {
2693             throw e.rethrowFromSystemServer();
2694         }
2695     }
2696 
2697     /**
2698      * Retrieve a list of {@link WifiConfiguration} for available {@link WifiNetworkSuggestion}
2699      * matching the given list of {@link ScanResult}.
2700      *
2701      * An available {@link WifiNetworkSuggestion} must satisfy:
2702      * <ul>
2703      * <li> Matching one of the {@link ScanResult} from the given list.
2704      * <li> and {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} set
2705      * to true.
2706      * </ul>
2707      *
2708      * @param scanResults a list of scanResult.
2709      * @return a list of @link WifiConfiguration} for available {@link WifiNetworkSuggestion}
2710      * @hide
2711      */
2712     @SystemApi
2713     @RequiresPermission(anyOf = {
2714             android.Manifest.permission.NETWORK_SETTINGS,
2715             android.Manifest.permission.NETWORK_SETUP_WIZARD
2716     })
2717     @NonNull
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( @onNull List<ScanResult> scanResults)2718     public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
2719             @NonNull List<ScanResult> scanResults) {
2720         try {
2721             return mService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
2722                     new ParceledListSlice<>(scanResults)).getList();
2723         } catch (RemoteException e) {
2724             throw e.rethrowAsRuntimeException();
2725         }
2726     }
2727 
2728     /**
2729      * Specify a set of SSIDs that will not get disabled internally by the Wi-Fi subsystem when
2730      * connection issues occur. To clear the list, call this API with an empty Set.
2731      * <p>
2732      * {@link #getSsidsAllowlist()} can be used to check the SSIDs that have been set.
2733      * @param ssids - list of WifiSsid that will not get disabled internally
2734      * @throws SecurityException if the calling app is not a Device Owner (DO), Profile Owner (PO),
2735      *                           or a privileged app that has one of the permissions required by
2736      *                           this API.
2737      * @throws IllegalArgumentException if the input is null.
2738      * @hide
2739      */
2740     @SystemApi
2741     @RequiresPermission(anyOf = {
2742             android.Manifest.permission.NETWORK_SETTINGS,
2743             android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional = true)
setSsidsAllowlist(@onNull Set<WifiSsid> ssids)2744     public void setSsidsAllowlist(@NonNull Set<WifiSsid> ssids) {
2745         if (ssids == null) {
2746             throw new IllegalArgumentException(TAG + ": ssids can not be null");
2747         }
2748         try {
2749             mService.setSsidsAllowlist(mContext.getOpPackageName(),
2750                     new ParceledListSlice<>(new ArrayList<>(ssids)));
2751         } catch (RemoteException e) {
2752             throw e.rethrowFromSystemServer();
2753         }
2754     }
2755 
2756     /**
2757      * Get the Set of SSIDs that will not get disabled internally by the Wi-Fi subsystem when
2758      * connection issues occur.
2759      * @throws SecurityException if the calling app is not a Device Owner (DO), Profile Owner (PO),
2760      *                           or a privileged app that has one of the permissions required by
2761      *                           this API.
2762      * @hide
2763      */
2764     @SystemApi
2765     @RequiresPermission(anyOf = {
2766             android.Manifest.permission.NETWORK_SETTINGS,
2767             android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional = true)
getSsidsAllowlist()2768     public @NonNull Set<WifiSsid> getSsidsAllowlist() {
2769         try {
2770             return new ArraySet<WifiSsid>(
2771                     mService.getSsidsAllowlist(mContext.getOpPackageName()).getList());
2772         } catch (RemoteException e) {
2773             throw e.rethrowFromSystemServer();
2774         }
2775     }
2776 
2777     /**
2778      * Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
2779      * list of ScanResult.
2780      *
2781      * An empty list will be returned if no match is found.
2782      *
2783      * @param scanResults a list of ScanResult
2784      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
2785      * @hide
2786      */
2787     @SystemApi
2788     @RequiresPermission(anyOf = {
2789             android.Manifest.permission.NETWORK_SETTINGS,
2790             android.Manifest.permission.NETWORK_SETUP_WIZARD
2791     })
2792     @NonNull
getMatchingOsuProviders( @ullable List<ScanResult> scanResults)2793     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
2794             @Nullable List<ScanResult> scanResults) {
2795         if (scanResults == null) {
2796             return new HashMap<>();
2797         }
2798         try {
2799             return mService.getMatchingOsuProviders(new ParceledListSlice<>(scanResults));
2800         } catch (RemoteException e) {
2801             throw e.rethrowFromSystemServer();
2802         }
2803     }
2804 
2805     /**
2806      * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers.
2807      *
2808      * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2
2809      * configurations in the device.
2810      * An empty map will be returned when there is no matching Passpoint R2 configuration for the
2811      * given OsuProviders.
2812      *
2813      * @param osuProviders a set of {@link OsuProvider}
2814      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
2815      * @hide
2816      */
2817     @SystemApi
2818     @RequiresPermission(anyOf = {
2819             android.Manifest.permission.NETWORK_SETTINGS,
2820             android.Manifest.permission.NETWORK_SETUP_WIZARD
2821     })
2822     @NonNull
getMatchingPasspointConfigsForOsuProviders( @onNull Set<OsuProvider> osuProviders)2823     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
2824             @NonNull Set<OsuProvider> osuProviders) {
2825         try {
2826             return mService.getMatchingPasspointConfigsForOsuProviders(
2827                     new ParceledListSlice<>(new ArrayList<>(osuProviders)));
2828         } catch (RemoteException e) {
2829             throw e.rethrowFromSystemServer();
2830         }
2831     }
2832 
2833     /**
2834      * Add a new network description to the set of configured networks.
2835      * The {@code networkId} field of the supplied configuration object
2836      * is ignored.
2837      * <p/>
2838      * The new network will be marked DISABLED by default. To enable it,
2839      * called {@link #enableNetwork}.
2840      *
2841      * @param config the set of variables that describe the configuration,
2842      *            contained in a {@link WifiConfiguration} object.
2843      *            If the {@link WifiConfiguration} has an Http Proxy set
2844      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
2845      * @return the ID of the newly created network description. This is used in
2846      *         other operations to specified the network to be acted upon.
2847      *         Returns {@code -1} on failure.
2848      *
2849      * @deprecated
2850      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2851      * mechanism to trigger connection to a Wi-Fi network.
2852      * b) See {@link #addNetworkSuggestions(List)},
2853      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2854      * when auto-connecting to wifi.
2855      * <b>Compatibility Note:</b> For applications targeting
2856      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2857      * {@code -1}.
2858      * <p>
2859      * Deprecation Exemptions:
2860      * <ul>
2861      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2862      * </ul>
2863      */
2864     @Deprecated
addNetwork(WifiConfiguration config)2865     public int addNetwork(WifiConfiguration config) {
2866         if (config == null) {
2867             return -1;
2868         }
2869         config.networkId = -1;
2870         return addOrUpdateNetwork(config);
2871     }
2872 
2873     /**
2874      * This is a new version of {@link #addNetwork(WifiConfiguration)} which returns more detailed
2875      * failure codes. The usage of this API is limited to Device Owner (DO), Profile Owner (PO),
2876      * system app, and privileged apps.
2877      * <p>
2878      * Add a new network description to the set of configured networks. The {@code networkId}
2879      * field of the supplied configuration object is ignored. The new network will be marked
2880      * DISABLED by default. To enable it, call {@link #enableNetwork}.
2881      * <p>
2882      * @param config the set of variables that describe the configuration,
2883      *            contained in a {@link WifiConfiguration} object.
2884      *            If the {@link WifiConfiguration} has an Http Proxy set
2885      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
2886      * @return A {@link AddNetworkResult} Object.
2887      * @throws SecurityException if the calling app is not a Device Owner (DO),
2888      *                           Profile Owner (PO), system app, or a privileged app that has one of
2889      *                           the permissions required by this API.
2890      * @throws IllegalArgumentException if the input configuration is null or if the
2891      *            security type in input configuration is not supported.
2892      */
2893     @RequiresPermission(anyOf = {
2894             android.Manifest.permission.NETWORK_SETTINGS,
2895             android.Manifest.permission.NETWORK_STACK,
2896             android.Manifest.permission.NETWORK_SETUP_WIZARD,
2897             android.Manifest.permission.NETWORK_MANAGED_PROVISIONING
2898             }, conditional = true)
2899     @NonNull
addNetworkPrivileged(@onNull WifiConfiguration config)2900     public AddNetworkResult addNetworkPrivileged(@NonNull WifiConfiguration config) {
2901         if (config == null) throw new IllegalArgumentException("config cannot be null");
2902         if (config.isSecurityType(WifiInfo.SECURITY_TYPE_DPP)
2903                 && !isFeatureSupported(WIFI_FEATURE_DPP_AKM)) {
2904             throw new IllegalArgumentException("dpp akm is not supported");
2905         }
2906         config.networkId = -1;
2907         try {
2908             return mService.addOrUpdateNetworkPrivileged(config, mContext.getOpPackageName());
2909         } catch (RemoteException e) {
2910             throw e.rethrowFromSystemServer();
2911         }
2912     }
2913 
2914     /**
2915      * Provides the results of a call to {@link #addNetworkPrivileged(WifiConfiguration)}
2916      */
2917     public static final class AddNetworkResult implements Parcelable {
2918         /**
2919          * The operation has completed successfully.
2920          */
2921         public static final int STATUS_SUCCESS = 0;
2922         /**
2923          * The operation has failed due to an unknown reason.
2924          */
2925         public static final int STATUS_FAILURE_UNKNOWN = 1;
2926         /**
2927          * The calling app does not have permission to call this API.
2928          */
2929         public static final int STATUS_NO_PERMISSION = 2;
2930         /**
2931          * Generic failure code for adding a passpoint network.
2932          */
2933         public static final int STATUS_ADD_PASSPOINT_FAILURE = 3;
2934         /**
2935          * Generic failure code for adding a non-passpoint network.
2936          */
2937         public static final int STATUS_ADD_WIFI_CONFIG_FAILURE = 4;
2938         /**
2939          * The network configuration is invalid.
2940          */
2941         public static final int STATUS_INVALID_CONFIGURATION = 5;
2942         /**
2943          * The calling app has no permission to modify the configuration.
2944          */
2945         public static final int STATUS_NO_PERMISSION_MODIFY_CONFIG = 6;
2946         /**
2947          * The calling app has no permission to modify the proxy setting.
2948          */
2949         public static final int STATUS_NO_PERMISSION_MODIFY_PROXY_SETTING = 7;
2950         /**
2951          * The calling app has no permission to modify the MAC randomization setting.
2952          */
2953         public static final int STATUS_NO_PERMISSION_MODIFY_MAC_RANDOMIZATION = 8;
2954         /**
2955          * Internal failure in updating network keys..
2956          */
2957         public static final int STATUS_FAILURE_UPDATE_NETWORK_KEYS = 9;
2958         /**
2959          * The enterprise network is missing either the root CA or domain name.
2960          */
2961         public static final int STATUS_INVALID_CONFIGURATION_ENTERPRISE = 10;
2962 
2963         /** @hide */
2964         @IntDef(prefix = { "STATUS_" }, value = {
2965                 STATUS_SUCCESS,
2966                 STATUS_FAILURE_UNKNOWN,
2967                 STATUS_NO_PERMISSION,
2968                 STATUS_ADD_PASSPOINT_FAILURE,
2969                 STATUS_ADD_WIFI_CONFIG_FAILURE,
2970                 STATUS_INVALID_CONFIGURATION,
2971                 STATUS_NO_PERMISSION_MODIFY_CONFIG,
2972                 STATUS_NO_PERMISSION_MODIFY_PROXY_SETTING,
2973                 STATUS_NO_PERMISSION_MODIFY_MAC_RANDOMIZATION,
2974                 STATUS_FAILURE_UPDATE_NETWORK_KEYS,
2975                 STATUS_INVALID_CONFIGURATION_ENTERPRISE,
2976         })
2977         @Retention(RetentionPolicy.SOURCE)
2978         public @interface AddNetworkStatusCode {}
2979 
2980         @Override
describeContents()2981         public int describeContents() {
2982             return 0;
2983         }
2984 
2985         @Override
writeToParcel(@onNull Parcel dest, int flags)2986         public void writeToParcel(@NonNull Parcel dest, int flags) {
2987             dest.writeInt(statusCode);
2988             dest.writeInt(networkId);
2989         }
2990 
2991         /** Implement the Parcelable interface */
2992         public static final @android.annotation.NonNull Creator<AddNetworkResult> CREATOR =
2993                 new Creator<AddNetworkResult>() {
2994                     public AddNetworkResult createFromParcel(Parcel in) {
2995                         return new AddNetworkResult(in.readInt(), in.readInt());
2996                     }
2997 
2998                     public AddNetworkResult[] newArray(int size) {
2999                         return new AddNetworkResult[size];
3000                     }
3001                 };
3002 
3003         /**
3004          * One of the {@code STATUS_} values. If the operation is successful this field
3005          * will be set to {@code STATUS_SUCCESS}.
3006          */
3007         public final @AddNetworkStatusCode int statusCode;
3008         /**
3009          * The identifier of the added network, which could be used in other operations. This field
3010          * will be set to {@code -1} if the operation failed.
3011          */
3012         public final int networkId;
3013 
AddNetworkResult(@ddNetworkStatusCode int statusCode, int networkId)3014         public AddNetworkResult(@AddNetworkStatusCode int statusCode, int networkId) {
3015             this.statusCode = statusCode;
3016             this.networkId = networkId;
3017         }
3018     }
3019 
3020     /**
3021      * Update the network description of an existing configured network.
3022      *
3023      * @param config the set of variables that describe the configuration,
3024      *            contained in a {@link WifiConfiguration} object. It may
3025      *            be sparse, so that only the items that are being changed
3026      *            are non-<code>null</code>. The {@code networkId} field
3027      *            must be set to the ID of the existing network being updated.
3028      *            If the {@link WifiConfiguration} has an Http Proxy set
3029      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
3030      * @return Returns the {@code networkId} of the supplied
3031      *         {@code WifiConfiguration} on success.
3032      *         <br/>
3033      *         Returns {@code -1} on failure, including when the {@code networkId}
3034      *         field of the {@code WifiConfiguration} does not refer to an
3035      *         existing network.
3036      *
3037      * @deprecated
3038      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3039      * mechanism to trigger connection to a Wi-Fi network.
3040      * b) See {@link #addNetworkSuggestions(List)},
3041      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3042      * when auto-connecting to wifi.
3043      * <b>Compatibility Note:</b> For applications targeting
3044      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3045      * {@code -1}.
3046      * <p>
3047      * Deprecation Exemptions:
3048      * <ul>
3049      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3050      * </ul>
3051      */
3052     @Deprecated
updateNetwork(WifiConfiguration config)3053     public int updateNetwork(WifiConfiguration config) {
3054         if (config == null || config.networkId < 0) {
3055             return -1;
3056         }
3057         return addOrUpdateNetwork(config);
3058     }
3059 
3060     /**
3061      * Internal method for doing the RPC that creates a new network description
3062      * or updates an existing one.
3063      *
3064      * @param config The possibly sparse object containing the variables that
3065      *         are to set or updated in the network description.
3066      * @return the ID of the network on success, {@code -1} on failure.
3067      */
addOrUpdateNetwork(WifiConfiguration config)3068     private int addOrUpdateNetwork(WifiConfiguration config) {
3069         Bundle extras = new Bundle();
3070         if (SdkLevel.isAtLeastS()) {
3071             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
3072                     mContext.getAttributionSource());
3073         }
3074 
3075         try {
3076             return mService.addOrUpdateNetwork(config, mContext.getOpPackageName(), extras);
3077         } catch (RemoteException e) {
3078             throw e.rethrowFromSystemServer();
3079         }
3080     }
3081 
3082     /**
3083      * Interface for indicating user selection from the list of networks presented in the
3084      * {@link NetworkRequestMatchCallback#onMatch(List)}.
3085      *
3086      * The platform will implement this callback and pass it along with the
3087      * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
3088      * NetworkRequestUserSelectionCallback)}. The UI component handling
3089      * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
3090      * {@link #reject()} to return the user's selection back to the platform via this callback.
3091      * @hide
3092      */
3093     @SystemApi
3094     public interface NetworkRequestUserSelectionCallback {
3095         /**
3096          * User selected this network to connect to.
3097          * @param wifiConfiguration WifiConfiguration object corresponding to the network
3098          *                          user selected.
3099          */
3100         @SuppressLint("CallbackMethodName")
select(@onNull WifiConfiguration wifiConfiguration)3101         default void select(@NonNull WifiConfiguration wifiConfiguration) {}
3102 
3103         /**
3104          * User rejected the app's request.
3105          */
3106         @SuppressLint("CallbackMethodName")
reject()3107         default void reject() {}
3108     }
3109 
3110     /**
3111      * Interface for network request callback. Should be implemented by applications and passed when
3112      * calling {@link #registerNetworkRequestMatchCallback(Executor,
3113      * WifiManager.NetworkRequestMatchCallback)}.
3114      *
3115      * This is meant to be implemented by a UI component to present the user with a list of networks
3116      * matching the app's request. The user is allowed to pick one of these networks to connect to
3117      * or reject the request by the app.
3118      * @hide
3119      */
3120     @SystemApi
3121     public interface NetworkRequestMatchCallback {
3122         /**
3123          * Invoked to register a callback to be invoked to convey user selection. The callback
3124          * object passed in this method is to be invoked by the UI component after the service sends
3125          * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
3126          * from that list.
3127          *
3128          * @param userSelectionCallback Callback object to send back the user selection.
3129          */
onUserSelectionCallbackRegistration( @onNull NetworkRequestUserSelectionCallback userSelectionCallback)3130         default void onUserSelectionCallbackRegistration(
3131                 @NonNull NetworkRequestUserSelectionCallback userSelectionCallback) {}
3132 
3133         /**
3134          * Invoked when the active network request is aborted, either because
3135          * <li> The app released the request, OR</li>
3136          * <li> Request was overridden by a new request</li>
3137          * This signals the end of processing for the current request and should stop the UI
3138          * component. No subsequent calls from the UI component will be handled by the platform.
3139          */
onAbort()3140         default void onAbort() {}
3141 
3142         /**
3143          * Invoked when a network request initiated by an app matches some networks in scan results.
3144          * This may be invoked multiple times for a single network request as the platform finds new
3145          * matching networks in scan results.
3146          *
3147          * @param scanResults List of {@link ScanResult} objects corresponding to the networks
3148          *                    matching the request.
3149          */
onMatch(@onNull List<ScanResult> scanResults)3150         default void onMatch(@NonNull List<ScanResult> scanResults) {}
3151 
3152         /**
3153          * Invoked on a successful connection with the network that the user selected
3154          * via {@link NetworkRequestUserSelectionCallback}.
3155          *
3156          * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
3157          *                          user selected.
3158          */
onUserSelectionConnectSuccess(@onNull WifiConfiguration wifiConfiguration)3159         default void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration) {}
3160 
3161         /**
3162          * Invoked on failure to establish connection with the network that the user selected
3163          * via {@link NetworkRequestUserSelectionCallback}.
3164          *
3165          * @param wifiConfiguration WifiConfiguration object corresponding to the network
3166          *                          user selected.
3167          */
onUserSelectionConnectFailure(@onNull WifiConfiguration wifiConfiguration)3168         default void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration) {}
3169     }
3170 
3171     /**
3172      * Callback proxy for NetworkRequestUserSelectionCallback objects.
3173      * @hide
3174      */
3175     private class NetworkRequestUserSelectionCallbackProxy implements
3176             NetworkRequestUserSelectionCallback {
3177         private final INetworkRequestUserSelectionCallback mCallback;
3178 
NetworkRequestUserSelectionCallbackProxy( INetworkRequestUserSelectionCallback callback)3179         NetworkRequestUserSelectionCallbackProxy(
3180                 INetworkRequestUserSelectionCallback callback) {
3181             mCallback = callback;
3182         }
3183 
3184         @Override
select(@onNull WifiConfiguration wifiConfiguration)3185         public void select(@NonNull WifiConfiguration wifiConfiguration) {
3186             if (mVerboseLoggingEnabled) {
3187                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
3188                         + "wificonfiguration: " + wifiConfiguration);
3189             }
3190             try {
3191                 mCallback.select(wifiConfiguration);
3192             } catch (RemoteException e) {
3193                 Log.e(TAG, "Failed to invoke onSelected", e);
3194                 throw e.rethrowFromSystemServer();
3195             }
3196         }
3197 
3198         @Override
reject()3199         public void reject() {
3200             if (mVerboseLoggingEnabled) {
3201                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
3202             }
3203             try {
3204                 mCallback.reject();
3205             } catch (RemoteException e) {
3206                 Log.e(TAG, "Failed to invoke onRejected", e);
3207                 throw e.rethrowFromSystemServer();
3208             }
3209         }
3210     }
3211 
3212     /**
3213      * Callback proxy for NetworkRequestMatchCallback objects.
3214      * @hide
3215      */
3216     private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
3217         private final Executor mExecutor;
3218         private final NetworkRequestMatchCallback mCallback;
3219 
NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback)3220         NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback) {
3221             mExecutor = executor;
3222             mCallback = callback;
3223         }
3224 
3225         @Override
onUserSelectionCallbackRegistration( INetworkRequestUserSelectionCallback userSelectionCallback)3226         public void onUserSelectionCallbackRegistration(
3227                 INetworkRequestUserSelectionCallback userSelectionCallback) {
3228             if (mVerboseLoggingEnabled) {
3229                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
3230                         + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
3231             }
3232             Binder.clearCallingIdentity();
3233             mExecutor.execute(() -> {
3234                 mCallback.onUserSelectionCallbackRegistration(
3235                         new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
3236             });
3237         }
3238 
3239         @Override
onAbort()3240         public void onAbort() {
3241             if (mVerboseLoggingEnabled) {
3242                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onAbort");
3243             }
3244             Binder.clearCallingIdentity();
3245             mExecutor.execute(() -> {
3246                 mCallback.onAbort();
3247             });
3248         }
3249 
3250         @Override
onMatch(List<ScanResult> scanResults)3251         public void onMatch(List<ScanResult> scanResults) {
3252             if (mVerboseLoggingEnabled) {
3253                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch scanResults: "
3254                         + scanResults);
3255             }
3256             Binder.clearCallingIdentity();
3257             mExecutor.execute(() -> {
3258                 mCallback.onMatch(scanResults);
3259             });
3260         }
3261 
3262         @Override
onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration)3263         public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
3264             if (mVerboseLoggingEnabled) {
3265                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
3266                         + " wificonfiguration: " + wifiConfiguration);
3267             }
3268             Binder.clearCallingIdentity();
3269             mExecutor.execute(() -> {
3270                 mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
3271             });
3272         }
3273 
3274         @Override
onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration)3275         public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
3276             if (mVerboseLoggingEnabled) {
3277                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
3278                         + " wificonfiguration: " + wifiConfiguration);
3279             }
3280             Binder.clearCallingIdentity();
3281             mExecutor.execute(() -> {
3282                 mCallback.onUserSelectionConnectFailure(wifiConfiguration);
3283             });
3284         }
3285     }
3286 
3287     /**
3288      * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
3289      * Caller can unregister a previously registered callback using
3290      * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
3291      * <p>
3292      * Applications should have the
3293      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
3294      * without the permission will trigger a {@link java.lang.SecurityException}.
3295      * <p>
3296      *
3297      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
3298      *                 object.
3299      * @param callback Callback for network match events to register.
3300      * @hide
3301      */
3302     @SystemApi
3303     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerNetworkRequestMatchCallback(@onNull @allbackExecutor Executor executor, @NonNull NetworkRequestMatchCallback callback)3304     public void registerNetworkRequestMatchCallback(@NonNull @CallbackExecutor Executor executor,
3305             @NonNull NetworkRequestMatchCallback callback) {
3306         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
3307         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3308         Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
3309                 + ", executor=" + executor);
3310 
3311         try {
3312             synchronized (sNetworkRequestMatchCallbackMap) {
3313                 INetworkRequestMatchCallback.Stub binderCallback =
3314                         new NetworkRequestMatchCallbackProxy(executor, callback);
3315                 sNetworkRequestMatchCallbackMap.put(System.identityHashCode(callback),
3316                         binderCallback);
3317                 mService.registerNetworkRequestMatchCallback(binderCallback);
3318             }
3319         } catch (RemoteException e) {
3320             throw e.rethrowFromSystemServer();
3321         }
3322     }
3323 
3324     /**
3325      * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
3326      * <p>
3327      * Applications should have the
3328      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
3329      * without the permission will trigger a {@link java.lang.SecurityException}.
3330      * <p>
3331      *
3332      * @param callback Callback for network match events to unregister.
3333      * @hide
3334      */
3335     @SystemApi
3336     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterNetworkRequestMatchCallback( @onNull NetworkRequestMatchCallback callback)3337     public void unregisterNetworkRequestMatchCallback(
3338             @NonNull NetworkRequestMatchCallback callback) {
3339         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3340         Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
3341 
3342         try {
3343             synchronized (sNetworkRequestMatchCallbackMap) {
3344                 int callbackIdentifier = System.identityHashCode(callback);
3345                 if (!sNetworkRequestMatchCallbackMap.contains(callbackIdentifier)) {
3346                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
3347                     return;
3348                 }
3349                 mService.unregisterNetworkRequestMatchCallback(
3350                         sNetworkRequestMatchCallbackMap.get(callbackIdentifier));
3351                 sNetworkRequestMatchCallbackMap.remove(callbackIdentifier);
3352             }
3353         } catch (RemoteException e) {
3354             throw e.rethrowFromSystemServer();
3355         }
3356     }
3357 
3358     /**
3359      * Privileged API to revoke all app state from wifi stack (equivalent to operations that the
3360      * wifi stack performs to clear state for an app that was uninstalled.
3361      * This removes:
3362      * <li> All saved networks or passpoint profiles added by the app </li>
3363      * <li> All previously approved peer to peer connection to access points initiated by the app
3364      * using {@link WifiNetworkSpecifier}</li>
3365      * <li> All network suggestions and approvals provided using {@link WifiNetworkSuggestion}</li>
3366      * <p>
3367      * @param targetAppUid UID of the app.
3368      * @param targetAppPackageName Package name of the app.
3369      * @hide
3370      */
3371     @SystemApi
3372     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
removeAppState(int targetAppUid, @NonNull String targetAppPackageName)3373     public void removeAppState(int targetAppUid, @NonNull String targetAppPackageName) {
3374         try {
3375             mService.removeAppState(targetAppUid, targetAppPackageName);
3376         } catch (RemoteException e) {
3377             throw e.rethrowAsRuntimeException();
3378         }
3379     }
3380 
3381     /**
3382      * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
3383      * for a detailed explanation of the parameters.
3384      * When the device decides to connect to one of the provided network suggestions, platform sends
3385      * a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
3386      * the network was created with
3387      * {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(boolean)} flag set and the
3388      * app holds {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
3389      * permission.
3390      *<p>
3391      * NOTE:
3392      * <ul>
3393      * <li> These networks are just a suggestion to the platform. The platform will ultimately
3394      * decide on which network the device connects to. </li>
3395      * <li> When an app is uninstalled or disabled, all its suggested networks are discarded.
3396      * If the device is currently connected to a suggested network which is being removed then the
3397      * device will disconnect from that network.</li>
3398      * <li> If user reset network settings, all added suggestions will be discarded. Apps can use
3399      * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
3400      * <li> In-place modification of existing suggestions are allowed.</li>
3401      * <ul>
3402      * <li> If the provided suggestions include any previously provided suggestions by the app,
3403      * previous suggestions will be updated.</li>
3404      * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and
3405      * the device is currently connected to that suggested network, then the device will disconnect
3406      * from that network. The system will immediately re-evaluate all the network candidates
3407      * and possibly reconnect back to the same suggestion. This disconnect is to make sure that any
3408      * traffic flowing over unmetered networks isn't accidentally continued over a metered network.
3409      * </li>
3410      * <li>
3411      * On {@link android.os.Build.VERSION_CODES#TIRAMISU} or above If one of the provided
3412      * suggestions marks a previously trusted suggestion as untrusted and the device is currently
3413      * connected to that suggested network, then the device will disconnect from that network. The
3414      * system will immediately re-evaluate all the network candidates. This disconnect is to make
3415      * sure device will not remain connected to an untrusted network without a related
3416      * {@link android.net.NetworkRequest}.
3417      * </li>
3418      * </ul>
3419      * </ul>
3420      *
3421      * @param networkSuggestions List of network suggestions provided by the app.
3422      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
3423      * @throws SecurityException if the caller is missing required permissions.
3424      * @see WifiNetworkSuggestion#equals(Object)
3425      */
3426     @RequiresPermission(CHANGE_WIFI_STATE)
addNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)3427     public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
3428             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
3429         try {
3430             return mService.addNetworkSuggestions(new ParceledListSlice<>(networkSuggestions),
3431                     mContext.getOpPackageName(), mContext.getAttributionTag());
3432         } catch (RemoteException e) {
3433             throw e.rethrowFromSystemServer();
3434         }
3435     }
3436 
3437     /**
3438      * Remove some or all of the network suggestions that were previously provided by the app.
3439      * If one of the suggestions being removed was used to establish connection to the current
3440      * network, then the device will immediately disconnect from that network. This method is same
3441      * as {@link #removeNetworkSuggestions(List, int)} with
3442      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT}
3443      *
3444      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
3445      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
3446      * <p></
3447      * Note: Use {@link #removeNetworkSuggestions(List, int)}. An {@code action} of
3448      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT} is equivalent to the current behavior.
3449      *
3450      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
3451      *                           to remove all the previous suggestions provided by the app.
3452      * @return Status code for the operation. One of the {@code STATUS_NETWORK_SUGGESTIONS_*}
3453      * values. Any matching suggestions are removed from the device and will not be considered for
3454      * any further connection attempts.
3455      */
3456     @RequiresPermission(CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)3457     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
3458             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
3459         return removeNetworkSuggestions(networkSuggestions, ACTION_REMOVE_SUGGESTION_DISCONNECT);
3460     }
3461 
3462     /**
3463      * Remove some or all of the network suggestions that were previously provided by the app.
3464      * If one of the suggestions being removed was used to establish connection to the current
3465      * network, then the specified action will be executed.
3466      *
3467      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
3468      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
3469      *
3470      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
3471      *                           to remove all the previous suggestions provided by the app.
3472      * @param action Desired action to execute after removing the suggestion. One of
3473      *               {@code ACTION_REMOVE_SUGGESTION_*}
3474      * @return Status code for the operation. One of the {@code STATUS_NETWORK_SUGGESTIONS_*}
3475      * values. Any matching suggestions are removed from the device and will not be considered for
3476      * further connection attempts.
3477      */
3478     @RequiresPermission(CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions, @ActionAfterRemovingSuggestion int action)3479     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
3480             @NonNull List<WifiNetworkSuggestion> networkSuggestions,
3481             @ActionAfterRemovingSuggestion int action) {
3482         try {
3483             return mService.removeNetworkSuggestions(new ParceledListSlice<>(networkSuggestions),
3484                     mContext.getOpPackageName(), action);
3485         } catch (RemoteException e) {
3486             throw e.rethrowFromSystemServer();
3487         }
3488     }
3489 
3490     /**
3491      * Get all network suggestions provided by the calling app.
3492      * See {@link #addNetworkSuggestions(List)}
3493      * See {@link #removeNetworkSuggestions(List)}
3494      * @return a list of {@link WifiNetworkSuggestion}
3495      */
3496     @RequiresPermission(ACCESS_WIFI_STATE)
getNetworkSuggestions()3497     public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
3498         try {
3499             return mService.getNetworkSuggestions(mContext.getOpPackageName()).getList();
3500         } catch (RemoteException e) {
3501             throw e.rethrowAsRuntimeException();
3502         }
3503     }
3504 
3505     /**
3506      * Returns the max number of network suggestions that are allowed per app on the device.
3507      * @see #addNetworkSuggestions(List)
3508      * @see #removeNetworkSuggestions(List)
3509      */
getMaxNumberOfNetworkSuggestionsPerApp()3510     public int getMaxNumberOfNetworkSuggestionsPerApp() {
3511         return getMaxNumberOfNetworkSuggestionsPerApp(
3512                 mContext.getSystemService(ActivityManager.class).isLowRamDevice());
3513     }
3514 
3515     /** @hide */
getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice)3516     public static int getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice) {
3517         return isLowRamDevice
3518                 ? NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM
3519                 : NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM;
3520     }
3521 
3522     /**
3523      * Add or update a Passpoint configuration.  The configuration provides a credential
3524      * for connecting to Passpoint networks that are operated by the Passpoint
3525      * service provider specified in the configuration.
3526      *
3527      * Each configuration is uniquely identified by a unique key which depends on the contents of
3528      * the configuration. This allows the caller to install multiple profiles with the same FQDN
3529      * (Fully qualified domain name). Therefore, in order to update an existing profile, it is
3530      * first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
3531      * Otherwise, a new profile will be added with both configuration.
3532      *
3533      * Deprecated for general app usage - except DO/PO apps.
3534      * See {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} to
3535      * create a passpoint suggestion.
3536      * See {@link #addNetworkSuggestions(List)}, {@link #removeNetworkSuggestions(List)} for new
3537      * API to add Wi-Fi networks for consideration when auto-connecting to wifi.
3538      * <b>Compatibility Note:</b> For applications targeting
3539      * {@link android.os.Build.VERSION_CODES#R} or above, this API will always fail and throw
3540      * {@link IllegalArgumentException}.
3541      * <p>
3542      * Deprecation Exemptions:
3543      * <ul>
3544      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3545      * </ul>
3546      *
3547      * @param config The Passpoint configuration to be added
3548      * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
3549      *                                  the device.
3550      */
addOrUpdatePasspointConfiguration(PasspointConfiguration config)3551     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
3552         try {
3553             if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
3554                 throw new IllegalArgumentException();
3555             }
3556         } catch (RemoteException e) {
3557             throw e.rethrowFromSystemServer();
3558         }
3559     }
3560 
3561     /**
3562      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name) added
3563      * by the caller.
3564      *
3565      * @param fqdn The FQDN of the Passpoint configuration added by the caller to be removed
3566      * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
3567      *                                  Passpoint is not enabled on the device.
3568      * @deprecated This will be non-functional in a future release.
3569      * <br>
3570      * Requires {@code android.Manifest.permission.NETWORK_SETTINGS} or
3571      * {@code android.Manifest.permission.NETWORK_CARRIER_PROVISIONING}.
3572      */
3573     @Deprecated
removePasspointConfiguration(String fqdn)3574     public void removePasspointConfiguration(String fqdn) {
3575         try {
3576             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
3577                 throw new IllegalArgumentException();
3578             }
3579         } catch (RemoteException e) {
3580             throw e.rethrowFromSystemServer();
3581         }
3582     }
3583 
3584     /**
3585      * Return the list of installed Passpoint configurations added by the caller.
3586      *
3587      * An empty list will be returned when no configurations are installed.
3588      *
3589      * @return A list of {@link PasspointConfiguration} added by the caller
3590      * @deprecated This will be non-functional in a future release.
3591      * <br>
3592      * Requires {@code android.Manifest.permission.NETWORK_SETTINGS} or
3593      * {@code android.Manifest.permission.NETWORK_SETUP_WIZARD}.
3594      */
3595     @Deprecated
getPasspointConfigurations()3596     public List<PasspointConfiguration> getPasspointConfigurations() {
3597         try {
3598             return mService.getPasspointConfigurations(mContext.getOpPackageName()).getList();
3599         } catch (RemoteException e) {
3600             throw e.rethrowFromSystemServer();
3601         }
3602     }
3603 
3604     /**
3605      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
3606      * will be broadcasted once the request is completed.  The presence of the intent extra
3607      * {@link #EXTRA_ICON} will indicate the result of the request.
3608      * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
3609      *
3610      * @param bssid The BSSID of the AP
3611      * @param fileName Name of the icon file (remote file) to query from the AP
3612      *
3613      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
3614      * @hide
3615      */
queryPasspointIcon(long bssid, String fileName)3616     public void queryPasspointIcon(long bssid, String fileName) {
3617         try {
3618             mService.queryPasspointIcon(bssid, fileName);
3619         } catch (RemoteException e) {
3620             throw e.rethrowFromSystemServer();
3621         }
3622     }
3623 
3624     /**
3625      * Match the currently associated network against the SP matching the given FQDN
3626      * @param fqdn FQDN of the SP
3627      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
3628      * @hide
3629      */
matchProviderWithCurrentNetwork(String fqdn)3630     public int matchProviderWithCurrentNetwork(String fqdn) {
3631         try {
3632             return mService.matchProviderWithCurrentNetwork(fqdn);
3633         } catch (RemoteException e) {
3634             throw e.rethrowFromSystemServer();
3635         }
3636     }
3637 
3638     /**
3639      * Remove the specified network from the list of configured networks.
3640      * This may result in the asynchronous delivery of state change
3641      * events.
3642      *
3643      * Applications are not allowed to remove networks created by other
3644      * applications.
3645      *
3646      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3647      *        #getConfiguredNetworks}.
3648      * @return {@code true} if the operation succeeded
3649      *
3650      * @deprecated
3651      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3652      * mechanism to trigger connection to a Wi-Fi network.
3653      * b) See {@link #addNetworkSuggestions(List)},
3654      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3655      * when auto-connecting to wifi.
3656      * <b>Compatibility Note:</b> For applications targeting
3657      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3658      * {@code false}.
3659      * <p>
3660      * Deprecation Exemptions:
3661      * <ul>
3662      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3663      * </ul>
3664      */
3665     @Deprecated
removeNetwork(int netId)3666     public boolean removeNetwork(int netId) {
3667         try {
3668             return mService.removeNetwork(netId, mContext.getOpPackageName());
3669         } catch (RemoteException e) {
3670             throw e.rethrowFromSystemServer();
3671         }
3672     }
3673 
3674     /**
3675      * Remove all configured networks that were not created by the calling app. Can only
3676      * be called by a Device Owner (DO) app.
3677      *
3678      * @return {@code true} if at least one network is removed, {@code false} otherwise
3679      * @throws SecurityException if the caller is not a Device Owner app
3680      */
3681     @RequiresPermission(CHANGE_WIFI_STATE)
removeNonCallerConfiguredNetworks()3682     public boolean removeNonCallerConfiguredNetworks() {
3683         try {
3684             return mService.removeNonCallerConfiguredNetworks(mContext.getOpPackageName());
3685         } catch (RemoteException e) {
3686             throw e.rethrowFromSystemServer();
3687         }
3688     }
3689     /**
3690      * Allow a previously configured network to be associated with. If
3691      * <code>attemptConnect</code> is true, an attempt to connect to the selected
3692      * network is initiated. This may result in the asynchronous delivery
3693      * of state change events.
3694      * <p>
3695      * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
3696      * traffic may instead be sent through another network, such as cellular data,
3697      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
3698      * Wi-Fi network that does not provide Internet access (e.g. a wireless
3699      * printer), if another network that does offer Internet access (e.g.
3700      * cellular data) is available. Applications that need to ensure that their
3701      * network traffic uses Wi-Fi should use APIs such as
3702      * {@link Network#bindSocket(java.net.Socket)},
3703      * {@link Network#openConnection(java.net.URL)}, or
3704      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
3705      *
3706      * Applications are not allowed to enable networks created by other
3707      * applications.
3708      *
3709      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3710      *        #getConfiguredNetworks}.
3711      * @param attemptConnect The way to select a particular network to connect to is specify
3712      *        {@code true} for this parameter.
3713      * @return {@code true} if the operation succeeded
3714      *
3715      * @deprecated
3716      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3717      * mechanism to trigger connection to a Wi-Fi network.
3718      * b) See {@link #addNetworkSuggestions(List)},
3719      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3720      * when auto-connecting to wifi.
3721      * <b>Compatibility Note:</b> For applications targeting
3722      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3723      * {@code false}.
3724      * Deprecation Exemptions:
3725      * <ul>
3726      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3727      * </ul>
3728      */
3729     @Deprecated
enableNetwork(int netId, boolean attemptConnect)3730     public boolean enableNetwork(int netId, boolean attemptConnect) {
3731         try {
3732             return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
3733         } catch (RemoteException e) {
3734             throw e.rethrowFromSystemServer();
3735         }
3736     }
3737 
3738     /**
3739      * Disable a configured network. The specified network will not be
3740      * a candidate for associating. This may result in the asynchronous
3741      * delivery of state change events.
3742      *
3743      * Applications are not allowed to disable networks created by other
3744      * applications.
3745      *
3746      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3747      *        #getConfiguredNetworks}.
3748      * @return {@code true} if the operation succeeded
3749      *
3750      * @deprecated
3751      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3752      * mechanism to trigger connection to a Wi-Fi network.
3753      * b) See {@link #addNetworkSuggestions(List)},
3754      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3755      * when auto-connecting to wifi.
3756      * <b>Compatibility Note:</b> For applications targeting
3757      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3758      * {@code false}.
3759      * <p>
3760      * Deprecation Exemptions:
3761      * <ul>
3762      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3763      * </ul>
3764      */
3765     @Deprecated
disableNetwork(int netId)3766     public boolean disableNetwork(int netId) {
3767         try {
3768             return mService.disableNetwork(netId, mContext.getOpPackageName());
3769         } catch (RemoteException e) {
3770             throw e.rethrowFromSystemServer();
3771         }
3772     }
3773 
3774     /**
3775      * Disassociate from the currently active access point. This may result
3776      * in the asynchronous delivery of state change events.
3777      * @return {@code true} if the operation succeeded
3778      *
3779      * @deprecated
3780      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3781      * mechanism to trigger connection to a Wi-Fi network.
3782      * b) See {@link #addNetworkSuggestions(List)},
3783      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3784      * when auto-connecting to wifi.
3785      * <b>Compatibility Note:</b> For applications targeting
3786      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3787      * {@code false}.
3788      * <p>
3789      * Deprecation Exemptions:
3790      * <ul>
3791      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3792      * </ul>
3793      */
3794     @Deprecated
disconnect()3795     public boolean disconnect() {
3796         try {
3797             return mService.disconnect(mContext.getOpPackageName());
3798         } catch (RemoteException e) {
3799             throw e.rethrowFromSystemServer();
3800         }
3801     }
3802 
3803     /**
3804      * Reconnect to the currently active access point, if we are currently
3805      * disconnected. This may result in the asynchronous delivery of state
3806      * change events.
3807      * @return {@code true} if the operation succeeded
3808      *
3809      * @deprecated
3810      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3811      * mechanism to trigger connection to a Wi-Fi network.
3812      * b) See {@link #addNetworkSuggestions(List)},
3813      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3814      * when auto-connecting to wifi.
3815      * <b>Compatibility Note:</b> For applications targeting
3816      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3817      * {@code false}.
3818      * <p>
3819      * Deprecation Exemptions:
3820      * <ul>
3821      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3822      * </ul>
3823      */
3824     @Deprecated
reconnect()3825     public boolean reconnect() {
3826         try {
3827             return mService.reconnect(mContext.getOpPackageName());
3828         } catch (RemoteException e) {
3829             throw e.rethrowFromSystemServer();
3830         }
3831     }
3832 
3833     /**
3834      * Reconnect to the currently active access point, even if we are already
3835      * connected. This may result in the asynchronous delivery of state
3836      * change events.
3837      * @return {@code true} if the operation succeeded
3838      *
3839      * @deprecated
3840      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3841      * mechanism to trigger connection to a Wi-Fi network.
3842      * b) See {@link #addNetworkSuggestions(List)},
3843      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3844      * when auto-connecting to wifi.
3845      * <b>Compatibility Note:</b> For applications targeting
3846      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
3847      */
3848     @Deprecated
reassociate()3849     public boolean reassociate() {
3850         try {
3851             return mService.reassociate(mContext.getOpPackageName());
3852         } catch (RemoteException e) {
3853             throw e.rethrowFromSystemServer();
3854         }
3855     }
3856 
3857     /**
3858      * Check that the supplicant daemon is responding to requests.
3859      * @return {@code true} if we were able to communicate with the supplicant and
3860      * it returned the expected response to the PING message.
3861      * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
3862      */
3863     @Deprecated
pingSupplicant()3864     public boolean pingSupplicant() {
3865         return isWifiEnabled();
3866     }
3867 
3868     /** @hide */
3869     public static final int WIFI_FEATURE_INFRA            = 0;  // Basic infrastructure mode
3870     /** @hide */
3871     public static final int WIFI_FEATURE_PASSPOINT        = 2;  // Support for GAS/ANQP
3872     /** @hide */
3873     public static final int WIFI_FEATURE_P2P              = 3;  // Wifi-Direct
3874     /** @hide */
3875     public static final int WIFI_FEATURE_MOBILE_HOTSPOT   = 4;  // Soft AP
3876     /** @hide */
3877     public static final int WIFI_FEATURE_SCANNER          = 5;  // WifiScanner APIs
3878     /** @hide */
3879     public static final int WIFI_FEATURE_AWARE            = 6;  // Wi-Fi Aware networking
3880     /** @hide */
3881     public static final int WIFI_FEATURE_D2D_RTT          = 7;  // Device-to-device RTT
3882     /** @hide */
3883     public static final int WIFI_FEATURE_D2AP_RTT         = 8;  // Device-to-AP RTT
3884     /** @hide */
3885     public static final int WIFI_FEATURE_PNO              = 10;  // Preferred network offload
3886     /** @hide */
3887     public static final int WIFI_FEATURE_TDLS             = 12; // Tunnel directed link setup
3888     /** @hide */
3889     public static final int WIFI_FEATURE_TDLS_OFFCHANNEL  = 13; // TDLS off channel
3890     /** @hide */
3891     public static final int WIFI_FEATURE_AP_STA           = 15; // AP STA Concurrency
3892     /** @hide */
3893     public static final int WIFI_FEATURE_LINK_LAYER_STATS = 16; // Link layer stats
3894     /** @hide */
3895     public static final int WIFI_FEATURE_LOGGER           = 17; // WiFi Logger
3896     /** @hide */
3897     public static final int WIFI_FEATURE_RSSI_MONITOR     = 19; // RSSI Monitor
3898     /** @hide */
3899     public static final int WIFI_FEATURE_MKEEP_ALIVE      = 20; // mkeep_alive
3900     /** @hide */
3901     public static final int WIFI_FEATURE_CONFIG_NDO       = 21; // ND offload
3902     /** @hide */
3903     public static final int WIFI_FEATURE_CONTROL_ROAMING  = 23; // Control firmware roaming
3904     /** @hide */
3905     public static final int WIFI_FEATURE_IE_WHITELIST     = 24; // Probe IE white listing
3906     /** @hide */
3907     public static final int WIFI_FEATURE_SCAN_RAND        = 25; // Random MAC & Probe seq
3908     /** @hide */
3909     public static final int WIFI_FEATURE_TX_POWER_LIMIT   = 26; // Set Tx power limit
3910     /** @hide */
3911     public static final int WIFI_FEATURE_WPA3_SAE         = 27; // WPA3-Personal SAE
3912     /** @hide */
3913     public static final int WIFI_FEATURE_WPA3_SUITE_B     = 28; // WPA3-Enterprise Suite-B
3914     /** @hide */
3915     public static final int WIFI_FEATURE_OWE              = 29; // Enhanced Open
3916     /** @hide */
3917     public static final int WIFI_FEATURE_LOW_LATENCY      = 30; // Low Latency modes
3918     /** @hide */
3919     public static final int WIFI_FEATURE_DPP              = 31; // DPP (Easy-Connect)
3920     /** @hide */
3921     public static final int WIFI_FEATURE_P2P_RAND_MAC     = 32; // Random P2P MAC
3922     /** @hide */
3923     public static final int WIFI_FEATURE_CONNECTED_RAND_MAC    = 33; // Random STA MAC
3924     /** @hide */
3925     public static final int WIFI_FEATURE_AP_RAND_MAC      = 34; // Random AP MAC
3926     /** @hide */
3927     public static final int WIFI_FEATURE_MBO              = 35; // MBO Support
3928     /** @hide */
3929     public static final int WIFI_FEATURE_OCE              = 36; // OCE Support
3930     /** @hide */
3931     public static final int WIFI_FEATURE_WAPI             = 37; // WAPI
3932 
3933     /** @hide */
3934     public static final int WIFI_FEATURE_FILS_SHA256      = 38; // FILS-SHA256
3935 
3936     /** @hide */
3937     public static final int WIFI_FEATURE_FILS_SHA384      = 39; // FILS-SHA384
3938 
3939     /** @hide */
3940     public static final int WIFI_FEATURE_SAE_PK           = 40; // SAE-PK
3941 
3942     /** @hide */
3943     public static final int WIFI_FEATURE_STA_BRIDGED_AP   = 41; // STA + Bridged AP
3944 
3945     /** @hide */
3946     public static final int WIFI_FEATURE_BRIDGED_AP       = 42; // Bridged AP
3947 
3948     /** @hide */
3949     public static final int WIFI_FEATURE_INFRA_60G        = 43; // 60 GHz Band Support
3950 
3951     /**
3952      * Support for 2 STA's for the local-only (peer to peer) connection + internet connection
3953      * concurrency.
3954      * @hide
3955      */
3956     public static final int WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY = 44;
3957 
3958     /**
3959      * Support for 2 STA's for the make before break concurrency.
3960      * @hide
3961      */
3962     public static final int WIFI_FEATURE_ADDITIONAL_STA_MBB = 45;
3963 
3964     /**
3965      * Support for 2 STA's for the restricted connection + internet connection concurrency.
3966      * @hide
3967      */
3968     public static final int WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED = 46;
3969 
3970     /**
3971      * DPP (Easy-Connect) Enrollee Responder mode support
3972      * @hide
3973      */
3974     public static final int WIFI_FEATURE_DPP_ENROLLEE_RESPONDER = 47;
3975 
3976     /**
3977      * Passpoint Terms and Conditions feature support
3978      * @hide
3979      */
3980     public static final int WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS = 48;
3981 
3982      /** @hide */
3983     public static final int WIFI_FEATURE_SAE_H2E          = 49; // Hash-to-Element
3984 
3985      /** @hide */
3986     public static final int WIFI_FEATURE_WFD_R2           = 50; // Wi-Fi Display R2
3987 
3988     /**
3989      * RFC 7542 decorated identity support
3990      * @hide */
3991     public static final int WIFI_FEATURE_DECORATED_IDENTITY = 51;
3992 
3993     /**
3994      * Trust On First Use support for WPA Enterprise network
3995      * @hide
3996      */
3997     public static final int WIFI_FEATURE_TRUST_ON_FIRST_USE = 52;
3998 
3999     /**
4000      * Support for 2 STA's multi internet concurrency.
4001      * @hide
4002      */
4003     public static final int WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET = 53;
4004 
4005     /**
4006      * Support for DPP (Easy-Connect) AKM.
4007      * @hide
4008      */
4009     public static final int WIFI_FEATURE_DPP_AKM = 54;
4010 
4011     /**
4012      * Support for setting TLS minimum version.
4013      * @hide
4014      */
4015     public static final int WIFI_FEATURE_SET_TLS_MINIMUM_VERSION = 55;
4016 
4017     /**
4018      * Support for TLS v.13.
4019      * @hide
4020      */
4021     public static final int WIFI_FEATURE_TLS_V1_3 = 56;
4022 
4023     /**
4024      * Support for Dual Band Simultaneous (DBS) operation.
4025      * @hide
4026      */
4027     public static final int WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS = 57;
4028 
4029     /**
4030      * Support for TID-To-Link Mapping negotiation.
4031      * @hide
4032      */
4033     public static final int WIFI_FEATURE_T2LM_NEGOTIATION = 58;
4034 
4035     /**
4036      * Support for WEP Wi-Fi Network
4037      * @hide
4038      */
4039     public static final int WIFI_FEATURE_WEP = 59;
4040 
4041     /**
4042      * Support for WPA PERSONAL Wi-Fi Network
4043      * @hide
4044      */
4045     public static final int WIFI_FEATURE_WPA_PERSONAL = 60;
4046 
4047     /**
4048      * Support for Roaming Mode
4049      * @hide
4050      */
4051     public static final int WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT = 61;
4052 
4053     /**
4054      * Supports device-to-device connections when infra STA is disabled.
4055      * @hide
4056      */
4057     public static final int WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED = 62;
4058 
4059     /**
4060      * Support for Soft AP multi-links operation.
4061      * @hide
4062      */
4063     public static final int WIFI_FEATURE_SOFTAP_MLO = 63;
4064 
4065     /**
4066      * Supports multiple Wi-Fi 7 multi-link devices (MLD) on SoftAp.
4067      * @hide
4068      */
4069     public static final int WIFI_FEATURE_MULTIPLE_MLD_ON_SAP = 64;
4070 
4071     /**
4072      * NOTE: When adding a new WIFI_FEATURE_ value, also be sure to update
4073      * {@link com.android.server.wifi.util.FeatureBitsetUtils}
4074      */
4075 
isFeatureSupported(int feature)4076     private boolean isFeatureSupported(int feature) {
4077         try {
4078             return mService.isFeatureSupported(feature);
4079         } catch (RemoteException e) {
4080             throw e.rethrowFromSystemServer();
4081         }
4082     }
4083 
4084     /**
4085      * @return true if this adapter supports Passpoint
4086      * @hide
4087      */
isPasspointSupported()4088     public boolean isPasspointSupported() {
4089         // Both OEM and chip support are required
4090         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)
4091                 && isFeatureSupported(WIFI_FEATURE_PASSPOINT);
4092     }
4093 
4094     /**
4095      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
4096      */
isP2pSupported()4097     public boolean isP2pSupported() {
4098         // Both OEM and chip support are required
4099         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)
4100                 && isFeatureSupported(WIFI_FEATURE_P2P);
4101     }
4102 
4103     /**
4104      * @return true if this adapter supports portable Wi-Fi hotspot
4105      * @hide
4106      */
4107     @SystemApi
isPortableHotspotSupported()4108     public boolean isPortableHotspotSupported() {
4109         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
4110     }
4111 
4112     /**
4113      * @return true if this adapter supports WifiScanner APIs
4114      * @hide
4115      */
4116     @SystemApi
isWifiScannerSupported()4117     public boolean isWifiScannerSupported() {
4118         return isFeatureSupported(WIFI_FEATURE_SCANNER);
4119     }
4120 
4121     /**
4122      * @return true if this adapter supports Neighbour Awareness Network APIs
4123      * @hide
4124      */
isWifiAwareSupported()4125     public boolean isWifiAwareSupported() {
4126         // Both OEM and chip support are required
4127         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_AWARE)
4128                 && isFeatureSupported(WIFI_FEATURE_AWARE);
4129     }
4130 
4131     /**
4132      * Query whether or not the device supports Station (STA) + Access point (AP) concurrency.
4133      *
4134      * @return true if this device supports STA + AP concurrency, false otherwise.
4135      */
isStaApConcurrencySupported()4136     public boolean isStaApConcurrencySupported() {
4137         return isFeatureSupported(WIFI_FEATURE_AP_STA);
4138     }
4139 
4140     /**
4141      * Query whether or not the device supports concurrent station (STA) connections for local-only
4142      * connections using {@link WifiNetworkSpecifier}.
4143      *
4144      * @return true if this device supports multiple STA concurrency for this use-case, false
4145      * otherwise.
4146      */
isStaConcurrencyForLocalOnlyConnectionsSupported()4147     public boolean isStaConcurrencyForLocalOnlyConnectionsSupported() {
4148         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY);
4149     }
4150 
4151     /**
4152      * Query whether or not the device supports concurrent station (STA) connections for
4153      * make-before-break wifi to wifi switching.
4154      *
4155      * Note: This is an internal feature which is not available to apps.
4156      *
4157      * @return true if this device supports multiple STA concurrency for this use-case, false
4158      * otherwise.
4159      */
isMakeBeforeBreakWifiSwitchingSupported()4160     public boolean isMakeBeforeBreakWifiSwitchingSupported() {
4161         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_MBB);
4162     }
4163 
4164     /**
4165      * Query whether or not the device supports concurrent station (STA) connections for multi
4166      * internet connections.
4167      *
4168      * @return true if this device supports multiple STA concurrency for this use-case, false
4169      * otherwise.
4170      */
4171     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
isStaConcurrencyForMultiInternetSupported()4172     public boolean isStaConcurrencyForMultiInternetSupported() {
4173         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET);
4174     }
4175 
4176     /**
4177      * Query whether or not the device supports concurrent station (STA) connections for restricted
4178      * connections using {@link WifiNetworkSuggestion.Builder#setOemPaid(boolean)} /
4179      * {@link WifiNetworkSuggestion.Builder#setOemPrivate(boolean)}.
4180      *
4181      * @return true if this device supports multiple STA concurrency for this use-case, false
4182      * otherwise.
4183      * @hide
4184      */
4185     @SystemApi
isStaConcurrencyForRestrictedConnectionsSupported()4186     public boolean isStaConcurrencyForRestrictedConnectionsSupported() {
4187         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED);
4188     }
4189 
4190     /**
4191      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
4192      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
4193      * {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
4194      *
4195      * @return true if this adapter supports Device-to-device RTT
4196      * @hide
4197      */
4198     @Deprecated
4199     @SystemApi
isDeviceToDeviceRttSupported()4200     public boolean isDeviceToDeviceRttSupported() {
4201         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
4202     }
4203 
4204     /**
4205      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
4206      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT}.
4207      *
4208      * @return true if this adapter supports Device-to-AP RTT
4209      */
4210     @Deprecated
isDeviceToApRttSupported()4211     public boolean isDeviceToApRttSupported() {
4212         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
4213     }
4214 
4215     /**
4216      * @return true if this adapter supports offloaded connectivity scan
4217      */
isPreferredNetworkOffloadSupported()4218     public boolean isPreferredNetworkOffloadSupported() {
4219         try {
4220             return mService.isPnoSupported();
4221         } catch (RemoteException e) {
4222             throw e.rethrowFromSystemServer();
4223         }
4224     }
4225 
4226     /**
4227      * @return true if this adapter supports Tunnel Directed Link Setup
4228      */
isTdlsSupported()4229     public boolean isTdlsSupported() {
4230         return isFeatureSupported(WIFI_FEATURE_TDLS);
4231     }
4232 
4233     /**
4234      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
4235      * @hide
4236      */
isOffChannelTdlsSupported()4237     public boolean isOffChannelTdlsSupported() {
4238         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
4239     }
4240 
4241     /**
4242      * @return true if this adapter supports advanced power/performance counters
4243      */
isEnhancedPowerReportingSupported()4244     public boolean isEnhancedPowerReportingSupported() {
4245         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
4246     }
4247 
4248     /**
4249      * @return true if this device supports connected MAC randomization.
4250      * @hide
4251      */
4252     @SystemApi
isConnectedMacRandomizationSupported()4253     public boolean isConnectedMacRandomizationSupported() {
4254         return isFeatureSupported(WIFI_FEATURE_CONNECTED_RAND_MAC);
4255     }
4256 
4257     /**
4258      * @return true if this device supports AP MAC randomization.
4259      * @hide
4260      */
4261     @SystemApi
isApMacRandomizationSupported()4262     public boolean isApMacRandomizationSupported() {
4263         return isFeatureSupported(WIFI_FEATURE_AP_RAND_MAC);
4264     }
4265 
4266     /**
4267      * @return true if this device supports Low latency mode.
4268      * @hide
4269      */
4270     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
4271     @SystemApi
isLowLatencyModeSupported()4272     public boolean isLowLatencyModeSupported() {
4273         return isFeatureSupported(WIFI_FEATURE_LOW_LATENCY);
4274     }
4275 
4276     /**
4277      * Check if the chipset supports 2.4GHz band.
4278      * @return {@code true} if supported, {@code false} otherwise.
4279      */
is24GHzBandSupported()4280     public boolean is24GHzBandSupported() {
4281         try {
4282             return mService.is24GHzBandSupported();
4283         } catch (RemoteException e) {
4284             throw e.rethrowFromSystemServer();
4285         }
4286     }
4287 
4288     /**
4289      * Check if the chipset supports 5GHz band.
4290      * @return {@code true} if supported, {@code false} otherwise.
4291      */
is5GHzBandSupported()4292     public boolean is5GHzBandSupported() {
4293         try {
4294             return mService.is5GHzBandSupported();
4295         } catch (RemoteException e) {
4296             throw e.rethrowFromSystemServer();
4297         }
4298     }
4299 
4300     /**
4301      * Check if the chipset supports the 60GHz frequency band.
4302      *
4303      * @return {@code true} if supported, {@code false} otherwise.
4304      */
4305     @RequiresApi(Build.VERSION_CODES.S)
is60GHzBandSupported()4306     public boolean is60GHzBandSupported() {
4307         try {
4308             return mService.is60GHzBandSupported();
4309         } catch (RemoteException e) {
4310             throw e.rethrowFromSystemServer();
4311         }
4312     }
4313 
4314     /**
4315      * Check if the chipset supports 6GHz band.
4316      * @return {@code true} if supported, {@code false} otherwise.
4317      */
is6GHzBandSupported()4318     public boolean is6GHzBandSupported() {
4319         try {
4320             return mService.is6GHzBandSupported();
4321         } catch (RemoteException e) {
4322             throw e.rethrowFromSystemServer();
4323         }
4324     }
4325 
4326     /**
4327      * Check if the chipset supports a certain Wi-Fi standard.
4328      * @param standard the IEEE 802.11 standard to check on.
4329      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
4330      * @return {@code true} if supported, {@code false} otherwise.
4331      */
isWifiStandardSupported(@ifiAnnotations.WifiStandard int standard)4332     public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
4333         try {
4334             return mService.isWifiStandardSupported(standard);
4335         } catch (RemoteException e) {
4336             throw e.rethrowFromSystemServer();
4337         }
4338     }
4339 
4340     /**
4341      * Query whether or not the device supports concurrency of Station (STA) + multiple access
4342      * points (AP) (where the APs bridged together).
4343      *
4344      * @return true if this device supports concurrency of STA + multiple APs which are bridged
4345      *         together, false otherwise.
4346      */
isStaBridgedApConcurrencySupported()4347     public boolean isStaBridgedApConcurrencySupported() {
4348         return isFeatureSupported(WIFI_FEATURE_STA_BRIDGED_AP);
4349     }
4350 
4351     /**
4352      * Query whether or not the device supports multiple Access point (AP) which are bridged
4353      * together.
4354      *
4355      * @return true if this device supports concurrency of multiple AP which bridged together,
4356      *         false otherwise.
4357      */
isBridgedApConcurrencySupported()4358     public boolean isBridgedApConcurrencySupported() {
4359         return isFeatureSupported(WIFI_FEATURE_BRIDGED_AP);
4360     }
4361 
4362     /**
4363      * @return true if this devices supports device-to-device (D2d) Wi-Fi use-cases
4364      * such as Wi-Fi Direct when infra station (STA) is disabled.
4365      */
4366     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isD2dSupportedWhenInfraStaDisabled()4367     public boolean isD2dSupportedWhenInfraStaDisabled() {
4368         return isFeatureSupported(WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED);
4369     }
4370 
4371     /**
4372      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
4373      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
4374      *
4375      * @hide
4376      */
4377     @SystemApi
4378     public interface OnWifiActivityEnergyInfoListener {
4379         /**
4380          * Called when Wi-Fi activity energy info is available.
4381          * Note: this listener is triggered at most once for each call to
4382          * {@link #getWifiActivityEnergyInfoAsync}.
4383          *
4384          * @param info the latest {@link WifiActivityEnergyInfo}, or null if unavailable.
4385          */
onWifiActivityEnergyInfo(@ullable WifiActivityEnergyInfo info)4386         void onWifiActivityEnergyInfo(@Nullable WifiActivityEnergyInfo info);
4387     }
4388 
4389     private static class OnWifiActivityEnergyInfoProxy
4390             extends IOnWifiActivityEnergyInfoListener.Stub {
4391         private final Object mLock = new Object();
4392         @Nullable @GuardedBy("mLock") private Executor mExecutor;
4393         @Nullable @GuardedBy("mLock") private OnWifiActivityEnergyInfoListener mListener;
4394 
OnWifiActivityEnergyInfoProxy(Executor executor, OnWifiActivityEnergyInfoListener listener)4395         OnWifiActivityEnergyInfoProxy(Executor executor,
4396                 OnWifiActivityEnergyInfoListener listener) {
4397             mExecutor = executor;
4398             mListener = listener;
4399         }
4400 
4401         @Override
onWifiActivityEnergyInfo(WifiActivityEnergyInfo info)4402         public void onWifiActivityEnergyInfo(WifiActivityEnergyInfo info) {
4403             Executor executor;
4404             OnWifiActivityEnergyInfoListener listener;
4405             synchronized (mLock) {
4406                 if (mExecutor == null || mListener == null) {
4407                     return;
4408                 }
4409                 executor = mExecutor;
4410                 listener = mListener;
4411                 // null out to allow garbage collection, prevent triggering listener more than once
4412                 mExecutor = null;
4413                 mListener = null;
4414             }
4415             Binder.clearCallingIdentity();
4416             executor.execute(() -> listener.onWifiActivityEnergyInfo(info));
4417         }
4418     }
4419 
4420     /**
4421      * Request to get the current {@link WifiActivityEnergyInfo} asynchronously.
4422      * Note: This method will return null if {@link #isEnhancedPowerReportingSupported()} returns
4423      * false.
4424      *
4425      * @param executor the executor that the listener will be invoked on
4426      * @param listener the listener that will receive the {@link WifiActivityEnergyInfo} object
4427      *                 when it becomes available. The listener will be triggered at most once for
4428      *                 each call to this method.
4429      *
4430      * @hide
4431      */
4432     @SystemApi
4433     @RequiresPermission(ACCESS_WIFI_STATE)
getWifiActivityEnergyInfoAsync( @onNull @allbackExecutor Executor executor, @NonNull OnWifiActivityEnergyInfoListener listener)4434     public void getWifiActivityEnergyInfoAsync(
4435             @NonNull @CallbackExecutor Executor executor,
4436             @NonNull OnWifiActivityEnergyInfoListener listener) {
4437         Objects.requireNonNull(executor, "executor cannot be null");
4438         Objects.requireNonNull(listener, "listener cannot be null");
4439         try {
4440             mService.getWifiActivityEnergyInfoAsync(
4441                     new OnWifiActivityEnergyInfoProxy(executor, listener));
4442         } catch (RemoteException e) {
4443             throw e.rethrowFromSystemServer();
4444         }
4445     }
4446 
4447     /**
4448      * Request a scan for access points. Returns immediately. The availability
4449      * of the results is made known later by means of an asynchronous event sent
4450      * on completion of the scan.
4451      * <p>
4452      * To initiate a Wi-Fi scan, declare the
4453      * {@link android.Manifest.permission#CHANGE_WIFI_STATE}
4454      * permission in the manifest, and perform these steps:
4455      * </p>
4456      * <ol style="1">
4457      * <li>Invoke the following method:
4458      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>
4459      * <li>
4460      * Register a BroadcastReceiver to listen to
4461      * {@code SCAN_RESULTS_AVAILABLE_ACTION}.</li>
4462      * <li>When a broadcast is received, call:
4463      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>
4464      * </ol>
4465      * @return {@code true} if the operation succeeded, i.e., the scan was initiated.
4466      * @deprecated The ability for apps to trigger scan requests will be removed in a future
4467      * release.
4468      */
4469     @Deprecated
startScan()4470     public boolean startScan() {
4471         return startScan(null);
4472     }
4473 
4474     /** @hide */
4475     @SystemApi
4476     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
startScan(WorkSource workSource)4477     public boolean startScan(WorkSource workSource) {
4478         try {
4479             String packageName = mContext.getOpPackageName();
4480             String attributionTag = mContext.getAttributionTag();
4481             return mService.startScan(packageName, attributionTag);
4482         } catch (RemoteException e) {
4483             throw e.rethrowFromSystemServer();
4484         }
4485     }
4486 
4487     /**
4488      * WPS has been deprecated from Client mode operation.
4489      *
4490      * @return null
4491      * @hide
4492      * @deprecated This API is deprecated
4493      */
getCurrentNetworkWpsNfcConfigurationToken()4494     public String getCurrentNetworkWpsNfcConfigurationToken() {
4495         return null;
4496     }
4497 
4498     /**
4499      * Return dynamic information about the current Wi-Fi connection, if any is active.
4500      * <p>
4501      *
4502      * @return the Wi-Fi information, contained in {@link WifiInfo}.
4503      *
4504      * @deprecated Starting with {@link Build.VERSION_CODES#S}, WifiInfo retrieval is moved to
4505      * {@link ConnectivityManager} API surface. WifiInfo is attached in
4506      * {@link NetworkCapabilities#getTransportInfo()} which is available via callback in
4507      * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} or on-demand from
4508      * {@link ConnectivityManager#getNetworkCapabilities(Network)}.
4509      *
4510      *</p>
4511      * Usage example:
4512      * <pre>
4513      * final NetworkRequest request =
4514      *      new NetworkRequest.Builder()
4515      *      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
4516      *      .build();
4517      * final ConnectivityManager connectivityManager =
4518      *      context.getSystemService(ConnectivityManager.class);
4519      * final NetworkCallback networkCallback = new NetworkCallback() {
4520      *      ...
4521      *      &#64;Override
4522      *      void onAvailable(Network network) {}
4523      *
4524      *      &#64;Override
4525      *      void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
4526      *          WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
4527      *      }
4528      *      // etc.
4529      * };
4530      * connectivityManager.requestNetwork(request, networkCallback); // For request
4531      * connectivityManager.registerNetworkCallback(request, networkCallback); // For listen
4532      * </pre>
4533      * <p>
4534      * <b>Compatibility Notes:</b>
4535      * <li>Apps can continue using this API, however newer features
4536      * such as ability to mask out location sensitive data in WifiInfo will not be supported
4537      * via this API. </li>
4538      * <li>On devices supporting concurrent connections (indicated via
4539      * {@link #isStaConcurrencyForLocalOnlyConnectionsSupported()}, etc) this API will return
4540      * the details of the internet providing connection (if any) to all apps, except for the apps
4541      * that triggered the creation of the concurrent connection. For such apps, this API will return
4542      * the details of the connection they created. e.g. apps using {@link WifiNetworkSpecifier} will
4543      * trigger a concurrent connection on supported devices and hence this API will provide
4544      * details of their peer to peer connection (not the internet providing connection). This
4545      * is to maintain backwards compatibility with behavior on single STA devices.</li>
4546      * </p>
4547      */
4548     @Deprecated
4549     @RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION}, conditional = true)
getConnectionInfo()4550     public WifiInfo getConnectionInfo() {
4551         try {
4552             return mService.getConnectionInfo(mContext.getOpPackageName(),
4553                     mContext.getAttributionTag());
4554         } catch (RemoteException e) {
4555             throw e.rethrowFromSystemServer();
4556         }
4557     }
4558 
4559     /**
4560      * Return the results of the latest access point scan.
4561      * @return the list of access points found in the most recent scan. An app must hold
4562      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
4563      * and {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission
4564      * in order to get valid results.
4565      *
4566      * <p>
4567      * When an Access Point’s beacon or probe response includes a Multi-BSSID Element, the
4568      * returned scan results should include separate scan result for each BSSID within the
4569      * Multi-BSSID Information Element. This includes both transmitted and non-transmitted BSSIDs.
4570      * Original Multi-BSSID Element will be included in the Information Elements attached to
4571      * each of the scan results.
4572      * Note: This is the expected behavior for devices supporting 11ax (WiFi-6) and above, and an
4573      * optional requirement for devices running with older WiFi generations.
4574      * </p>
4575      */
4576     @RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION})
getScanResults()4577     public List<ScanResult> getScanResults() {
4578         try {
4579             ParceledListSlice<ScanResult> parceledList = mService
4580                     .getScanResults(mContext.getOpPackageName(), mContext.getAttributionTag());
4581             if (parceledList == null) {
4582                 return Collections.emptyList();
4583             }
4584             return parceledList.getList();
4585         } catch (RemoteException e) {
4586             throw e.rethrowFromSystemServer();
4587         }
4588     }
4589 
4590     /**
4591      * Get the filtered ScanResults which match the network configurations specified by the
4592      * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
4593      * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
4594      * use the matching rules of Hotspot 2.0.
4595      * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
4596      * These may or may not be suggestions which are installed on the device.
4597      * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
4598      * the Wi-Fi service will use the most recent scan results which the system has.
4599      * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
4600      * corresponding to networks which match them.
4601      * @hide
4602      */
4603     @SystemApi
4604     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
4605     @NonNull
getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestionsToMatch, @Nullable List<ScanResult> scanResults)4606     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
4607             @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
4608             @Nullable List<ScanResult> scanResults) {
4609         if (networkSuggestionsToMatch == null) {
4610             throw new IllegalArgumentException("networkSuggestions must not be null.");
4611         }
4612         try {
4613             return mService.getMatchingScanResults(
4614                     new ParceledListSlice<>(networkSuggestionsToMatch),
4615                     new ParceledListSlice<>(scanResults),
4616                     mContext.getOpPackageName(), mContext.getAttributionTag());
4617         } catch (RemoteException e) {
4618             throw e.rethrowFromSystemServer();
4619         }
4620     }
4621 
4622     /**
4623      * Set if scanning is always available.
4624      *
4625      * If set to {@code true}, apps can issue {@link #startScan} and fetch scan results
4626      * even when Wi-Fi is turned off.
4627      *
4628      * @param isAvailable true to enable, false to disable.
4629      * @hide
4630      * @see #isScanAlwaysAvailable()
4631      */
4632     @SystemApi
4633     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanAlwaysAvailable(boolean isAvailable)4634     public void setScanAlwaysAvailable(boolean isAvailable) {
4635         try {
4636             mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName());
4637         } catch (RemoteException e) {
4638             throw e.rethrowFromSystemServer();
4639         }
4640     }
4641 
4642     /**
4643      * Check if scanning is always available.
4644      *
4645      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
4646      * even when Wi-Fi is turned off.
4647      *
4648      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
4649      * @deprecated The ability for apps to trigger scan requests will be removed in a future
4650      * release.
4651      */
4652     @Deprecated
isScanAlwaysAvailable()4653     public boolean isScanAlwaysAvailable() {
4654         try {
4655             return mService.isScanAlwaysAvailable();
4656         } catch (RemoteException e) {
4657             throw e.rethrowFromSystemServer();
4658         }
4659     }
4660 
4661     /**
4662      * Get channel data such as the number of APs found on each channel from the most recent scan.
4663      * App requires {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}
4664      *
4665      * @param executor        The executor on which callback will be invoked.
4666      * @param resultsCallback A callback that will return {@code List<Bundle>} containing channel
4667      *                       data such as the number of APs found on each channel.
4668      *                       {@link WifiManager#CHANNEL_DATA_KEY_FREQUENCY_MHZ} and
4669      *                       {@link WifiManager#CHANNEL_DATA_KEY_NUM_AP} are used to get
4670      *                       the frequency (Mhz) and number of APs.
4671      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
4672      * @throws SecurityException             if the caller does not have permission.
4673      * @throws NullPointerException          if the caller provided invalid inputs.
4674      */
4675     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4676     @RequiresPermission(NEARBY_WIFI_DEVICES)
getChannelData(@onNull @allbackExecutor Executor executor, @NonNull Consumer<List<Bundle>> resultsCallback)4677     public void getChannelData(@NonNull @CallbackExecutor Executor executor,
4678             @NonNull Consumer<List<Bundle>> resultsCallback) {
4679         Objects.requireNonNull(executor, "executor cannot be null");
4680         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
4681         try {
4682             Bundle extras = new Bundle();
4683             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
4684                     mContext.getAttributionSource());
4685             mService.getChannelData(new IListListener.Stub() {
4686                 @Override
4687                 public void onResult(List value) {
4688                     Binder.clearCallingIdentity();
4689                     executor.execute(() -> {
4690                         resultsCallback.accept(value);
4691                     });
4692                 }
4693             }, mContext.getOpPackageName(), extras);
4694         } catch (RemoteException e) {
4695             throw e.rethrowFromSystemServer();
4696         }
4697     }
4698 
4699     /**
4700      * Tell the device to persist the current list of configured networks.
4701      * <p>
4702      * Note: It is possible for this method to change the network IDs of
4703      * existing networks. You should assume the network IDs can be different
4704      * after calling this method.
4705      *
4706      * @return {@code false}.
4707      * @deprecated There is no need to call this method -
4708      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
4709      * and {@link #removeNetwork(int)} already persist the configurations automatically.
4710      */
4711     @Deprecated
saveConfiguration()4712     public boolean saveConfiguration() {
4713         return false;
4714     }
4715 
4716     /**
4717      * Helper class to support driver country code changed listener.
4718      */
4719     private static class OnDriverCountryCodeChangedProxy
4720             extends IOnWifiDriverCountryCodeChangedListener.Stub {
4721 
4722         @NonNull private Executor mExecutor;
4723         @NonNull private ActiveCountryCodeChangedCallback mCallback;
4724 
OnDriverCountryCodeChangedProxy(@onNull Executor executor, @NonNull ActiveCountryCodeChangedCallback callback)4725         OnDriverCountryCodeChangedProxy(@NonNull Executor executor,
4726                 @NonNull ActiveCountryCodeChangedCallback callback) {
4727             Objects.requireNonNull(executor);
4728             Objects.requireNonNull(callback);
4729             mExecutor = executor;
4730             mCallback = callback;
4731         }
4732 
4733         @Override
onDriverCountryCodeChanged(String countryCode)4734         public void onDriverCountryCodeChanged(String countryCode) {
4735             Log.i(TAG, "OnDriverCountryCodeChangedProxy: receive onDriverCountryCodeChanged: "
4736                     + countryCode);
4737             Binder.clearCallingIdentity();
4738             if (countryCode != null) {
4739                 mExecutor.execute(() -> mCallback.onActiveCountryCodeChanged(countryCode));
4740             } else {
4741                 mExecutor.execute(() -> mCallback.onCountryCodeInactive());
4742             }
4743         }
4744     }
4745 
4746     /**
4747      * Interface used to listen the active country code changed event.
4748      * @hide
4749      */
4750     @SystemApi
4751     public interface ActiveCountryCodeChangedCallback {
4752         /**
4753          * Called when the country code used by the Wi-Fi subsystem has changed.
4754          *
4755          * @param countryCode An ISO-3166-alpha2 country code which is 2-Character alphanumeric.
4756          */
onActiveCountryCodeChanged(@onNull String countryCode)4757         void onActiveCountryCodeChanged(@NonNull String countryCode);
4758 
4759         /**
4760          * Called when the Wi-Fi subsystem does not have an active country code.
4761          * This can happen when Wi-Fi is disabled.
4762          */
onCountryCodeInactive()4763         void onCountryCodeInactive();
4764     }
4765 
4766     /**
4767      * Add the provided callback for the active country code changed event.
4768      * Caller will receive either
4769      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}
4770      * or {@link WifiManager.ActiveCountryCodeChangedCallback#onCountryCodeInactive()}
4771      * on registration.
4772      *
4773      * Note: When the global location setting is off or the caller does not have runtime location
4774      * permission, caller will not receive the callback even if caller register callback succeeded.
4775      *
4776      *
4777      * Caller can remove a previously registered callback using
4778      * {@link WifiManager#unregisterActiveCountryCodeChangedCallback(
4779      * ActiveCountryCodeChangedCallback)}.
4780      *
4781      * <p>
4782      * Note:
4783      * The value provided by
4784      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}
4785      * may be different from the returned value from {@link WifiManager#getCountryCode()} even if
4786      * the Wi-Fi subsystem is active. See: {@link WifiManager#getCountryCode()} for details.
4787      * </p>
4788      *
4789      * @param executor The Executor on which to execute the callbacks.
4790      * @param callback callback for the driver country code changed events.
4791      * @hide
4792      */
4793     @SystemApi
4794     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4795     @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
registerActiveCountryCodeChangedCallback( @onNull @allbackExecutor Executor executor, @NonNull ActiveCountryCodeChangedCallback callback)4796     public void registerActiveCountryCodeChangedCallback(
4797             @NonNull @CallbackExecutor Executor executor,
4798             @NonNull ActiveCountryCodeChangedCallback callback) {
4799         if (!SdkLevel.isAtLeastT()) {
4800             throw new UnsupportedOperationException();
4801         }
4802         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
4803         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
4804         if (mVerboseLoggingEnabled) {
4805             Log.d(TAG, "registerActiveCountryCodeChangedCallback: callback=" + callback
4806                     + ", executor=" + executor);
4807         }
4808         final int callbackIdentifier = System.identityHashCode(callback);
4809         synchronized (sActiveCountryCodeChangedCallbackMap) {
4810             try {
4811                 IOnWifiDriverCountryCodeChangedListener.Stub binderListener =
4812                         new OnDriverCountryCodeChangedProxy(executor, callback);
4813                 sActiveCountryCodeChangedCallbackMap.put(callbackIdentifier,
4814                         binderListener);
4815                 mService.registerDriverCountryCodeChangedListener(binderListener,
4816                         mContext.getOpPackageName(), mContext.getAttributionTag());
4817             } catch (RemoteException e) {
4818                 sActiveCountryCodeChangedCallbackMap.remove(callbackIdentifier);
4819                 throw e.rethrowFromSystemServer();
4820             }
4821         }
4822     }
4823 
4824     /**
4825      * Allow callers to remove a previously registered listener. After calling this method,
4826      * applications will no longer receive the active country code changed events through that
4827      * callback.
4828      *
4829      * @param callback Callback to remove the active country code changed events.
4830      *
4831      * @hide
4832      */
4833     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4834     @SystemApi
unregisterActiveCountryCodeChangedCallback( @onNull ActiveCountryCodeChangedCallback callback)4835     public void unregisterActiveCountryCodeChangedCallback(
4836             @NonNull ActiveCountryCodeChangedCallback callback) {
4837         if (!SdkLevel.isAtLeastT()) {
4838             throw new UnsupportedOperationException();
4839         }
4840         if (callback == null) throw new IllegalArgumentException("Callback cannot be null");
4841         if (mVerboseLoggingEnabled) {
4842             Log.d(TAG, "unregisterActiveCountryCodeChangedCallback: callback=" + callback);
4843         }
4844         final int callbackIdentifier = System.identityHashCode(callback);
4845         synchronized (sActiveCountryCodeChangedCallbackMap) {
4846             try {
4847                 if (!sActiveCountryCodeChangedCallbackMap.contains(callbackIdentifier)) {
4848                     Log.w(TAG, "Unknown external listener " + callbackIdentifier);
4849                     return;
4850                 }
4851                 mService.unregisterDriverCountryCodeChangedListener(
4852                         sActiveCountryCodeChangedCallbackMap.get(callbackIdentifier));
4853             } catch (RemoteException e) {
4854                 throw e.rethrowFromSystemServer();
4855             } finally {
4856                 sActiveCountryCodeChangedCallbackMap.remove(callbackIdentifier);
4857             }
4858         }
4859     }
4860 
4861     /**
4862      * Interface used to listen to changes in current network state.
4863      * @hide
4864      */
4865     @SystemApi
4866     public interface WifiNetworkStateChangedListener {
4867         /** @hide */
4868         @Retention(RetentionPolicy.SOURCE)
4869         @IntDef(prefix = {"WIFI_ROLE_CLIENT_"}, value = {
4870                 WIFI_ROLE_CLIENT_PRIMARY,
4871                 WIFI_ROLE_CLIENT_SECONDARY_INTERNET,
4872                 WIFI_ROLE_CLIENT_SECONDARY_LOCAL_ONLY
4873         })
4874         @interface WifiClientModeRole {}
4875 
4876         /**
4877          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4878          * Represents the primary Client Mode Manager which is mostly used for internet, but could
4879          * also be used for other use-cases such as local only connections.
4880          **/
4881         int WIFI_ROLE_CLIENT_PRIMARY = 1;
4882         /**
4883          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4884          * Represents a Client Mode Manager dedicated for the secondary internet use-case.
4885          **/
4886         int WIFI_ROLE_CLIENT_SECONDARY_INTERNET = 2;
4887         /**
4888          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4889          * Represents a Client Mode Manager dedicated for the local only connection use-case.
4890          **/
4891         int WIFI_ROLE_CLIENT_SECONDARY_LOCAL_ONLY = 3;
4892 
4893         /** @hide */
4894         @Retention(RetentionPolicy.SOURCE)
4895         @IntDef(prefix = {"WIFI_NETWORK_STATUS_"}, value = {
4896                 WIFI_NETWORK_STATUS_IDLE,
4897                 WIFI_NETWORK_STATUS_SCANNING,
4898                 WIFI_NETWORK_STATUS_CONNECTING,
4899                 WIFI_NETWORK_STATUS_AUTHENTICATING,
4900                 WIFI_NETWORK_STATUS_OBTAINING_IPADDR,
4901                 WIFI_NETWORK_STATUS_CONNECTED,
4902                 WIFI_NETWORK_STATUS_DISCONNECTED,
4903                 WIFI_NETWORK_STATUS_FAILED
4904         })
4905         @interface WifiNetworkState {}
4906 
4907         /**
4908          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4909          * Supplicant is in uninitialized state.
4910          **/
4911         int WIFI_NETWORK_STATUS_IDLE = 1;
4912         /**
4913          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4914          * Supplicant is scanning.
4915          **/
4916         int WIFI_NETWORK_STATUS_SCANNING = 2;
4917         /**
4918          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4919          * L2 connection is in progress.
4920          **/
4921         int WIFI_NETWORK_STATUS_CONNECTING = 3;
4922         /**
4923          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4924          * L2 connection 4 way handshake.
4925          **/
4926         int WIFI_NETWORK_STATUS_AUTHENTICATING = 4;
4927         /**
4928          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4929          * L2 connection complete. Obtaining IP address.
4930          **/
4931         int WIFI_NETWORK_STATUS_OBTAINING_IPADDR = 5;
4932         /**
4933          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4934          * L3 connection is complete.
4935          **/
4936         int WIFI_NETWORK_STATUS_CONNECTED = 6;
4937         /**
4938          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4939          * Network disconnected.
4940          **/
4941         int WIFI_NETWORK_STATUS_DISCONNECTED = 7;
4942         /**
4943          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4944          * A pseudo-state that should normally never be seen.
4945          **/
4946         int WIFI_NETWORK_STATUS_FAILED = 8;
4947 
4948 
4949         /**
4950          * Provides network state changes per client mode role.
4951          * @param cmmRole the role of the wifi client mode manager having the state change.
4952          *                One of {@link WifiClientModeRole}.
4953          * @param state the wifi network state specified by one of {@link WifiNetworkState}.
4954          */
onWifiNetworkStateChanged(@ifiClientModeRole int cmmRole, @WifiNetworkState int state)4955         void onWifiNetworkStateChanged(@WifiClientModeRole int cmmRole,
4956                 @WifiNetworkState int state);
4957     }
4958 
4959     /**
4960      * Helper class to support wifi network state changed listener.
4961      */
4962     private static class OnWifiNetworkStateChangedProxy
4963             extends IWifiNetworkStateChangedListener.Stub {
4964 
4965         @NonNull private Executor mExecutor;
4966         @NonNull private WifiNetworkStateChangedListener mListener;
4967 
OnWifiNetworkStateChangedProxy(@onNull Executor executor, @NonNull WifiNetworkStateChangedListener listener)4968         OnWifiNetworkStateChangedProxy(@NonNull Executor executor,
4969                 @NonNull WifiNetworkStateChangedListener listener) {
4970             Objects.requireNonNull(executor);
4971             Objects.requireNonNull(listener);
4972             mExecutor = executor;
4973             mListener = listener;
4974         }
4975 
4976         @Override
onWifiNetworkStateChanged(int cmmRole, int state)4977         public void onWifiNetworkStateChanged(int cmmRole, int state) {
4978             Log.i(TAG, "OnWifiNetworkStateChangedProxy: onWifiNetworkStateChanged: "
4979                     + cmmRole + ", " + state);
4980             Binder.clearCallingIdentity();
4981             mExecutor.execute(() -> mListener.onWifiNetworkStateChanged(cmmRole, state));
4982         }
4983     }
4984 
4985     /**
4986      * Add a listener to listen to Wi-Fi network state changes on available client mode roles
4987      * specified in {@link WifiNetworkStateChangedListener.WifiClientModeRole}.
4988      * When wifi state changes such as connected/disconnect happens, results will be delivered via
4989      * {@link WifiNetworkStateChangedListener#onWifiNetworkStateChanged(int, int)}.
4990      *
4991      * @param executor The Executor on which to execute the callbacks.
4992      * @param listener listener for the network status updates.
4993      * @throws SecurityException if the caller is missing required permissions.
4994      * @throws IllegalArgumentException if incorrect input arguments are provided.
4995      * @hide
4996      */
4997     @SystemApi
4998     @RequiresPermission(Manifest.permission.NETWORK_SETTINGS)
addWifiNetworkStateChangedListener(@onNull @allbackExecutor Executor executor, @NonNull WifiNetworkStateChangedListener listener)4999     public void addWifiNetworkStateChangedListener(@NonNull @CallbackExecutor Executor executor,
5000             @NonNull WifiNetworkStateChangedListener listener) {
5001         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5002         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
5003         if (mVerboseLoggingEnabled) {
5004             Log.d(TAG, "addWifiNetworkStateChangedListener: listener=" + listener
5005                     + ", executor=" + executor);
5006         }
5007         final int listenerIdentifier = System.identityHashCode(listener);
5008         synchronized (sOnWifiNetworkStateChangedListenerMap) {
5009             try {
5010                 IWifiNetworkStateChangedListener.Stub listenerProxy =
5011                         new OnWifiNetworkStateChangedProxy(executor, listener);
5012                 sOnWifiNetworkStateChangedListenerMap.put(listenerIdentifier,
5013                         listenerProxy);
5014                 mService.addWifiNetworkStateChangedListener(listenerProxy);
5015             } catch (RemoteException e) {
5016                 sOnWifiNetworkStateChangedListenerMap.remove(listenerIdentifier);
5017                 throw e.rethrowFromSystemServer();
5018             }
5019         }
5020     }
5021 
5022     /**
5023      * Remove a listener added using
5024      * {@link #addWifiNetworkStateChangedListener(Executor, WifiNetworkStateChangedListener)}.
5025      * @param listener the listener to be removed.
5026      * @throws IllegalArgumentException if incorrect input arguments are provided.
5027      * @hide
5028      */
5029     @SystemApi
5030     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
removeWifiNetworkStateChangedListener( @onNull WifiNetworkStateChangedListener listener)5031     public void removeWifiNetworkStateChangedListener(
5032             @NonNull WifiNetworkStateChangedListener listener) {
5033         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
5034         if (mVerboseLoggingEnabled) {
5035             Log.d(TAG, "removeWifiNetworkStateChangedListener: listener=" + listener);
5036         }
5037         final int listenerIdentifier = System.identityHashCode(listener);
5038         synchronized (sOnWifiNetworkStateChangedListenerMap) {
5039             try {
5040                 if (!sOnWifiNetworkStateChangedListenerMap.contains(listenerIdentifier)) {
5041                     Log.w(TAG, "Unknown external listener " + listenerIdentifier);
5042                     return;
5043                 }
5044                 mService.removeWifiNetworkStateChangedListener(
5045                         sOnWifiNetworkStateChangedListenerMap.get(listenerIdentifier));
5046             } catch (RemoteException e) {
5047                 throw e.rethrowFromSystemServer();
5048             } finally {
5049                 sOnWifiNetworkStateChangedListenerMap.remove(listenerIdentifier);
5050             }
5051         }
5052     }
5053 
5054     /**
5055      * Get the country code as resolved by the Wi-Fi framework.
5056      * The Wi-Fi framework uses multiple sources to resolve a country code
5057      * - in order of priority (high to low):
5058      * 1. Override country code set by {@link WifiManager#setOverrideCountryCode(String)}
5059      * and cleared by {@link WifiManager#clearOverrideCountryCode()}. Typically only used
5060      * for testing.
5061      * 2. Country code supplied by the telephony module. Typically provided from the
5062      * current network or from emergency cell information.
5063      * 3. Country code supplied by the wifi driver module. (802.11d)
5064      * 4. Default country code set either via {@code ro.boot.wificountrycode}
5065      * or the {@link WifiManager#setDefaultCountryCode(String)}.
5066      *
5067      * <p>
5068      * Note:
5069      * This method returns the Country Code value used by the framework - even if not currently
5070      * used by the Wi-Fi subsystem. I.e. the returned value from this API may be different from the
5071      * value provided by
5072      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}.
5073      * Such a difference may happen when there is an ongoing network connection (STA, AP, Direct,
5074      * or Aware) and the Wi-Fi subsystem does not support dynamic updates - at that point the
5075      * framework may defer setting the Country Code to the Wi-Fi subsystem.
5076      * </p>
5077      * @return the country code in ISO 3166 alpha-2 (2-letter) upper format,
5078      * or null if there is no country code configured.
5079      *
5080      * @hide
5081      */
5082     @Nullable
5083     @SystemApi
5084     @RequiresPermission(anyOf = {
5085             android.Manifest.permission.NETWORK_SETTINGS,
5086             android.Manifest.permission.ACCESS_COARSE_LOCATION
5087     })
getCountryCode()5088     public String getCountryCode() {
5089         try {
5090             return mService.getCountryCode(mContext.getOpPackageName(),
5091                     mContext.getAttributionTag());
5092         } catch (RemoteException e) {
5093             throw e.rethrowFromSystemServer();
5094         }
5095     }
5096 
5097     /**
5098      * Set the override country code - may be used for testing. See the country code resolution
5099      * order and format in {@link #getCountryCode()}.
5100      * @param country A 2-Character alphanumeric country code.
5101      * @see #getCountryCode().
5102      *
5103      * @hide
5104      */
5105     @RequiresApi(Build.VERSION_CODES.S)
5106     @SystemApi
5107     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
setOverrideCountryCode(@onNull String country)5108     public void setOverrideCountryCode(@NonNull String country) {
5109         try {
5110             mService.setOverrideCountryCode(country);
5111         } catch (RemoteException e) {
5112             throw e.rethrowFromSystemServer();
5113         }
5114     }
5115 
5116     /**
5117      * This clears the override country code which was previously set by
5118      * {@link WifiManager#setOverrideCountryCode(String)} method.
5119      * @see #getCountryCode().
5120      *
5121      * @hide
5122      */
5123     @RequiresApi(Build.VERSION_CODES.S)
5124     @SystemApi
5125     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
clearOverrideCountryCode()5126     public void clearOverrideCountryCode() {
5127         try {
5128             mService.clearOverrideCountryCode();
5129         } catch (RemoteException e) {
5130             throw e.rethrowFromSystemServer();
5131         }
5132     }
5133     /**
5134      * Used to configure the default country code. See {@link #getCountryCode()} for resolution
5135      * method of the country code.
5136      * @param country A 2-character alphanumeric country code.
5137      * @see #getCountryCode().
5138      *
5139      * @hide
5140      */
5141     @RequiresApi(Build.VERSION_CODES.S)
5142     @SystemApi
5143     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
setDefaultCountryCode(@onNull String country)5144     public void setDefaultCountryCode(@NonNull String country) {
5145         try {
5146             mService.setDefaultCountryCode(country);
5147         } catch (RemoteException e) {
5148             throw e.rethrowFromSystemServer();
5149         }
5150     }
5151 
5152     /**
5153      * Return the DHCP-assigned addresses from the last successful DHCP request,
5154      * if any.
5155      *
5156      * @return the DHCP information
5157      *
5158      * @deprecated Use the methods on {@link android.net.LinkProperties} which can be obtained
5159      * either via {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)} or
5160      * {@link ConnectivityManager#getLinkProperties(Network)}.
5161      *
5162      * <p>
5163      * <b>Compatibility Notes:</b>
5164      * <li>On devices supporting concurrent connections (indicated via
5165      * {@link #isStaConcurrencyForLocalOnlyConnectionsSupported()}, etc), this API will return
5166      * the details of the internet providing connection (if any) to all apps, except for the apps
5167      * that triggered the creation of the concurrent connection. For such apps, this API will return
5168      * the details of the connection they created. e.g. apps using {@link WifiNetworkSpecifier} will
5169      * trigger a concurrent connection on supported devices and hence this API will provide
5170      * details of their peer to peer connection (not the internet providing connection). This
5171      * is to maintain backwards compatibility with behavior on single STA devices.</li>
5172      * </p>
5173      */
5174     @Deprecated
getDhcpInfo()5175     public DhcpInfo getDhcpInfo() {
5176         try {
5177             return mService.getDhcpInfo(mContext.getOpPackageName());
5178         } catch (RemoteException e) {
5179             throw e.rethrowFromSystemServer();
5180         }
5181     }
5182 
5183     /**
5184      * Enable or disable Wi-Fi.
5185      * <p>
5186      * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
5187      * permission to toggle wifi.
5188      *
5189      * @param enabled {@code true} to enable, {@code false} to disable.
5190      * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
5191      *         either already in the requested state, or in progress toward the requested state.
5192      * @throws  SecurityException if the caller is missing required permissions.
5193      *
5194      * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
5195      * enable/disable Wi-Fi.
5196      * <b>Compatibility Note:</b> For applications targeting
5197      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
5198      * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
5199      * or below), they can continue to use this API.
5200      * <p>
5201      * Deprecation Exemptions:
5202      * <ul>
5203      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
5204      * </ul>
5205      *
5206      * Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, DO and a profile owner of
5207      * an organization owned device may set a user restriction (DISALLOW_CHANGE_WIFI_STATE)
5208      * to only allow DO/PO to use this API.
5209      */
5210     @Deprecated
setWifiEnabled(boolean enabled)5211     public boolean setWifiEnabled(boolean enabled) {
5212         try {
5213             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
5214         } catch (RemoteException e) {
5215             throw e.rethrowFromSystemServer();
5216         }
5217     }
5218 
5219     /**
5220      * Abstract callback class for applications to receive updates about the Wi-Fi subsystem
5221      * restarting. The Wi-Fi subsystem can restart due to internal recovery mechanisms or via user
5222      * action.
5223      */
5224     @RequiresApi(Build.VERSION_CODES.S)
5225     public abstract static class SubsystemRestartTrackingCallback {
5226         private final SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy mProxy;
5227 
SubsystemRestartTrackingCallback()5228         public SubsystemRestartTrackingCallback() {
5229             mProxy = new SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy();
5230         }
5231 
5232         /*package*/ @NonNull
getProxy()5233         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy getProxy() {
5234             return mProxy;
5235         }
5236 
5237         /**
5238          * Indicates that the Wi-Fi subsystem is about to restart.
5239          */
onSubsystemRestarting()5240         public abstract void onSubsystemRestarting();
5241 
5242         /**
5243          * Indicates that the Wi-Fi subsystem has restarted.
5244          */
onSubsystemRestarted()5245         public abstract void onSubsystemRestarted();
5246 
5247         private static class SubsystemRestartCallbackProxy extends ISubsystemRestartCallback.Stub {
5248             private final Object mLock = new Object();
5249             @Nullable
5250             @GuardedBy("mLock")
5251             private Executor mExecutor;
5252             @Nullable
5253             @GuardedBy("mLock")
5254             private SubsystemRestartTrackingCallback mCallback;
5255 
SubsystemRestartCallbackProxy()5256             SubsystemRestartCallbackProxy() {
5257                 mExecutor = null;
5258                 mCallback = null;
5259             }
5260 
initProxy(@onNull Executor executor, @NonNull SubsystemRestartTrackingCallback callback)5261             /*package*/ void initProxy(@NonNull Executor executor,
5262                     @NonNull SubsystemRestartTrackingCallback callback) {
5263                 synchronized (mLock) {
5264                     mExecutor = executor;
5265                     mCallback = callback;
5266                 }
5267             }
5268 
cleanUpProxy()5269             /*package*/ void cleanUpProxy() {
5270                 synchronized (mLock) {
5271                     mExecutor = null;
5272                     mCallback = null;
5273                 }
5274             }
5275 
5276             @Override
onSubsystemRestarting()5277             public void onSubsystemRestarting() {
5278                 Executor executor;
5279                 SubsystemRestartTrackingCallback callback;
5280                 synchronized (mLock) {
5281                     executor = mExecutor;
5282                     callback = mCallback;
5283                 }
5284                 if (executor == null || callback == null) {
5285                     return;
5286                 }
5287                 Binder.clearCallingIdentity();
5288                 executor.execute(callback::onSubsystemRestarting);
5289             }
5290 
5291             @Override
onSubsystemRestarted()5292             public void onSubsystemRestarted() {
5293                 Executor executor;
5294                 SubsystemRestartTrackingCallback callback;
5295                 synchronized (mLock) {
5296                     executor = mExecutor;
5297                     callback = mCallback;
5298                 }
5299                 if (executor == null || callback == null) {
5300                     return;
5301                 }
5302                 Binder.clearCallingIdentity();
5303                 executor.execute(callback::onSubsystemRestarted);
5304             }
5305         }
5306     }
5307 
5308     /**
5309      * Registers a {@link SubsystemRestartTrackingCallback} to listen to Wi-Fi subsystem restarts.
5310      * The subsystem may restart due to internal recovery mechanisms or via user action.
5311      *
5312      * @see #unregisterSubsystemRestartTrackingCallback(SubsystemRestartTrackingCallback)
5313      *
5314      * @param executor Executor to execute callback on
5315      * @param callback {@link SubsystemRestartTrackingCallback} to register
5316      */
5317     @RequiresApi(Build.VERSION_CODES.S)
5318     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
registerSubsystemRestartTrackingCallback( @onNull @allbackExecutor Executor executor, @NonNull SubsystemRestartTrackingCallback callback)5319     public void registerSubsystemRestartTrackingCallback(
5320             @NonNull @CallbackExecutor Executor executor,
5321             @NonNull SubsystemRestartTrackingCallback callback) {
5322         if (executor == null) throw new IllegalArgumentException("executor must not be null");
5323         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5324         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy proxy = callback.getProxy();
5325         proxy.initProxy(executor, callback);
5326         try {
5327             mService.registerSubsystemRestartCallback(proxy);
5328         } catch (RemoteException e) {
5329             proxy.cleanUpProxy();
5330             throw e.rethrowFromSystemServer();
5331         }
5332     }
5333 
5334     /**
5335      * Unregisters a {@link SubsystemRestartTrackingCallback} registered with
5336      * {@link #registerSubsystemRestartTrackingCallback(Executor, SubsystemRestartTrackingCallback)}
5337      *
5338      * @param callback {@link SubsystemRestartTrackingCallback} to unregister
5339      */
5340     @RequiresApi(Build.VERSION_CODES.S)
5341     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
unregisterSubsystemRestartTrackingCallback( @onNull SubsystemRestartTrackingCallback callback)5342     public void unregisterSubsystemRestartTrackingCallback(
5343             @NonNull SubsystemRestartTrackingCallback callback) {
5344         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5345         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy proxy = callback.getProxy();
5346         try {
5347             mService.unregisterSubsystemRestartCallback(proxy);
5348         } catch (RemoteException e) {
5349             throw e.rethrowFromSystemServer();
5350         } finally {
5351             proxy.cleanUpProxy();
5352         }
5353     }
5354 
5355     /**
5356      * Restart the Wi-Fi subsystem.
5357      *
5358      * Restarts the Wi-Fi subsystem - effectively disabling it and re-enabling it. All existing
5359      * Access Point (AP) associations are torn down, all Soft APs are disabled, Wi-Fi Direct and
5360      * Wi-Fi Aware are disabled.
5361      *
5362      * The state of the system after restart is not guaranteed to match its state before the API is
5363      * called - for instance the device may associate to a different Access Point (AP), and tethered
5364      * hotspots may or may not be restored.
5365      *
5366      * Use the
5367      * {@link #registerSubsystemRestartTrackingCallback(Executor, SubsystemRestartTrackingCallback)}
5368      * to track the operation.
5369      *
5370      * @hide
5371      */
5372     @RequiresApi(Build.VERSION_CODES.S)
5373     @SystemApi
5374     @RequiresPermission(android.Manifest.permission.RESTART_WIFI_SUBSYSTEM)
restartWifiSubsystem()5375     public void restartWifiSubsystem() {
5376         try {
5377             mService.restartWifiSubsystem();
5378         } catch (RemoteException e) {
5379             throw e.rethrowFromSystemServer();
5380         }
5381     }
5382 
5383     /**
5384      * Gets the Wi-Fi enabled state.
5385      * @return One of {@link #WIFI_STATE_DISABLED},
5386      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
5387      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
5388      * @see #isWifiEnabled()
5389      */
getWifiState()5390     public int getWifiState() {
5391         try {
5392             return mService.getWifiEnabledState();
5393         } catch (RemoteException e) {
5394             throw e.rethrowFromSystemServer();
5395         }
5396     }
5397 
5398     /**
5399      * Return whether Wi-Fi is enabled or disabled.
5400      * @return {@code true} if Wi-Fi is enabled
5401      * @see #getWifiState()
5402      */
isWifiEnabled()5403     public boolean isWifiEnabled() {
5404         return getWifiState() == WIFI_STATE_ENABLED;
5405     }
5406 
5407     /**
5408      * Register a callback for Wi-Fi state. See {@link WifiStateChangedListener}.
5409      * Caller will receive the event when the Wi-Fi state changes.
5410      * Caller can remove a previously registered callback using
5411      * {@link WifiManager#removeWifiStateChangedListener(WifiStateChangedListener)}
5412      *
5413      * @param executor Executor to execute listener callback on
5414      * @param listener Listener to register
5415      */
5416     @FlaggedApi(Flags.FLAG_WIFI_STATE_CHANGED_LISTENER)
5417     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
addWifiStateChangedListener(@onNull @allbackExecutor Executor executor, @NonNull WifiStateChangedListener listener)5418     public void addWifiStateChangedListener(@NonNull @CallbackExecutor Executor executor,
5419             @NonNull WifiStateChangedListener listener) {
5420         Objects.requireNonNull(executor);
5421         Objects.requireNonNull(listener);
5422         if (mVerboseLoggingEnabled) {
5423             Log.d(TAG, "addWifiStateChangedListener: listener=" + listener
5424                     + ", executor=" + executor);
5425         }
5426         final int listenerIdentifier = System.identityHashCode(listener);
5427         synchronized (sWifiStateChangedListenerMap) {
5428             try {
5429                 if (sWifiStateChangedListenerMap.contains(listenerIdentifier)) {
5430                     Log.w(TAG, "Same listener already registered");
5431                     return;
5432                 }
5433                 IWifiStateChangedListener.Stub listenerProxy =
5434                         new WifiStateChangedListenerProxy(executor, listener);
5435                 sWifiStateChangedListenerMap.put(listenerIdentifier, listenerProxy);
5436                 mService.addWifiStateChangedListener(listenerProxy);
5437             } catch (RemoteException e) {
5438                 sWifiStateChangedListenerMap.remove(listenerIdentifier);
5439                 throw e.rethrowFromSystemServer();
5440             }
5441         }
5442     }
5443 
5444     /**
5445      * Unregisters a WifiStateChangedListener from listening on the current Wi-Fi state.
5446      *
5447      * @param listener WifiStateChangedListener to unregister
5448      */
5449     @FlaggedApi(Flags.FLAG_WIFI_STATE_CHANGED_LISTENER)
5450     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
removeWifiStateChangedListener(@onNull WifiStateChangedListener listener)5451     public void removeWifiStateChangedListener(@NonNull WifiStateChangedListener listener) {
5452         Objects.requireNonNull(listener);
5453         if (mVerboseLoggingEnabled) {
5454             Log.d(TAG, "removeWifiStateChangedListener: listener=" + listener);
5455         }
5456         final int listenerIdentifier = System.identityHashCode(listener);
5457         synchronized (sWifiStateChangedListenerMap) {
5458             try {
5459                 if (!sWifiStateChangedListenerMap.contains(listenerIdentifier)) {
5460                     Log.w(TAG, "Unknown external listener " + listenerIdentifier);
5461                     return;
5462                 }
5463                 mService.removeWifiStateChangedListener(
5464                         sWifiStateChangedListenerMap.get(listenerIdentifier));
5465             } catch (RemoteException e) {
5466                 throw e.rethrowFromSystemServer();
5467             } finally {
5468                 sWifiStateChangedListenerMap.remove(listenerIdentifier);
5469             }
5470         }
5471     }
5472 
5473     /**
5474      * Listener interface for applications to be notified when the Wi-Fi enabled state changes.
5475      */
5476     @FlaggedApi(Flags.FLAG_WIFI_STATE_CHANGED_LISTENER)
5477     public interface WifiStateChangedListener {
5478         /**
5479          * Called when the Wi-Fi enabled state changes.
5480          * The new value can be queried via {@link WifiManager#getWifiState()}.
5481          */
onWifiStateChanged()5482         void onWifiStateChanged();
5483     }
5484 
5485     /**
5486      * Listener proxy for WifiStateChangedListener objects.
5487      */
5488     private static class WifiStateChangedListenerProxy extends IWifiStateChangedListener.Stub {
5489         private Executor mExecutor;
5490         private WifiStateChangedListener mListener;
5491 
WifiStateChangedListenerProxy(@onNull Executor executor, @NonNull WifiStateChangedListener listener)5492         WifiStateChangedListenerProxy(@NonNull Executor executor,
5493                 @NonNull WifiStateChangedListener listener) {
5494             Objects.requireNonNull(executor);
5495             Objects.requireNonNull(listener);
5496             mExecutor = executor;
5497             mListener = listener;
5498         }
5499 
5500         @Override
onWifiStateChanged()5501         public void onWifiStateChanged() {
5502             Log.i(TAG, "WifiStateChangedListenerProxy: onWifiStateChanged");
5503             Binder.clearCallingIdentity();
5504             mExecutor.execute(() -> mListener.onWifiStateChanged());
5505         }
5506     }
5507 
5508     /**
5509      * Calculates the level of the signal. This should be used any time a signal
5510      * is being shown.
5511      *
5512      * @param rssi The power of the signal measured in RSSI.
5513      * @param numLevels The number of levels to consider in the calculated level.
5514      * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive).
5515      * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the
5516      * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level
5517      * themselves using their own formula.
5518      */
5519     @Deprecated
calculateSignalLevel(int rssi, int numLevels)5520     public static int calculateSignalLevel(int rssi, int numLevels) {
5521         if (rssi <= MIN_RSSI) {
5522             return 0;
5523         } else if (rssi >= MAX_RSSI) {
5524             return numLevels - 1;
5525         } else {
5526             float inputRange = (MAX_RSSI - MIN_RSSI);
5527             float outputRange = (numLevels - 1);
5528             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
5529         }
5530     }
5531 
5532     /**
5533      * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI
5534      * quality rating thresholds.
5535      * @param rssi a raw RSSI value, in dBm, usually between -55 and -90
5536      * @return the RSSI signal quality rating, in the range
5537      * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
5538      * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
5539      */
5540     @IntRange(from = 0)
calculateSignalLevel(int rssi)5541     public int calculateSignalLevel(int rssi) {
5542         try {
5543             return mService.calculateSignalLevel(rssi);
5544         } catch (RemoteException e) {
5545             throw e.rethrowFromSystemServer();
5546         }
5547     }
5548 
5549     /**
5550      * Get the system default maximum signal level.
5551      * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
5552      */
5553     @IntRange(from = 0)
getMaxSignalLevel()5554     public int getMaxSignalLevel() {
5555         return calculateSignalLevel(Integer.MAX_VALUE);
5556     }
5557 
5558     /**
5559      * Compares two signal strengths.
5560      *
5561      * @param rssiA The power of the first signal measured in RSSI.
5562      * @param rssiB The power of the second signal measured in RSSI.
5563      * @return Returns <0 if the first signal is weaker than the second signal,
5564      *         0 if the two signals have the same strength, and >0 if the first
5565      *         signal is stronger than the second signal.
5566      */
compareSignalLevel(int rssiA, int rssiB)5567     public static int compareSignalLevel(int rssiA, int rssiB) {
5568         return rssiA - rssiB;
5569     }
5570 
5571     /**
5572      * Call allowing ConnectivityService to update WifiService with interface mode changes.
5573      *
5574      * @param ifaceName String name of the updated interface, or null to represent all interfaces
5575      * @param mode int representing the new mode, one of:
5576      *             {@link #IFACE_IP_MODE_TETHERED},
5577      *             {@link #IFACE_IP_MODE_LOCAL_ONLY},
5578      *             {@link #IFACE_IP_MODE_CONFIGURATION_ERROR},
5579      *             {@link #IFACE_IP_MODE_UNSPECIFIED}
5580      *
5581      * @hide
5582      */
5583     @SystemApi
5584     @RequiresPermission(anyOf = {
5585             android.Manifest.permission.NETWORK_STACK,
5586             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5587     })
updateInterfaceIpState(@ullable String ifaceName, @IfaceIpMode int mode)5588     public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
5589         try {
5590             mService.updateInterfaceIpState(ifaceName, mode);
5591         } catch (RemoteException e) {
5592             throw e.rethrowFromSystemServer();
5593         }
5594     }
5595 
5596     /* Wi-Fi/Cellular Coex */
5597 
5598     /**
5599      * Mandatory coex restriction flag for Wi-Fi Direct.
5600      *
5601      * @see #setCoexUnsafeChannels(List, int)
5602      *
5603      * @hide
5604      */
5605     @SystemApi
5606     @RequiresApi(Build.VERSION_CODES.S)
5607     public static final int COEX_RESTRICTION_WIFI_DIRECT = 0x1 << 0;
5608 
5609     /**
5610      * Mandatory coex restriction flag for SoftAP
5611      *
5612      * @see #setCoexUnsafeChannels(List, int)
5613      *
5614      * @hide
5615      */
5616     @SystemApi
5617     @RequiresApi(Build.VERSION_CODES.S)
5618     public static final int COEX_RESTRICTION_SOFTAP = 0x1 << 1;
5619 
5620     /**
5621      * Mandatory coex restriction flag for Wi-Fi Aware.
5622      *
5623      * @see #setCoexUnsafeChannels(List, int)
5624      *
5625      * @hide
5626      */
5627     @SystemApi
5628     @RequiresApi(Build.VERSION_CODES.S)
5629     public static final int COEX_RESTRICTION_WIFI_AWARE = 0x1 << 2;
5630 
5631     /** @hide */
5632     @RequiresApi(Build.VERSION_CODES.S)
5633     @Retention(RetentionPolicy.SOURCE)
5634     @IntDef(flag = true, prefix = {"COEX_RESTRICTION_"}, value = {
5635             COEX_RESTRICTION_WIFI_DIRECT,
5636             COEX_RESTRICTION_SOFTAP,
5637             COEX_RESTRICTION_WIFI_AWARE
5638     })
5639     public @interface CoexRestriction {}
5640 
5641     /**
5642      * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
5643      *
5644      * @hide
5645      */
isDefaultCoexAlgorithmEnabled()5646     public boolean isDefaultCoexAlgorithmEnabled() {
5647         try {
5648             return mService.isDefaultCoexAlgorithmEnabled();
5649         } catch (RemoteException e) {
5650             throw e.rethrowFromSystemServer();
5651         }
5652     }
5653 
5654     /**
5655      * Specify the list of {@link CoexUnsafeChannel} to propagate through the framework for
5656      * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
5657      * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
5658      *
5659      * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
5660      * @param restrictions Bitmap of {@code COEX_RESTRICTION_*} constants specifying the mode
5661      *                     restrictions on the specified channels. If any restrictions are set,
5662      *                     then the supplied CoexUnsafeChannels should be completely avoided for
5663      *                     the specified modes, rather than be avoided with best effort.
5664      *
5665      * @hide
5666      */
5667     @SystemApi
5668     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS)
5669     @RequiresApi(Build.VERSION_CODES.S)
setCoexUnsafeChannels( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5670     public void setCoexUnsafeChannels(
5671             @NonNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions) {
5672         if (unsafeChannels == null) {
5673             throw new IllegalArgumentException("unsafeChannels must not be null");
5674         }
5675         try {
5676             mService.setCoexUnsafeChannels(unsafeChannels, restrictions);
5677         } catch (RemoteException e) {
5678             throw e.rethrowFromSystemServer();
5679         }
5680     }
5681 
5682     /**
5683      * Registers a CoexCallback to listen on the current CoexUnsafeChannels and restrictions being
5684      * used for Wi-Fi/cellular coex channel avoidance. The callback method
5685      * {@link CoexCallback#onCoexUnsafeChannelsChanged(List, int)} will be called immediately after
5686      * registration to return the current values.
5687      *
5688      * @param executor Executor to execute listener callback on
5689      * @param callback CoexCallback to register
5690      *
5691      * @hide
5692      */
5693     @SystemApi
5694     @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
5695     @RequiresApi(Build.VERSION_CODES.S)
registerCoexCallback( @onNull @allbackExecutor Executor executor, @NonNull CoexCallback callback)5696     public void registerCoexCallback(
5697             @NonNull @CallbackExecutor Executor executor, @NonNull CoexCallback callback) {
5698         if (executor == null) throw new IllegalArgumentException("executor must not be null");
5699         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5700         CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
5701         proxy.initProxy(executor, callback);
5702         try {
5703             mService.registerCoexCallback(proxy);
5704         } catch (RemoteException e) {
5705             throw e.rethrowFromSystemServer();
5706         }
5707     }
5708 
5709     /**
5710      * Unregisters a CoexCallback from listening on the current CoexUnsafeChannels and restrictions
5711      * being used for Wi-Fi/cellular coex channel avoidance.
5712      * @param callback CoexCallback to unregister
5713      *
5714      * @hide
5715      */
5716     @SystemApi
5717     @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
5718     @RequiresApi(Build.VERSION_CODES.S)
unregisterCoexCallback(@onNull CoexCallback callback)5719     public void unregisterCoexCallback(@NonNull CoexCallback callback) {
5720         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5721         CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
5722         try {
5723             mService.unregisterCoexCallback(proxy);
5724         } catch (RemoteException e) {
5725             throw e.rethrowFromSystemServer();
5726         } finally {
5727             proxy.cleanUpProxy();
5728         }
5729     }
5730 
5731     /**
5732      * Abstract callback class for applications to receive updates about current CoexUnsafeChannels
5733      * for Wi-Fi/Cellular coex channel avoidance.
5734      *
5735      * @hide
5736      */
5737     @SystemApi
5738     @RequiresApi(Build.VERSION_CODES.S)
5739     public abstract static class CoexCallback {
5740         private final CoexCallbackProxy mCoexCallbackProxy;
5741 
CoexCallback()5742         public CoexCallback() {
5743             if (!SdkLevel.isAtLeastS()) {
5744                 throw new UnsupportedOperationException();
5745             }
5746             mCoexCallbackProxy = new CoexCallbackProxy();
5747         }
5748 
5749         /*package*/ @NonNull
getProxy()5750         CoexCallbackProxy getProxy() {
5751             return mCoexCallbackProxy;
5752         }
5753 
5754         /**
5755          * This indicates the current CoexUnsafeChannels and restrictions calculated by the default
5756          * coex algorithm if config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, the
5757          * values will match the ones supplied to {@link #setCoexUnsafeChannels(List, int)}.
5758          *
5759          * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
5760          * @param restrictions Bitmap of {@code COEX_RESTRICTION_*} constants specifying the mode
5761          *                     restrictions on the specified channels. If any restrictions are set,
5762          *                     then the supplied CoexUnsafeChannels should be completely avoided for
5763          *                     the specified modes, rather than be avoided with best effort.
5764          */
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5765         public abstract void onCoexUnsafeChannelsChanged(
5766                 @NonNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions);
5767 
5768         /**
5769          * Callback proxy for CoexCallback objects.
5770          */
5771         private static class CoexCallbackProxy extends ICoexCallback.Stub {
5772             private final Object mLock = new Object();
5773             @Nullable @GuardedBy("mLock") private Executor mExecutor;
5774             @Nullable @GuardedBy("mLock") private CoexCallback mCallback;
5775 
CoexCallbackProxy()5776             CoexCallbackProxy() {
5777                 mExecutor = null;
5778                 mCallback = null;
5779             }
5780 
initProxy(@onNull Executor executor, @NonNull CoexCallback callback)5781             /*package*/ void initProxy(@NonNull Executor executor,
5782                     @NonNull CoexCallback callback) {
5783                 synchronized (mLock) {
5784                     mExecutor = executor;
5785                     mCallback = callback;
5786                 }
5787             }
5788 
cleanUpProxy()5789             /*package*/ void cleanUpProxy() {
5790                 synchronized (mLock) {
5791                     mExecutor = null;
5792                     mCallback = null;
5793                 }
5794             }
5795 
5796             @Override
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5797             public void onCoexUnsafeChannelsChanged(
5798                     @NonNull List<CoexUnsafeChannel> unsafeChannels,
5799                     @CoexRestriction int restrictions) {
5800                 Executor executor;
5801                 CoexCallback callback;
5802                 synchronized (mLock) {
5803                     executor = mExecutor;
5804                     callback = mCallback;
5805                 }
5806                 if (executor == null || callback == null) {
5807                     return;
5808                 }
5809                 Binder.clearCallingIdentity();
5810                 executor.execute(() ->
5811                         callback.onCoexUnsafeChannelsChanged(unsafeChannels, restrictions));
5812             }
5813         }
5814     }
5815 
5816     /**
5817      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
5818      * Note that starting Soft AP mode may disable station mode operation if the device does not
5819      * support concurrency.
5820      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
5821      *                   use the persisted Soft AP configuration that was previously set using
5822      *                   {@link #setWifiApConfiguration(WifiConfiguration)}.
5823      * @return {@code true} if the operation succeeded, {@code false} otherwise
5824      *
5825      * @hide
5826      */
5827     @RequiresPermission(anyOf = {
5828             android.Manifest.permission.NETWORK_STACK,
5829             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5830     })
startSoftAp(@ullable WifiConfiguration wifiConfig)5831     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
5832         try {
5833             return mService.startSoftAp(wifiConfig, mContext.getOpPackageName());
5834         } catch (RemoteException e) {
5835             throw e.rethrowFromSystemServer();
5836         }
5837     }
5838 
5839     /**
5840      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
5841      * Note that starting Soft AP mode may disable station mode operation if the device does not
5842      * support concurrency.
5843      *
5844      * Note: Call {@link WifiManager#validateSoftApConfiguration(SoftApConfiguration)} to avoid
5845      * unexpected error due to invalid configuration.
5846      *
5847      * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP, or
5848      *                     null to use the persisted Soft AP configuration that was previously set
5849      *                     using {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}.
5850      * @return {@code true} if the operation succeeded, {@code false} otherwise
5851      *
5852      * @deprecated Use {@link #startTetheredHotspot(TetheringManager.TetheringRequest)}
5853      *             instead.
5854      * @hide
5855      */
5856     @SystemApi
5857     @RequiresPermission(anyOf = {
5858             android.Manifest.permission.NETWORK_STACK,
5859             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5860     })
5861     @Deprecated
startTetheredHotspot(@ullable SoftApConfiguration softApConfig)5862     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
5863         try {
5864             return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
5865         } catch (RemoteException e) {
5866             throw e.rethrowFromSystemServer();
5867         }
5868     }
5869 
5870     /**
5871      * Start Soft AP (hotspot) mode for tethering purposes with the specified TetheringRequest.
5872      * Note that starting Soft AP mode may disable station mode operation if the device does not
5873      * support concurrency.
5874      *
5875      * @param request  A valid TetheringRequest specifying the configuration of the SAP.
5876      * @param executor Executor to run the callback on.
5877      * @param callback Callback to listen on state changes for this specific request.
5878      * @hide
5879      */
5880     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
5881     @SystemApi
5882     @RequiresPermission(anyOf = {
5883             android.Manifest.permission.NETWORK_STACK,
5884             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5885     })
startTetheredHotspot(@onNull TetheringManager.TetheringRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull SoftApCallback callback)5886     public void startTetheredHotspot(@NonNull TetheringManager.TetheringRequest request,
5887             @NonNull @CallbackExecutor Executor executor, @NonNull SoftApCallback callback) {
5888         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5889         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5890         ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
5891                 IFACE_IP_MODE_TETHERED);
5892         try {
5893             mService.startTetheredHotspotRequest(request, binderCallback,
5894                     mContext.getOpPackageName());
5895         } catch (RemoteException e) {
5896             throw e.rethrowFromSystemServer();
5897         }
5898     }
5899 
5900     /**
5901      * Stop SoftAp mode.
5902      * Note that stopping softap mode will restore the previous wifi mode.
5903      * @return {@code true} if the operation succeeds, {@code false} otherwise
5904      *
5905      * @hide
5906      */
5907     @SystemApi
5908     @RequiresPermission(anyOf = {
5909             android.Manifest.permission.NETWORK_STACK,
5910             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5911     })
stopSoftAp()5912     public boolean stopSoftAp() {
5913         try {
5914             return mService.stopSoftAp();
5915         } catch (RemoteException e) {
5916             throw e.rethrowFromSystemServer();
5917         }
5918     }
5919 
5920     /**
5921      * Check if input configuration is valid.
5922      *
5923      * @param config a configuration would like to be checked.
5924      * @return true if config is valid, otherwise false.
5925      */
validateSoftApConfiguration(@onNull SoftApConfiguration config)5926     public boolean validateSoftApConfiguration(@NonNull SoftApConfiguration config) {
5927         if (config == null) {
5928             throw new IllegalArgumentException(TAG + ": config can not be null");
5929         }
5930         try {
5931             return mService.validateSoftApConfiguration(config);
5932         } catch (RemoteException e) {
5933             throw e.rethrowFromSystemServer();
5934         }
5935     }
5936 
5937     /**
5938      * Request a local only hotspot that an application can use to communicate between co-located
5939      * devices connected to the created WiFi hotspot.  The network created by this method will not
5940      * have Internet access.  Each application can make a single request for the hotspot, but
5941      * multiple applications could be requesting the hotspot at the same time.  When multiple
5942      * applications have successfully registered concurrently, they will be sharing the underlying
5943      * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called
5944      * when the hotspot is ready for use by the application.
5945      * <p>
5946      * Each application can make a single active call to this method. The {@link
5947      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
5948      * requestor with a {@link LocalOnlyHotspotReservation} that contains a
5949      * {@link SoftApConfiguration} with the SSID, security type and credentials needed to connect
5950      * to the hotspot.  Communicating this information is up to the application.
5951      * <p>
5952      * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
5953      * method will be called. Example failures include errors bringing up the network or if
5954      * there is an incompatible operating mode.  For example, if the user is currently using Wifi
5955      * Tethering to provide an upstream to another device, LocalOnlyHotspot may not start due to
5956      * an incompatible mode. The possible error codes include:
5957      * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL},
5958      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC},
5959      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and
5960      * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}.
5961      * <p>
5962      * Internally, requests will be tracked to prevent the hotspot from being torn down while apps
5963      * are still using it.  The {@link LocalOnlyHotspotReservation} object passed in the  {@link
5964      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when
5965      * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}.
5966      * Since the hotspot may be shared among multiple applications, removing the final registered
5967      * application request will trigger the hotspot teardown.  This means that applications should
5968      * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after
5969      * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is
5970      * called, applications will not receive callbacks of any kind.
5971      * <p>
5972      * Applications should be aware that the user may also stop the LocalOnlyHotspot through the
5973      * Settings UI; it is not guaranteed to stay up as long as there is a requesting application.
5974      * The requestors will be notified of this case via
5975      * {@link LocalOnlyHotspotCallback#onStopped()}.  Other cases may arise where the hotspot is
5976      * torn down (Emergency mode, etc).  Application developers should be aware that it can stop
5977      * unexpectedly, but they will receive a notification if they have properly registered.
5978      * <p>
5979      * Applications should also be aware that this network will be shared with other applications.
5980      * Applications are responsible for protecting their data on this network (e.g. TLS).
5981      * <p>
5982      * Applications targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later need to have
5983      * the following permissions: {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
5984      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}.
5985      * Applications targeting {@link Build.VERSION_CODES#S} or prior SDK levels need to have the
5986      * following permissions: {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
5987      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
5988      * Callers without
5989      * the permissions will trigger a {@link java.lang.SecurityException}.
5990      * <p>
5991      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
5992      * operating status.
5993      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
5994      * main thread will be used.
5995      */
5996     @RequiresPermission(allOf = {CHANGE_WIFI_STATE, ACCESS_FINE_LOCATION, NEARBY_WIFI_DEVICES},
5997             conditional = true)
startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler)5998     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
5999             @Nullable Handler handler) {
6000         Executor executor = handler == null ? null : new HandlerExecutor(handler);
6001         startLocalOnlyHotspotInternal(null, executor, callback, false);
6002     }
6003 
6004    /**
6005      * Starts a local-only hotspot with a specific configuration applied. See
6006      * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
6007      *
6008      * Since custom configuration settings may be incompatible with each other, the hotspot started
6009      * through this method cannot coexist with another hotspot created through
6010      * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}. If this is attempted,
6011      * the first hotspot request wins and others receive
6012      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
6013      * {@link LocalOnlyHotspotCallback#onFailed}.
6014      *
6015      * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
6016      * @param executor Executor to run callback methods on.
6017      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
6018      * operating status.
6019      */
6020     @RequiresPermission(allOf = {CHANGE_WIFI_STATE, NEARBY_WIFI_DEVICES})
6021     @FlaggedApi(Flags.FLAG_PUBLIC_BANDS_FOR_LOHS)
startLocalOnlyHotspotWithConfiguration(@onNull SoftApConfiguration config, @NonNull @CallbackExecutor Executor executor, @NonNull LocalOnlyHotspotCallback callback)6022     public void startLocalOnlyHotspotWithConfiguration(@NonNull SoftApConfiguration config,
6023             @NonNull @CallbackExecutor Executor executor,
6024             @NonNull LocalOnlyHotspotCallback callback) {
6025         Objects.requireNonNull(config);
6026         Objects.requireNonNull(executor);
6027         Objects.requireNonNull(callback);
6028         startLocalOnlyHotspotInternal(config, executor, callback, false);
6029     }
6030 
6031 
6032     /**
6033      * Starts a local-only hotspot with a specific configuration applied. See
6034      * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
6035      *
6036      * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD},
6037      * {@link android.Manifest.permission#NETWORK_SETTINGS} or
6038      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} to call this method.
6039      *
6040      * Since custom configuration settings may be incompatible with each other, the hotspot started
6041      * through this method cannot coexist with another hotspot created through
6042      * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others
6043      * receive {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
6044      * {@link LocalOnlyHotspotCallback#onFailed}.
6045      *
6046      * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
6047      * @param executor Executor to run callback methods on, or null to use the main thread.
6048      * @param callback Callback object for updates about hotspot status, or null for no updates.
6049      * @hide
6050      */
6051     @SystemApi
6052     @RequiresPermission(anyOf = {
6053             android.Manifest.permission.NETWORK_SETTINGS,
6054             android.Manifest.permission.NETWORK_SETUP_WIZARD,
6055             NEARBY_WIFI_DEVICES})
startLocalOnlyHotspot(@onNull SoftApConfiguration config, @Nullable @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)6056     public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config,
6057             @Nullable @CallbackExecutor Executor executor,
6058             @Nullable LocalOnlyHotspotCallback callback) {
6059         Objects.requireNonNull(config);
6060         startLocalOnlyHotspotInternal(config, executor, callback, true);
6061     }
6062 
6063     /**
6064      * Common implementation of both configurable and non-configurable LOHS.
6065      *
6066      * @param config App-specified configuration, or null. When present, additional privileges are
6067      *               required, and the hotspot cannot be shared with other clients.
6068      * @param executor Executor to run callback methods on, or null to use the main thread.
6069      * @param callback Callback object for updates about hotspot status, or null for no updates.
6070      */
startLocalOnlyHotspotInternal( @ullable SoftApConfiguration config, @Nullable @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback, boolean isCalledFromSystemApi)6071     private void startLocalOnlyHotspotInternal(
6072             @Nullable SoftApConfiguration config,
6073             @Nullable @CallbackExecutor Executor executor,
6074             @Nullable LocalOnlyHotspotCallback callback,
6075             boolean isCalledFromSystemApi) {
6076         if (executor == null) {
6077             executor = mContext.getMainExecutor();
6078         }
6079         synchronized (mLock) {
6080             LocalOnlyHotspotCallbackProxy proxy =
6081                     new LocalOnlyHotspotCallbackProxy(this, executor, callback);
6082             try {
6083                 String packageName = mContext.getOpPackageName();
6084                 String featureId = mContext.getAttributionTag();
6085                 Bundle extras = new Bundle();
6086                 if (SdkLevel.isAtLeastS()) {
6087                     extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
6088                             mContext.getAttributionSource());
6089                 }
6090                 int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
6091                         config, extras, isCalledFromSystemApi);
6092                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
6093                     // Send message to the proxy to make sure we call back on the correct thread
6094                     proxy.onHotspotFailed(returnCode);
6095                     return;
6096                 }
6097                 mLOHSCallbackProxy = proxy;
6098             } catch (RemoteException e) {
6099                 throw e.rethrowFromSystemServer();
6100             }
6101         }
6102     }
6103 
6104     /**
6105      * Cancels a pending local only hotspot request.  This can be used by the calling application to
6106      * cancel the existing request if the provided callback has not been triggered.  Calling this
6107      * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not
6108      * explicitly required.
6109      * <p>
6110      * When cancelling this request, application developers should be aware that there may still be
6111      * outstanding local only hotspot requests and the hotspot may still start, or continue running.
6112      * Additionally, if a callback was registered, it will no longer be triggered after calling
6113      * cancel.
6114      *
6115      * @hide
6116      */
6117     @UnsupportedAppUsage
cancelLocalOnlyHotspotRequest()6118     public void cancelLocalOnlyHotspotRequest() {
6119         synchronized (mLock) {
6120             stopLocalOnlyHotspot();
6121         }
6122     }
6123 
6124     /**
6125      *  Method used to inform WifiService that the LocalOnlyHotspot is no longer needed.  This
6126      *  method is used by WifiManager to release LocalOnlyHotspotReservations held by calling
6127      *  applications and removes the internal tracking for the hotspot request.  When all requesting
6128      *  applications are finished using the hotspot, it will be stopped and WiFi will return to the
6129      *  previous operational mode.
6130      *
6131      *  This method should not be called by applications.  Instead, they should call the close()
6132      *  method on their LocalOnlyHotspotReservation.
6133      */
stopLocalOnlyHotspot()6134     private void stopLocalOnlyHotspot() {
6135         synchronized (mLock) {
6136             if (mLOHSCallbackProxy == null) {
6137                 // nothing to do, the callback was already cleaned up.
6138                 return;
6139             }
6140             mLOHSCallbackProxy = null;
6141             try {
6142                 mService.stopLocalOnlyHotspot();
6143             } catch (RemoteException e) {
6144                 throw e.rethrowFromSystemServer();
6145             }
6146         }
6147     }
6148 
6149     /**
6150      * Registers a callback for local only hotspot. See {@link SoftApCallback}. Caller will receive
6151      * the following callbacks on registration:
6152      * <ul>
6153      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
6154      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
6155      * <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
6156      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
6157      * </ul>
6158      *
6159      * Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
6160      * if there are any clients connected to a specific bridged instance of this AP
6161      * (if bridged AP is enabled).
6162      *
6163      * Note: Caller will receive the callback
6164      * {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)}
6165      * on registration when there are clients connected to AP.
6166      *
6167      * These will be dispatched on registration to provide the caller with the current state
6168      * (and are not an indication of any current change). Note that receiving an immediate
6169      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
6170      * soft AP has failed. Caller can unregister a previously registered callback using
6171      * {@link #unregisterLocalOnlyHotspotSoftApCallback}
6172      * <p>
6173      *
6174      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
6175      *                 object.
6176      * @param callback Callback for local only hotspot events
6177      * @hide
6178      */
6179     @SystemApi
6180     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
6181     @RequiresPermission(NEARBY_WIFI_DEVICES)
registerLocalOnlyHotspotSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)6182     public void registerLocalOnlyHotspotSoftApCallback(@NonNull @CallbackExecutor Executor executor,
6183             @NonNull SoftApCallback callback) {
6184         if (!SdkLevel.isAtLeastT()) {
6185             throw new UnsupportedOperationException();
6186         }
6187         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
6188         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
6189         Log.v(TAG, "registerLocalOnlyHotspotSoftApCallback: callback=" + callback + ", executor="
6190                 + executor);
6191         try {
6192             synchronized (sLocalOnlyHotspotSoftApCallbackMap) {
6193                 ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
6194                         IFACE_IP_MODE_LOCAL_ONLY);
6195                 sLocalOnlyHotspotSoftApCallbackMap.put(System.identityHashCode(callback),
6196                         binderCallback);
6197                 Bundle extras = new Bundle();
6198                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
6199                         mContext.getAttributionSource());
6200                 mService.registerLocalOnlyHotspotSoftApCallback(binderCallback, extras);
6201             }
6202         } catch (RemoteException e) {
6203             throw e.rethrowFromSystemServer();
6204         }
6205     }
6206 
6207     /**
6208      * Allow callers to unregister a previously registered callback. After calling this method,
6209      * applications will no longer receive local only hotspot events.
6210      *
6211      * <p>
6212      *
6213      * @param callback Callback to unregister for soft AP events
6214      *
6215      * @hide
6216      */
6217     @SystemApi
6218     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
6219     @RequiresPermission(NEARBY_WIFI_DEVICES)
unregisterLocalOnlyHotspotSoftApCallback(@onNull SoftApCallback callback)6220     public void unregisterLocalOnlyHotspotSoftApCallback(@NonNull SoftApCallback callback) {
6221         if (!SdkLevel.isAtLeastT()) {
6222             throw new UnsupportedOperationException();
6223         }
6224         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
6225         Log.v(TAG, "unregisterLocalOnlyHotspotSoftApCallback: callback=" + callback);
6226 
6227         try {
6228             synchronized (sLocalOnlyHotspotSoftApCallbackMap) {
6229                 int callbackIdentifier = System.identityHashCode(callback);
6230                 if (!sLocalOnlyHotspotSoftApCallbackMap.contains(callbackIdentifier)) {
6231                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
6232                     return;
6233                 }
6234                 Bundle extras = new Bundle();
6235                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
6236                         mContext.getAttributionSource());
6237                 mService.unregisterLocalOnlyHotspotSoftApCallback(
6238                         sLocalOnlyHotspotSoftApCallbackMap.get(callbackIdentifier), extras);
6239                 sLocalOnlyHotspotSoftApCallbackMap.remove(callbackIdentifier);
6240             }
6241         } catch (RemoteException e) {
6242             throw e.rethrowFromSystemServer();
6243         }
6244     }
6245 
6246     /**
6247      * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes.  Callers will
6248      * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
6249      * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
6250      * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(SoftApConfiguration)} and
6251      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
6252      * <p>
6253      * Applications should have the
6254      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
6255      * permission.  Callers without the permission will trigger a
6256      * {@link java.lang.SecurityException}.
6257      * <p>
6258      * @param observer LocalOnlyHotspotObserver callback.
6259      * @param handler Handler to use for callbacks
6260      *
6261      * @hide
6262      */
watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, @Nullable Handler handler)6263     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
6264             @Nullable Handler handler) {
6265         Executor executor = handler == null ? mContext.getMainExecutor()
6266                 : new HandlerExecutor(handler);
6267         synchronized (mLock) {
6268             mLOHSObserverProxy =
6269                     new LocalOnlyHotspotObserverProxy(this, executor, observer);
6270             try {
6271                 mService.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
6272                 mLOHSObserverProxy.registered();
6273             } catch (RemoteException e) {
6274                 mLOHSObserverProxy = null;
6275                 throw e.rethrowFromSystemServer();
6276             }
6277         }
6278     }
6279 
6280     /**
6281      * Allow callers to stop watching LocalOnlyHotspot state changes.  After calling this method,
6282      * applications will no longer receive callbacks.
6283      *
6284      * @hide
6285      */
unregisterLocalOnlyHotspotObserver()6286     public void unregisterLocalOnlyHotspotObserver() {
6287         synchronized (mLock) {
6288             if (mLOHSObserverProxy == null) {
6289                 // nothing to do, the callback was already cleaned up
6290                 return;
6291             }
6292             mLOHSObserverProxy = null;
6293             try {
6294                 mService.stopWatchLocalOnlyHotspot();
6295             } catch (RemoteException e) {
6296                 throw e.rethrowFromSystemServer();
6297             }
6298         }
6299     }
6300 
6301     /**
6302      * Gets the tethered Wi-Fi hotspot enabled state.
6303      * @return One of {@link #WIFI_AP_STATE_DISABLED},
6304      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
6305      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
6306      * @see #isWifiApEnabled()
6307      *
6308      * @hide
6309      */
6310     @SystemApi
6311     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getWifiApState()6312     public int getWifiApState() {
6313         try {
6314             return mService.getWifiApEnabledState();
6315         } catch (RemoteException e) {
6316             throw e.rethrowFromSystemServer();
6317         }
6318     }
6319 
6320     /**
6321      * Return whether tethered Wi-Fi AP is enabled or disabled.
6322      * @return {@code true} if tethered  Wi-Fi AP is enabled
6323      * @see #getWifiApState()
6324      *
6325      * @hide
6326      */
6327     @SystemApi
6328     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiApEnabled()6329     public boolean isWifiApEnabled() {
6330         return getWifiApState() == WIFI_AP_STATE_ENABLED;
6331     }
6332 
6333     /**
6334      * Gets the tethered Wi-Fi AP Configuration.
6335      * @return AP details in WifiConfiguration
6336      *
6337      * Note that AP detail may contain configuration which is cannot be represented
6338      * by the legacy WifiConfiguration, in such cases a null will be returned.
6339      *
6340      * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
6341      * @hide
6342      */
6343     @Nullable
6344     @SystemApi
6345     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
6346     @Deprecated
getWifiApConfiguration()6347     public WifiConfiguration getWifiApConfiguration() {
6348         try {
6349             return mService.getWifiApConfiguration();
6350         } catch (RemoteException e) {
6351             throw e.rethrowFromSystemServer();
6352         }
6353     }
6354 
6355     /**
6356      * Gets the Wi-Fi tethered AP Configuration.
6357      * @return AP details in {@link SoftApConfiguration}
6358      *
6359      * @hide
6360      */
6361     @NonNull
6362     @SystemApi
6363     @RequiresPermission(anyOf = {
6364             android.Manifest.permission.NETWORK_SETTINGS,
6365             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6366     })
getSoftApConfiguration()6367     public SoftApConfiguration getSoftApConfiguration() {
6368         try {
6369             return mService.getSoftApConfiguration();
6370         } catch (RemoteException e) {
6371             throw e.rethrowFromSystemServer();
6372         }
6373     }
6374 
6375     /**
6376      * Gets the last configured Wi-Fi tethered AP passphrase.
6377      *
6378      * Note: It may be null when there is no passphrase changed since
6379      * device boot.
6380      *
6381      * @param executor The executor on which callback will be invoked.
6382      * @param resultCallback An asynchronous callback that will return the last configured
6383      *                       Wi-Fi tethered AP passphrase.
6384      *
6385      * @throws SecurityException if the caller does not have permission.
6386      * @throws NullPointerException if the caller provided invalid inputs.
6387      *
6388      * @hide
6389      */
6390     @Nullable
6391     @SystemApi
6392     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
queryLastConfiguredTetheredApPassphraseSinceBoot( @onNull @allbackExecutor Executor executor, @NonNull Consumer<String> resultCallback)6393     public void queryLastConfiguredTetheredApPassphraseSinceBoot(
6394             @NonNull @CallbackExecutor Executor executor,
6395             @NonNull Consumer<String> resultCallback) {
6396         Objects.requireNonNull(executor, "executor cannot be null");
6397         Objects.requireNonNull(resultCallback, "resultsCallback cannot be null");
6398         try {
6399             mService.queryLastConfiguredTetheredApPassphraseSinceBoot(
6400                     new IStringListener.Stub() {
6401                         @Override
6402                         public void onResult(String value) {
6403                             Binder.clearCallingIdentity();
6404                             executor.execute(() -> {
6405                                 resultCallback.accept(value);
6406                             });
6407                         }
6408                     });
6409         } catch (RemoteException e) {
6410             throw e.rethrowFromSystemServer();
6411         }
6412     }
6413 
6414     /**
6415      * Sets the tethered Wi-Fi AP Configuration.
6416      * @return {@code true} if the operation succeeded, {@code false} otherwise
6417      *
6418      * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
6419      * instead.
6420      * @hide
6421      */
6422     @SystemApi
6423     @RequiresPermission(CHANGE_WIFI_STATE)
6424     @Deprecated
setWifiApConfiguration(WifiConfiguration wifiConfig)6425     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
6426         try {
6427             return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
6428         } catch (RemoteException e) {
6429             throw e.rethrowFromSystemServer();
6430         }
6431     }
6432 
6433     /**
6434      * Sets the tethered Wi-Fi AP Configuration.
6435      *
6436      * If the API is called while the tethered soft AP is enabled, the configuration will apply to
6437      * the current soft AP if the new configuration only includes
6438      * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
6439      * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
6440      * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
6441      * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
6442      * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
6443      * or {@link SoftApConfiguration.Builder#setAutoShutdownEnabled(boolean)}
6444      * or {@link SoftApConfiguration.Builder#setBridgedModeOpportunisticShutdownEnabled(boolean)}
6445      *
6446      * Otherwise, the configuration changes will be applied when the Soft AP is next started
6447      * (the framework will not stop/start the AP).
6448      *
6449      * Note: Call {@link WifiManager#validateSoftApConfiguration(SoftApConfiguration)} to avoid
6450      * unexpected error due to invalid configuration.
6451      *
6452      * @param softApConfig  A valid SoftApConfiguration specifying the configuration of the SAP.
6453      * @return {@code true} if the operation succeeded, {@code false} otherwise
6454      *
6455      * @hide
6456      */
6457     @SystemApi
6458     @RequiresPermission(anyOf = {
6459             android.Manifest.permission.NETWORK_SETTINGS,
6460             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6461     })
setSoftApConfiguration(@onNull SoftApConfiguration softApConfig)6462     public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
6463         try {
6464             return mService.setSoftApConfiguration(
6465                     softApConfig, mContext.getOpPackageName());
6466         } catch (RemoteException e) {
6467             throw e.rethrowFromSystemServer();
6468         }
6469     }
6470 
6471     /**
6472      * Enable/Disable TDLS on a specific local route.
6473      *
6474      * <p>
6475      * TDLS enables two wireless endpoints to talk to each other directly
6476      * without going through the access point that is managing the local
6477      * network. It saves bandwidth and improves quality of the link.
6478      * </p>
6479      * <p>
6480      * This API enables/disables the option of using TDLS. If enabled, the
6481      * underlying hardware is free to use TDLS or a hop through the access
6482      * point. If disabled, existing TDLS session is torn down and
6483      * hardware is restricted to use access point for transferring wireless
6484      * packets. Default value for all routes is 'disabled', meaning restricted
6485      * to use access point for transferring packets.
6486      * </p>
6487      *
6488      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
6489      * @param enable true = setup and false = tear down TDLS
6490      */
setTdlsEnabled(InetAddress remoteIPAddress, boolean enable)6491     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
6492         try {
6493             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
6494         } catch (RemoteException e) {
6495             throw e.rethrowFromSystemServer();
6496         }
6497     }
6498 
6499     /**
6500      * Enable/Disable TDLS on a specific local route.
6501      *
6502      * Similar to {@link #setTdlsEnabled(InetAddress, boolean)}, except
6503      * this version sends the result of the Enable/Disable request.
6504      *
6505      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
6506      * @param enable true = setup and false = tear down TDLS
6507      * @param executor The executor on which callback will be invoked.
6508      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6509      *                        whether TDLS was successfully enabled or disabled.
6510      *                        {@code true} for success, {@code false} for failure.
6511      *
6512      * @throws NullPointerException if the caller provided invalid inputs.
6513      */
setTdlsEnabled(@onNull InetAddress remoteIPAddress, boolean enable, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6514     public void setTdlsEnabled(@NonNull InetAddress remoteIPAddress, boolean enable,
6515             @NonNull @CallbackExecutor Executor executor,
6516             @NonNull Consumer<Boolean> resultsCallback) {
6517         Objects.requireNonNull(executor, "executor cannot be null");
6518         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6519         Objects.requireNonNull(remoteIPAddress, "remote IP address cannot be null");
6520         try {
6521             mService.enableTdlsWithRemoteIpAddress(remoteIPAddress.getHostAddress(), enable,
6522                     new IBooleanListener.Stub() {
6523                         @Override
6524                         public void onResult(boolean value) {
6525                             Binder.clearCallingIdentity();
6526                             executor.execute(() -> {
6527                                 resultsCallback.accept(value);
6528                             });
6529                         }
6530                     });
6531         } catch (RemoteException e) {
6532             throw e.rethrowFromSystemServer();
6533         }
6534     }
6535 
6536     /**
6537      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
6538      * this version allows you to specify remote endpoint with a MAC address.
6539      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
6540      * @param enable true = setup and false = tear down TDLS
6541      */
setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable)6542     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
6543         try {
6544             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
6545         } catch (RemoteException e) {
6546             throw e.rethrowFromSystemServer();
6547         }
6548     }
6549 
6550     /**
6551      * Enable/Disable TDLS with a specific peer Mac Address.
6552      *
6553      * Similar to {@link #setTdlsEnabledWithMacAddress(String, boolean)}, except
6554      * this version sends the result of the Enable/Disable request.
6555      *
6556      * @param remoteMacAddress Mac address of the endpoint to setup TDLS with
6557      * @param enable true = setup and false = tear down TDLS
6558      * @param executor The executor on which callback will be invoked.
6559      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6560      *                        whether TDLS was successfully enabled or disabled.
6561      *                        {@code true} for success, {@code false} for failure.
6562      *
6563      * @throws NullPointerException if the caller provided invalid inputs.
6564      */
setTdlsEnabledWithMacAddress(@onNull String remoteMacAddress, boolean enable, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6565     public void setTdlsEnabledWithMacAddress(@NonNull String remoteMacAddress, boolean enable,
6566             @NonNull @CallbackExecutor Executor executor,
6567             @NonNull Consumer<Boolean> resultsCallback) {
6568         Objects.requireNonNull(executor, "executor cannot be null");
6569         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6570         Objects.requireNonNull(remoteMacAddress, "remote Mac address cannot be null");
6571         try {
6572             mService.enableTdlsWithRemoteMacAddress(remoteMacAddress, enable,
6573                     new IBooleanListener.Stub() {
6574                         @Override
6575                         public void onResult(boolean value) {
6576                             Binder.clearCallingIdentity();
6577                             executor.execute(() -> {
6578                                 resultsCallback.accept(value);
6579                             });
6580                         }
6581                     });
6582         } catch (RemoteException e) {
6583             throw e.rethrowFromSystemServer();
6584         }
6585     }
6586 
6587     /**
6588      * Check if a TDLS session can be established at this time via
6589      * {@link #setTdlsEnabled(InetAddress, boolean)} or
6590      * {@link #setTdlsEnabledWithMacAddress(String, boolean)} or
6591      * {@link #setTdlsEnabled(InetAddress, boolean, Executor, Consumer)} or
6592      * {@link #setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
6593      *
6594      * Internally framework checks the STA connected state, device support for TDLS and
6595      * the number of TDLS sessions available in driver/firmware.
6596      *
6597      * @param executor The executor on which callback will be invoked.
6598      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6599      *                        whether a TDLS session can be established at this time.
6600      *                        {@code true} for available, {@code false} for not available.
6601      *
6602      * @throws NullPointerException if the caller provided invalid inputs.
6603      */
isTdlsOperationCurrentlyAvailable(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6604     public void isTdlsOperationCurrentlyAvailable(@NonNull @CallbackExecutor Executor executor,
6605             @NonNull Consumer<Boolean> resultsCallback) {
6606         Objects.requireNonNull(executor, "executor cannot be null");
6607         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6608         try {
6609             mService.isTdlsOperationCurrentlyAvailable(
6610                     new IBooleanListener.Stub() {
6611                         @Override
6612                         public void onResult(boolean value) {
6613                             Binder.clearCallingIdentity();
6614                             executor.execute(() -> {
6615                                 resultsCallback.accept(value);
6616                             });
6617                         }
6618                     });
6619         } catch (RemoteException e) {
6620             throw e.rethrowFromSystemServer();
6621         }
6622     }
6623 
6624     /**
6625      * Return the maximum number of concurrent TDLS sessions supported by the device.
6626      *
6627      * @param executor The executor on which callback will be invoked.
6628      * @param resultsCallback An asynchronous callback that will return the maximum number of
6629      *                        concurrent TDLS sessions supported by the device. Returns
6630      *                        {@code -1} if information is not available,
6631      *                        e.g. if the driver/firmware doesn't provide this information.
6632      *
6633      * @throws NullPointerException if the caller provided invalid inputs.
6634      * @throws UnsupportedOperationException if the feature is not available.
6635      */
6636     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
getMaxSupportedConcurrentTdlsSessions(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)6637     public void getMaxSupportedConcurrentTdlsSessions(@NonNull @CallbackExecutor Executor executor,
6638             @NonNull Consumer<Integer> resultsCallback) {
6639         Objects.requireNonNull(executor, "executor cannot be null");
6640         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6641         try {
6642             mService.getMaxSupportedConcurrentTdlsSessions(
6643                     new IIntegerListener.Stub() {
6644                         @Override
6645                         public void onResult(int value) {
6646                             Binder.clearCallingIdentity();
6647                             executor.execute(() -> {
6648                                 resultsCallback.accept(value);
6649                             });
6650                         }
6651                     });
6652         } catch (RemoteException e) {
6653             throw e.rethrowFromSystemServer();
6654         }
6655     }
6656 
6657     /**
6658      * Return the number of currently enabled TDLS sessions.
6659      *
6660      * Tracks the number of peers enabled for TDLS session via
6661      * {@link #setTdlsEnabled(InetAddress, boolean) },
6662      * {@link #setTdlsEnabledWithMacAddress(String, boolean) },
6663      * {@link #setTdlsEnabled(InetAddress, boolean, Executor, Consumer) } and
6664      * {@link #setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer) }
6665      *
6666      * @param executor The executor on which callback will be invoked.
6667      * @param resultsCallback An asynchronous callback that will return the number of Peer
6668      *                        Mac addresses configured in the driver for TDLS session.
6669      *
6670      * @throws NullPointerException if the caller provided invalid inputs.
6671      */
getNumberOfEnabledTdlsSessions(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)6672     public void getNumberOfEnabledTdlsSessions(@NonNull @CallbackExecutor Executor executor,
6673             @NonNull Consumer<Integer> resultsCallback) {
6674         Objects.requireNonNull(executor, "executor cannot be null");
6675         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6676         try {
6677             mService.getNumberOfEnabledTdlsSessions(
6678                     new IIntegerListener.Stub() {
6679                         @Override
6680                         public void onResult(int value) {
6681                             Binder.clearCallingIdentity();
6682                             executor.execute(() -> {
6683                                 resultsCallback.accept(value);
6684                             });
6685                         }
6686                     });
6687         } catch (RemoteException e) {
6688             throw e.rethrowFromSystemServer();
6689         }
6690     }
6691 
6692     /** @hide */
6693     @Retention(RetentionPolicy.SOURCE)
6694     @IntDef({ActionListener.FAILURE_INTERNAL_ERROR,
6695             ActionListener.FAILURE_IN_PROGRESS,
6696             ActionListener.FAILURE_BUSY,
6697             ActionListener.FAILURE_INVALID_ARGS,
6698             ActionListener.FAILURE_NOT_AUTHORIZED})
6699     public @interface ActionListenerFailureReason {}
6700 
6701     /* WPS specific errors */
6702     /** WPS overlap detected
6703      * @deprecated This is deprecated
6704      */
6705     public static final int WPS_OVERLAP_ERROR           = 3;
6706     /** WEP on WPS is prohibited
6707      * @deprecated This is deprecated
6708      */
6709     public static final int WPS_WEP_PROHIBITED          = 4;
6710     /** TKIP only prohibited
6711      * @deprecated This is deprecated
6712      */
6713     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
6714     /** Authentication failure on WPS
6715      * @deprecated This is deprecated
6716      */
6717     public static final int WPS_AUTH_FAILURE            = 6;
6718     /** WPS timed out
6719      * @deprecated This is deprecated
6720      */
6721     public static final int WPS_TIMED_OUT               = 7;
6722 
6723     /**
6724      * Interface for callback invocation on an application action.
6725      * @hide
6726      */
6727     @SystemApi
6728     public interface ActionListener {
6729         /**
6730          * Passed with {@link #onFailure}.
6731          * Indicates that the operation failed due to an internal error.
6732          */
6733         int FAILURE_INTERNAL_ERROR = 0;
6734 
6735         /**
6736          * Passed with {@link #onFailure}.
6737          * Indicates that the operation is already in progress.
6738          */
6739         int FAILURE_IN_PROGRESS = 1;
6740 
6741         /**
6742          * Passed with {@link #onFailure}.
6743          * Indicates that the operation failed because the framework is busy and is unable to
6744          * service the request.
6745          */
6746         int FAILURE_BUSY = 2;
6747 
6748         /**
6749          * Passed with {@link #onFailure}.
6750          * Indicates that the operation failed due to invalid inputs.
6751          */
6752         int FAILURE_INVALID_ARGS = 3;
6753 
6754         /**
6755          * Passed with {@link #onFailure}.
6756          * Indicates that the operation failed due to insufficient user permissions.
6757          */
6758         int FAILURE_NOT_AUTHORIZED = 4;
6759 
6760         /**
6761          * The operation succeeded.
6762          */
onSuccess()6763         void onSuccess();
6764         /**
6765          * The operation failed.
6766          * @param reason The reason for failure depends on the operation.
6767          */
onFailure(@ctionListenerFailureReason int reason)6768         void onFailure(@ActionListenerFailureReason int reason);
6769     }
6770 
6771     /** Interface for callback invocation on a start WPS action
6772      * @deprecated This is deprecated
6773      */
6774     public static abstract class WpsCallback {
6775 
6776         /** WPS start succeeded
6777          * @deprecated This API is deprecated
6778          */
onStarted(String pin)6779         public abstract void onStarted(String pin);
6780 
6781         /** WPS operation completed successfully
6782          * @deprecated This API is deprecated
6783          */
onSucceeded()6784         public abstract void onSucceeded();
6785 
6786         /**
6787          * WPS operation failed
6788          * @param reason The reason for failure could be one of
6789          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
6790          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
6791          * and some generic errors.
6792          * @deprecated This API is deprecated
6793          */
onFailed(int reason)6794         public abstract void onFailed(int reason);
6795     }
6796 
6797     /**
6798      * Base class for soft AP callback. Should be extended by applications and set when calling
6799      * {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
6800      *
6801      * @hide
6802      */
6803     @SystemApi
6804     public interface SoftApCallback {
6805         /**
6806          * Called when soft AP state changes.
6807          *
6808          * @param state         the new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
6809          *                      {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
6810          *                      {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
6811          * @param failureReason reason when in failed state. One of
6812          *                      {@link #SAP_START_FAILURE_GENERAL},
6813          *                      {@link #SAP_START_FAILURE_NO_CHANNEL},
6814          *                      {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION},
6815          *                      {@link #SAP_START_FAILURE_USER_REJECTED}
6816          */
onStateChanged(@ifiApState int state, @SapStartFailure int failureReason)6817         default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
6818 
6819         /**
6820          * Called when soft AP state changes.
6821          * <p>
6822          * This provides the same state and failure reason as {@link #onStateChanged(int, int)}, but
6823          * also provides extra information such as interface name and TetheringRequest in order to
6824          * replace usage of the WIFI_AP_STATE_CHANGED_ACTION broadcast. If this method is overridden
6825          * then {@link #onStateChanged(int, int)} will no longer be called.
6826          *
6827          * @param state the new state.
6828          */
6829         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onStateChanged(@onNull SoftApState state)6830         default void onStateChanged(@NonNull SoftApState state) {
6831             onStateChanged(state.mState, state.mFailureReason);
6832         }
6833 
6834         /**
6835          * Called when the connected clients to soft AP changes.
6836          *
6837          * @param clients the currently connected clients
6838          *
6839          * @deprecated This API is deprecated.
6840          * Use {@link #onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} instead.
6841          */
6842         @Deprecated
onConnectedClientsChanged(@onNull List<WifiClient> clients)6843         default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
6844 
6845 
6846         /**
6847          * Called when the connected clients for a soft AP instance change.
6848          *
6849          * When the Soft AP is configured in single AP mode, this callback is invoked
6850          * with the same {@link SoftApInfo} for all connected clients changes.
6851          * When the Soft AP is configured as multiple Soft AP instances (using
6852          * {@link SoftApConfiguration.Builder#setBands(int[])} or
6853          * {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)}), this
6854          * callback is invoked with the corresponding {@link SoftApInfo} for the instance in which
6855          * the connected clients changed.
6856          *
6857          * @param info The {@link SoftApInfo} of the AP.
6858          * @param clients The currently connected clients on the AP instance specified by
6859          *                {@code info}.
6860          */
onConnectedClientsChanged(@onNull SoftApInfo info, @NonNull List<WifiClient> clients)6861         default void onConnectedClientsChanged(@NonNull SoftApInfo info,
6862                 @NonNull List<WifiClient> clients) {}
6863 
6864         /**
6865          * Called when the Soft AP information changes.
6866          *
6867          * Note: this API remains valid only when the Soft AP is configured as a single AP -
6868          * not as multiple Soft APs (which are bridged to each other). When multiple Soft APs are
6869          * configured (using {@link SoftApConfiguration.Builder#setBands(int[])} or
6870          * {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)})
6871          * this callback will not be triggered -  use the
6872          * {@link #onInfoChanged(List<SoftApInfo>)} callback in that case.
6873          *
6874          * @param softApInfo is the Soft AP information. {@link SoftApInfo}
6875          *
6876          * @deprecated This API is deprecated. Use {@link #onInfoChanged(List<SoftApInfo>)}
6877          * instead.
6878          */
6879         @Deprecated
onInfoChanged(@onNull SoftApInfo softApInfo)6880         default void onInfoChanged(@NonNull SoftApInfo softApInfo) {
6881             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
6882         }
6883 
6884         /**
6885          * Called when the Soft AP information changes.
6886          *
6887          * Returns information on all configured Soft AP instances. The number of the elements in
6888          * the list depends on Soft AP configuration and state:
6889          * <ul>
6890          * <li>An empty list will be returned when the Soft AP is disabled.
6891          * <li>One information element will be returned in the list when the Soft AP is configured
6892          *     as a single AP or when a single Soft AP remains active.
6893          * <li>Two information elements will be returned in the list when the multiple Soft APs are
6894          *     configured and are active.
6895          *     (configured using {@link SoftApConfiguration.Builder#setBands(int[])} or
6896          *     {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)}).
6897          * </ul>
6898          *
6899          * Note: When multiple Soft AP instances are configured, one of the Soft APs may
6900          * be shut down independently of the other by the framework. This can happen if no devices
6901          * are connected to it for some duration. In that case, one information element will be
6902          * returned.
6903          *
6904          * See {@link #isBridgedApConcurrencySupported()} for support info of multiple (bridged) AP.
6905          *
6906          * @param softApInfoList is the list of the Soft AP information elements -
6907          *        {@link SoftApInfo}.
6908          */
onInfoChanged(@onNull List<SoftApInfo> softApInfoList)6909         default void onInfoChanged(@NonNull List<SoftApInfo> softApInfoList) {
6910             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
6911         }
6912 
6913         /**
6914          * Called when capability of Soft AP changes.
6915          *
6916          * @param softApCapability is the Soft AP capability. {@link SoftApCapability}
6917          */
onCapabilityChanged(@onNull SoftApCapability softApCapability)6918         default void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
6919             // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported
6920             // client number) to the UI.
6921         }
6922 
6923         /**
6924          * Called when client trying to connect but device blocked the client with specific reason.
6925          *
6926          * Can be used to ask user to update client to allowed list or blocked list
6927          * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or
6928          * indicate the block due to maximum supported client number limitation when reason is
6929          * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}.
6930          *
6931          * @param client the currently blocked client.
6932          * @param blockedReason one of blocked reason from {@link SapClientBlockedReason}
6933          */
onBlockedClientConnecting(@onNull WifiClient client, @SapClientBlockedReason int blockedReason)6934         default void onBlockedClientConnecting(@NonNull WifiClient client,
6935                 @SapClientBlockedReason int blockedReason) {
6936             // Do nothing: can be used to ask user to update client to allowed list or blocked list.
6937         }
6938 
6939         /**
6940          * Called when clients disconnect from a soft AP instance.
6941          *
6942          * @param info The {@link SoftApInfo} of the AP.
6943          * @param clients The clients that have disconnected from the AP instance specified by
6944          *                {@code info}.
6945          */
6946         @FlaggedApi(Flags.FLAG_SOFTAP_DISCONNECT_REASON)
onClientsDisconnected(@onNull SoftApInfo info, @NonNull List<WifiClient> clients)6947         default void onClientsDisconnected(@NonNull SoftApInfo info,
6948                 @NonNull List<WifiClient> clients) {}
6949     }
6950 
6951     /**
6952      * Callback proxy for SoftApCallback objects.
6953      *
6954      * @hide
6955      */
6956     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
6957         private final Executor mExecutor;
6958         private final SoftApCallback mCallback;
6959         // Either {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
6960         private final int mIpMode;
6961         private Map<String, List<WifiClient>> mCurrentClients = new HashMap<>();
6962         private Map<String, SoftApInfo> mCurrentInfos = new HashMap<>();
6963 
getConnectedClientList(Map<String, List<WifiClient>> clientsMap)6964         private List<WifiClient> getConnectedClientList(Map<String, List<WifiClient>> clientsMap) {
6965             List<WifiClient> connectedClientList = new ArrayList<>();
6966             for (List<WifiClient> it : clientsMap.values()) {
6967                 connectedClientList.addAll(it);
6968             }
6969             return connectedClientList;
6970         }
6971 
SoftApCallbackProxy(Executor executor, SoftApCallback callback, int mode)6972         SoftApCallbackProxy(Executor executor, SoftApCallback callback, int mode) {
6973             mExecutor = executor;
6974             mCallback = callback;
6975             mIpMode = mode;
6976         }
6977 
6978         @Override
onStateChanged(SoftApState state)6979         public void onStateChanged(SoftApState state) {
6980             if (mVerboseLoggingEnabled) {
6981                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6982                         + ", onStateChanged: " + state);
6983             }
6984 
6985             Binder.clearCallingIdentity();
6986             mExecutor.execute(() -> {
6987                 mCallback.onStateChanged(state);
6988             });
6989         }
6990 
6991         @Override
onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration)6992         public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
6993                 Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration) {
6994             if (mVerboseLoggingEnabled) {
6995                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6996                         + ", onConnectedClientsOrInfoChanged: clients: "
6997                         + clients + ", infos: " + infos + ", isBridged is " + isBridged
6998                         + ", isRegistration is " + isRegistration);
6999             }
7000 
7001             List<SoftApInfo> changedInfoList = new ArrayList<>(infos.values());
7002             Map<SoftApInfo, List<WifiClient>> changedInfoClients = new HashMap<>();
7003             // Some devices may not support infos callback, allow them to support client
7004             // connection changed callback.
7005             boolean areClientsChangedWithoutInfosChanged =
7006                     infos.size() == 0 && getConnectedClientList(clients).size()
7007                     != getConnectedClientList(mCurrentClients).size();
7008             boolean isInfoChanged = infos.size() != mCurrentInfos.size();
7009 
7010             if (isRegistration) {
7011                 // Check if there are clients connected, put it to changedInfoClients
7012                 for (SoftApInfo currentInfo : infos.values()) {
7013                     String instance = currentInfo.getApInstanceIdentifier();
7014                     if (clients.getOrDefault(instance, Collections.emptyList()).size() > 0) {
7015                         changedInfoClients.put(currentInfo, clients.get(instance));
7016                     }
7017                 }
7018             }
7019 
7020             // Check if old info removed or not (client changed case)
7021             for (SoftApInfo info : mCurrentInfos.values()) {
7022                 String changedInstance = info.getApInstanceIdentifier();
7023                 List<WifiClient> changedClientList = clients.getOrDefault(
7024                         changedInstance, Collections.emptyList());
7025                 if (!changedInfoList.contains(info)) {
7026                     isInfoChanged = true;
7027                     if (mCurrentClients.getOrDefault(changedInstance,
7028                               Collections.emptyList()).size() > 0) {
7029                         SoftApInfo changedInfo = infos.get(changedInstance);
7030                         if (changedInfo == null || changedInfo.getFrequency() == 0) {
7031                             Log.d(TAG, "SoftApCallbackProxy on mode " + mIpMode
7032                                     + ", info changed on client connected instance(AP disabled)");
7033                             // Send old info with empty client list for shutdown case
7034                             changedInfoClients.put(info, Collections.emptyList());
7035                         } else {
7036                             Log.d(TAG, "SoftApCallbackProxy on mode " + mIpMode
7037                                     + ", info changed on client connected instance");
7038                             changedInfoClients.put(changedInfo, changedClientList);
7039                         }
7040                     }
7041                 } else {
7042                     // info doesn't change, check client list
7043                     if (changedClientList.size()
7044                             != mCurrentClients
7045                             .getOrDefault(changedInstance, Collections.emptyList()).size()) {
7046                         // Here should notify client changed on new info(same as old info)
7047                         changedInfoClients.put(info, changedClientList);
7048                     }
7049                 }
7050             }
7051 
7052             mCurrentClients = clients;
7053             mCurrentInfos = infos;
7054             if (!isInfoChanged && changedInfoClients.isEmpty()
7055                     && !isRegistration && !areClientsChangedWithoutInfosChanged) {
7056                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7057                         + ", No changed & Not Registration don't need to notify the client");
7058                 return;
7059             }
7060             Binder.clearCallingIdentity();
7061             // Notify the clients changed first for old info shutdown case
7062             for (SoftApInfo changedInfo : changedInfoClients.keySet()) {
7063                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7064                         + ", send onConnectedClientsChanged, changedInfo is "
7065                         + changedInfo + " and clients are " + changedInfoClients.get(changedInfo));
7066                 mExecutor.execute(() -> {
7067                     mCallback.onConnectedClientsChanged(
7068                             changedInfo, changedInfoClients.get(changedInfo));
7069                 });
7070             }
7071 
7072             if (isInfoChanged || isRegistration) {
7073                 if (!isBridged) {
7074                     SoftApInfo newInfo = changedInfoList.isEmpty()
7075                             ? new SoftApInfo() : changedInfoList.get(0);
7076                     Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7077                             + ", send InfoChanged, newInfo: " + newInfo);
7078                     mExecutor.execute(() -> {
7079                         mCallback.onInfoChanged(newInfo);
7080                     });
7081                 }
7082                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7083                         + ", send InfoChanged, changedInfoList: " + changedInfoList);
7084                 mExecutor.execute(() -> {
7085                     mCallback.onInfoChanged(changedInfoList);
7086                 });
7087             }
7088 
7089             if (isRegistration || !changedInfoClients.isEmpty()
7090                     || areClientsChangedWithoutInfosChanged) {
7091                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7092                         + ", send onConnectedClientsChanged(clients): "
7093                         + getConnectedClientList(clients));
7094                 mExecutor.execute(() -> {
7095                     mCallback.onConnectedClientsChanged(getConnectedClientList(clients));
7096                 });
7097             }
7098         }
7099 
7100         @Override
onCapabilityChanged(SoftApCapability capability)7101         public void onCapabilityChanged(SoftApCapability capability) {
7102             if (mVerboseLoggingEnabled) {
7103                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7104                         + ",  onCapabilityChanged: SoftApCapability = " + capability);
7105             }
7106 
7107             Binder.clearCallingIdentity();
7108             mExecutor.execute(() -> {
7109                 mCallback.onCapabilityChanged(capability);
7110             });
7111         }
7112 
7113         @Override
onBlockedClientConnecting(@onNull WifiClient client, int blockedReason)7114         public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) {
7115             if (mVerboseLoggingEnabled) {
7116                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7117                         + ", onBlockedClientConnecting: client =" + client
7118                         + " with reason = " + blockedReason);
7119             }
7120 
7121             Binder.clearCallingIdentity();
7122             mExecutor.execute(() -> {
7123                 mCallback.onBlockedClientConnecting(client, blockedReason);
7124             });
7125         }
7126 
7127         @Override
onClientsDisconnected(SoftApInfo info, List<WifiClient> clients)7128         public void onClientsDisconnected(SoftApInfo info, List<WifiClient> clients) {
7129             if (mVerboseLoggingEnabled) {
7130                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
7131                         + ", onClientsDisconnected: info =" + info
7132                         + " with clients = " + clients);
7133             }
7134 
7135             Binder.clearCallingIdentity();
7136             mExecutor.execute(() -> mCallback.onClientsDisconnected(info, clients));
7137         }
7138     }
7139 
7140     /**
7141      * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the
7142      * following callbacks on registration:
7143      * <ul>
7144      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
7145      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
7146      * <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
7147      * <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
7148      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
7149      * </ul>
7150      *
7151      * Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
7152      * if there are any clients connected to a specific bridged instance of this AP
7153      * (if bridged AP is enabled).
7154      *
7155      * Note: Caller will receive the callback
7156      * {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)}
7157      * on registration when there are clients connected to AP.
7158      *
7159      * These will be dispatched on registration to provide the caller with the current state
7160      * (and are not an indication of any current change). Note that receiving an immediate
7161      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
7162      * soft AP has failed. Caller can unregister a previously registered callback using
7163      * {@link #unregisterSoftApCallback}
7164      * <p>
7165      * Applications should have the
7166      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
7167      * without the permission will trigger a {@link java.lang.SecurityException}.
7168      * <p>
7169      *
7170      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
7171      *                 object.
7172      * @param callback Callback for soft AP events
7173      * @hide
7174      */
7175     @SystemApi
7176     @RequiresPermission(anyOf = {
7177             android.Manifest.permission.NETWORK_SETTINGS,
7178             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
7179             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
7180     })
registerSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)7181     public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
7182             @NonNull SoftApCallback callback) {
7183         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
7184         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
7185         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
7186 
7187         try {
7188             synchronized (sSoftApCallbackMap) {
7189                 ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
7190                         IFACE_IP_MODE_TETHERED);
7191                 sSoftApCallbackMap.put(System.identityHashCode(callback), binderCallback);
7192                 mService.registerSoftApCallback(binderCallback);
7193             }
7194         } catch (RemoteException e) {
7195             throw e.rethrowFromSystemServer();
7196         }
7197     }
7198 
7199     /**
7200      * Allow callers to unregister a previously registered callback. After calling this method,
7201      * applications will no longer receive soft AP events.
7202      *
7203      * @param callback Callback to unregister for soft AP events
7204      *
7205      * @hide
7206      */
7207     @SystemApi
7208     @RequiresPermission(anyOf = {
7209             android.Manifest.permission.NETWORK_SETTINGS,
7210             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
7211             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
7212     })
unregisterSoftApCallback(@onNull SoftApCallback callback)7213     public void unregisterSoftApCallback(@NonNull SoftApCallback callback) {
7214         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
7215         Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
7216 
7217         try {
7218             synchronized (sSoftApCallbackMap) {
7219                 int callbackIdentifier = System.identityHashCode(callback);
7220                 if (!sSoftApCallbackMap.contains(callbackIdentifier)) {
7221                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
7222                     return;
7223                 }
7224                 mService.unregisterSoftApCallback(sSoftApCallbackMap.get(callbackIdentifier));
7225                 sSoftApCallbackMap.remove(callbackIdentifier);
7226             }
7227         } catch (RemoteException e) {
7228             throw e.rethrowFromSystemServer();
7229         }
7230     }
7231 
7232     /**
7233      * LocalOnlyHotspotReservation that contains the {@link SoftApConfiguration} for the active
7234      * LocalOnlyHotspot request.
7235      * <p>
7236      * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
7237      * LocalOnlyHotspotReservation in the
7238      * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call.  This
7239      * reservation contains the relevant {@link SoftApConfiguration}.
7240      * When an application is done with the LocalOnlyHotspot, they should call {@link
7241      * LocalOnlyHotspotReservation#close()}.  Once this happens, the application will not receive
7242      * any further callbacks. If the LocalOnlyHotspot is stopped due to a
7243      * user triggered mode change, applications will be notified via the {@link
7244      * LocalOnlyHotspotCallback#onStopped()} callback.
7245      */
7246     public class LocalOnlyHotspotReservation implements AutoCloseable {
7247 
7248         private final CloseGuard mCloseGuard = new CloseGuard();
7249         private final SoftApConfiguration mSoftApConfig;
7250         private final WifiConfiguration mWifiConfig;
7251         private boolean mClosed = false;
7252 
7253         /** @hide */
7254         @VisibleForTesting
LocalOnlyHotspotReservation(SoftApConfiguration config)7255         public LocalOnlyHotspotReservation(SoftApConfiguration config) {
7256             mSoftApConfig = config;
7257             mWifiConfig = config.toWifiConfiguration();
7258             mCloseGuard.open("close");
7259         }
7260 
7261         /**
7262          * Returns the {@link WifiConfiguration} of the current Local Only Hotspot (LOHS).
7263          * May be null if hotspot enabled and security type is not
7264          * {@code WifiConfiguration.KeyMgmt.None} or {@code WifiConfiguration.KeyMgmt.WPA2_PSK}.
7265          *
7266          * @deprecated Use {@code WifiManager#getSoftApConfiguration()} to get the
7267          * LOHS configuration.
7268          */
7269         @Deprecated
7270         @Nullable
getWifiConfiguration()7271         public WifiConfiguration getWifiConfiguration() {
7272             return mWifiConfig;
7273         }
7274 
7275         /**
7276          * Returns the {@link SoftApConfiguration} of the current Local Only Hotspot (LOHS).
7277          */
7278         @NonNull
getSoftApConfiguration()7279         public SoftApConfiguration getSoftApConfiguration() {
7280             return mSoftApConfig;
7281         }
7282 
7283         @Override
close()7284         public void close() {
7285             try {
7286                 synchronized (mLock) {
7287                     if (!mClosed) {
7288                         mClosed = true;
7289                         stopLocalOnlyHotspot();
7290                         mCloseGuard.close();
7291                     }
7292                 }
7293             } catch (Exception e) {
7294                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
7295             } finally {
7296                 Reference.reachabilityFence(this);
7297             }
7298         }
7299 
7300         @Override
finalize()7301         protected void finalize() throws Throwable {
7302             try {
7303                 if (mCloseGuard != null) {
7304                     mCloseGuard.warnIfOpen();
7305                 }
7306                 close();
7307             } finally {
7308                 super.finalize();
7309             }
7310         }
7311     }
7312 
7313     /**
7314      * Callback class for applications to receive updates about the LocalOnlyHotspot status.
7315      */
7316     public static class LocalOnlyHotspotCallback {
7317         /** @hide */
7318         public static final int REQUEST_REGISTERED = 0;
7319 
7320         public static final int ERROR_NO_CHANNEL = 1;
7321         public static final int ERROR_GENERIC = 2;
7322         public static final int ERROR_INCOMPATIBLE_MODE = 3;
7323         public static final int ERROR_TETHERING_DISALLOWED = 4;
7324 
7325         /** LocalOnlyHotspot start succeeded. */
onStarted(LocalOnlyHotspotReservation reservation)7326         public void onStarted(LocalOnlyHotspotReservation reservation) {};
7327 
7328         /**
7329          * LocalOnlyHotspot stopped.
7330          * <p>
7331          * The LocalOnlyHotspot can be disabled at any time by the user.  When this happens,
7332          * applications will be notified that it was stopped. This will not be invoked when an
7333          * application calls {@link LocalOnlyHotspotReservation#close()}.
7334          */
onStopped()7335         public void onStopped() {};
7336 
7337         /**
7338          * LocalOnlyHotspot failed to start.
7339          * <p>
7340          * Applications can attempt to call
7341          * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at
7342          * a later time.
7343          * <p>
7344          * @param reason The reason for failure could be one of: {@link
7345          * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE},
7346          * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}.
7347          */
onFailed(int reason)7348         public void onFailed(int reason) { };
7349     }
7350 
7351     /**
7352      * Callback proxy for LocalOnlyHotspotCallback objects.
7353      */
7354     private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub {
7355         private final WeakReference<WifiManager> mWifiManager;
7356         private final Executor mExecutor;
7357         private final LocalOnlyHotspotCallback mCallback;
7358 
7359         /**
7360          * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor.  All
7361          * callbacks will run using the given executor.
7362          *
7363          * @param manager WifiManager
7364          * @param executor Executor for delivering callbacks.
7365          * @param callback LocalOnlyHotspotCallback to notify the calling application, or null.
7366          */
LocalOnlyHotspotCallbackProxy( @onNull WifiManager manager, @NonNull @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)7367         LocalOnlyHotspotCallbackProxy(
7368                 @NonNull WifiManager manager,
7369                 @NonNull @CallbackExecutor Executor executor,
7370                 @Nullable LocalOnlyHotspotCallback callback) {
7371             mWifiManager = new WeakReference<>(manager);
7372             mExecutor = executor;
7373             mCallback = callback;
7374         }
7375 
7376         @Override
onHotspotStarted(SoftApConfiguration config)7377         public void onHotspotStarted(SoftApConfiguration config) {
7378             WifiManager manager = mWifiManager.get();
7379             if (manager == null) return;
7380 
7381             if (config == null) {
7382                 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
7383                 onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
7384                 return;
7385             }
7386             final LocalOnlyHotspotReservation reservation =
7387                     manager.new LocalOnlyHotspotReservation(config);
7388             if (mCallback == null) return;
7389             mExecutor.execute(() -> mCallback.onStarted(reservation));
7390         }
7391 
7392         @Override
onHotspotStopped()7393         public void onHotspotStopped() {
7394             WifiManager manager = mWifiManager.get();
7395             if (manager == null) return;
7396 
7397             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
7398             if (mCallback == null) return;
7399             mExecutor.execute(() -> mCallback.onStopped());
7400         }
7401 
7402         @Override
onHotspotFailed(int reason)7403         public void onHotspotFailed(int reason) {
7404             WifiManager manager = mWifiManager.get();
7405             if (manager == null) return;
7406 
7407             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
7408                     + reason);
7409             if (mCallback == null) return;
7410             mExecutor.execute(() -> mCallback.onFailed(reason));
7411         }
7412     }
7413 
7414     /**
7415      * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications
7416      * watching for LocalOnlyHotspot changes.
7417      *
7418      * @hide
7419      */
7420     public class LocalOnlyHotspotSubscription implements AutoCloseable {
7421         private final CloseGuard mCloseGuard = new CloseGuard();
7422 
7423         /** @hide */
7424         @VisibleForTesting
LocalOnlyHotspotSubscription()7425         public LocalOnlyHotspotSubscription() {
7426             mCloseGuard.open("close");
7427         }
7428 
7429         @Override
close()7430         public void close() {
7431             try {
7432                 unregisterLocalOnlyHotspotObserver();
7433                 mCloseGuard.close();
7434             } catch (Exception e) {
7435                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
7436             } finally {
7437                 Reference.reachabilityFence(this);
7438             }
7439         }
7440 
7441         @Override
finalize()7442         protected void finalize() throws Throwable {
7443             try {
7444                 if (mCloseGuard != null) {
7445                     mCloseGuard.warnIfOpen();
7446                 }
7447                 close();
7448             } finally {
7449                 super.finalize();
7450             }
7451         }
7452     }
7453 
7454     /**
7455      * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates.
7456      *
7457      * @hide
7458      */
7459     public static class LocalOnlyHotspotObserver {
7460         /**
7461          * Confirm registration for LocalOnlyHotspotChanges by returning a
7462          * LocalOnlyHotspotSubscription.
7463          */
onRegistered(LocalOnlyHotspotSubscription subscription)7464         public void onRegistered(LocalOnlyHotspotSubscription subscription) {};
7465 
7466         /**
7467          * LocalOnlyHotspot started with the supplied config.
7468          */
onStarted(SoftApConfiguration config)7469         public void onStarted(SoftApConfiguration config) {};
7470 
7471         /**
7472          * LocalOnlyHotspot stopped.
7473          */
onStopped()7474         public void onStopped() {};
7475     }
7476 
7477     /**
7478      * Callback proxy for LocalOnlyHotspotObserver objects.
7479      */
7480     private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub {
7481         private final WeakReference<WifiManager> mWifiManager;
7482         private final Executor mExecutor;
7483         private final LocalOnlyHotspotObserver mObserver;
7484 
7485         /**
7486          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
7487          * All callbacks will be delivered on the thread of the specified looper.
7488          *
7489          * @param manager WifiManager
7490          * @param executor Executor for delivering callbacks
7491          * @param observer LocalOnlyHotspotObserver to notify the calling application.
7492          */
LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor, final LocalOnlyHotspotObserver observer)7493         LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor,
7494                 final LocalOnlyHotspotObserver observer) {
7495             mWifiManager = new WeakReference<>(manager);
7496             mExecutor = executor;
7497             mObserver = observer;
7498         }
7499 
registered()7500         public void registered() throws RemoteException {
7501             WifiManager manager = mWifiManager.get();
7502             if (manager == null) return;
7503 
7504             mExecutor.execute(() ->
7505                     mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription()));
7506         }
7507 
7508         @Override
onHotspotStarted(SoftApConfiguration config)7509         public void onHotspotStarted(SoftApConfiguration config) {
7510             WifiManager manager = mWifiManager.get();
7511             if (manager == null) return;
7512 
7513             if (config == null) {
7514                 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
7515                 return;
7516             }
7517             mExecutor.execute(() -> mObserver.onStarted(config));
7518         }
7519 
7520         @Override
onHotspotStopped()7521         public void onHotspotStopped() {
7522             WifiManager manager = mWifiManager.get();
7523             if (manager == null) return;
7524 
7525             mExecutor.execute(() -> mObserver.onStopped());
7526         }
7527 
7528         @Override
onHotspotFailed(int reason)7529         public void onHotspotFailed(int reason) {
7530             // do nothing
7531         }
7532     }
7533 
7534     /**
7535      * Callback proxy for ActionListener objects.
7536      */
7537     private class ActionListenerProxy extends IActionListener.Stub {
7538         private final String mActionTag;
7539         private final Handler mHandler;
7540         private final ActionListener mCallback;
7541 
ActionListenerProxy(String actionTag, Looper looper, ActionListener callback)7542         ActionListenerProxy(String actionTag, Looper looper, ActionListener callback) {
7543             mActionTag = actionTag;
7544             mHandler = new Handler(looper);
7545             mCallback = callback;
7546         }
7547 
7548         @Override
onSuccess()7549         public void onSuccess() {
7550             if (mVerboseLoggingEnabled) {
7551                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onSuccess");
7552             }
7553             mHandler.post(() -> {
7554                 mCallback.onSuccess();
7555             });
7556         }
7557 
7558         @Override
onFailure(@ctionListenerFailureReason int reason)7559         public void onFailure(@ActionListenerFailureReason int reason) {
7560             if (mVerboseLoggingEnabled) {
7561                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onFailure=" + reason);
7562             }
7563             mHandler.post(() -> {
7564                 mCallback.onFailure(reason);
7565             });
7566         }
7567     }
7568 
connectInternal(@ullable WifiConfiguration config, int networkId, @Nullable ActionListener listener)7569     private void connectInternal(@Nullable WifiConfiguration config, int networkId,
7570             @Nullable ActionListener listener) {
7571         ActionListenerProxy listenerProxy = null;
7572         if (listener != null) {
7573             listenerProxy = new ActionListenerProxy("connect", mContext.getMainLooper(), listener);
7574         }
7575         try {
7576             Bundle extras = new Bundle();
7577             if (SdkLevel.isAtLeastS()) {
7578                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
7579                         mContext.getAttributionSource());
7580             }
7581             mService.connect(config, networkId, listenerProxy, mContext.getOpPackageName(), extras);
7582         } catch (RemoteException e) {
7583             if (listenerProxy != null) {
7584                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7585             }
7586         } catch (SecurityException e) {
7587             if (listenerProxy != null) {
7588                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7589             }
7590         }
7591     }
7592 
7593     /**
7594      * Connect to a network with the given configuration. The network also
7595      * gets added to the list of configured networks for the foreground user.
7596      *
7597      * For a new network, this function is used instead of a
7598      * sequence of addNetwork(), enableNetwork(), and reconnect()
7599      *
7600      * @param config the set of variables that describe the configuration,
7601      *            contained in a {@link WifiConfiguration} object.
7602      * @param listener for callbacks on success or failure. Can be null.
7603      * @throws IllegalStateException if the WifiManager instance needs to be
7604      * initialized again
7605      *
7606      * @hide
7607      */
7608     @SystemApi
7609     @RequiresPermission(anyOf = {
7610             android.Manifest.permission.NETWORK_SETTINGS,
7611             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7612             android.Manifest.permission.NETWORK_STACK
7613     })
connect(@onNull WifiConfiguration config, @Nullable ActionListener listener)7614     public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
7615         if (config == null) throw new IllegalArgumentException("config cannot be null");
7616         connectInternal(config, WifiConfiguration.INVALID_NETWORK_ID, listener);
7617     }
7618 
7619     /**
7620      * Connect to a network with the given networkId.
7621      *
7622      * This function is used instead of a enableNetwork() and reconnect()
7623      *
7624      * <li> This API will cause reconnect if the credentials of the current active
7625      * connection has been changed.</li>
7626      * <li> This API will cause reconnect if the current active connection is marked metered.</li>
7627      *
7628      * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
7629      *        #getConfiguredNetworks()}.
7630      * @param listener for callbacks on success or failure. Can be null.
7631      * @throws IllegalStateException if the WifiManager instance needs to be
7632      * initialized again
7633      * @hide
7634      */
7635     @SystemApi
7636     @RequiresPermission(anyOf = {
7637             android.Manifest.permission.NETWORK_SETTINGS,
7638             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7639             android.Manifest.permission.NETWORK_STACK
7640     })
connect(int networkId, @Nullable ActionListener listener)7641     public void connect(int networkId, @Nullable ActionListener listener) {
7642         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7643         connectInternal(null, networkId, listener);
7644     }
7645 
7646     /**
7647      * Temporarily disable autojoin for all currently visible and provisioned (saved, suggested)
7648      * wifi networks except merged carrier networks from the provided subscription ID.
7649      *
7650      * Disabled networks will get automatically re-enabled when they are out of range for a period
7651      * of time, or after the maximum disable duration specified in the framework.
7652      *
7653      * Calling {@link #stopRestrictingAutoJoinToSubscriptionId()} will immediately re-enable
7654      * autojoin on all disabled networks.
7655      *
7656      * @param subscriptionId the subscription ID of the carrier whose merged wifi networks won't be
7657      *                       disabled {@link android.telephony.SubscriptionInfo#getSubscriptionId()}
7658      * @hide
7659      */
7660     @SystemApi
7661     @RequiresPermission(anyOf = {
7662             android.Manifest.permission.NETWORK_SETTINGS,
7663             android.Manifest.permission.NETWORK_SETUP_WIZARD})
7664     @RequiresApi(Build.VERSION_CODES.S)
startRestrictingAutoJoinToSubscriptionId(int subscriptionId)7665     public void startRestrictingAutoJoinToSubscriptionId(int subscriptionId) {
7666         try {
7667             mService.startRestrictingAutoJoinToSubscriptionId(subscriptionId);
7668         } catch (RemoteException e) {
7669             throw e.rethrowFromSystemServer();
7670         }
7671     }
7672 
7673     /**
7674      * Re-enable autojoin for all non carrier merged wifi networks temporarily disconnected by
7675      * {@link #startRestrictingAutoJoinToSubscriptionId(int)}.
7676      * @hide
7677      */
7678     @SystemApi
7679     @RequiresPermission(anyOf = {
7680             android.Manifest.permission.NETWORK_SETTINGS,
7681             android.Manifest.permission.NETWORK_SETUP_WIZARD})
7682     @RequiresApi(Build.VERSION_CODES.S)
stopRestrictingAutoJoinToSubscriptionId()7683     public void stopRestrictingAutoJoinToSubscriptionId() {
7684         try {
7685             mService.stopRestrictingAutoJoinToSubscriptionId();
7686         } catch (RemoteException e) {
7687             throw e.rethrowFromSystemServer();
7688         }
7689     }
7690 
7691     /**
7692      * Save the given network to the list of configured networks for the
7693      * foreground user. If the network already exists, the configuration
7694      * is updated. Any new network is enabled by default.
7695      *
7696      * For a new network, this function is used instead of a
7697      * sequence of addNetwork() and enableNetwork().
7698      *
7699      * For an existing network, it accomplishes the task of updateNetwork()
7700      *
7701      * <li> This API will cause reconnect if the credentials of the current active
7702      * connection has been changed.</li>
7703      * <li> This API will cause disconnect if the current active connection is marked metered.</li>
7704      *
7705      * @param config the set of variables that describe the configuration,
7706      *            contained in a {@link WifiConfiguration} object.
7707      * @param listener for callbacks on success or failure. Can be null.
7708      * @throws IllegalStateException if the WifiManager instance needs to be
7709      * initialized again
7710      * @hide
7711      */
7712     @SystemApi
7713     @RequiresPermission(anyOf = {
7714             android.Manifest.permission.NETWORK_SETTINGS,
7715             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7716             android.Manifest.permission.NETWORK_STACK
7717     })
save(@onNull WifiConfiguration config, @Nullable ActionListener listener)7718     public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
7719         if (config == null) throw new IllegalArgumentException("config cannot be null");
7720         ActionListenerProxy listenerProxy = null;
7721         if (listener != null) {
7722             listenerProxy = new ActionListenerProxy("save", mContext.getMainLooper(), listener);
7723         }
7724         try {
7725             mService.save(config, listenerProxy, mContext.getOpPackageName());
7726         } catch (RemoteException e) {
7727             if (listenerProxy != null) {
7728                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7729             }
7730         } catch (SecurityException e) {
7731             if (listenerProxy != null) {
7732                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7733             }
7734         }
7735     }
7736 
7737     /**
7738      * Delete the network from the list of configured networks for the
7739      * foreground user.
7740      *
7741      * This function is used instead of a sequence of removeNetwork()
7742      *
7743      * @param config the set of variables that describe the configuration,
7744      *            contained in a {@link WifiConfiguration} object.
7745      * @param listener for callbacks on success or failure. Can be null.
7746      * @throws IllegalStateException if the WifiManager instance needs to be
7747      * initialized again
7748      * @hide
7749      */
7750     @SystemApi
7751     @RequiresPermission(anyOf = {
7752             android.Manifest.permission.NETWORK_SETTINGS,
7753             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7754             android.Manifest.permission.NETWORK_STACK
7755     })
forget(int netId, @Nullable ActionListener listener)7756     public void forget(int netId, @Nullable ActionListener listener) {
7757         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7758         ActionListenerProxy listenerProxy = null;
7759         if (listener != null) {
7760             listenerProxy = new ActionListenerProxy("forget", mContext.getMainLooper(), listener);
7761         }
7762         try {
7763             mService.forget(netId, listenerProxy);
7764         } catch (RemoteException e) {
7765             if (listenerProxy != null) {
7766                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7767             }
7768         } catch (SecurityException e) {
7769             if (listenerProxy != null) {
7770                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7771             }
7772         }
7773     }
7774 
7775     /**
7776      * Disable network
7777      *
7778      * @param netId is the network Id
7779      * @param listener for callbacks on success or failure. Can be null.
7780      * @throws IllegalStateException if the WifiManager instance needs to be
7781      * initialized again
7782      * @deprecated This API is deprecated. Use {@link #disableNetwork(int)} instead.
7783      * @hide
7784      */
7785     @SystemApi
7786     @RequiresPermission(anyOf = {
7787             android.Manifest.permission.NETWORK_SETTINGS,
7788             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7789             android.Manifest.permission.NETWORK_STACK
7790     })
7791     @Deprecated
disable(int netId, @Nullable ActionListener listener)7792     public void disable(int netId, @Nullable ActionListener listener) {
7793         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7794         // Simple wrapper which forwards the call to disableNetwork. This is a temporary
7795         // implementation until we can remove this API completely.
7796         boolean status = disableNetwork(netId);
7797         if (listener != null) {
7798             if (status) {
7799                 listener.onSuccess();
7800             } else {
7801                 listener.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7802             }
7803         }
7804     }
7805 
7806     /**
7807      * Control whether the device will automatically search for and connect to Wi-Fi networks -
7808      * auto-join Wi-Fi networks. Disabling this option will not impact manual connections - i.e.
7809      * the user will still be able to manually select and connect to a Wi-Fi network. Disabling
7810      * this option significantly impacts the device connectivity and is a restricted operation
7811      * (see below for permissions). Note that disabling this operation will also disable
7812      * connectivity initiated scanning operations.
7813      * <p>
7814      * Disabling the auto-join configuration is a temporary operation (with the exception of a
7815      * DO/PO caller): it will be reset (to enabled) when the device reboots or the user toggles
7816      * Wi-Fi off/on. When the caller is a DO/PO then toggling Wi-Fi will not reset the
7817      * configuration. Additionally, if a DO/PO disables auto-join then it cannot be (re)enabled by
7818      * a non-DO/PO caller.
7819      *
7820      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
7821      *
7822      * Available for DO/PO apps.
7823      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
7824      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
7825      */
allowAutojoinGlobal(boolean allowAutojoin)7826     public void allowAutojoinGlobal(boolean allowAutojoin) {
7827         try {
7828             Bundle extras = new Bundle();
7829             if (SdkLevel.isAtLeastS()) {
7830                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
7831                         mContext.getAttributionSource());
7832             }
7833             mService.allowAutojoinGlobal(allowAutojoin, mContext.getOpPackageName(), extras);
7834         } catch (RemoteException e) {
7835             throw e.rethrowFromSystemServer();
7836         }
7837     }
7838 
7839     /**
7840      * Query whether or not auto-join global is enabled/disabled
7841      * @see #allowAutojoinGlobal(boolean)
7842      *
7843      * Available for DO/PO apps.
7844      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
7845      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
7846      *
7847      * @param executor The executor on which callback will be invoked.
7848      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
7849      *                        whether auto-join global is enabled/disabled.
7850      *
7851      * @throws SecurityException if the caller does not have permission.
7852      * @throws NullPointerException if the caller provided invalid inputs.
7853      */
queryAutojoinGlobal(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)7854     public void queryAutojoinGlobal(@NonNull @CallbackExecutor Executor executor,
7855             @NonNull Consumer<Boolean> resultsCallback) {
7856         Objects.requireNonNull(executor, "executor cannot be null");
7857         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
7858         try {
7859             mService.queryAutojoinGlobal(
7860                     new IBooleanListener.Stub() {
7861                         @Override
7862                         public void onResult(boolean value) {
7863                             Binder.clearCallingIdentity();
7864                             executor.execute(() -> {
7865                                 resultsCallback.accept(value);
7866                             });
7867                         }
7868                     });
7869         } catch (RemoteException e) {
7870             throw e.rethrowFromSystemServer();
7871         }
7872     }
7873 
7874     /**
7875      * Sets the user choice for allowing auto-join to a network.
7876      * The updated choice will be made available through the updated config supplied by the
7877      * CONFIGURED_NETWORKS_CHANGED broadcast.
7878      *
7879      * @param netId the id of the network to allow/disallow auto-join for.
7880      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
7881      * @hide
7882      */
7883     @SystemApi
7884     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoin(int netId, boolean allowAutojoin)7885     public void allowAutojoin(int netId, boolean allowAutojoin) {
7886         try {
7887             mService.allowAutojoin(netId, allowAutojoin);
7888         } catch (RemoteException e) {
7889             throw e.rethrowFromSystemServer();
7890         }
7891     }
7892 
7893     /**
7894      * Configure auto-join settings for a Passpoint profile.
7895      *
7896      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7897      * @param allowAutojoin true to enable auto-join, false to disable auto-join.
7898      * @hide
7899      */
7900     @SystemApi
7901     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoinPasspoint(@onNull String fqdn, boolean allowAutojoin)7902     public void allowAutojoinPasspoint(@NonNull String fqdn, boolean allowAutojoin) {
7903         try {
7904             mService.allowAutojoinPasspoint(fqdn, allowAutojoin);
7905         } catch (RemoteException e) {
7906             throw e.rethrowFromSystemServer();
7907         }
7908     }
7909 
7910     /**
7911      * Configure MAC randomization setting for a Passpoint profile.
7912      * MAC randomization is enabled by default.
7913      *
7914      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7915      * @param enable true to enable MAC randomization, false to disable MAC randomization.
7916      * @hide
7917      */
7918     @SystemApi
7919     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setMacRandomizationSettingPasspointEnabled(@onNull String fqdn, boolean enable)7920     public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
7921         try {
7922             mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
7923         } catch (RemoteException e) {
7924             throw e.rethrowFromSystemServer();
7925         }
7926     }
7927 
7928     /**
7929      * Sets the user's choice of metered override for a Passpoint profile.
7930      *
7931      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7932      * @param meteredOverride One of three values: {@link WifiConfiguration#METERED_OVERRIDE_NONE},
7933      *                        {@link WifiConfiguration#METERED_OVERRIDE_METERED},
7934      *                        {@link WifiConfiguration#METERED_OVERRIDE_NOT_METERED}
7935      * @hide
7936      */
7937     @SystemApi
7938     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setPasspointMeteredOverride(@onNull String fqdn, @WifiConfiguration.MeteredOverride int meteredOverride)7939     public void setPasspointMeteredOverride(@NonNull String fqdn,
7940             @WifiConfiguration.MeteredOverride int meteredOverride) {
7941         try {
7942             mService.setPasspointMeteredOverride(fqdn, meteredOverride);
7943         } catch (RemoteException e) {
7944             throw e.rethrowFromSystemServer();
7945         }
7946     }
7947 
7948     /**
7949      * Temporarily disable a network. Should always trigger with user disconnect network.
7950      *
7951      * @param network Input can be SSID or FQDN. And caller must ensure that the SSID passed thru
7952      *                this API matched the WifiConfiguration.SSID rules, and thus be surrounded by
7953      *                quotes.
7954      * @hide
7955      */
7956     @SystemApi
7957     @RequiresPermission(anyOf = {
7958             android.Manifest.permission.NETWORK_SETTINGS,
7959             android.Manifest.permission.NETWORK_STACK
7960     })
disableEphemeralNetwork(@onNull String network)7961     public void disableEphemeralNetwork(@NonNull String network) {
7962         if (TextUtils.isEmpty(network)) {
7963             throw new IllegalArgumentException("SSID cannot be null or empty!");
7964         }
7965         try {
7966             mService.disableEphemeralNetwork(network, mContext.getOpPackageName());
7967         } catch (RemoteException e) {
7968             throw e.rethrowFromSystemServer();
7969         }
7970     }
7971 
7972     /**
7973      * WPS suport has been deprecated from Client mode and this method will immediately trigger
7974      * {@link WpsCallback#onFailed(int)} with a generic error.
7975      *
7976      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
7977      * @param listener for callbacks on success or failure. Can be null.
7978      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
7979      * @deprecated This API is deprecated
7980      */
startWps(WpsInfo config, WpsCallback listener)7981     public void startWps(WpsInfo config, WpsCallback listener) {
7982         if (listener != null ) {
7983             listener.onFailed(ActionListener.FAILURE_INTERNAL_ERROR);
7984         }
7985     }
7986 
7987     /**
7988      * WPS support has been deprecated from Client mode and this method will immediately trigger
7989      * {@link WpsCallback#onFailed(int)} with a generic error.
7990      *
7991      * @param listener for callbacks on success or failure. Can be null.
7992      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
7993      * @deprecated This API is deprecated
7994      */
cancelWps(WpsCallback listener)7995     public void cancelWps(WpsCallback listener) {
7996         if (listener != null) {
7997             listener.onFailed(ActionListener.FAILURE_INTERNAL_ERROR);
7998         }
7999     }
8000 
8001     /**
8002      * Allows an application to keep the Wi-Fi radio awake.
8003      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
8004      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
8005      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
8006      * WifiLocks are held in any application.
8007      * <p>
8008      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
8009      * could function over a mobile network, if available.  A program that needs to download large
8010      * files should hold a WifiLock to ensure that the download will complete, but a program whose
8011      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
8012      * affecting battery life.
8013      * <p>
8014      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
8015      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
8016      * is idle.
8017      * <p>
8018      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
8019      * permission in an {@code <uses-permission>} element of the application's manifest.
8020      */
8021     public class WifiLock {
8022         private String mTag;
8023         private final IBinder mBinder;
8024         private int mRefCount;
8025         int mLockType;
8026         private boolean mRefCounted;
8027         private boolean mHeld;
8028         private WorkSource mWorkSource;
8029 
WifiLock(int lockType, String tag)8030         private WifiLock(int lockType, String tag) {
8031             mTag = tag;
8032             mLockType = lockType;
8033             mBinder = new Binder();
8034             mRefCount = 0;
8035             mRefCounted = true;
8036             mHeld = false;
8037         }
8038 
8039         /**
8040          * Locks the Wi-Fi radio on until {@link #release} is called.
8041          *
8042          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
8043          * reference count, and the radio will remain locked as long as the reference count is
8044          * above zero.
8045          *
8046          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
8047          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
8048          * will be required, regardless of the number of times that {@code acquire} is called.
8049          */
acquire()8050         public void acquire() {
8051             synchronized (mBinder) {
8052                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
8053                     try {
8054                         Bundle extras = new Bundle();
8055                         if (SdkLevel.isAtLeastS()) {
8056                             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
8057                                     mContext.getAttributionSource());
8058                         }
8059                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource,
8060                                 mContext.getOpPackageName(), extras);
8061                         synchronized (WifiManager.this) {
8062                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
8063                                 mService.releaseWifiLock(mBinder);
8064                                 throw new UnsupportedOperationException(
8065                                             "Exceeded maximum number of wifi locks");
8066                             }
8067                             mActiveLockCount++;
8068                         }
8069                     } catch (RemoteException e) {
8070                         throw e.rethrowFromSystemServer();
8071                     }
8072                     mHeld = true;
8073                 }
8074             }
8075         }
8076 
8077         /**
8078          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
8079          *
8080          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
8081          * reference count, and the radio will be unlocked only when the reference count reaches
8082          * zero.  If the reference count goes below zero (that is, if {@code release} is called
8083          * a greater number of times than {@link #acquire}), an exception is thrown.
8084          *
8085          * If this WifiLock is not reference-counted, the first call to {@code release} (after
8086          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
8087          * calls will be ignored.
8088          */
release()8089         public void release() {
8090             synchronized (mBinder) {
8091                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
8092                     try {
8093                         mService.releaseWifiLock(mBinder);
8094                         synchronized (WifiManager.this) {
8095                             mActiveLockCount--;
8096                         }
8097                     } catch (RemoteException e) {
8098                         throw e.rethrowFromSystemServer();
8099                     }
8100                     mHeld = false;
8101                 }
8102                 if (mRefCount < 0) {
8103                     throw new RuntimeException("WifiLock under-locked " + mTag);
8104                 }
8105             }
8106         }
8107 
8108         /**
8109          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
8110          *
8111          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
8112          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
8113          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
8114          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
8115          * radio whenever {@link #release} is called and it is locked.
8116          *
8117          * @param refCounted true if this WifiLock should keep a reference count
8118          */
setReferenceCounted(boolean refCounted)8119         public void setReferenceCounted(boolean refCounted) {
8120             mRefCounted = refCounted;
8121         }
8122 
8123         /**
8124          * Checks whether this WifiLock is currently held.
8125          *
8126          * @return true if this WifiLock is held, false otherwise
8127          */
isHeld()8128         public boolean isHeld() {
8129             synchronized (mBinder) {
8130                 return mHeld;
8131             }
8132         }
8133 
setWorkSource(WorkSource ws)8134         public void setWorkSource(WorkSource ws) {
8135             synchronized (mBinder) {
8136                 if (ws != null && ws.isEmpty()) {
8137                     ws = null;
8138                 }
8139                 boolean changed = true;
8140                 if (ws == null) {
8141                     mWorkSource = null;
8142                 } else {
8143                     ws = ws.withoutNames();
8144                     if (mWorkSource == null) {
8145                         changed = mWorkSource != null;
8146                         mWorkSource = new WorkSource(ws);
8147                     } else {
8148                         changed = !mWorkSource.equals(ws);
8149                         if (changed) {
8150                             mWorkSource.set(ws);
8151                         }
8152                     }
8153                 }
8154                 if (changed && mHeld) {
8155                     try {
8156                         Bundle extras = new Bundle();
8157                         if (SdkLevel.isAtLeastS()) {
8158                             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
8159                                     mContext.getAttributionSource());
8160                         }
8161                         mService.updateWifiLockWorkSource(mBinder, mWorkSource,
8162                                 mContext.getOpPackageName(), extras);
8163                     } catch (RemoteException e) {
8164                         throw e.rethrowFromSystemServer();
8165                     }
8166                 }
8167             }
8168         }
8169 
toString()8170         public String toString() {
8171             String s1, s2, s3;
8172             synchronized (mBinder) {
8173                 s1 = Integer.toHexString(System.identityHashCode(this));
8174                 s2 = mHeld ? "held; " : "";
8175                 if (mRefCounted) {
8176                     s3 = "refcounted: refcount = " + mRefCount;
8177                 } else {
8178                     s3 = "not refcounted";
8179                 }
8180                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
8181             }
8182         }
8183 
8184         @Override
finalize()8185         protected void finalize() throws Throwable {
8186             super.finalize();
8187             synchronized (mBinder) {
8188                 if (mHeld) {
8189                     try {
8190                         mService.releaseWifiLock(mBinder);
8191                         synchronized (WifiManager.this) {
8192                             mActiveLockCount--;
8193                         }
8194                     } catch (RemoteException e) {
8195                         throw e.rethrowFromSystemServer();
8196                     }
8197                 }
8198             }
8199         }
8200     }
8201 
8202     /**
8203      * Creates a new WifiLock.
8204      *
8205      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL_HIGH_PERF}
8206      * and {@link #WIFI_MODE_FULL_LOW_LATENCY} for descriptions of the types of Wi-Fi locks.
8207      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
8208      *            never shown to the user under normal conditions, but should be descriptive
8209      *            enough to identify your application and the specific WifiLock within it, if it
8210      *            holds multiple WifiLocks.
8211      *
8212      * @return a new, unacquired WifiLock with the given tag.
8213      *
8214      * @see WifiLock
8215      */
createWifiLock(int lockType, String tag)8216     public WifiLock createWifiLock(int lockType, String tag) {
8217         return new WifiLock(lockType, tag);
8218     }
8219 
8220     /**
8221      * Interface for low latency lock listener. Should be extended by application and set when
8222      * calling {@link WifiManager#addWifiLowLatencyLockListener(Executor,
8223      * WifiLowLatencyLockListener)}.
8224      *
8225      * @hide
8226      */
8227     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
8228     @SystemApi
8229     public interface WifiLowLatencyLockListener {
8230         /**
8231          * Provides low latency mode is activated or not. Triggered when Wi-Fi chip enters into low
8232          * latency mode.
8233          *
8234          * <p>Note: Always called with current state when a new listener gets registered.
8235          */
8236         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onActivatedStateChanged(boolean activated)8237         void onActivatedStateChanged(boolean activated);
8238 
8239         /**
8240          * Provides UIDs (lock owners) of the applications which currently acquired low latency
8241          * lock. Triggered when an application acquires or releases a lock.
8242          *
8243          * <p>Note: Always called with UIDs of the current acquired locks when a new listener gets
8244          * registered.
8245          *
8246          * @param ownerUids An array of UIDs.
8247          */
8248         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onOwnershipChanged(@onNull int[] ownerUids)8249         default void onOwnershipChanged(@NonNull int[] ownerUids) {}
8250 
8251         /**
8252          * Provides UIDs of the applications which acquired the low latency lock and is currently
8253          * active. See {@link WifiManager#WIFI_MODE_FULL_LOW_LATENCY} for the conditions to be met
8254          * for low latency lock to be active. Triggered when application acquiring the lock
8255          * satisfies or does not satisfy low latency conditions when the low latency mode is
8256          * activated. Also gets triggered when the lock becomes active, immediately after the {@link
8257          * WifiLowLatencyLockListener#onActivatedStateChanged(boolean)} callback is triggered.
8258          *
8259          * <p>Note: Always called with UIDs of the current active locks when a new listener gets
8260          * registered if the Wi-Fi chip is in low latency mode.
8261          *
8262          * @param activeUids An array of UIDs.
8263          */
8264         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onActiveUsersChanged(@onNull int[] activeUids)8265         default void onActiveUsersChanged(@NonNull int[] activeUids) {}
8266     }
8267 
8268     /**
8269      * Helper class to support wifi low latency lock listener.
8270      */
8271     private static class OnWifiLowLatencyLockProxy extends IWifiLowLatencyLockListener.Stub {
8272         @NonNull
8273         private Executor mExecutor;
8274         @NonNull
8275         private WifiLowLatencyLockListener mListener;
8276 
OnWifiLowLatencyLockProxy(@onNull Executor executor, @NonNull WifiLowLatencyLockListener listener)8277         OnWifiLowLatencyLockProxy(@NonNull Executor executor,
8278                 @NonNull WifiLowLatencyLockListener listener) {
8279             Objects.requireNonNull(executor);
8280             Objects.requireNonNull(listener);
8281             mExecutor = executor;
8282             mListener = listener;
8283         }
8284 
8285         @Override
onActivatedStateChanged(boolean activated)8286         public void onActivatedStateChanged(boolean activated) {
8287             Binder.clearCallingIdentity();
8288             mExecutor.execute(() -> mListener.onActivatedStateChanged(activated));
8289 
8290         }
8291 
8292         @Override
onOwnershipChanged(@onNull int[] ownerUids)8293         public void onOwnershipChanged(@NonNull int[] ownerUids) {
8294             Binder.clearCallingIdentity();
8295             mExecutor.execute(() -> mListener.onOwnershipChanged(ownerUids));
8296 
8297         }
8298 
8299         @Override
onActiveUsersChanged(@onNull int[] activeUids)8300         public void onActiveUsersChanged(@NonNull int[] activeUids) {
8301             Binder.clearCallingIdentity();
8302             mExecutor.execute(() -> mListener.onActiveUsersChanged(activeUids));
8303         }
8304     }
8305 
8306     /**
8307      * Add a listener for monitoring the low latency lock. The caller can unregister a previously
8308      * registered listener using {@link WifiManager#removeWifiLowLatencyLockListener(
8309      * WifiLowLatencyLockListener)}.
8310      *
8311      * <p>Applications should have the {@link android.Manifest.permission#NETWORK_SETTINGS} and
8312      * {@link android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission. Callers without
8313      * the permission will trigger a {@link java.lang.SecurityException}.
8314      *
8315      * @param executor The Executor on which to execute the callbacks.
8316      * @param listener The listener for the latency mode change.
8317      * @throws IllegalArgumentException if incorrect input arguments are provided.
8318      * @throws SecurityException if the caller is not allowed to call this API
8319      * @hide
8320      */
8321     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
8322     @SystemApi
8323     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
8324     @RequiresPermission(
8325             anyOf = {android.Manifest.permission.NETWORK_SETTINGS, MANAGE_WIFI_NETWORK_SELECTION})
addWifiLowLatencyLockListener( @onNull @allbackExecutor Executor executor, @NonNull WifiLowLatencyLockListener listener)8326     public void addWifiLowLatencyLockListener(
8327             @NonNull @CallbackExecutor Executor executor,
8328             @NonNull WifiLowLatencyLockListener listener) {
8329         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
8330         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
8331         if (mVerboseLoggingEnabled) {
8332             Log.d(TAG, "addWifiLowLatencyLockListener: listener=" + listener + ", executor="
8333                     + executor);
8334         }
8335         final int listenerIdentifier = System.identityHashCode(listener);
8336         try {
8337             synchronized (sWifiLowLatencyLockListenerMap) {
8338                 IWifiLowLatencyLockListener.Stub listenerProxy = new OnWifiLowLatencyLockProxy(
8339                         executor,
8340                         listener);
8341                 sWifiLowLatencyLockListenerMap.put(listenerIdentifier, listenerProxy);
8342                 mService.addWifiLowLatencyLockListener(listenerProxy);
8343             }
8344         } catch (RemoteException e) {
8345             sWifiLowLatencyLockListenerMap.remove(listenerIdentifier);
8346             throw e.rethrowFromSystemServer();
8347         }
8348     }
8349 
8350     /**
8351      * Removes a listener added using {@link WifiManager#addWifiLowLatencyLockListener(Executor,
8352      * WifiLowLatencyLockListener)}. After calling this method, applications will no longer receive
8353      * low latency mode notifications.
8354      *
8355      * @param listener the listener to be removed.
8356      * @throws IllegalArgumentException if incorrect input arguments are provided.
8357      * @hide
8358      */
8359     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
8360     @SystemApi
8361     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
removeWifiLowLatencyLockListener(@onNull WifiLowLatencyLockListener listener)8362     public void removeWifiLowLatencyLockListener(@NonNull WifiLowLatencyLockListener listener) {
8363         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
8364         if (mVerboseLoggingEnabled) {
8365             Log.d(TAG, "removeWifiLowLatencyLockListener: listener=" + listener);
8366         }
8367         final int listenerIdentifier = System.identityHashCode(listener);
8368         synchronized (sWifiLowLatencyLockListenerMap) {
8369             try {
8370                 if (!sWifiLowLatencyLockListenerMap.contains(listenerIdentifier)) {
8371                     Log.w(TAG, "Unknown external listener " + listenerIdentifier);
8372                     return;
8373                 }
8374                 mService.removeWifiLowLatencyLockListener(
8375                         sWifiLowLatencyLockListenerMap.get(listenerIdentifier));
8376 
8377             } catch (RemoteException e) {
8378                 throw e.rethrowFromSystemServer();
8379             } finally {
8380                 sWifiLowLatencyLockListenerMap.remove(listenerIdentifier);
8381             }
8382         }
8383     }
8384 
8385     /**
8386      * Creates a new WifiLock.
8387      *
8388      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
8389      *            never shown to the user under normal conditions, but should be descriptive
8390      *            enough to identify your application and the specific WifiLock within it, if it
8391      *            holds multiple WifiLocks.
8392      *
8393      * @return a new, unacquired WifiLock with the given tag.
8394      *
8395      * @see WifiLock
8396      *
8397      * @deprecated This API is non-functional.
8398      */
8399     @Deprecated
createWifiLock(String tag)8400     public WifiLock createWifiLock(String tag) {
8401         return new WifiLock(WIFI_MODE_FULL, tag);
8402     }
8403 
8404     /**
8405      * Create a new MulticastLock
8406      *
8407      * @param tag a tag for the MulticastLock to identify it in debugging
8408      *            messages.  This string is never shown to the user under
8409      *            normal conditions, but should be descriptive enough to
8410      *            identify your application and the specific MulticastLock
8411      *            within it, if it holds multiple MulticastLocks.
8412      *
8413      * @return a new, unacquired MulticastLock with the given tag.
8414      *
8415      * @see MulticastLock
8416      */
createMulticastLock(String tag)8417     public MulticastLock createMulticastLock(String tag) {
8418         return new MulticastLock(tag);
8419     }
8420 
8421     /**
8422      * Allows an application to receive Wifi Multicast packets.
8423      * Normally the Wifi stack filters out packets not explicitly
8424      * addressed to this device.  Acquring a MulticastLock will
8425      * cause the stack to receive packets addressed to multicast
8426      * addresses.  Processing these extra packets can cause a noticeable
8427      * battery drain and should be disabled when not needed.
8428      */
8429     public class MulticastLock {
8430         private String mTag;
8431         private final IBinder mBinder;
8432         private int mRefCount;
8433         private boolean mRefCounted;
8434         private boolean mHeld;
8435 
MulticastLock(String tag)8436         private MulticastLock(String tag) {
8437             mTag = tag;
8438             mBinder = new Binder();
8439             mRefCount = 0;
8440             mRefCounted = true;
8441             mHeld = false;
8442         }
8443 
8444         /**
8445          * Locks Wifi Multicast on until {@link #release} is called.
8446          *
8447          * If this MulticastLock is reference-counted each call to
8448          * {@code acquire} will increment the reference count, and the
8449          * wifi interface will receive multicast packets as long as the
8450          * reference count is above zero.
8451          *
8452          * If this MulticastLock is not reference-counted, the first call to
8453          * {@code acquire} will turn on the multicast packets, but subsequent
8454          * calls will be ignored.  Only one call to {@link #release} will
8455          * be required, regardless of the number of times that {@code acquire}
8456          * is called.
8457          *
8458          * Note that other applications may also lock Wifi Multicast on.
8459          * Only they can relinquish their lock.
8460          *
8461          * Also note that applications cannot leave Multicast locked on.
8462          * When an app exits or crashes, any Multicast locks will be released.
8463          */
acquire()8464         public void acquire() {
8465             synchronized (mBinder) {
8466                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
8467                     try {
8468                         mService.acquireMulticastLock(mBinder, mTag,
8469                                 mContext.getAttributionTag(), mContext.getOpPackageName());
8470                         synchronized (WifiManager.this) {
8471                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
8472                                 mService.releaseMulticastLock(mBinder, mTag);
8473                                 throw new UnsupportedOperationException(
8474                                         "Exceeded maximum number of wifi locks");
8475                             }
8476                             mActiveLockCount++;
8477                         }
8478                     } catch (RemoteException e) {
8479                         throw e.rethrowFromSystemServer();
8480                     }
8481                     mHeld = true;
8482                 }
8483             }
8484         }
8485 
8486         /**
8487          * Unlocks Wifi Multicast, restoring the filter of packets
8488          * not addressed specifically to this device and saving power.
8489          *
8490          * If this MulticastLock is reference-counted, each call to
8491          * {@code release} will decrement the reference count, and the
8492          * multicast packets will only stop being received when the reference
8493          * count reaches zero.  If the reference count goes below zero (that
8494          * is, if {@code release} is called a greater number of times than
8495          * {@link #acquire}), an exception is thrown.
8496          *
8497          * If this MulticastLock is not reference-counted, the first call to
8498          * {@code release} (after the radio was multicast locked using
8499          * {@link #acquire}) will unlock the multicast, and subsequent calls
8500          * will be ignored.
8501          *
8502          * Note that if any other Wifi Multicast Locks are still outstanding
8503          * this {@code release} call will not have an immediate effect.  Only
8504          * when all applications have released all their Multicast Locks will
8505          * the Multicast filter be turned back on.
8506          *
8507          * Also note that when an app exits or crashes all of its Multicast
8508          * Locks will be automatically released.
8509          */
release()8510         public void release() {
8511             synchronized (mBinder) {
8512                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
8513                     try {
8514                         mService.releaseMulticastLock(mBinder, mTag);
8515                         synchronized (WifiManager.this) {
8516                             mActiveLockCount--;
8517                         }
8518                     } catch (RemoteException e) {
8519                         throw e.rethrowFromSystemServer();
8520                     }
8521                     mHeld = false;
8522                 }
8523                 if (mRefCount < 0) {
8524                     throw new RuntimeException("MulticastLock under-locked "
8525                             + mTag);
8526                 }
8527             }
8528         }
8529 
8530         /**
8531          * Controls whether this is a reference-counted or non-reference-
8532          * counted MulticastLock.
8533          *
8534          * Reference-counted MulticastLocks keep track of the number of calls
8535          * to {@link #acquire} and {@link #release}, and only stop the
8536          * reception of multicast packets when every call to {@link #acquire}
8537          * has been balanced with a call to {@link #release}.  Non-reference-
8538          * counted MulticastLocks allow the reception of multicast packets
8539          * whenever {@link #acquire} is called and stop accepting multicast
8540          * packets whenever {@link #release} is called.
8541          *
8542          * @param refCounted true if this MulticastLock should keep a reference
8543          * count
8544          */
setReferenceCounted(boolean refCounted)8545         public void setReferenceCounted(boolean refCounted) {
8546             mRefCounted = refCounted;
8547         }
8548 
8549         /**
8550          * Checks whether this MulticastLock is currently held.
8551          *
8552          * @return true if this MulticastLock is held, false otherwise
8553          */
isHeld()8554         public boolean isHeld() {
8555             synchronized (mBinder) {
8556                 return mHeld;
8557             }
8558         }
8559 
toString()8560         public String toString() {
8561             String s1, s2, s3;
8562             synchronized (mBinder) {
8563                 s1 = Integer.toHexString(System.identityHashCode(this));
8564                 s2 = mHeld ? "held; " : "";
8565                 if (mRefCounted) {
8566                     s3 = "refcounted: refcount = " + mRefCount;
8567                 } else {
8568                     s3 = "not refcounted";
8569                 }
8570                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
8571             }
8572         }
8573 
8574         @Override
finalize()8575         protected void finalize() throws Throwable {
8576             super.finalize();
8577             setReferenceCounted(false);
8578             release();
8579         }
8580     }
8581 
8582     /**
8583      * Check multicast filter status.
8584      *
8585      * @return true if multicast packets are allowed.
8586      *
8587      * @hide pending API council approval
8588      */
isMulticastEnabled()8589     public boolean isMulticastEnabled() {
8590         try {
8591             return mService.isMulticastEnabled();
8592         } catch (RemoteException e) {
8593             throw e.rethrowFromSystemServer();
8594         }
8595     }
8596 
8597     /**
8598      * Initialize the multicast filtering to 'on'
8599      * @hide no intent to publish
8600      */
8601     @UnsupportedAppUsage
initializeMulticastFiltering()8602     public boolean initializeMulticastFiltering() {
8603         try {
8604             mService.initializeMulticastFiltering();
8605             return true;
8606         } catch (RemoteException e) {
8607             throw e.rethrowFromSystemServer();
8608         }
8609     }
8610 
8611     /**
8612      * Set Wi-Fi verbose logging level from developer settings.
8613      *
8614      * @param enable true to enable verbose logging, false to disable.
8615      *
8616      * @hide
8617      */
8618     @SystemApi
8619     @RequiresPermission(anyOf = {
8620             android.Manifest.permission.NETWORK_SETTINGS,
8621             android.Manifest.permission.DUMP
8622     })
setVerboseLoggingEnabled(boolean enable)8623     public void setVerboseLoggingEnabled(boolean enable) {
8624         enableVerboseLogging(enable ? VERBOSE_LOGGING_LEVEL_ENABLED
8625                 : VERBOSE_LOGGING_LEVEL_DISABLED);
8626     }
8627 
8628     /**
8629      * Set Wi-Fi verbose logging level from developer settings.
8630      *
8631      * @param verbose the verbose logging mode which could be
8632      * {@link #VERBOSE_LOGGING_LEVEL_DISABLED}, {@link #VERBOSE_LOGGING_LEVEL_ENABLED}, or
8633      * {@link #VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY}.
8634      *
8635      * @hide
8636      */
8637     @SystemApi
8638     @RequiresPermission(anyOf = {
8639             android.Manifest.permission.NETWORK_SETTINGS,
8640             android.Manifest.permission.DUMP
8641     })
setVerboseLoggingLevel(@erboseLoggingLevel int verbose)8642     public void setVerboseLoggingLevel(@VerboseLoggingLevel int verbose) {
8643         enableVerboseLogging(verbose);
8644     }
8645 
8646     /** @hide */
8647     @UnsupportedAppUsage(
8648             maxTargetSdk = Build.VERSION_CODES.Q,
8649             publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead."
8650     )
8651     @RequiresPermission(anyOf = {
8652             android.Manifest.permission.NETWORK_SETTINGS,
8653             android.Manifest.permission.DUMP
8654     })
enableVerboseLogging(@erboseLoggingLevel int verbose)8655     public void enableVerboseLogging(@VerboseLoggingLevel int verbose) {
8656         try {
8657             mService.enableVerboseLogging(verbose);
8658             mVerboseLoggingEnabled =
8659                     verbose == VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY
8660                             || verbose == VERBOSE_LOGGING_LEVEL_ENABLED;
8661         } catch (RemoteException e) {
8662             throw e.rethrowFromSystemServer();
8663         }
8664     }
8665 
8666     /**
8667      * Get the persisted Wi-Fi verbose logging level, set by
8668      * {@link #setVerboseLoggingEnabled(boolean)} or {@link #setVerboseLoggingLevel(int)}.
8669      * No permissions are required to call this method.
8670      *
8671      * @return true to indicate that verbose logging is enabled, false to indicate that verbose
8672      * logging is disabled.
8673      *
8674      * @hide
8675      */
8676     @SystemApi
isVerboseLoggingEnabled()8677     public boolean isVerboseLoggingEnabled() {
8678         int verboseLoggingLevel = getVerboseLoggingLevel();
8679         return verboseLoggingLevel == VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY
8680                 || verboseLoggingLevel == VERBOSE_LOGGING_LEVEL_ENABLED;
8681     }
8682 
8683     /**
8684      * Get the persisted Wi-Fi verbose logging level, set by
8685      * {@link #setVerboseLoggingEnabled(boolean)} or {@link #setVerboseLoggingLevel(int)}.
8686      * No permissions are required to call this method.
8687      *
8688      * @return one of {@link #VERBOSE_LOGGING_LEVEL_DISABLED},
8689      *         {@link #VERBOSE_LOGGING_LEVEL_ENABLED},
8690      *         or {@link #VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY}.
8691      *
8692      * @hide
8693      */
8694     @SystemApi
getVerboseLoggingLevel()8695     public @VerboseLoggingLevel int getVerboseLoggingLevel() {
8696         try {
8697             return mService.getVerboseLoggingLevel();
8698         } catch (RemoteException e) {
8699             throw e.rethrowFromSystemServer();
8700         }
8701     }
8702 
8703     /**
8704      * Removes all saved Wi-Fi networks, Passpoint configurations, ephemeral networks, Network
8705      * Requests, and Network Suggestions.
8706      *
8707      * @hide
8708      */
8709     @SystemApi
8710     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
factoryReset()8711     public void factoryReset() {
8712         try {
8713             mService.factoryReset(mContext.getOpPackageName());
8714         } catch (RemoteException e) {
8715             throw e.rethrowFromSystemServer();
8716         }
8717     }
8718 
8719     /**
8720      * Get {@link Network} object of current wifi network, or null if not connected.
8721      * @hide
8722      */
8723     @Nullable
8724     @SystemApi
8725     @RequiresPermission(anyOf = {
8726             android.Manifest.permission.NETWORK_SETTINGS,
8727             android.Manifest.permission.NETWORK_SETUP_WIZARD
8728     })
getCurrentNetwork()8729     public Network getCurrentNetwork() {
8730         try {
8731             return mService.getCurrentNetwork();
8732         } catch (RemoteException e) {
8733             throw e.rethrowFromSystemServer();
8734         }
8735     }
8736 
8737     /**
8738      * Deprecated
8739      * returns false
8740      * @hide
8741      * @deprecated
8742      */
setEnableAutoJoinWhenAssociated(boolean enabled)8743     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
8744         return false;
8745     }
8746 
8747     /**
8748      * Deprecated
8749      * returns false
8750      * @hide
8751      * @deprecated
8752      */
getEnableAutoJoinWhenAssociated()8753     public boolean getEnableAutoJoinWhenAssociated() {
8754         return false;
8755     }
8756 
8757     /**
8758      * Returns a byte stream representing the data that needs to be backed up to save the
8759      * current Wifi state.
8760      * This Wifi state can be restored by calling {@link #restoreWifiBackupData(byte[])}.
8761      * @hide
8762      */
8763     @SystemApi
8764     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
8765     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
8766     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
retrieveWifiBackupData(@onNull @allbackExecutor Executor executor, @NonNull Consumer<byte[]> resultsCallback)8767     public void retrieveWifiBackupData(@NonNull @CallbackExecutor Executor executor,
8768             @NonNull Consumer<byte[]> resultsCallback) {
8769         if (!SdkLevel.isAtLeastV()) {
8770             throw new UnsupportedOperationException();
8771         }
8772 
8773         Objects.requireNonNull(executor, "executor cannot be null");
8774         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
8775         try {
8776             mService.retrieveWifiBackupData(
8777                     new IByteArrayListener.Stub() {
8778                         @Override
8779                         public void onResult(byte[] value) {
8780                             Binder.clearCallingIdentity();
8781                             executor.execute(() -> {
8782                                 resultsCallback.accept(value);
8783                             });
8784                         }
8785                     });
8786         } catch (RemoteException e) {
8787             throw e.rethrowFromSystemServer();
8788         }
8789     }
8790 
8791     /**
8792      * Restore state from the backed up data.
8793      * @param data byte stream in the same format produced by {@link #retrieveWifiBackupData()}
8794      * @hide
8795      */
8796     @SystemApi
8797     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
8798     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
8799     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
restoreWifiBackupData(@onNull byte[] data)8800     public void restoreWifiBackupData(@NonNull byte[] data) {
8801         if (!SdkLevel.isAtLeastV()) {
8802             throw new UnsupportedOperationException();
8803         }
8804         try {
8805             mService.restoreWifiBackupData(data);
8806         } catch (RemoteException e) {
8807             throw e.rethrowFromSystemServer();
8808         }
8809     }
8810 
8811     /**
8812      * Returns a byte stream representing the data that needs to be backed up to save the
8813      * current Wifi state.
8814      * This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}.
8815      * @hide
8816      */
8817     @NonNull
8818     @SystemApi
8819     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveBackupData()8820     public byte[] retrieveBackupData() {
8821         try {
8822             return mService.retrieveBackupData();
8823         } catch (RemoteException e) {
8824             throw e.rethrowFromSystemServer();
8825         }
8826     }
8827 
8828     /**
8829      * Restore state from the backed up data.
8830      * @param data byte stream in the same format produced by {@link #retrieveBackupData()}
8831      * @hide
8832      */
8833     @SystemApi
8834     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreBackupData(@onNull byte[] data)8835     public void restoreBackupData(@NonNull byte[] data) {
8836         try {
8837             mService.restoreBackupData(data);
8838         } catch (RemoteException e) {
8839             throw e.rethrowFromSystemServer();
8840         }
8841     }
8842 
8843     /**
8844      * Returns a byte stream representing the data that needs to be backed up to save the
8845      * current soft ap config data.
8846      *
8847      * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
8848      * @hide
8849      */
8850     @NonNull
8851     @SystemApi
8852     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveSoftApBackupData()8853     public byte[] retrieveSoftApBackupData() {
8854         try {
8855             return mService.retrieveSoftApBackupData();
8856         } catch (RemoteException e) {
8857             throw e.rethrowFromSystemServer();
8858         }
8859     }
8860 
8861     /**
8862      * Returns soft ap config from the backed up data or null if data is invalid.
8863      * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
8864      *
8865      * @hide
8866      */
8867     @Nullable
8868     @SystemApi
8869     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSoftApBackupData(@onNull byte[] data)8870     public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
8871         try {
8872             return mService.restoreSoftApBackupData(data);
8873         } catch (RemoteException e) {
8874             throw e.rethrowFromSystemServer();
8875         }
8876     }
8877 
8878     /**
8879      * Restore state from the older version of back up data.
8880      * The old backup data was essentially a backup of wpa_supplicant.conf
8881      * and ipconfig.txt file.
8882      * @param supplicantData bytes representing wpa_supplicant.conf
8883      * @param ipConfigData bytes representing ipconfig.txt
8884      * @hide
8885      */
8886     @SystemApi
8887     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSupplicantBackupData( @onNull byte[] supplicantData, @NonNull byte[] ipConfigData)8888     public void restoreSupplicantBackupData(
8889             @NonNull byte[] supplicantData, @NonNull byte[] ipConfigData) {
8890         try {
8891             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
8892         } catch (RemoteException e) {
8893             throw e.rethrowFromSystemServer();
8894         }
8895     }
8896 
8897     /**
8898      * Start subscription provisioning flow
8899      *
8900      * @param provider {@link OsuProvider} to provision with
8901      * @param executor the Executor on which to run the callback.
8902      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
8903      * @hide
8904      */
8905     @SystemApi
8906     @RequiresPermission(anyOf = {
8907             android.Manifest.permission.NETWORK_SETTINGS,
8908             android.Manifest.permission.NETWORK_SETUP_WIZARD
8909     })
startSubscriptionProvisioning(@onNull OsuProvider provider, @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback)8910     public void startSubscriptionProvisioning(@NonNull OsuProvider provider,
8911             @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback) {
8912         // Verify arguments
8913         if (executor == null) {
8914             throw new IllegalArgumentException("executor must not be null");
8915         }
8916         if (callback == null) {
8917             throw new IllegalArgumentException("callback must not be null");
8918         }
8919         try {
8920             mService.startSubscriptionProvisioning(provider,
8921                     new ProvisioningCallbackProxy(executor, callback));
8922         } catch (RemoteException e) {
8923             throw e.rethrowFromSystemServer();
8924         }
8925     }
8926 
8927     /**
8928      * Helper class to support OSU Provisioning callbacks
8929      */
8930     private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
8931         private final Executor mExecutor;
8932         private final ProvisioningCallback mCallback;
8933 
ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback)8934         ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback) {
8935             mExecutor = executor;
8936             mCallback = callback;
8937         }
8938 
8939         @Override
onProvisioningStatus(int status)8940         public void onProvisioningStatus(int status) {
8941             mExecutor.execute(() -> mCallback.onProvisioningStatus(status));
8942         }
8943 
8944         @Override
onProvisioningFailure(int status)8945         public void onProvisioningFailure(int status) {
8946             mExecutor.execute(() -> mCallback.onProvisioningFailure(status));
8947         }
8948 
8949         @Override
onProvisioningComplete()8950         public void onProvisioningComplete() {
8951             mExecutor.execute(() -> mCallback.onProvisioningComplete());
8952         }
8953     }
8954 
8955     /**
8956      * Interface for Traffic state callback. Should be extended by applications and set when
8957      * calling {@link #registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}.
8958      * @hide
8959      */
8960     @SystemApi
8961     public interface TrafficStateCallback {
8962         /** @hide */
8963         @Retention(RetentionPolicy.SOURCE)
8964         @IntDef(prefix = {"DATA_ACTIVITY_"}, value = {
8965                 DATA_ACTIVITY_NONE,
8966                 DATA_ACTIVITY_IN,
8967                 DATA_ACTIVITY_OUT,
8968                 DATA_ACTIVITY_INOUT})
8969         @interface DataActivity {}
8970 
8971         // Lowest bit indicates data reception and the second lowest bit indicates data transmitted
8972         /** No data in or out */
8973         int DATA_ACTIVITY_NONE         = 0x00;
8974         /** Data in, no data out */
8975         int DATA_ACTIVITY_IN           = 0x01;
8976         /** Data out, no data in */
8977         int DATA_ACTIVITY_OUT          = 0x02;
8978         /** Data in and out */
8979         int DATA_ACTIVITY_INOUT        = 0x03;
8980 
8981         /**
8982          * Callback invoked to inform clients about the current traffic state.
8983          *
8984          * @param state One of the values: {@link #DATA_ACTIVITY_NONE}, {@link #DATA_ACTIVITY_IN},
8985          * {@link #DATA_ACTIVITY_OUT} & {@link #DATA_ACTIVITY_INOUT}.
8986          */
onStateChanged(@ataActivity int state)8987         void onStateChanged(@DataActivity int state);
8988     }
8989 
8990     /**
8991      * Callback proxy for TrafficStateCallback objects.
8992      *
8993      * @hide
8994      */
8995     private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub {
8996         private final Executor mExecutor;
8997         private final TrafficStateCallback mCallback;
8998 
TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback)8999         TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback) {
9000             mExecutor = executor;
9001             mCallback = callback;
9002         }
9003 
9004         @Override
onStateChanged(int state)9005         public void onStateChanged(int state) {
9006             if (mVerboseLoggingEnabled) {
9007                 Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state);
9008             }
9009             Binder.clearCallingIdentity();
9010             mExecutor.execute(() -> {
9011                 mCallback.onStateChanged(state);
9012             });
9013         }
9014     }
9015 
9016     /**
9017      * Registers a callback for monitoring traffic state. See {@link TrafficStateCallback}. These
9018      * callbacks will be invoked periodically by platform to inform clients about the current
9019      * traffic state. Caller can unregister a previously registered callback using
9020      * {@link #unregisterTrafficStateCallback(TrafficStateCallback)}
9021      * <p>
9022      * Applications should have the
9023      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
9024      * without the permission will trigger a {@link java.lang.SecurityException}.
9025      * <p>
9026      *
9027      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
9028      *                 object.
9029      * @param callback Callback for traffic state events
9030      * @hide
9031      */
9032     @SystemApi
9033     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerTrafficStateCallback(@onNull @allbackExecutor Executor executor, @NonNull TrafficStateCallback callback)9034     public void registerTrafficStateCallback(@NonNull @CallbackExecutor Executor executor,
9035                                              @NonNull TrafficStateCallback callback) {
9036         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
9037         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9038         Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", executor=" + executor);
9039 
9040         try {
9041             synchronized (sTrafficStateCallbackMap) {
9042                 ITrafficStateCallback.Stub binderCallback = new TrafficStateCallbackProxy(executor,
9043                         callback);
9044                 sTrafficStateCallbackMap.put(System.identityHashCode(callback), binderCallback);
9045                 mService.registerTrafficStateCallback(binderCallback);
9046             }
9047         } catch (RemoteException e) {
9048             throw e.rethrowFromSystemServer();
9049         }
9050     }
9051 
9052     /**
9053      * Allow callers to unregister a previously registered callback. After calling this method,
9054      * applications will no longer receive traffic state notifications.
9055      *
9056      * @param callback Callback to unregister for traffic state events
9057      * @hide
9058      */
9059     @SystemApi
9060     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterTrafficStateCallback(@onNull TrafficStateCallback callback)9061     public void unregisterTrafficStateCallback(@NonNull TrafficStateCallback callback) {
9062         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9063         Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
9064 
9065         try {
9066             synchronized (sTrafficStateCallbackMap) {
9067                 int callbackIdentifier = System.identityHashCode(callback);
9068                 if (!sTrafficStateCallbackMap.contains(callbackIdentifier)) {
9069                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
9070                     return;
9071                 }
9072                 mService.unregisterTrafficStateCallback(
9073                         sTrafficStateCallbackMap.get(callbackIdentifier));
9074                 sTrafficStateCallbackMap.remove(callbackIdentifier);
9075             }
9076         } catch (RemoteException e) {
9077             throw e.rethrowFromSystemServer();
9078         }
9079     }
9080 
9081     /**
9082      * Helper method to update the local verbose logging flag based on the verbose logging
9083      * level from wifi service.
9084      */
updateVerboseLoggingEnabledFromService()9085     private void updateVerboseLoggingEnabledFromService() {
9086         mVerboseLoggingEnabled = isVerboseLoggingEnabled();
9087     }
9088 
9089     /**
9090      * @return true if this device supports WPA3-Personal SAE
9091      */
isWpa3SaeSupported()9092     public boolean isWpa3SaeSupported() {
9093         return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
9094     }
9095 
9096     /**
9097      * @return true if this device supports WPA3-Enterprise Suite-B-192
9098      */
isWpa3SuiteBSupported()9099     public boolean isWpa3SuiteBSupported() {
9100         return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
9101     }
9102 
9103     /**
9104      * @return true if this device supports Wi-Fi Enhanced Open (OWE)
9105      */
isEnhancedOpenSupported()9106     public boolean isEnhancedOpenSupported() {
9107         return isFeatureSupported(WIFI_FEATURE_OWE);
9108     }
9109 
9110     /**
9111      * Wi-Fi Easy Connect (DPP) introduces standardized mechanisms to simplify the provisioning and
9112      * configuration of Wi-Fi devices.
9113      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
9114      * search for "Easy Connect" or "Device Provisioning Protocol specification".
9115      *
9116      * @return true if this device supports Wi-Fi Easy-connect (Device Provisioning Protocol)
9117      */
isEasyConnectSupported()9118     public boolean isEasyConnectSupported() {
9119         return isFeatureSupported(WIFI_FEATURE_DPP);
9120     }
9121 
9122     /**
9123      * @return true if this device supports Wi-Fi Easy Connect (DPP) Enrollee Responder mode.
9124      */
isEasyConnectEnrolleeResponderModeSupported()9125     public boolean isEasyConnectEnrolleeResponderModeSupported() {
9126         return isFeatureSupported(WIFI_FEATURE_DPP_ENROLLEE_RESPONDER);
9127     }
9128 
9129     /**
9130      * @return true if this device supports WAPI.
9131      */
isWapiSupported()9132     public boolean isWapiSupported() {
9133         return isFeatureSupported(WIFI_FEATURE_WAPI);
9134     }
9135 
9136     /**
9137      * @return true if this device supports WPA3 SAE Public Key.
9138      */
isWpa3SaePublicKeySupported()9139     public boolean isWpa3SaePublicKeySupported() {
9140         // This feature is not fully implemented in the framework yet.
9141         // After the feature complete, it returns whether WIFI_FEATURE_SAE_PK
9142         // is supported or not directly.
9143         return false;
9144     }
9145 
9146     /**
9147      * @return true if this device supports Wi-Fi Passpoint Terms and Conditions feature.
9148      */
isPasspointTermsAndConditionsSupported()9149     public boolean isPasspointTermsAndConditionsSupported() {
9150         return isFeatureSupported(WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS);
9151     }
9152 
9153     /**
9154      * @return true if this device supports WPA3 SAE Hash-to-Element.
9155      */
isWpa3SaeH2eSupported()9156     public boolean isWpa3SaeH2eSupported() {
9157         return isFeatureSupported(WIFI_FEATURE_SAE_H2E);
9158     }
9159 
9160     /**
9161      * @return true if this device supports Wi-Fi Display R2.
9162      */
isWifiDisplayR2Supported()9163     public boolean isWifiDisplayR2Supported() {
9164         return isFeatureSupported(WIFI_FEATURE_WFD_R2);
9165     }
9166 
9167     /**
9168      * @return true if this device supports RFC 7542 decorated identity.
9169      */
isDecoratedIdentitySupported()9170     public boolean isDecoratedIdentitySupported() {
9171         return isFeatureSupported(WIFI_FEATURE_DECORATED_IDENTITY);
9172     }
9173 
9174     /**
9175      * @return true if this device supports Trust On First Use (TOFU).
9176      */
isTrustOnFirstUseSupported()9177     public boolean isTrustOnFirstUseSupported() {
9178         return isFeatureSupported(WIFI_FEATURE_TRUST_ON_FIRST_USE);
9179     }
9180 
9181     /**
9182      * Wi-Fi Easy Connect DPP AKM enables provisioning and configuration of Wi-Fi devices without
9183      * the need of using the device PSK passphrase.
9184      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
9185      * search for "Easy Connect" or "Device Provisioning Protocol specification".
9186      *
9187      * @return true if this device supports Wi-Fi Easy-connect DPP (Device Provisioning Protocol)
9188      * AKM, false otherwise.
9189      */
isEasyConnectDppAkmSupported()9190     public boolean isEasyConnectDppAkmSupported() {
9191         return isFeatureSupported(WIFI_FEATURE_DPP_AKM);
9192     }
9193 
9194     /**
9195      * Indicate that whether or not settings required TLS minimum version is supported.
9196      *
9197      * If the device doesn't support this capability, the minimum accepted TLS version is 1.0.
9198      *
9199      * @return true if this device supports setting TLS minimum version.
9200      */
isTlsMinimumVersionSupported()9201     public boolean isTlsMinimumVersionSupported() {
9202         return isFeatureSupported(WIFI_FEATURE_SET_TLS_MINIMUM_VERSION);
9203     }
9204 
9205     /**
9206      * Indicate that whether or not TLS v1.3 is supported.
9207      *
9208      * If requested minimum is not supported, it will default to the maximum supported version.
9209      *
9210      * @return true if this device supports TLS v1.3.
9211      */
isTlsV13Supported()9212     public boolean isTlsV13Supported() {
9213         return isFeatureSupported(WIFI_FEATURE_TLS_V1_3);
9214     }
9215 
9216     /**
9217      * @return true if this device supports Dual Band Simultaneous (DBS) operation.
9218      */
isDualBandSimultaneousSupported()9219     public boolean isDualBandSimultaneousSupported() {
9220         return isFeatureSupported(WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS);
9221     }
9222 
9223     /**
9224      * @return true if this device supports TID-To-Link Mapping Negotiation.
9225      */
isTidToLinkMappingNegotiationSupported()9226     public boolean isTidToLinkMappingNegotiationSupported() {
9227         return isFeatureSupported(WIFI_FEATURE_T2LM_NEGOTIATION);
9228     }
9229 
9230 
9231     /**
9232     * @return true if this device supports connections to Wi-Fi WEP networks.
9233     */
9234     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isWepSupported()9235     public boolean isWepSupported() {
9236         return isFeatureSupported(WIFI_FEATURE_WEP);
9237     }
9238 
9239     /**
9240     * @return true if this device supports connections to Wi-Fi WPA-Personal networks.
9241     *
9242     * Note that this is the older and less secure WPA-Personal protocol, not WPA2-Personal
9243     * or later protocols.
9244     */
9245     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isWpaPersonalSupported()9246     public boolean isWpaPersonalSupported() {
9247         return isFeatureSupported(WIFI_FEATURE_WPA_PERSONAL);
9248     }
9249 
9250     /**
9251      * Gets the factory Wi-Fi MAC addresses.
9252      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
9253      * if failed.
9254      * @hide
9255      */
9256     @NonNull
9257     @SystemApi
9258     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getFactoryMacAddresses()9259     public String[] getFactoryMacAddresses() {
9260         try {
9261             return mService.getFactoryMacAddresses();
9262         } catch (RemoteException e) {
9263             throw e.rethrowFromSystemServer();
9264         }
9265     }
9266 
9267     /** @hide */
9268     @Retention(RetentionPolicy.SOURCE)
9269     @IntDef(prefix = {"DEVICE_MOBILITY_STATE_"}, value = {
9270             DEVICE_MOBILITY_STATE_UNKNOWN,
9271             DEVICE_MOBILITY_STATE_HIGH_MVMT,
9272             DEVICE_MOBILITY_STATE_LOW_MVMT,
9273             DEVICE_MOBILITY_STATE_STATIONARY})
9274     public @interface DeviceMobilityState {}
9275 
9276     /**
9277      * Unknown device mobility state
9278      *
9279      * @see #setDeviceMobilityState(int)
9280      *
9281      * @hide
9282      */
9283     @SystemApi
9284     public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0;
9285 
9286     /**
9287      * High movement device mobility state.
9288      * e.g. on a bike, in a motor vehicle
9289      *
9290      * @see #setDeviceMobilityState(int)
9291      *
9292      * @hide
9293      */
9294     @SystemApi
9295     public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1;
9296 
9297     /**
9298      * Low movement device mobility state.
9299      * e.g. walking, running
9300      *
9301      * @see #setDeviceMobilityState(int)
9302      *
9303      * @hide
9304      */
9305     @SystemApi
9306     public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2;
9307 
9308     /**
9309      * Stationary device mobility state
9310      *
9311      * @see #setDeviceMobilityState(int)
9312      *
9313      * @hide
9314      */
9315     @SystemApi
9316     public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3;
9317 
9318     /**
9319      * Updates the device mobility state. Wifi uses this information to adjust the interval between
9320      * Wifi scans in order to balance power consumption with scan accuracy.
9321      * The default mobility state when the device boots is {@link #DEVICE_MOBILITY_STATE_UNKNOWN}.
9322      * This API should be called whenever there is a change in the mobility state.
9323      * @param state the updated device mobility state
9324      * @hide
9325      */
9326     @SystemApi
9327     @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
setDeviceMobilityState(@eviceMobilityState int state)9328     public void setDeviceMobilityState(@DeviceMobilityState int state) {
9329         try {
9330             mService.setDeviceMobilityState(state);
9331         } catch (RemoteException e) {
9332             throw e.rethrowFromSystemServer();
9333         }
9334     }
9335 
9336     /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
9337 
9338     /**
9339      * Easy Connect Network role: Station.
9340      *
9341      * @hide
9342      */
9343     @SystemApi
9344     public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
9345 
9346     /**
9347      * Easy Connect Network role: Access Point.
9348      *
9349      * @hide
9350      */
9351     @SystemApi
9352     public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
9353 
9354     /** @hide */
9355     @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
9356             EASY_CONNECT_NETWORK_ROLE_STA,
9357             EASY_CONNECT_NETWORK_ROLE_AP,
9358     })
9359     @Retention(RetentionPolicy.SOURCE)
9360     public @interface EasyConnectNetworkRole {
9361     }
9362 
9363     /** Easy Connect Device information maximum allowed length */
9364     private static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40;
9365 
9366     /**
9367      * Easy Connect Cryptography Curve name: prime256v1
9368      *
9369      * @hide
9370      */
9371     @SystemApi
9372     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0;
9373 
9374     /**
9375      * Easy Connect Cryptography Curve name: secp384r1
9376      *
9377      * @hide
9378      */
9379     @SystemApi
9380     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1;
9381 
9382     /**
9383      * Easy Connect Cryptography Curve name: secp521r1
9384      *
9385      * @hide
9386      */
9387     @SystemApi
9388     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2;
9389 
9390 
9391     /**
9392      * Easy Connect Cryptography Curve name: brainpoolP256r1
9393      *
9394      * @hide
9395      */
9396     @SystemApi
9397     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3;
9398 
9399 
9400     /**
9401      * Easy Connect Cryptography Curve name: brainpoolP384r1
9402      *
9403      * @hide
9404      */
9405     @SystemApi
9406     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4;
9407 
9408 
9409     /**
9410      * Easy Connect Cryptography Curve name: brainpoolP512r1
9411      *
9412      * @hide
9413      */
9414     @SystemApi
9415     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5;
9416 
9417     /** @hide */
9418     @IntDef(prefix = {"EASY_CONNECT_CRYPTOGRAPHY_CURVE_"}, value = {
9419             EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1,
9420             EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1,
9421             EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1,
9422             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1,
9423             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1,
9424             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1,
9425     })
9426     @Retention(RetentionPolicy.SOURCE)
9427     public @interface EasyConnectCryptographyCurve {
9428     }
9429 
9430     /**
9431      * Verbose logging mode: DISABLED.
9432      * @hide
9433      */
9434     @SystemApi
9435     public static final int VERBOSE_LOGGING_LEVEL_DISABLED = 0;
9436 
9437     /**
9438      * Verbose logging mode: ENABLED.
9439      * @hide
9440      */
9441     @SystemApi
9442     public static final int VERBOSE_LOGGING_LEVEL_ENABLED = 1;
9443 
9444     /**
9445      * Verbose logging mode: ENABLED_SHOW_KEY. This mode causes the Wi-Fi password and encryption
9446      * keys to be output to the logcat. This is security sensitive information useful for debugging.
9447      * This configuration is enabled for 30 seconds and then falls back to the regular verbose mode
9448      * (i.e. to {@link VERBOSE_LOGGING_LEVEL_ENABLED}). Show key mode is not persistent, i.e.
9449      * rebooting the device would fallback to the regular verbose mode.
9450      *
9451      * @hide
9452      */
9453     @SystemApi public static final int VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY = 2;
9454 
9455     /**
9456      * Verbose logging mode: only enable for Wi-Fi Aware feature.
9457      *
9458      * @hide
9459      */
9460     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
9461     @SystemApi
9462     public static final int VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY = 3;
9463 
9464     /** @hide */
9465     @IntDef(prefix = {"VERBOSE_LOGGING_LEVEL_"}, value = {
9466             VERBOSE_LOGGING_LEVEL_DISABLED,
9467             VERBOSE_LOGGING_LEVEL_ENABLED,
9468             VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY,
9469             VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY,
9470     })
9471     @Retention(RetentionPolicy.SOURCE)
9472     public @interface VerboseLoggingLevel {
9473     }
9474 
9475     /**
9476      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
9477      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
9478      * the specified network using the Easy Connect protocol on an encrypted link.
9479      *
9480      * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
9481      * @param selectedNetworkId   Selected network ID to be sent to the peer
9482      * @param enrolleeNetworkRole The network role of the enrollee
9483      * @param callback            Callback for status updates
9484      * @param executor            The Executor on which to run the callback.
9485      * @hide
9486      */
9487     @SystemApi
9488     @RequiresPermission(anyOf = {
9489             android.Manifest.permission.NETWORK_SETTINGS,
9490             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsConfiguratorInitiator(@onNull String enrolleeUri, int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)9491     public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
9492             int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
9493             @NonNull @CallbackExecutor Executor executor,
9494             @NonNull EasyConnectStatusCallback callback) {
9495         Binder binder = new Binder();
9496         try {
9497             mService.startDppAsConfiguratorInitiator(binder, mContext.getOpPackageName(),
9498                     enrolleeUri, selectedNetworkId, enrolleeNetworkRole,
9499                     new EasyConnectCallbackProxy(executor, callback));
9500         } catch (RemoteException e) {
9501             throw e.rethrowFromSystemServer();
9502         }
9503     }
9504 
9505     /**
9506      * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
9507      * Connect bootstrapping with a peer, and receive the SSID and password from the peer
9508      * configurator.
9509      *
9510      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
9511      * @param callback        Callback for status updates
9512      * @param executor        The Executor on which to run the callback.
9513      * @hide
9514      */
9515     @SystemApi
9516     @RequiresPermission(anyOf = {
9517             android.Manifest.permission.NETWORK_SETTINGS,
9518             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsEnrolleeInitiator(@onNull String configuratorUri, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)9519     public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
9520             @NonNull @CallbackExecutor Executor executor,
9521             @NonNull EasyConnectStatusCallback callback) {
9522         Binder binder = new Binder();
9523         try {
9524             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
9525                     new EasyConnectCallbackProxy(executor, callback));
9526         } catch (RemoteException e) {
9527             throw e.rethrowFromSystemServer();
9528         }
9529     }
9530 
9531     /**
9532      * Start Easy Connect (DPP) in Enrollee-Responder role.
9533      * The device will:
9534      * 1. Generate a DPP bootstrap URI and return it using the
9535      * {@link EasyConnectStatusCallback#onBootstrapUriGenerated(Uri)} method.
9536      * 2. Start DPP as a Responder, waiting for an Initiator device to start the DPP
9537      * authentication process.
9538      * The caller should use the URI provided in step #1, for instance display it as a QR code
9539      * or communicate it in some other way to the initiator device.
9540      *
9541      * @param deviceInfo      Device specific information to add to the DPP URI. This field allows
9542      *                        the users of the configurators to identify the device.
9543      *                        Optional - if not provided or in case of an empty string,
9544      *                        Info field (I:) will be skipped in the generated DPP URI.
9545      *                        Allowed Range of ASCII characters in deviceInfo - %x20-7E.
9546      *                        semicolon and space are not allowed. Due to the limitation of maximum
9547      *                        allowed characters in QR code, framework adds a limit to maximum
9548      *                        characters in deviceInfo. Users must call
9549      *                        {@link WifiManager#getEasyConnectMaxAllowedResponderDeviceInfoLength()
9550      *                        } method to know max allowed length. Violation of these rules will
9551      *                        result in an exception.
9552      * @param curve           Elliptic curve cryptography used to generate DPP
9553      *                        public/private key pair. If application is not interested in a
9554      *                        specific curve, use specification mandated NIST P-256 elliptic curve,
9555      *                        {@link WifiManager#EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1}.
9556      * @param callback        Callback for status updates
9557      * @param executor        The Executor on which to run the callback.
9558      * @hide
9559      */
9560     @SystemApi
9561     @RequiresPermission(anyOf = {
9562             android.Manifest.permission.NETWORK_SETTINGS,
9563             android.Manifest.permission.NETWORK_SETUP_WIZARD})
9564     @RequiresApi(Build.VERSION_CODES.S)
startEasyConnectAsEnrolleeResponder(@ullable String deviceInfo, @EasyConnectCryptographyCurve int curve, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)9565     public void startEasyConnectAsEnrolleeResponder(@Nullable String deviceInfo,
9566             @EasyConnectCryptographyCurve int curve,
9567             @NonNull @CallbackExecutor Executor executor,
9568             @NonNull EasyConnectStatusCallback callback) {
9569         Binder binder = new Binder();
9570         try {
9571             mService.startDppAsEnrolleeResponder(binder, deviceInfo, curve,
9572                     new EasyConnectCallbackProxy(executor, callback));
9573         } catch (RemoteException e) {
9574             throw e.rethrowFromSystemServer();
9575         }
9576     }
9577 
9578     /**
9579      * Maximum allowed length of Device specific information that can be added to the URI of
9580      * Easy Connect responder device.
9581      * @see #startEasyConnectAsEnrolleeResponder(String, int, Executor, EasyConnectStatusCallback)}
9582      *
9583      * @hide
9584      */
9585     @SystemApi
getEasyConnectMaxAllowedResponderDeviceInfoLength()9586     public static int getEasyConnectMaxAllowedResponderDeviceInfoLength() {
9587         return EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH;
9588     }
9589 
9590     /**
9591      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
9592      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
9593      * expect any callbacks once this call is made. However, due to the asynchronous nature of
9594      * this call, a callback may be fired if it was already pending in the queue.
9595      *
9596      * @hide
9597      */
9598     @SystemApi
9599     @RequiresPermission(anyOf = {
9600             android.Manifest.permission.NETWORK_SETTINGS,
9601             android.Manifest.permission.NETWORK_SETUP_WIZARD})
stopEasyConnectSession()9602     public void stopEasyConnectSession() {
9603         try {
9604             /* Request lower layers to stop/abort and clear resources */
9605             mService.stopDppSession();
9606         } catch (RemoteException e) {
9607             throw e.rethrowFromSystemServer();
9608         }
9609     }
9610 
9611     /**
9612      * Helper class to support Easy Connect (DPP) callbacks
9613      *
9614      * @hide
9615      */
9616     private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
9617         private final Executor mExecutor;
9618         private final EasyConnectStatusCallback mEasyConnectStatusCallback;
9619 
EasyConnectCallbackProxy(Executor executor, EasyConnectStatusCallback easyConnectStatusCallback)9620         EasyConnectCallbackProxy(Executor executor,
9621                 EasyConnectStatusCallback easyConnectStatusCallback) {
9622             mExecutor = executor;
9623             mEasyConnectStatusCallback = easyConnectStatusCallback;
9624         }
9625 
9626         @Override
onSuccessConfigReceived(int newNetworkId)9627         public void onSuccessConfigReceived(int newNetworkId) {
9628             Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
9629             Binder.clearCallingIdentity();
9630             mExecutor.execute(() -> {
9631                 mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
9632             });
9633         }
9634 
9635         @Override
onSuccess(int status)9636         public void onSuccess(int status) {
9637             Log.d(TAG, "Easy Connect onSuccess callback");
9638             Binder.clearCallingIdentity();
9639             mExecutor.execute(() -> {
9640                 mEasyConnectStatusCallback.onConfiguratorSuccess(status);
9641             });
9642         }
9643 
9644         @Override
onFailure(int status, String ssid, String channelList, int[] operatingClassArray)9645         public void onFailure(int status, String ssid, String channelList,
9646                 int[] operatingClassArray) {
9647             Log.d(TAG, "Easy Connect onFailure callback");
9648             Binder.clearCallingIdentity();
9649             mExecutor.execute(() -> {
9650                 SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
9651                 mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
9652                         operatingClassArray);
9653             });
9654         }
9655 
9656         @Override
onProgress(int status)9657         public void onProgress(int status) {
9658             Log.d(TAG, "Easy Connect onProgress callback");
9659             Binder.clearCallingIdentity();
9660             mExecutor.execute(() -> {
9661                 mEasyConnectStatusCallback.onProgress(status);
9662             });
9663         }
9664 
9665         @Override
onBootstrapUriGenerated(@onNull String uri)9666         public void onBootstrapUriGenerated(@NonNull String uri) {
9667             Log.d(TAG, "Easy Connect onBootstrapUriGenerated callback");
9668             if (!SdkLevel.isAtLeastS()) {
9669                 Log.e(TAG, "Easy Connect bootstrap URI callback supported only on S+");
9670                 return;
9671             }
9672             Binder.clearCallingIdentity();
9673             mExecutor.execute(() -> {
9674                 mEasyConnectStatusCallback.onBootstrapUriGenerated(Uri.parse(uri));
9675             });
9676         }
9677     }
9678 
9679     /**
9680      * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
9681      * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor,
9682      * OnWifiUsabilityStatsListener)}.
9683      *
9684      * @hide
9685      */
9686     @SystemApi
9687     public interface OnWifiUsabilityStatsListener {
9688         /**
9689          * Called when Wi-Fi usability statistics is updated.
9690          *
9691          * @param seqNum The sequence number of statistics, used to derive the timing of updated
9692          *               Wi-Fi usability statistics, set by framework and incremented by one after
9693          *               each update.
9694          * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
9695          *                           network stays the same or not relative to the last update of
9696          *                           Wi-Fi usability stats.
9697          * @param stats The updated Wi-Fi usability statistics.
9698          */
onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, @NonNull WifiUsabilityStatsEntry stats)9699         void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
9700                 @NonNull WifiUsabilityStatsEntry stats);
9701     }
9702 
9703     /**
9704      * Interface for Wi-Fi verbose logging status listener. Should be implemented by applications
9705      * and set when calling {@link WifiManager#addWifiVerboseLoggingStatusListener(Executor,
9706      * WifiVerboseLoggingStatusListener)}.
9707      *
9708      * @hide
9709      */
9710     @SystemApi
9711     public interface WifiVerboseLoggingStatusChangedListener {
9712         /**
9713          * Called when Wi-Fi verbose logging setting is updated.
9714          *
9715          * @param enabled true if verbose logging is enabled, false if verbose logging is disabled.
9716          */
onWifiVerboseLoggingStatusChanged(boolean enabled)9717         void onWifiVerboseLoggingStatusChanged(boolean enabled);
9718     }
9719 
9720     /**
9721      * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}.
9722      * Multiple listeners can be added. Callers will be invoked periodically by framework to
9723      * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
9724      * added listener using
9725      * {@link #removeOnWifiUsabilityStatsListener(OnWifiUsabilityStatsListener)}.
9726      *
9727      * @param executor The executor on which callback will be invoked.
9728      * @param listener Listener for Wifi usability statistics.
9729      *
9730      * @hide
9731      */
9732     @SystemApi
9733     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
addOnWifiUsabilityStatsListener(@onNull @allbackExecutor Executor executor, @NonNull OnWifiUsabilityStatsListener listener)9734     public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
9735             @NonNull OnWifiUsabilityStatsListener listener) {
9736         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
9737         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
9738         if (mVerboseLoggingEnabled) {
9739             Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
9740         }
9741         try {
9742             synchronized (sOnWifiUsabilityStatsListenerMap) {
9743                 IOnWifiUsabilityStatsListener.Stub binderCallback =
9744                         new IOnWifiUsabilityStatsListener.Stub() {
9745                             @Override
9746                             public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
9747                                     WifiUsabilityStatsEntry stats) {
9748                                 if (mVerboseLoggingEnabled) {
9749                                     Log.v(TAG, "OnWifiUsabilityStatsListener: "
9750                                             + "onWifiUsabilityStats: seqNum=" + seqNum);
9751                                 }
9752                                 Binder.clearCallingIdentity();
9753                                 executor.execute(() -> listener.onWifiUsabilityStats(
9754                                         seqNum, isSameBssidAndFreq, stats));
9755                             }
9756                         };
9757                 sOnWifiUsabilityStatsListenerMap.put(System.identityHashCode(listener),
9758                         binderCallback);
9759                 mService.addOnWifiUsabilityStatsListener(binderCallback);
9760             }
9761         } catch (RemoteException e) {
9762             throw e.rethrowFromSystemServer();
9763         }
9764     }
9765 
9766     /**
9767      * Allow callers to remove a previously registered listener. After calling this method,
9768      * applications will no longer receive Wi-Fi usability statistics.
9769      *
9770      * @param listener Listener to remove the Wi-Fi usability statistics.
9771      *
9772      * @hide
9773      */
9774     @SystemApi
9775     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
removeOnWifiUsabilityStatsListener(@onNull OnWifiUsabilityStatsListener listener)9776     public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) {
9777         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
9778         if (mVerboseLoggingEnabled) {
9779             Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
9780         }
9781         try {
9782             synchronized (sOnWifiUsabilityStatsListenerMap) {
9783                 int listenerIdentifier = System.identityHashCode(listener);
9784                 if (!sOnWifiUsabilityStatsListenerMap.contains(listenerIdentifier)) {
9785                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9786                     return;
9787                 }
9788                 mService.removeOnWifiUsabilityStatsListener(
9789                         sOnWifiUsabilityStatsListenerMap.get(listenerIdentifier));
9790                 sOnWifiUsabilityStatsListenerMap.remove(listenerIdentifier);
9791             }
9792         } catch (RemoteException e) {
9793             throw e.rethrowFromSystemServer();
9794         }
9795     }
9796 
9797     /**
9798      * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
9799      * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
9800      * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
9801      * is used to quantify whether Wi-Fi is usable in a future time.
9802      *
9803      * @param seqNum Sequence number of the Wi-Fi usability score.
9804      * @param score The Wi-Fi usability score, expected range: [0, 100].
9805      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
9806      *                             expected range: [0, 30].
9807      *
9808      * @hide
9809      */
9810     @SystemApi
9811     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)9812     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
9813         try {
9814             mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
9815         } catch (RemoteException e) {
9816             throw e.rethrowFromSystemServer();
9817         }
9818     }
9819 
9820     /**
9821      * Gets the list of BSSIDs which are currently disabled for Wi-Fi auto-join connections.
9822      *
9823      * @param ssids If empty, then get all currently disabled BSSIDs.
9824      *              If non-empty, then only get currently disabled BSSIDs with matching SSIDs.
9825      * @param executor The executor to execute the callback of the {@code resultListener} object.
9826      * @param resultListener callback to retrieve the blocked BSSIDs
9827      *
9828      * @hide
9829      */
9830     @SystemApi
9831     @FlaggedApi(Flags.FLAG_GET_BSSID_BLOCKLIST_API)
9832     @RequiresPermission(anyOf = {
9833             android.Manifest.permission.NETWORK_SETTINGS,
9834             android.Manifest.permission.NETWORK_SETUP_WIZARD})
getBssidBlocklist(@onNull List<WifiSsid> ssids, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<List<MacAddress>> resultListener)9835     public void getBssidBlocklist(@NonNull List<WifiSsid> ssids,
9836             @NonNull @CallbackExecutor Executor executor,
9837             @NonNull Consumer<List<MacAddress>> resultListener) {
9838         Objects.requireNonNull(ssids, "ssids cannot be null");
9839         Objects.requireNonNull(executor, "executor cannot be null");
9840         Objects.requireNonNull(resultListener, "resultsCallback cannot be null");
9841         try {
9842             mService.getBssidBlocklist(
9843                     new ParceledListSlice<>(ssids),
9844                     new IMacAddressListListener.Stub() {
9845                         @Override
9846                         public void onResult(ParceledListSlice<MacAddress> value) {
9847                             Binder.clearCallingIdentity();
9848                             executor.execute(() -> {
9849                                 resultListener.accept(value.getList());
9850                             });
9851                         }
9852                     });
9853         } catch (RemoteException e) {
9854             throw e.rethrowFromSystemServer();
9855         }
9856     }
9857 
9858     /**
9859      * Abstract class for scan results callback. Should be extended by applications and set when
9860      * calling {@link WifiManager#registerScanResultsCallback(Executor, ScanResultsCallback)}.
9861      */
9862     public abstract static class ScanResultsCallback {
9863         private final ScanResultsCallbackProxy mScanResultsCallbackProxy;
9864 
ScanResultsCallback()9865         public ScanResultsCallback() {
9866             mScanResultsCallbackProxy = new ScanResultsCallbackProxy();
9867         }
9868 
9869         /**
9870          * Called when new scan results are available.
9871          * Clients should use {@link WifiManager#getScanResults()} to get the scan results.
9872          */
onScanResultsAvailable()9873         public abstract void onScanResultsAvailable();
9874 
getProxy()9875         /*package*/ @NonNull ScanResultsCallbackProxy getProxy() {
9876             return mScanResultsCallbackProxy;
9877         }
9878 
9879         private static class ScanResultsCallbackProxy extends IScanResultsCallback.Stub {
9880             private final Object mLock = new Object();
9881             @Nullable @GuardedBy("mLock") private Executor mExecutor;
9882             @Nullable @GuardedBy("mLock") private ScanResultsCallback mCallback;
9883 
ScanResultsCallbackProxy()9884             ScanResultsCallbackProxy() {
9885                 mCallback = null;
9886                 mExecutor = null;
9887             }
9888 
initProxy(@onNull Executor executor, @NonNull ScanResultsCallback callback)9889             /*package*/ void initProxy(@NonNull Executor executor,
9890                     @NonNull ScanResultsCallback callback) {
9891                 synchronized (mLock) {
9892                     mExecutor = executor;
9893                     mCallback = callback;
9894                 }
9895             }
9896 
cleanUpProxy()9897             /*package*/ void cleanUpProxy() {
9898                 synchronized (mLock) {
9899                     mExecutor = null;
9900                     mCallback = null;
9901                 }
9902             }
9903 
9904             @Override
onScanResultsAvailable()9905             public void onScanResultsAvailable() {
9906                 ScanResultsCallback callback;
9907                 Executor executor;
9908                 synchronized (mLock) {
9909                     executor = mExecutor;
9910                     callback = mCallback;
9911                 }
9912                 if (callback == null || executor == null) {
9913                     return;
9914                 }
9915                 Binder.clearCallingIdentity();
9916                 executor.execute(callback::onScanResultsAvailable);
9917             }
9918         }
9919     }
9920 
9921     /**
9922      * Register a callback for Scan Results. See {@link ScanResultsCallback}.
9923      * Caller will receive the event when scan results are available.
9924      * Caller should use {@link WifiManager#getScanResults()} requires
9925      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results.
9926      * Caller can remove a previously registered callback using
9927      * {@link WifiManager#unregisterScanResultsCallback(ScanResultsCallback)}
9928      * Same caller can add multiple listeners.
9929      * <p>
9930      * Applications should have the
9931      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers
9932      * without the permission will trigger a {@link java.lang.SecurityException}.
9933      * <p>
9934      *
9935      * @param executor The executor to execute the callback of the {@code callback} object.
9936      * @param callback callback for Scan Results events
9937      */
9938 
9939     @RequiresPermission(ACCESS_WIFI_STATE)
registerScanResultsCallback(@onNull @allbackExecutor Executor executor, @NonNull ScanResultsCallback callback)9940     public void registerScanResultsCallback(@NonNull @CallbackExecutor Executor executor,
9941             @NonNull ScanResultsCallback callback) {
9942         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
9943         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9944 
9945         Log.v(TAG, "registerScanResultsCallback: callback=" + callback
9946                 + ", executor=" + executor);
9947         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
9948         proxy.initProxy(executor, callback);
9949         try {
9950             mService.registerScanResultsCallback(proxy);
9951         } catch (RemoteException e) {
9952             throw e.rethrowFromSystemServer();
9953         }
9954     }
9955 
9956     /**
9957      * Allow callers to unregister a previously registered callback. After calling this method,
9958      * applications will no longer receive Scan Results events.
9959      *
9960      * @param callback callback to unregister for Scan Results events
9961      */
9962     @RequiresPermission(ACCESS_WIFI_STATE)
unregisterScanResultsCallback(@onNull ScanResultsCallback callback)9963     public void unregisterScanResultsCallback(@NonNull ScanResultsCallback callback) {
9964         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9965         Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback);
9966         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
9967         try {
9968             mService.unregisterScanResultsCallback(proxy);
9969         } catch (RemoteException e) {
9970             throw e.rethrowFromSystemServer();
9971         } finally {
9972             proxy.cleanUpProxy();
9973         }
9974     }
9975 
9976     /**
9977      * Interface for suggestion connection status listener.
9978      * Should be implemented by applications and set when calling
9979      * {@link WifiManager#addSuggestionConnectionStatusListener(
9980      * Executor, SuggestionConnectionStatusListener)}.
9981      */
9982     public interface SuggestionConnectionStatusListener {
9983 
9984         /**
9985          * Called when the framework attempted to connect to a suggestion provided by the
9986          * registering app, but the connection to the suggestion failed.
9987          * @param wifiNetworkSuggestion The suggestion which failed to connect.
9988          * @param failureReason the connection failure reason code.
9989          */
onConnectionStatus( @onNull WifiNetworkSuggestion wifiNetworkSuggestion, @SuggestionConnectionStatusCode int failureReason)9990         void onConnectionStatus(
9991                 @NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
9992                 @SuggestionConnectionStatusCode int failureReason);
9993     }
9994 
9995     private class SuggestionConnectionStatusListenerProxy extends
9996             ISuggestionConnectionStatusListener.Stub {
9997         private final Executor mExecutor;
9998         private final SuggestionConnectionStatusListener mListener;
9999 
SuggestionConnectionStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionConnectionStatusListener listener)10000         SuggestionConnectionStatusListenerProxy(@NonNull Executor executor,
10001                 @NonNull SuggestionConnectionStatusListener listener) {
10002             mExecutor = executor;
10003             mListener = listener;
10004         }
10005 
10006         @Override
onConnectionStatus(@onNull WifiNetworkSuggestion wifiNetworkSuggestion, int failureReason)10007         public void onConnectionStatus(@NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
10008                 int failureReason) {
10009             Binder.clearCallingIdentity();
10010             mExecutor.execute(() ->
10011                     mListener.onConnectionStatus(wifiNetworkSuggestion, failureReason));
10012         }
10013 
10014     }
10015 
10016     /**
10017      * Interface for local-only connection failure listener.
10018      * Should be implemented by applications and set when calling
10019      * {@link WifiManager#addLocalOnlyConnectionFailureListener(Executor, LocalOnlyConnectionFailureListener)}
10020      */
10021     public interface LocalOnlyConnectionFailureListener {
10022 
10023         /**
10024          * Called when the framework attempted to connect to a local-only network requested by the
10025          * registering app, but the connection to the network failed.
10026          * @param wifiNetworkSpecifier The {@link WifiNetworkSpecifier} which failed to connect.
10027          * @param failureReason the connection failure reason code.
10028          */
onConnectionFailed( @onNull WifiNetworkSpecifier wifiNetworkSpecifier, @LocalOnlyConnectionStatusCode int failureReason)10029         void onConnectionFailed(
10030                 @NonNull WifiNetworkSpecifier wifiNetworkSpecifier,
10031                 @LocalOnlyConnectionStatusCode int failureReason);
10032     }
10033 
10034     private static class LocalOnlyConnectionStatusListenerProxy extends
10035             ILocalOnlyConnectionStatusListener.Stub {
10036         private final Executor mExecutor;
10037         private final LocalOnlyConnectionFailureListener mListener;
10038 
LocalOnlyConnectionStatusListenerProxy(@onNull Executor executor, @NonNull LocalOnlyConnectionFailureListener listener)10039         LocalOnlyConnectionStatusListenerProxy(@NonNull Executor executor,
10040                 @NonNull LocalOnlyConnectionFailureListener listener) {
10041             mExecutor = executor;
10042             mListener = listener;
10043         }
10044 
10045         @Override
onConnectionStatus(@onNull WifiNetworkSpecifier networkSpecifier, int failureReason)10046         public void onConnectionStatus(@NonNull WifiNetworkSpecifier networkSpecifier,
10047                 int failureReason) {
10048             Binder.clearCallingIdentity();
10049             mExecutor.execute(() ->
10050                     mListener.onConnectionFailed(networkSpecifier, failureReason));
10051         }
10052 
10053     }
10054 
10055     /**
10056      * Add a listener listening to wifi verbose logging changes.
10057      * See {@link WifiVerboseLoggingStatusChangedListener}.
10058      * Caller can remove a previously registered listener using
10059      * {@link WifiManager#removeWifiVerboseLoggingStatusChangedListener(
10060      * WifiVerboseLoggingStatusChangedListener)}
10061      * Same caller can add multiple listeners to monitor the event.
10062      * <p>
10063      * Applications should have the
10064      * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
10065      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
10066      * <p>
10067      * @param executor The executor to execute the listener of the {@code listener} object.
10068      * @param listener listener for changes in wifi verbose logging.
10069      *
10070      * @hide
10071      */
10072     @SystemApi
10073     @RequiresPermission(ACCESS_WIFI_STATE)
addWifiVerboseLoggingStatusChangedListener( @onNull @allbackExecutor Executor executor, @NonNull WifiVerboseLoggingStatusChangedListener listener)10074     public void addWifiVerboseLoggingStatusChangedListener(
10075             @NonNull @CallbackExecutor Executor executor,
10076             @NonNull WifiVerboseLoggingStatusChangedListener listener) {
10077         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10078         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
10079         if (mVerboseLoggingEnabled) {
10080             Log.v(TAG, "addWifiVerboseLoggingStatusChangedListener listener=" + listener
10081                     + ", executor=" + executor);
10082         }
10083         try {
10084             synchronized (sWifiVerboseLoggingStatusChangedListenerMap) {
10085                 IWifiVerboseLoggingStatusChangedListener.Stub binderCallback =
10086                         new IWifiVerboseLoggingStatusChangedListener.Stub() {
10087                             @Override
10088                             public void onStatusChanged(boolean enabled) {
10089                                 if (mVerboseLoggingEnabled) {
10090                                     Log.v(TAG, "WifiVerboseLoggingStatusListener: "
10091                                             + "onVerboseLoggingStatusChanged: enabled=" + enabled);
10092                                 }
10093                                 Binder.clearCallingIdentity();
10094                                 executor.execute(() -> listener.onWifiVerboseLoggingStatusChanged(
10095                                         enabled));
10096                             }
10097                         };
10098                 sWifiVerboseLoggingStatusChangedListenerMap.put(System.identityHashCode(listener),
10099                         binderCallback);
10100                 mService.addWifiVerboseLoggingStatusChangedListener(binderCallback);
10101             }
10102         } catch (RemoteException e) {
10103             throw e.rethrowFromSystemServer();
10104         }
10105     }
10106 
10107     /**
10108      * Allow callers to remove a previously registered listener.
10109      * <p>
10110      * Applications should have the
10111      * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
10112      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
10113      * <p>
10114      * @param listener listener to remove.
10115      *
10116      * @hide
10117      */
10118     @SystemApi
10119     @RequiresPermission(ACCESS_WIFI_STATE)
removeWifiVerboseLoggingStatusChangedListener( @onNull WifiVerboseLoggingStatusChangedListener listener)10120     public void removeWifiVerboseLoggingStatusChangedListener(
10121             @NonNull WifiVerboseLoggingStatusChangedListener listener) {
10122         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10123         Log.v(TAG, "removeWifiVerboseLoggingStatusChangedListener: listener=" + listener);
10124         try {
10125             synchronized (sWifiVerboseLoggingStatusChangedListenerMap) {
10126                 int listenerIdentifier = System.identityHashCode(listener);
10127                 if (!sWifiVerboseLoggingStatusChangedListenerMap.contains(listenerIdentifier)) {
10128                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
10129                     return;
10130                 }
10131                 mService.removeWifiVerboseLoggingStatusChangedListener(
10132                         sWifiVerboseLoggingStatusChangedListenerMap.get(listenerIdentifier));
10133                 sWifiVerboseLoggingStatusChangedListenerMap.remove(listenerIdentifier);
10134             }
10135         } catch (RemoteException e) {
10136             throw e.rethrowFromSystemServer();
10137         }
10138     }
10139 
10140     /**
10141      * Add a listener for suggestion networks. See {@link SuggestionConnectionStatusListener}.
10142      * Caller will receive the event when suggested network have connection failure.
10143      * Caller can remove a previously registered listener using
10144      * {@link WifiManager#removeSuggestionConnectionStatusListener(
10145      * SuggestionConnectionStatusListener)}
10146      * Same caller can add multiple listeners to monitor the event.
10147      * <p>
10148      * Applications should have the
10149      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
10150      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permissions.
10151      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
10152      * <p>
10153      *
10154      * @param executor The executor to execute the listener of the {@code listener} object.
10155      * @param listener listener for suggestion network connection failure.
10156      */
10157     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
addSuggestionConnectionStatusListener(@onNull @allbackExecutor Executor executor, @NonNull SuggestionConnectionStatusListener listener)10158     public void addSuggestionConnectionStatusListener(@NonNull @CallbackExecutor Executor executor,
10159             @NonNull SuggestionConnectionStatusListener listener) {
10160         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10161         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
10162         Log.v(TAG, "addSuggestionConnectionStatusListener listener=" + listener
10163                 + ", executor=" + executor);
10164         try {
10165             synchronized (sSuggestionConnectionStatusListenerMap) {
10166                 ISuggestionConnectionStatusListener.Stub binderCallback =
10167                         new SuggestionConnectionStatusListenerProxy(executor, listener);
10168                 sSuggestionConnectionStatusListenerMap.put(System.identityHashCode(listener),
10169                         binderCallback);
10170                 mService.registerSuggestionConnectionStatusListener(binderCallback,
10171                         mContext.getOpPackageName(), mContext.getAttributionTag());
10172             }
10173         } catch (RemoteException e) {
10174             throw e.rethrowFromSystemServer();
10175         }
10176 
10177     }
10178 
10179     /**
10180      * Allow callers to remove a previously registered listener. After calling this method,
10181      * applications will no longer receive suggestion connection events through that listener.
10182      *
10183      * @param listener listener to remove.
10184      */
10185     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionConnectionStatusListener( @onNull SuggestionConnectionStatusListener listener)10186     public void removeSuggestionConnectionStatusListener(
10187             @NonNull SuggestionConnectionStatusListener listener) {
10188         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10189         Log.v(TAG, "removeSuggestionConnectionStatusListener: listener=" + listener);
10190         try {
10191             synchronized (sSuggestionConnectionStatusListenerMap) {
10192                 int listenerIdentifier = System.identityHashCode(listener);
10193                 if (!sSuggestionConnectionStatusListenerMap.contains(listenerIdentifier)) {
10194                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
10195                     return;
10196                 }
10197                 mService.unregisterSuggestionConnectionStatusListener(
10198                         sSuggestionConnectionStatusListenerMap.get(listenerIdentifier),
10199                         mContext.getOpPackageName());
10200                 sSuggestionConnectionStatusListenerMap.remove(listenerIdentifier);
10201             }
10202         } catch (RemoteException e) {
10203             throw e.rethrowFromSystemServer();
10204         }
10205     }
10206 
10207     /**
10208      * Add a listener for local-only networks. See {@link WifiNetworkSpecifier}.
10209      * Specify the caller will only get connection failures for networks they requested.
10210      * Caller can remove a previously registered listener using
10211      * {@link WifiManager#removeLocalOnlyConnectionFailureListener(LocalOnlyConnectionFailureListener)}
10212      * Same caller can add multiple listeners to monitor the event.
10213      * <p>
10214      * Applications should have the {@link android.Manifest.permission#ACCESS_WIFI_STATE}
10215      * permissions.
10216      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
10217      * <p>
10218      *
10219      * @param executor The executor to execute the listener of the {@code listener} object.
10220      * @param listener listener for local-only network connection failure.
10221      */
10222     @RequiresPermission(ACCESS_WIFI_STATE)
addLocalOnlyConnectionFailureListener(@onNull @allbackExecutor Executor executor, @NonNull LocalOnlyConnectionFailureListener listener)10223     public void addLocalOnlyConnectionFailureListener(@NonNull @CallbackExecutor Executor executor,
10224             @NonNull LocalOnlyConnectionFailureListener listener) {
10225         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10226         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
10227         try {
10228             synchronized (sLocalOnlyConnectionStatusListenerMap) {
10229                 if (sLocalOnlyConnectionStatusListenerMap
10230                         .contains(System.identityHashCode(listener))) {
10231                     Log.w(TAG, "Same listener already registered");
10232                     return;
10233                 }
10234                 ILocalOnlyConnectionStatusListener.Stub binderCallback =
10235                         new LocalOnlyConnectionStatusListenerProxy(executor, listener);
10236                 sLocalOnlyConnectionStatusListenerMap.put(System.identityHashCode(listener),
10237                         binderCallback);
10238                 mService.addLocalOnlyConnectionStatusListener(binderCallback,
10239                         mContext.getOpPackageName(), mContext.getAttributionTag());
10240             }
10241         } catch (RemoteException e) {
10242             throw e.rethrowFromSystemServer();
10243         }
10244     }
10245 
10246     /**
10247      * Allow callers to remove a previously registered listener. After calling this method,
10248      * applications will no longer receive local-only connection events through that listener.
10249      *
10250      * @param listener listener to remove.
10251      */
10252     @RequiresPermission(ACCESS_WIFI_STATE)
removeLocalOnlyConnectionFailureListener( @onNull LocalOnlyConnectionFailureListener listener)10253     public void removeLocalOnlyConnectionFailureListener(
10254             @NonNull LocalOnlyConnectionFailureListener listener) {
10255         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10256         try {
10257             synchronized (sLocalOnlyConnectionStatusListenerMap) {
10258                 int listenerIdentifier = System.identityHashCode(listener);
10259                 if (!sLocalOnlyConnectionStatusListenerMap.contains(listenerIdentifier)) {
10260                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
10261                     return;
10262                 }
10263                 mService.removeLocalOnlyConnectionStatusListener(
10264                         sLocalOnlyConnectionStatusListenerMap.get(listenerIdentifier),
10265                         mContext.getOpPackageName());
10266                 sLocalOnlyConnectionStatusListenerMap.remove(listenerIdentifier);
10267             }
10268         } catch (RemoteException e) {
10269             throw e.rethrowFromSystemServer();
10270         }
10271     }
10272 
10273     /**
10274      * Parse the list of channels the DPP enrollee reports when it fails to find an AP.
10275      *
10276      * @param channelList List of channels in the format defined in the DPP specification.
10277      * @return A parsed sparse array, where the operating class is the key.
10278      * @hide
10279      */
10280     @VisibleForTesting
parseDppChannelList(String channelList)10281     public static SparseArray<int[]> parseDppChannelList(String channelList) {
10282         SparseArray<int[]> channelListArray = new SparseArray<>();
10283 
10284         if (TextUtils.isEmpty(channelList)) {
10285             return channelListArray;
10286         }
10287         StringTokenizer str = new StringTokenizer(channelList, ",");
10288         String classStr = null;
10289         List<Integer> channelsInClass = new ArrayList<>();
10290 
10291         try {
10292             while (str.hasMoreElements()) {
10293                 String cur = str.nextToken();
10294 
10295                 /**
10296                  * Example for a channel list:
10297                  *
10298                  * 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,
10299                  * 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
10300                  *
10301                  * Detect operating class by the delimiter of '/' and use a string tokenizer with
10302                  * ',' as a delimiter.
10303                  */
10304                 int classDelim = cur.indexOf('/');
10305                 if (classDelim != -1) {
10306                     if (classStr != null) {
10307                         // Store the last channel array in the sparse array, where the operating
10308                         // class is the key (as an integer).
10309                         int[] channelsArray = new int[channelsInClass.size()];
10310                         for (int i = 0; i < channelsInClass.size(); i++) {
10311                             channelsArray[i] = channelsInClass.get(i);
10312                         }
10313                         channelListArray.append(Integer.parseInt(classStr), channelsArray);
10314                         channelsInClass = new ArrayList<>();
10315                     }
10316 
10317                     // Init a new operating class and store the first channel
10318                     classStr = cur.substring(0, classDelim);
10319                     String channelStr = cur.substring(classDelim + 1);
10320                     channelsInClass.add(Integer.parseInt(channelStr));
10321                 } else {
10322                     if (classStr == null) {
10323                         // Invalid format
10324                         Log.e(TAG, "Cannot parse DPP channel list");
10325                         return new SparseArray<>();
10326                     }
10327                     channelsInClass.add(Integer.parseInt(cur));
10328                 }
10329             }
10330 
10331             // Store the last array
10332             if (classStr != null) {
10333                 int[] channelsArray = new int[channelsInClass.size()];
10334                 for (int i = 0; i < channelsInClass.size(); i++) {
10335                     channelsArray[i] = channelsInClass.get(i);
10336                 }
10337                 channelListArray.append(Integer.parseInt(classStr), channelsArray);
10338             }
10339             return channelListArray;
10340         } catch (NumberFormatException e) {
10341             Log.e(TAG, "Cannot parse DPP channel list");
10342             return new SparseArray<>();
10343         }
10344     }
10345 
10346     /**
10347      * If isFullCapture is true, capture everything in ring buffer
10348      *
10349      * If isFullCapture is false, extract WifiUsabilityStatsEntries from ring buffer whose
10350      * timestamps are within [triggerStartTimeMillis, triggerStopTimeMillis) in WiFiMetrics, and
10351      * store them as upload candidates.
10352      *
10353      * Source of elapsed time since boot will be android.os.SystemClock.elapsedRealtime()
10354      *
10355      * @param executor The executor on which callback will be invoked.
10356      * @param resultsCallback An asynchronous callback that will return a execution result of
10357      *                        mWifiMetrics.storeCapturedData
10358      * @param triggerType data capture trigger type
10359      * @param isFullCapture if we do full capture on ring buffer or not
10360      * @param triggerStartTimeMillis data capture start timestamp, elapsed time since boot
10361      * @param triggerStopTimeMillis data capture stop timestamp, elapsed time since boot
10362      * @hide
10363      */
10364     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
storeCapturedData(@onNull @allbackExecutor Executor executor, @NonNull IntConsumer resultsCallback, int triggerType, boolean isFullCapture, long triggerStartTimeMillis, long triggerStopTimeMillis)10365     public void storeCapturedData(@NonNull @CallbackExecutor Executor executor,
10366             @NonNull IntConsumer resultsCallback, int triggerType, boolean isFullCapture,
10367             long triggerStartTimeMillis, long triggerStopTimeMillis) {
10368         Objects.requireNonNull(executor, "executor cannot be null");
10369         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
10370         try {
10371             mService.storeCapturedData(triggerType, isFullCapture, triggerStartTimeMillis,
10372                     triggerStopTimeMillis, new IIntegerListener.Stub() {
10373                         @Override
10374                         public void onResult(int value) {
10375                             Binder.clearCallingIdentity();
10376                             executor.execute(() -> {
10377                                 resultsCallback.accept(value);
10378                             });
10379                         }
10380                     });
10381         } catch (RemoteException e) {
10382             throw e.rethrowFromSystemServer();
10383         }
10384     }
10385 
10386     /**
10387      * Callback interface for framework to receive network status updates and trigger of updating
10388      * {@link WifiUsabilityStatsEntry}.
10389      *
10390      * @hide
10391      */
10392     @SystemApi
10393     public interface ScoreUpdateObserver {
10394         /**
10395          * Called by applications to indicate network status. For applications targeting
10396          * {@link android.os.Build.VERSION_CODES#S} or above: The score is not used to take action
10397          * on network selection but for the purpose of Wifi metric collection only; Network
10398          * selection is influenced by inputs from
10399          * {@link ScoreUpdateObserver#notifyStatusUpdate(int, boolean)},
10400          * {@link ScoreUpdateObserver#requestNudOperation(int, boolean)}, and
10401          * {@link ScoreUpdateObserver#blocklistCurrentBssid(int)}.
10402          *
10403          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10404          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10405          * @param score The score representing link quality of current Wi-Fi network connection.
10406          *              Populated by connected network scorer in applications..
10407          */
notifyScoreUpdate(int sessionId, int score)10408         void notifyScoreUpdate(int sessionId, int score);
10409 
10410         /**
10411          * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
10412          * To receive update applications need to add WifiUsabilityStatsEntry listener. See
10413          * {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
10414          *
10415          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10416          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10417          */
triggerUpdateOfWifiUsabilityStats(int sessionId)10418         void triggerUpdateOfWifiUsabilityStats(int sessionId);
10419 
10420         /**
10421          * Called by applications to indicate whether current Wi-Fi network is usable or not.
10422          *
10423          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10424          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10425          * @param isUsable The boolean representing whether current Wi-Fi network is usable, and it
10426          *                 may be sent to ConnectivityService and used for setting default network.
10427          *                 Populated by connected network scorer in applications.
10428          */
10429         @RequiresApi(Build.VERSION_CODES.S)
notifyStatusUpdate(int sessionId, boolean isUsable)10430         default void notifyStatusUpdate(int sessionId, boolean isUsable) {}
10431 
10432         /**
10433          * Called by applications to start a NUD (Neighbor Unreachability Detection) operation. The
10434          * framework throttles NUD operations to no more frequently than every five seconds
10435          * (see {@link WifiScoreReport#NUD_THROTTLE_MILLIS}). The framework keeps track of requests
10436          * and executes them as soon as possible based on the throttling criteria.
10437          *
10438          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10439          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10440          */
10441         @RequiresApi(Build.VERSION_CODES.S)
requestNudOperation(int sessionId)10442         default void requestNudOperation(int sessionId) {}
10443 
10444         /**
10445          * Called by applications to blocklist currently connected BSSID. No blocklisting operation
10446          * if called after disconnection.
10447          *
10448          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10449          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10450          */
10451         @RequiresApi(Build.VERSION_CODES.S)
blocklistCurrentBssid(int sessionId)10452         default void blocklistCurrentBssid(int sessionId) {}
10453     }
10454 
10455     /**
10456      * Callback proxy for {@link ScoreUpdateObserver} objects.
10457      *
10458      * @hide
10459      */
10460     private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
10461         private final IScoreUpdateObserver mScoreUpdateObserver;
10462 
ScoreUpdateObserverProxy(IScoreUpdateObserver observer)10463         private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
10464             mScoreUpdateObserver = observer;
10465         }
10466 
10467         @Override
notifyScoreUpdate(int sessionId, int score)10468         public void notifyScoreUpdate(int sessionId, int score) {
10469             try {
10470                 mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
10471             } catch (RemoteException e) {
10472                 throw e.rethrowFromSystemServer();
10473             }
10474         }
10475 
10476         @Override
triggerUpdateOfWifiUsabilityStats(int sessionId)10477         public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
10478             try {
10479                 mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
10480             } catch (RemoteException e) {
10481                 throw e.rethrowFromSystemServer();
10482             }
10483         }
10484 
10485         @Override
notifyStatusUpdate(int sessionId, boolean isUsable)10486         public void notifyStatusUpdate(int sessionId, boolean isUsable) {
10487             if (!SdkLevel.isAtLeastS()) {
10488                 throw new UnsupportedOperationException();
10489             }
10490             try {
10491                 mScoreUpdateObserver.notifyStatusUpdate(sessionId, isUsable);
10492             } catch (RemoteException e) {
10493                 throw e.rethrowFromSystemServer();
10494             }
10495         }
10496 
10497         @Override
requestNudOperation(int sessionId)10498         public void requestNudOperation(int sessionId) {
10499             if (!SdkLevel.isAtLeastS()) {
10500                 throw new UnsupportedOperationException();
10501             }
10502             try {
10503                 mScoreUpdateObserver.requestNudOperation(sessionId);
10504             } catch (RemoteException e) {
10505                 throw e.rethrowFromSystemServer();
10506             }
10507         }
10508 
10509         @Override
blocklistCurrentBssid(int sessionId)10510         public void blocklistCurrentBssid(int sessionId) {
10511             if (!SdkLevel.isAtLeastS()) {
10512                 throw new UnsupportedOperationException();
10513             }
10514             try {
10515                 mScoreUpdateObserver.blocklistCurrentBssid(sessionId);
10516             } catch (RemoteException e) {
10517                 throw e.rethrowFromSystemServer();
10518             }
10519         }
10520     }
10521 
10522     /**
10523      * Interface for Wi-Fi connected network scorer. Should be implemented by applications and set
10524      * when calling
10525      * {@link WifiManager#setWifiConnectedNetworkScorer(Executor, WifiConnectedNetworkScorer)}.
10526      *
10527      * @hide
10528      */
10529     @SystemApi
10530     public interface WifiConnectedNetworkScorer {
10531         /**
10532          * Called by framework to indicate the start of a network connection.
10533          * @param sessionId The ID to indicate current Wi-Fi network connection.
10534          * @deprecated This API is deprecated.  Please use
10535          *             {@link WifiConnectedNetworkScorer#onStart(WifiConnectedSessionInfo)}.
10536          */
10537         @Deprecated
onStart(int sessionId)10538         default void onStart(int sessionId) {}
10539 
10540         /**
10541          * Called by framework to indicate the start of a network connection.
10542          * @param sessionInfo The session information to indicate current Wi-Fi network connection.
10543          *                    See {@link WifiConnectedSessionInfo}.
10544          */
onStart(@onNull WifiConnectedSessionInfo sessionInfo)10545         default void onStart(@NonNull WifiConnectedSessionInfo sessionInfo) {
10546             onStart(sessionInfo.getSessionId());
10547         }
10548 
10549         /**
10550          * Called by framework to indicate the end of a network connection.
10551          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10552          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10553          */
onStop(int sessionId)10554         void onStop(int sessionId);
10555 
10556         /**
10557          * Framework sets callback for score change events after application sets its scorer.
10558          * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
10559          * implemented and instantiated by framework.
10560          */
onSetScoreUpdateObserver(@onNull ScoreUpdateObserver observerImpl)10561         void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
10562 
10563         /**
10564          * Called by framework to indicate the user accepted a dialog to switch to a new network.
10565          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10566          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10567          * @param targetNetworkId Network ID of the target network.
10568          * @param targetBssid BSSID of the target network.
10569          */
onNetworkSwitchAccepted( int sessionId, int targetNetworkId, @NonNull String targetBssid)10570         default void onNetworkSwitchAccepted(
10571                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10572             // No-op.
10573         }
10574 
10575         /**
10576          * Called by framework to indicate the user rejected a dialog to switch to new network.
10577          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10578          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10579          * @param targetNetworkId Network ID of the target network.
10580          * @param targetBssid BSSID of the target network.
10581          */
onNetworkSwitchRejected( int sessionId, int targetNetworkId, @NonNull String targetBssid)10582         default void onNetworkSwitchRejected(
10583                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10584             // No-op.
10585         }
10586     }
10587 
10588 
10589     /**
10590      * Callback registered with {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
10591      * PnoScanResultsCallback)}. Returns status and result information on offloaded external PNO
10592      * requests.
10593      * @hide
10594      */
10595     @SystemApi
10596     public interface PnoScanResultsCallback {
10597         /**
10598          * A status code returned by {@link #onRegisterFailed(int)}.
10599          * Unknown failure.
10600          */
10601         int REGISTER_PNO_CALLBACK_UNKNOWN = 0;
10602 
10603         /**
10604          * A status code returned by {@link #onRegisterFailed(int)}.
10605          * A callback has already been registered by the caller.
10606          */
10607         int REGISTER_PNO_CALLBACK_ALREADY_REGISTERED = 1;
10608 
10609         /**
10610          * A status code returned by {@link #onRegisterFailed(int)}.
10611          * The platform is unable to serve this request because another app has a PNO scan request
10612          * active.
10613          */
10614         int REGISTER_PNO_CALLBACK_RESOURCE_BUSY = 2;
10615 
10616         /**
10617          * A status code returned by {@link #onRegisterFailed(int)}.
10618          * PNO scans are not supported on this device.
10619          */
10620         int REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED = 3;
10621 
10622         /** @hide */
10623         @IntDef(prefix = { "REGISTER_PNO_CALLBACK_" }, value = {
10624                 REGISTER_PNO_CALLBACK_UNKNOWN,
10625                 REGISTER_PNO_CALLBACK_ALREADY_REGISTERED,
10626                 REGISTER_PNO_CALLBACK_RESOURCE_BUSY,
10627                 REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED
10628         })
10629         @Retention(RetentionPolicy.SOURCE)
10630         public @interface RegisterFailureReason {}
10631 
10632         /**
10633          * A status code returned by {@link #onRemoved(int)}.
10634          * Unknown reason.
10635          */
10636         int REMOVE_PNO_CALLBACK_UNKNOWN = 0;
10637 
10638         /**
10639          * A status code returned by {@link #onRemoved(int)}.
10640          * This Callback is automatically removed after results ScanResults are delivered.
10641          */
10642         int REMOVE_PNO_CALLBACK_RESULTS_DELIVERED = 1;
10643 
10644         /**
10645          * A status code returned by {@link #onRemoved(int)}.
10646          * This callback has been unregistered via {@link WifiManager#clearExternalPnoScanRequest()}
10647          */
10648         int REMOVE_PNO_CALLBACK_UNREGISTERED = 2;
10649 
10650         /** @hide */
10651         @IntDef(prefix = { "REMOVE_PNO_CALLBACK_" }, value = {
10652                 REMOVE_PNO_CALLBACK_UNKNOWN,
10653                 REMOVE_PNO_CALLBACK_RESULTS_DELIVERED,
10654                 REMOVE_PNO_CALLBACK_UNREGISTERED
10655         })
10656         @Retention(RetentionPolicy.SOURCE)
10657         public @interface RemovalReason {}
10658 
10659         /**
10660          * Called when PNO scan finds one of the requested SSIDs. This is a one time callback.
10661          * After results are reported the callback will be automatically unregistered.
10662          */
onScanResultsAvailable(@onNull List<ScanResult> scanResults)10663         void onScanResultsAvailable(@NonNull List<ScanResult> scanResults);
10664 
10665         /**
10666          * Called when this callback has been successfully registered.
10667          */
onRegisterSuccess()10668         void onRegisterSuccess();
10669 
10670         /**
10671          * Called when this callback failed to register with the failure reason.
10672          * See {@link RegisterFailureReason} for details.
10673          */
onRegisterFailed(@egisterFailureReason int reason)10674         void onRegisterFailed(@RegisterFailureReason int reason);
10675 
10676         /**
10677          * Called when this callback has been unregistered from the Wi-Fi subsystem.
10678          * See {@link RemovalReason} for details.
10679          */
onRemoved(@emovalReason int reason)10680         void onRemoved(@RemovalReason int reason);
10681     }
10682 
10683 
10684     private class PnoScanResultsCallbackProxy extends IPnoScanResultsCallback.Stub {
10685         private Executor mExecutor;
10686         private PnoScanResultsCallback mCallback;
10687 
PnoScanResultsCallbackProxy(@onNull Executor executor, @NonNull PnoScanResultsCallback callback)10688         PnoScanResultsCallbackProxy(@NonNull Executor executor,
10689                 @NonNull PnoScanResultsCallback callback) {
10690             mExecutor = executor;
10691             mCallback = callback;
10692         }
10693 
10694         @Override
onScanResultsAvailable(List<ScanResult> scanResults)10695         public void onScanResultsAvailable(List<ScanResult> scanResults) {
10696             if (mVerboseLoggingEnabled) {
10697                 Log.v(TAG, "PnoScanResultsCallback: " + "onScanResultsAvailable");
10698             }
10699             Binder.clearCallingIdentity();
10700             mExecutor.execute(() -> mCallback.onScanResultsAvailable(scanResults));
10701         }
10702 
10703         @Override
onRegisterSuccess()10704         public void onRegisterSuccess() {
10705             if (mVerboseLoggingEnabled) {
10706                 Log.v(TAG, "PnoScanResultsCallback: " + "onRegisterSuccess");
10707             }
10708             Binder.clearCallingIdentity();
10709             mExecutor.execute(() -> mCallback.onRegisterSuccess());
10710         }
10711 
10712         @Override
onRegisterFailed(int reason)10713         public void onRegisterFailed(int reason) {
10714             if (mVerboseLoggingEnabled) {
10715                 Log.v(TAG, "PnoScanResultsCallback: " + "onRegisterFailed " + reason);
10716             }
10717             Binder.clearCallingIdentity();
10718             mExecutor.execute(() -> mCallback.onRegisterFailed(reason));
10719         }
10720 
10721         @Override
onRemoved(int reason)10722         public void onRemoved(int reason) {
10723             if (mVerboseLoggingEnabled) {
10724                 Log.v(TAG, "PnoScanResultsCallback: " + "onRemoved");
10725             }
10726             Binder.clearCallingIdentity();
10727             mExecutor.execute(() -> mCallback.onRemoved(reason));
10728         }
10729     }
10730 
10731     /**
10732      * Callback proxy for {@link WifiConnectedNetworkScorer} objects.
10733      *
10734      * @hide
10735      */
10736     private class WifiConnectedNetworkScorerProxy extends IWifiConnectedNetworkScorer.Stub {
10737         private Executor mExecutor;
10738         private WifiConnectedNetworkScorer mScorer;
10739 
WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer)10740         WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer) {
10741             mExecutor = executor;
10742             mScorer = scorer;
10743         }
10744 
10745         @Override
onStart(@onNull WifiConnectedSessionInfo sessionInfo)10746         public void onStart(@NonNull WifiConnectedSessionInfo sessionInfo) {
10747             if (mVerboseLoggingEnabled) {
10748                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionInfo=" + sessionInfo);
10749             }
10750             Binder.clearCallingIdentity();
10751             mExecutor.execute(() -> mScorer.onStart(sessionInfo));
10752         }
10753 
10754         @Override
onStop(int sessionId)10755         public void onStop(int sessionId) {
10756             if (mVerboseLoggingEnabled) {
10757                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
10758             }
10759             Binder.clearCallingIdentity();
10760             mExecutor.execute(() -> mScorer.onStop(sessionId));
10761         }
10762 
10763         @Override
onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl)10764         public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
10765             if (mVerboseLoggingEnabled) {
10766                 Log.v(TAG, "WifiConnectedNetworkScorer: "
10767                         + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
10768             }
10769             Binder.clearCallingIdentity();
10770             mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
10771                     new ScoreUpdateObserverProxy(observerImpl)));
10772         }
10773 
10774         @Override
onNetworkSwitchAccepted( int sessionId, int targetNetworkId, @NonNull String targetBssid)10775         public void onNetworkSwitchAccepted(
10776                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10777             if (mVerboseLoggingEnabled) {
10778                 Log.v(TAG, "WifiConnectedNetworkScorer: onNetworkSwitchAccepted:"
10779                         + " sessionId=" + sessionId
10780                         + " targetNetworkId=" + targetNetworkId
10781                         + " targetBssid=" + targetBssid);
10782             }
10783             Binder.clearCallingIdentity();
10784             mExecutor.execute(() -> mScorer.onNetworkSwitchAccepted(
10785                     sessionId, targetNetworkId, targetBssid));
10786         }
10787         @Override
onNetworkSwitchRejected( int sessionId, int targetNetworkId, @NonNull String targetBssid)10788         public void onNetworkSwitchRejected(
10789                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10790             if (mVerboseLoggingEnabled) {
10791                 Log.v(TAG, "WifiConnectedNetworkScorer: onNetworkSwitchRejected:"
10792                                 + " sessionId=" + sessionId
10793                                 + " targetNetworkId=" + targetNetworkId
10794                                 + " targetBssid=" + targetBssid);
10795             }
10796             Binder.clearCallingIdentity();
10797             mExecutor.execute(() -> mScorer.onNetworkSwitchRejected(
10798                     sessionId, targetNetworkId, targetBssid));
10799         }
10800     }
10801 
10802     /**
10803      * This API allows the caller to program up to 2 SSIDs for PNO scans. PNO scans are offloaded
10804      * to the Wi-Fi chip when the device is inactive (typically screen-off).
10805      * If the screen is currently off when this API is called, then a PNO scan including the
10806      * requested SSIDs will immediately get started. If the screen is on when this API is called,
10807      * the requested SSIDs will get included for PNO scans the next time the screen turns off.
10808      * <p>
10809      * Note, due to PNO being a limited resource, only one external PNO request is supported, and
10810      * calling this API will fail if an external PNO scan request is already registered by another
10811      * caller. If the caller that has already registered a callback calls this API again, the new
10812      * callback will override the previous one.
10813      * <p>
10814      * After this API is called, {@link PnoScanResultsCallback#onRegisterSuccess()} will be invoked
10815      * if the operation is successful, or {@link PnoScanResultsCallback#onRegisterFailed(int)} will
10816      * be invoked if the operation failed.
10817      * <p>
10818      * {@link PnoScanResultsCallback#onRemoved(int)} will be invoked to notify the caller when the
10819      * external PNO scan request is removed, which will happen when one of the following events
10820      * happen:
10821      * </p>
10822      * <ul>
10823      * <li>Upon finding any of the requested SSIDs through either a connectivity scan or PNO scan,
10824      * the matching ScanResults will be returned
10825      * via {@link PnoScanResultsCallback#onScanResultsAvailable(List)}, and the registered PNO
10826      * scan request will get automatically removed.</li>
10827      * <li>The external PNO scan request is removed by a call to
10828      * {@link #clearExternalPnoScanRequest()}</li>
10829      * </ul>
10830      *
10831      * @param ssids The list of SSIDs to request for PNO scan.
10832      * @param frequencies Provide as hint a list of up to 10 frequencies to be used for PNO scan.
10833      *                    Each frequency should be in MHz. For example 2412 and 5180 are valid
10834      *                    frequencies. {@link WifiInfo#getFrequency()} is a location where this
10835      *                    information could be obtained. If a null or empty array is provided, the
10836      *                    Wi-Fi framework will automatically decide the list of frequencies to scan.
10837      * @param executor The executor on which callback will be invoked.
10838      * @param callback For the calling application to receive results and status updates.
10839      *
10840      * @throws SecurityException if the caller does not have permission.
10841      * @throws IllegalArgumentException if the caller provided invalid inputs.
10842      * @throws UnsupportedOperationException if this API is not supported on this SDK version.
10843      * @hide
10844      */
10845     @SystemApi
10846     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION,
10847             REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION})
10848     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setExternalPnoScanRequest(@onNull List<WifiSsid> ssids, @Nullable int[] frequencies, @NonNull @CallbackExecutor Executor executor, @NonNull PnoScanResultsCallback callback)10849     public void setExternalPnoScanRequest(@NonNull List<WifiSsid> ssids,
10850             @Nullable int[] frequencies, @NonNull @CallbackExecutor Executor executor,
10851             @NonNull PnoScanResultsCallback callback) {
10852         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
10853         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
10854         try {
10855             mService.setExternalPnoScanRequest(new Binder(),
10856                     new PnoScanResultsCallbackProxy(executor, callback),
10857                     ssids, frequencies == null ? new int[0] : frequencies,
10858                     mContext.getOpPackageName(), mContext.getAttributionTag());
10859         } catch (RemoteException e) {
10860             throw e.rethrowFromSystemServer();
10861         }
10862     }
10863 
10864     /**
10865      * Wi-Fi Preferred Network Offload (PNO) scanning offloads scanning to the chip to save power
10866      * when Wi-Fi is disconnected and the screen is off. See
10867      * {@link https://source.android.com/docs/core/connect/wifi-scan} for more details.
10868      * <p>
10869      * This API can be used to enable or disable PNO scanning. After boot, PNO scanning is enabled
10870      * by default. When PNO scanning is disabled, the Wi-Fi framework will not trigger scans at all
10871      * when the screen is off. This can be used to save power on devices with small batteries.
10872      *
10873      * @param enabled True - enable PNO scanning
10874      *                False - disable PNO scanning
10875      * @param enablePnoScanAfterWifiToggle True - Wifi being enabled by
10876      *                                     {@link #setWifiEnabled(boolean)} will re-enable PNO
10877      *                                     scanning.
10878      *                                     False - Wifi being enabled by
10879      *                                     {@link #setWifiEnabled(boolean)} will not re-enable PNO
10880      *                                     scanning.
10881      *
10882      * @throws SecurityException if the caller does not have permission.
10883      * @hide
10884      */
10885     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
10886     @SystemApi
10887     @RequiresPermission(
10888             anyOf = {MANAGE_WIFI_NETWORK_SELECTION, NETWORK_SETTINGS, NETWORK_SETUP_WIZARD})
setPnoScanState(@noScanState int pnoScanState)10889     public void setPnoScanState(@PnoScanState int pnoScanState) {
10890         try {
10891             boolean enabled = false;
10892             boolean enablePnoScanAfterWifiToggle = false;
10893             switch (pnoScanState) {
10894                 case PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT:
10895                     break;
10896                 case PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE:
10897                     enablePnoScanAfterWifiToggle = true;
10898                     break;
10899                 case PNO_SCAN_STATE_ENABLED:
10900                     enabled = true;
10901                     break;
10902                 default:
10903                     throw new IllegalArgumentException("Invalid PnoScanState");
10904             }
10905             mService.setPnoScanEnabled(enabled, enablePnoScanAfterWifiToggle,
10906                     mContext.getOpPackageName());
10907         } catch (RemoteException e) {
10908             throw e.rethrowFromSystemServer();
10909         }
10910     }
10911 
10912     /**
10913      * Wi-Fi Preferred Network Offload (PNO) scanning offloads scanning to the chip to save power
10914      * when Wi-Fi is disconnected and the screen is off. See
10915      * {@link https://source.android.com/docs/core/connect/wifi-scan} for more details.
10916      * <p>
10917      * This API can be used to enable or disable PNO scanning. After boot, PNO scanning is enabled
10918      * by default. When PNO scanning is disabled, the Wi-Fi framework will not trigger scans at all
10919      * when the screen is off. This can be used to save power on devices with small batteries.
10920      *
10921      * @param enabled True - enable PNO scanning
10922      *                False - disable PNO scanning
10923      * @param enablePnoScanAfterWifiToggle True - Wifi being enabled by
10924      *                                     {@link #setWifiEnabled(boolean)} will re-enable PNO
10925      *                                     scanning.
10926      *                                     False - Wifi being enabled by
10927      *                                     {@link #setWifiEnabled(boolean)} will not re-enable PNO
10928      *                                     scanning.
10929      *
10930      * @throws SecurityException if the caller does not have permission.
10931      * @hide
10932      */
10933     @RequiresPermission(
10934             anyOf = {MANAGE_WIFI_NETWORK_SELECTION, NETWORK_SETTINGS, NETWORK_SETUP_WIZARD})
setPnoScanEnabled(boolean enabled, boolean enablePnoScanAfterWifiToggle)10935     public void setPnoScanEnabled(boolean enabled, boolean enablePnoScanAfterWifiToggle) {
10936         try {
10937             mService.setPnoScanEnabled(enabled, enablePnoScanAfterWifiToggle,
10938                     mContext.getOpPackageName());
10939         } catch (RemoteException e) {
10940             throw e.rethrowFromSystemServer();
10941         }
10942     }
10943 
10944     /**
10945      * Clear the current PNO scan request that's been set by the calling UID. Note, the call will
10946      * be no-op if the current PNO scan request is set by a different UID.
10947      *
10948      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
10949      * @hide
10950      */
10951     @SystemApi
10952     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
clearExternalPnoScanRequest()10953     public void clearExternalPnoScanRequest() {
10954         try {
10955             mService.clearExternalPnoScanRequest();
10956         } catch (RemoteException e) {
10957             throw e.rethrowFromSystemServer();
10958         }
10959     }
10960 
10961     /**
10962      * Returns information about the last caller of an API.
10963      *
10964      * @param apiType The type of API to request information for the last caller.
10965      * @param executor The executor on which callback will be invoked.
10966      * @param resultsCallback An asynchronous callback that will return 2 arguments.
10967      *                        {@code String} the name of the package that performed the last API
10968      *                        call. {@code Boolean} the value associated with the last API call.
10969      *
10970      * @throws SecurityException if the caller does not have permission.
10971      * @throws IllegalArgumentException if the caller provided invalid inputs.
10972      * @hide
10973      */
10974     @SystemApi
10975     @RequiresPermission(anyOf = {
10976             android.Manifest.permission.NETWORK_SETTINGS,
10977             android.Manifest.permission.NETWORK_STACK,
10978             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
getLastCallerInfoForApi(@piType int apiType, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<String, Boolean> resultsCallback)10979     public void getLastCallerInfoForApi(@ApiType int apiType,
10980             @NonNull @CallbackExecutor Executor executor,
10981             @NonNull BiConsumer<String, Boolean> resultsCallback) {
10982         if (executor == null) {
10983             throw new IllegalArgumentException("executor can't be null");
10984         }
10985         if (resultsCallback == null) {
10986             throw new IllegalArgumentException("resultsCallback can't be null");
10987         }
10988         try {
10989             mService.getLastCallerInfoForApi(apiType,
10990                     new ILastCallerListener.Stub() {
10991                         @Override
10992                         public void onResult(String packageName, boolean enabled) {
10993                             Binder.clearCallingIdentity();
10994                             executor.execute(() -> {
10995                                 resultsCallback.accept(packageName, enabled);
10996                             });
10997                         }
10998                     });
10999         } catch (RemoteException e) {
11000             throw e.rethrowFromSystemServer();
11001         }
11002     }
11003 
11004     /**
11005      * Set a callback for Wi-Fi connected network scorer.  See {@link WifiConnectedNetworkScorer}.
11006      * Only a single scorer can be set. Caller will be invoked periodically by framework to inform
11007      * client about start and stop of Wi-Fi connection. Caller can clear a previously set scorer
11008      * using {@link clearWifiConnectedNetworkScorer()}.
11009      *
11010      * @param executor The executor on which callback will be invoked.
11011      * @param scorer Scorer for Wi-Fi network implemented by application.
11012      * @return true Scorer is set successfully.
11013      *
11014      * @hide
11015      */
11016     @SystemApi
11017     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
setWifiConnectedNetworkScorer(@onNull @allbackExecutor Executor executor, @NonNull WifiConnectedNetworkScorer scorer)11018     public boolean setWifiConnectedNetworkScorer(@NonNull @CallbackExecutor Executor executor,
11019             @NonNull WifiConnectedNetworkScorer scorer) {
11020         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
11021         if (scorer == null) throw new IllegalArgumentException("scorer cannot be null");
11022         if (mVerboseLoggingEnabled) {
11023             Log.v(TAG, "setWifiConnectedNetworkScorer: scorer=" + scorer);
11024         }
11025         try {
11026             return mService.setWifiConnectedNetworkScorer(new Binder(),
11027                     new WifiConnectedNetworkScorerProxy(executor, scorer));
11028         } catch (RemoteException e) {
11029             throw e.rethrowFromSystemServer();
11030         }
11031     }
11032 
11033     /**
11034      * Allow caller to clear a previously set scorer. After calling this method,
11035      * client will no longer receive information about start and stop of Wi-Fi connection.
11036      *
11037      * @hide
11038      */
11039     @SystemApi
11040     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
clearWifiConnectedNetworkScorer()11041     public void clearWifiConnectedNetworkScorer() {
11042         if (mVerboseLoggingEnabled) {
11043             Log.v(TAG, "clearWifiConnectedNetworkScorer");
11044         }
11045         try {
11046             mService.clearWifiConnectedNetworkScorer();
11047         } catch (RemoteException e) {
11048             throw e.rethrowFromSystemServer();
11049         }
11050     }
11051 
11052     /**
11053      * Enable/disable wifi scan throttling from 3rd party apps.
11054      *
11055      * <p>
11056      * The throttling limits for apps are described in
11057      * <a href="Wi-Fi Scan Throttling">
11058      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
11059      * </p>
11060      *
11061      * @param enable true to allow scan throttling, false to disallow scan throttling.
11062      * @hide
11063      */
11064     @SystemApi
11065     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanThrottleEnabled(boolean enable)11066     public void setScanThrottleEnabled(boolean enable) {
11067         try {
11068             mService.setScanThrottleEnabled(enable);
11069         } catch (RemoteException e) {
11070             throw e.rethrowFromSystemServer();
11071         }
11072     }
11073 
11074     /**
11075      * Get the persisted Wi-Fi scan throttle state. Defaults to true, unless changed by the user via
11076      * Developer options.
11077      *
11078      * <p>
11079      * The throttling limits for apps are described in
11080      * <a href="Wi-Fi Scan Throttling">
11081      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
11082      * </p>
11083      *
11084      * @return true to indicate that scan throttling is enabled, false to indicate that scan
11085      * throttling is disabled.
11086      */
11087     @RequiresPermission(ACCESS_WIFI_STATE)
isScanThrottleEnabled()11088     public boolean isScanThrottleEnabled() {
11089         try {
11090             return mService.isScanThrottleEnabled();
11091         } catch (RemoteException e) {
11092             throw e.rethrowFromSystemServer();
11093         }
11094     }
11095 
11096     /**
11097      * Enable/disable wifi auto wakeup feature.
11098      *
11099      * <p>
11100      * The feature is described in
11101      * <a href="Wi-Fi Turn on automatically">
11102      * https://source.android.com/devices/tech/connect/wifi-infrastructure
11103      * #turn_on_wi-fi_automatically
11104      * </a>
11105      *
11106      * @param enable true to enable, false to disable.
11107      * @hide
11108      */
11109     @SystemApi
11110     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setAutoWakeupEnabled(boolean enable)11111     public void setAutoWakeupEnabled(boolean enable) {
11112         try {
11113             mService.setAutoWakeupEnabled(enable);
11114         } catch (RemoteException e) {
11115             throw e.rethrowFromSystemServer();
11116         }
11117     }
11118 
11119     /**
11120      * Get the persisted Wi-Fi auto wakeup feature state. Defaults to false, unless changed by the
11121      * user via Settings.
11122      *
11123      * <p>
11124      * The feature is described in
11125      * <a href="Wi-Fi Turn on automatically">
11126      * https://source.android.com/devices/tech/connect/wifi-infrastructure
11127      * #turn_on_wi-fi_automatically
11128      * </a>
11129      *
11130      * @return true to indicate that wakeup feature is enabled, false to indicate that wakeup
11131      * feature is disabled.
11132      */
11133     @RequiresPermission(ACCESS_WIFI_STATE)
isAutoWakeupEnabled()11134     public boolean isAutoWakeupEnabled() {
11135         try {
11136             return mService.isAutoWakeupEnabled();
11137         } catch (RemoteException e) {
11138             throw e.rethrowFromSystemServer();
11139         }
11140     }
11141 
11142     /**
11143      * Sets the state of carrier offload on merged or unmerged networks for specified subscription.
11144      *
11145      * <p>
11146      * When a subscription's carrier network offload is disabled, all network suggestions related to
11147      * this subscription will not be considered for auto join.
11148      * <p>
11149      * If calling app want disable all carrier network offload from a specified subscription, should
11150      * call this API twice to disable both merged and unmerged carrier network suggestions.
11151      *
11152      * @param subscriptionId See {@link SubscriptionInfo#getSubscriptionId()}.
11153      * @param merged True for carrier merged network, false otherwise.
11154      *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
11155      * @param enabled True for enable carrier network offload, false otherwise.
11156      * @see #isCarrierNetworkOffloadEnabled(int, boolean)
11157      * @hide
11158      */
11159     @SystemApi
11160     @RequiresPermission(anyOf = {
11161             android.Manifest.permission.NETWORK_SETTINGS,
11162             android.Manifest.permission.NETWORK_SETUP_WIZARD})
setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged, boolean enabled)11163     public void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged,
11164             boolean enabled) {
11165         try {
11166             mService.setCarrierNetworkOffloadEnabled(subscriptionId, merged, enabled);
11167         } catch (RemoteException e) {
11168             throw e.rethrowFromSystemServer();
11169         }
11170     }
11171 
11172     /**
11173      * Get the carrier network offload state for merged or unmerged networks for specified
11174      * subscription.
11175      * @param subscriptionId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
11176      * @param merged True for carrier merged network, false otherwise.
11177      *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
11178      * @return True to indicate that carrier network offload is enabled, false otherwise.
11179      */
11180     @RequiresPermission(ACCESS_WIFI_STATE)
isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged)11181     public boolean isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged) {
11182         try {
11183             return mService.isCarrierNetworkOffloadEnabled(subscriptionId, merged);
11184         } catch (RemoteException e) {
11185             throw e.rethrowFromSystemServer();
11186         }
11187     }
11188 
11189     /**
11190      * Interface for network suggestion user approval status change listener.
11191      * Should be implemented by applications and registered using
11192      * {@link #addSuggestionUserApprovalStatusListener(Executor,
11193      * SuggestionUserApprovalStatusListener)} (
11194      */
11195     public interface SuggestionUserApprovalStatusListener {
11196 
11197         /**
11198          * Called when the user approval status of the App has changed.
11199          * @param status The current status code for the user approval. One of the
11200          *               {@code STATUS_SUGGESTION_APPROVAL_} values.
11201          */
onUserApprovalStatusChange(@uggestionUserApprovalStatus int status)11202         void onUserApprovalStatusChange(@SuggestionUserApprovalStatus int status);
11203     }
11204 
11205     private class SuggestionUserApprovalStatusListenerProxy extends
11206             ISuggestionUserApprovalStatusListener.Stub {
11207         private final Executor mExecutor;
11208         private final SuggestionUserApprovalStatusListener mListener;
11209 
SuggestionUserApprovalStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionUserApprovalStatusListener listener)11210         SuggestionUserApprovalStatusListenerProxy(@NonNull Executor executor,
11211                 @NonNull SuggestionUserApprovalStatusListener listener) {
11212             mExecutor = executor;
11213             mListener = listener;
11214         }
11215 
11216         @Override
onUserApprovalStatusChange(int status)11217         public void onUserApprovalStatusChange(int status) {
11218             mExecutor.execute(() -> mListener.onUserApprovalStatusChange(status));
11219         }
11220 
11221     }
11222 
11223     /**
11224      * Add a listener for Wi-Fi network suggestion user approval status.
11225      * See {@link SuggestionUserApprovalStatusListener}.
11226      * Caller will receive a callback immediately after adding a listener and when the user approval
11227      * status of the caller has changed.
11228      * Caller can remove a previously registered listener using
11229      * {@link WifiManager#removeSuggestionUserApprovalStatusListener(
11230      * SuggestionUserApprovalStatusListener)}
11231      * A caller can add multiple listeners to monitor the event.
11232      * @param executor The executor to execute the listener of the {@code listener} object.
11233      * @param listener listener for suggestion user approval status changes.
11234      */
11235     @RequiresPermission(ACCESS_WIFI_STATE)
addSuggestionUserApprovalStatusListener( @onNull @allbackExecutor Executor executor, @NonNull SuggestionUserApprovalStatusListener listener)11236     public void addSuggestionUserApprovalStatusListener(
11237             @NonNull @CallbackExecutor Executor executor,
11238             @NonNull SuggestionUserApprovalStatusListener listener) {
11239         if (listener == null) throw new NullPointerException("Listener cannot be null");
11240         if (executor == null) throw new NullPointerException("Executor cannot be null");
11241         Log.v(TAG, "addSuggestionUserApprovalStatusListener listener=" + listener
11242                 + ", executor=" + executor);
11243         try {
11244             synchronized (sSuggestionUserApprovalStatusListenerMap) {
11245                 ISuggestionUserApprovalStatusListener.Stub binderCallback =
11246                         new SuggestionUserApprovalStatusListenerProxy(executor, listener);
11247                 sSuggestionUserApprovalStatusListenerMap.put(System.identityHashCode(listener),
11248                         binderCallback);
11249                 mService.addSuggestionUserApprovalStatusListener(binderCallback,
11250                         mContext.getOpPackageName());
11251             }
11252         } catch (RemoteException e) {
11253             throw e.rethrowFromSystemServer();
11254         }
11255 
11256     }
11257 
11258     /**
11259      * Allow callers to remove a previously registered listener using
11260      * {@link #addSuggestionUserApprovalStatusListener(Executor,
11261      * SuggestionUserApprovalStatusListener)}. After calling this method,
11262      * applications will no longer receive network suggestion user approval status change through
11263      * that listener.
11264      */
11265     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionUserApprovalStatusListener( @onNull SuggestionUserApprovalStatusListener listener)11266     public void removeSuggestionUserApprovalStatusListener(
11267             @NonNull SuggestionUserApprovalStatusListener listener) {
11268         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
11269         Log.v(TAG, "removeSuggestionUserApprovalStatusListener: listener=" + listener);
11270         try {
11271             synchronized (sSuggestionUserApprovalStatusListenerMap) {
11272                 int listenerIdentifier = System.identityHashCode(listener);
11273                 if (!sSuggestionUserApprovalStatusListenerMap.contains(listenerIdentifier)) {
11274                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
11275                     return;
11276                 }
11277                 mService.removeSuggestionUserApprovalStatusListener(
11278                         sSuggestionUserApprovalStatusListenerMap.get(listenerIdentifier),
11279                         mContext.getOpPackageName());
11280                 sSuggestionUserApprovalStatusListenerMap.remove(listenerIdentifier);
11281             }
11282         } catch (RemoteException e) {
11283             throw e.rethrowFromSystemServer();
11284         }
11285     }
11286 
11287     /**
11288      * Indicates the start/end of an emergency scan request being processed by {@link WifiScanner}.
11289      * The wifi stack should ensure that the wifi chip remains on for the duration of the scan.
11290      * WifiScanner detects emergency scan requests via
11291      * {@link WifiScanner.ScanSettings#ignoreLocationSettings} flag.
11292      *
11293      * If the wifi stack is off (because location & wifi toggles are off) when this indication is
11294      * received, the wifi stack will temporarily move to a scan only mode. Since location toggle
11295      * is off, only scan with
11296      * {@link WifiScanner.ScanSettings#ignoreLocationSettings} flag set will be
11297      * allowed to be processed for this duration.
11298      *
11299      * @hide
11300      */
11301     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
setEmergencyScanRequestInProgress(boolean inProgress)11302     public void setEmergencyScanRequestInProgress(boolean inProgress) {
11303         try {
11304             mService.setEmergencyScanRequestInProgress(inProgress);
11305         } catch (RemoteException e) {
11306             throw e.rethrowFromSystemServer();
11307         }
11308     }
11309 
11310     /**
11311      * Enable or disable Wi-Fi scoring.  Wi-Fi network status is evaluated by Wi-Fi scoring
11312      * {@link WifiScoreReport}. This API enables/disables Wi-Fi scoring to take action on network
11313      * selection.
11314      *
11315      * @param enabled {@code true} to enable, {@code false} to disable.
11316      * @return true The status of Wifi scoring is set successfully.
11317      * @hide
11318      */
11319     @SystemApi
11320     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setWifiScoringEnabled(boolean enabled)11321     public boolean setWifiScoringEnabled(boolean enabled) {
11322         if (mVerboseLoggingEnabled) {
11323             Log.v(TAG, "setWifiScoringEnabled: " + enabled);
11324         }
11325         try {
11326             return mService.setWifiScoringEnabled(enabled);
11327         } catch (RemoteException e) {
11328             throw e.rethrowFromSystemServer();
11329         }
11330     }
11331 
11332     /**
11333      * Flush Passpoint ANQP cache, and clear pending ANQP requests. Allows the caller to reset the
11334      * Passpoint ANQP state, if required.
11335      *
11336      * Notes:
11337      * 1. Flushing the ANQP cache may cause delays in discovering and connecting to Passpoint
11338      * networks.
11339      * 2. Intended to be used by Device Owner (DO), Profile Owner (PO), Settings and provisioning
11340      * apps.
11341      */
11342     @RequiresPermission(anyOf = {
11343             android.Manifest.permission.NETWORK_SETTINGS,
11344             android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
11345             android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
11346             }, conditional = true)
flushPasspointAnqpCache()11347     public void flushPasspointAnqpCache() {
11348         try {
11349             mService.flushPasspointAnqpCache(mContext.getOpPackageName());
11350         } catch (RemoteException e) {
11351             throw e.rethrowFromSystemServer();
11352         }
11353     }
11354 
11355     /**
11356      * Returns a list of {@link WifiAvailableChannel} for the specified band and operational
11357      * mode(s), that is allowed for the current regulatory domain. An empty list implies that there
11358      * are no available channels for use.
11359      *
11360      * Note: the {@code band} parameter which is specified as a {@code WifiScanner#WIFI_BAND_*}
11361      * constant is limited to one of the band values specified below. Specifically, if the 5GHz
11362      * band is included then it must include the DFS channels - an exception will be thrown
11363      * otherwise. The caller should not make any assumptions about whether DFS channels are allowed.
11364      * This API will indicate whether DFS channels are allowed for the specified operation mode(s)
11365      * per device policy.
11366      *
11367      * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
11368      *             constants.
11369      *             1. {@code WifiScanner#WIFI_BAND_UNSPECIFIED}=0 - no band specified; Looks for the
11370      *                channels in all the available bands - 2.4 GHz, 5 GHz, 6 GHz and 60 GHz
11371      *             2. {@code WifiScanner#WIFI_BAND_24_GHZ}=1
11372      *             3. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}=6
11373      *             4. {@code WifiScanner#WIFI_BAND_BOTH_WITH_DFS}=7
11374      *             5. {@code WifiScanner#WIFI_BAND_6_GHZ}=8
11375      *             6. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_GHZ}=15
11376      *             7. {@code WifiScanner#WIFI_BAND_60_GHZ}=16
11377      *             8. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_60_GHZ}=31
11378      * @param mode Bitwise OR of {@code WifiAvailableChannel#OP_MODE_*} constants
11379      *        e.g. {@link WifiAvailableChannel#OP_MODE_WIFI_AWARE}
11380      * @return a list of {@link WifiAvailableChannel}
11381      *
11382      * @throws UnsupportedOperationException - if this API is not supported on this device
11383      *         or IllegalArgumentException - if the band specified is not one among the list
11384      *         of bands mentioned above.
11385      */
11386     @RequiresApi(Build.VERSION_CODES.S)
11387     @NonNull
11388     @RequiresPermission(NEARBY_WIFI_DEVICES)
getAllowedChannels( int band, @WifiAvailableChannel.OpMode int mode)11389     public List<WifiAvailableChannel> getAllowedChannels(
11390             int band,
11391             @WifiAvailableChannel.OpMode int mode) {
11392         if (!SdkLevel.isAtLeastS()) {
11393             throw new UnsupportedOperationException();
11394         }
11395         try {
11396             Bundle extras = new Bundle();
11397             if (SdkLevel.isAtLeastS()) {
11398                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
11399                         mContext.getAttributionSource());
11400             }
11401             return mService.getUsableChannels(band, mode,
11402                     WifiAvailableChannel.FILTER_REGULATORY, mContext.getOpPackageName(), extras);
11403         } catch (RemoteException e) {
11404             throw e.rethrowFromSystemServer();
11405         }
11406     }
11407 
11408     /**
11409      * Returns a list of {@link WifiAvailableChannel} for the specified band and operational
11410      * mode(s) per the current regulatory domain and device-specific constraints such as concurrency
11411      * state and interference due to other radios. An empty list implies that there are no available
11412      * channels for use.
11413      *
11414      * Note: the {@code band} parameter which is specified as a {@code WifiScanner#WIFI_BAND_*}
11415      * constant is limited to one of the band values specified below. Specifically, if the 5GHz
11416      * band is included then it must include the DFS channels - an exception will be thrown
11417      * otherwise. The caller should not make any assumptions about whether DFS channels are allowed.
11418      * This API will indicate whether DFS channels are allowed for the specified operation mode(s)
11419      * per device policy.
11420      *
11421      * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
11422      *             constants.
11423      *             1. {@code WifiScanner#WIFI_BAND_UNSPECIFIED}=0 - no band specified; Looks for the
11424      *                channels in all the available bands - 2.4 GHz, 5 GHz, 6 GHz and 60 GHz
11425      *             2. {@code WifiScanner#WIFI_BAND_24_GHZ}=1
11426      *             3. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}=6
11427      *             4. {@code WifiScanner#WIFI_BAND_BOTH_WITH_DFS}=7
11428      *             5. {@code WifiScanner#WIFI_BAND_6_GHZ}=8
11429      *             6. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_GHZ}=15
11430      *             7. {@code WifiScanner#WIFI_BAND_60_GHZ}=16
11431      *             8. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_60_GHZ}=31
11432      * @param mode Bitwise OR of {@code WifiAvailableChannel#OP_MODE_*} constants
11433      *        e.g. {@link WifiAvailableChannel#OP_MODE_WIFI_AWARE}
11434      * @return a list of {@link WifiAvailableChannel}
11435      *
11436      * @throws UnsupportedOperationException - if this API is not supported on this device
11437      *         or IllegalArgumentException - if the band specified is not one among the list
11438      *         of bands mentioned above.
11439      */
11440     @RequiresApi(Build.VERSION_CODES.S)
11441     @NonNull
11442     @RequiresPermission(NEARBY_WIFI_DEVICES)
getUsableChannels( int band, @WifiAvailableChannel.OpMode int mode)11443     public List<WifiAvailableChannel> getUsableChannels(
11444             int band,
11445             @WifiAvailableChannel.OpMode int mode) {
11446         if (!SdkLevel.isAtLeastS()) {
11447             throw new UnsupportedOperationException();
11448         }
11449         try {
11450             Bundle extras = new Bundle();
11451             if (SdkLevel.isAtLeastS()) {
11452                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
11453                         mContext.getAttributionSource());
11454             }
11455             return mService.getUsableChannels(band, mode,
11456                     WifiAvailableChannel.getUsableFilter(), mContext.getOpPackageName(), extras);
11457         } catch (RemoteException e) {
11458             throw e.rethrowFromSystemServer();
11459         }
11460     }
11461 
11462     /**
11463      * If the device supports Wi-Fi Passpoint, the user can explicitly enable or disable it.
11464      * That status can be queried using this method.
11465      * @return {@code true} if Wi-Fi Passpoint is enabled
11466      *
11467      */
11468     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiPasspointEnabled()11469     public boolean isWifiPasspointEnabled() {
11470         try {
11471             return mService.isWifiPasspointEnabled();
11472         } catch (RemoteException e) {
11473             throw e.rethrowFromSystemServer();
11474         }
11475     }
11476 
11477     /**
11478      * Explicitly enable or disable Wi-Fi Passpoint as a global switch.
11479      * The global Passpoint enabling/disabling overrides individual configuration
11480      * enabling/disabling.
11481      * Passpoint global status can be queried by {@link WifiManager#isWifiPasspointEnabled }.
11482      *
11483      * @param enabled {@code true} to enable, {@code false} to disable.
11484      * @hide
11485      */
11486     @SystemApi
11487     @RequiresPermission(anyOf = {
11488             android.Manifest.permission.NETWORK_SETTINGS,
11489             android.Manifest.permission.NETWORK_SETUP_WIZARD
11490     })
setWifiPasspointEnabled(boolean enabled)11491     public void setWifiPasspointEnabled(boolean enabled) {
11492         if (mVerboseLoggingEnabled) {
11493             Log.v(TAG, "setWifiPasspointEnabled: " + enabled);
11494         }
11495         try {
11496             mService.setWifiPasspointEnabled(enabled);
11497         } catch (RemoteException e) {
11498             throw e.rethrowFromSystemServer();
11499         }
11500     }
11501 
11502     /**
11503      * The device may support concurrent connections to multiple internet-providing Wi-Fi
11504      * networks (APs) - that is indicated by
11505      * {@link WifiManager#isStaConcurrencyForMultiInternetSupported()}.
11506      * This method indicates whether or not the feature is currently enabled.
11507      * A value of {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DISABLED} indicates that the feature
11508      * is disabled, a value of {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DBS_AP} or
11509      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_MULTI_AP} indicates that the feature is enabled.
11510      *
11511      * The app can register to receive the corresponding Wi-Fi networks using the
11512      * {@link ConnectivityManager#registerNetworkCallback(NetworkRequest, NetworkCallback)} API with
11513      * a {@link WifiNetworkSpecifier} configured using the
11514      * {@link WifiNetworkSpecifier.Builder#setBand(int)} method.
11515      */
11516     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11517     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getStaConcurrencyForMultiInternetMode()11518     public @WifiMultiInternetMode int getStaConcurrencyForMultiInternetMode() {
11519         try {
11520             return mService.getStaConcurrencyForMultiInternetMode();
11521         } catch (RemoteException e) {
11522             throw e.rethrowFromSystemServer();
11523         }
11524     }
11525 
11526     /**
11527      * Check if the currently connected network meets the minimum required Wi-Fi security level set.
11528      * If not, the current network will be disconnected.
11529      *
11530      * @throws SecurityException if the caller does not have permission.
11531      * @hide
11532      */
11533     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11534     @SystemApi
11535     @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
notifyMinimumRequiredWifiSecurityLevelChanged(int level)11536     public void notifyMinimumRequiredWifiSecurityLevelChanged(int level) {
11537         if (mVerboseLoggingEnabled) {
11538             Log.v(TAG, "notifyMinimumRequiredWifiSecurityLevelChanged");
11539         }
11540         try {
11541             mService.notifyMinimumRequiredWifiSecurityLevelChanged(level);
11542         } catch (RemoteException e) {
11543             throw e.rethrowFromSystemServer();
11544         }
11545     }
11546 
11547     /**
11548      * Check if the currently connected network meets the Wi-Fi SSID policy set.
11549      * If not, the current network will be disconnected.
11550      *
11551      * @throws SecurityException if the caller does not have permission.
11552      * @hide
11553      */
11554     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11555     @SystemApi
11556     @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
notifyWifiSsidPolicyChanged(@onNull WifiSsidPolicy policy)11557     public void notifyWifiSsidPolicyChanged(@NonNull WifiSsidPolicy policy) {
11558         if (mVerboseLoggingEnabled) {
11559             Log.v(TAG, "notifyWifiSsidPolicyChanged");
11560         }
11561         try {
11562             if (policy != null) {
11563                 mService.notifyWifiSsidPolicyChanged(policy.getPolicyType(),
11564                         new ParceledListSlice<>(new ArrayList<>(policy.getSsids())));
11565             }
11566         } catch (RemoteException e) {
11567             throw e.rethrowFromSystemServer();
11568         }
11569     }
11570 
11571     /**
11572      * Configure whether or not concurrent multiple connections to internet-providing Wi-Fi
11573      * networks (AP) is enabled.
11574      * Use {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DISABLED} to disable, and either
11575      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DBS_AP} or
11576      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_MULTI_AP} to enable in different modes.
11577      * The {@link WifiManager#getStaConcurrencyForMultiInternetMode() } can be used to retrieve
11578      * the current mode.
11579      *
11580      * @param mode Multi internet mode.
11581      * @return true when the mode is set successfully, false when failed.
11582      * @hide
11583      */
11584     @SystemApi
11585     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11586     @RequiresPermission(anyOf = {
11587             android.Manifest.permission.NETWORK_SETTINGS,
11588             android.Manifest.permission.NETWORK_SETUP_WIZARD
11589     })
setStaConcurrencyForMultiInternetMode(@ifiMultiInternetMode int mode)11590     public boolean setStaConcurrencyForMultiInternetMode(@WifiMultiInternetMode int mode) {
11591         if (mVerboseLoggingEnabled) {
11592             Log.v(TAG, "setStaConcurrencyForMultiInternetMode: " + mode);
11593         }
11594         try {
11595             return mService.setStaConcurrencyForMultiInternetMode(mode);
11596         } catch (RemoteException e) {
11597             throw e.rethrowFromSystemServer();
11598         }
11599     }
11600 
11601     /**
11602      * Intent action to launch a dialog from the WifiDialog app.
11603      * Must include EXTRA_DIALOG_ID, EXTRA_DIALOG_TYPE, and appropriate extras for the dialog type.
11604      * @hide
11605      */
11606     public static final String ACTION_LAUNCH_DIALOG =
11607             "android.net.wifi.action.LAUNCH_DIALOG";
11608 
11609     /**
11610      * Intent action to dismiss an existing dialog from the WifiDialog app.
11611      * Must include EXTRA_DIALOG_ID.
11612      * @hide
11613      */
11614     public static final String ACTION_DISMISS_DIALOG =
11615             "android.net.wifi.action.DISMISS_DIALOG";
11616 
11617     /**
11618      * Unknown DialogType.
11619      * @hide
11620      */
11621     public static final int DIALOG_TYPE_UNKNOWN = 0;
11622 
11623     /**
11624      * DialogType for a simple dialog.
11625      * @see {@link com.android.server.wifi.WifiDialogManager#createSimpleDialog}
11626      * @hide
11627      */
11628     public static final int DIALOG_TYPE_SIMPLE = 1;
11629 
11630     /**
11631      * DialogType for a P2P Invitation Sent dialog.
11632      * @see {@link com.android.server.wifi.WifiDialogManager#createP2pInvitationSentDialog}
11633      * @hide
11634      */
11635     public static final int DIALOG_TYPE_P2P_INVITATION_SENT = 2;
11636 
11637     /**
11638      * DialogType for a P2P Invitation Received dialog.
11639      * @see {@link com.android.server.wifi.WifiDialogManager#createP2pInvitationReceivedDialog}
11640      * @hide
11641      */
11642     public static final int DIALOG_TYPE_P2P_INVITATION_RECEIVED = 3;
11643 
11644     /** @hide */
11645     @IntDef(prefix = { "DIALOG_TYPE_" }, value = {
11646             DIALOG_TYPE_UNKNOWN,
11647             DIALOG_TYPE_SIMPLE,
11648             DIALOG_TYPE_P2P_INVITATION_SENT,
11649             DIALOG_TYPE_P2P_INVITATION_RECEIVED,
11650     })
11651     @Retention(RetentionPolicy.SOURCE)
11652     public @interface DialogType {}
11653 
11654     /**
11655      * Dialog positive button was clicked.
11656      * @hide
11657      */
11658     public static final int DIALOG_REPLY_POSITIVE = 0;
11659 
11660     /**
11661      * Dialog negative button was clicked.
11662      * @hide
11663      */
11664     public static final int DIALOG_REPLY_NEGATIVE = 1;
11665 
11666     /**
11667      * Dialog neutral button was clicked.
11668      * @hide
11669      */
11670     public static final int DIALOG_REPLY_NEUTRAL = 2;
11671 
11672     /**
11673      * Dialog was cancelled.
11674      * @hide
11675      */
11676     public static final int DIALOG_REPLY_CANCELLED = 3;
11677 
11678     /**
11679      * Indication of a reply to a dialog.
11680      * See {@link WifiManager#replyToSimpleDialog(int, int)}
11681      * @hide
11682      */
11683     @IntDef(prefix = { "DIALOG_TYPE_" }, value = {
11684             DIALOG_REPLY_POSITIVE,
11685             DIALOG_REPLY_NEGATIVE,
11686             DIALOG_REPLY_NEUTRAL,
11687             DIALOG_REPLY_CANCELLED,
11688     })
11689     @Retention(RetentionPolicy.SOURCE)
11690     public @interface DialogReply {}
11691 
11692     /**
11693      * Invalid dialog id for dialogs that are not currently active.
11694      * @hide
11695      */
11696     public static final int INVALID_DIALOG_ID = -1;
11697 
11698     /**
11699      * Extra int indicating the type of dialog to display.
11700      * @hide
11701      */
11702     public static final String EXTRA_DIALOG_TYPE = "android.net.wifi.extra.DIALOG_TYPE";
11703 
11704     /**
11705      * Extra int indicating the ID of a dialog. The value must not be {@link #INVALID_DIALOG_ID}.
11706      * @hide
11707      */
11708     public static final String EXTRA_DIALOG_ID = "android.net.wifi.extra.DIALOG_ID";
11709 
11710     /**
11711      * Extra String indicating the title of a simple dialog.
11712      * @hide
11713      */
11714     public static final String EXTRA_DIALOG_TITLE = "android.net.wifi.extra.DIALOG_TITLE";
11715 
11716     /**
11717      * Extra String indicating the message of a simple dialog.
11718      * @hide
11719      */
11720     public static final String EXTRA_DIALOG_MESSAGE = "android.net.wifi.extra.DIALOG_MESSAGE";
11721 
11722     /**
11723      * Extra String indicating the message URL of a simple dialog.
11724      * @hide
11725      */
11726     public static final String EXTRA_DIALOG_MESSAGE_URL =
11727             "android.net.wifi.extra.DIALOG_MESSAGE_URL";
11728 
11729     /**
11730      * Extra String indicating the start index of a message URL span of a simple dialog.
11731      * @hide
11732      */
11733     public static final String EXTRA_DIALOG_MESSAGE_URL_START =
11734             "android.net.wifi.extra.DIALOG_MESSAGE_URL_START";
11735 
11736     /**
11737      * Extra String indicating the end index of a message URL span of a simple dialog.
11738      * @hide
11739      */
11740     public static final String EXTRA_DIALOG_MESSAGE_URL_END =
11741             "android.net.wifi.extra.DIALOG_MESSAGE_URL_END";
11742 
11743     /**
11744      * Extra String indicating the positive button text of a simple dialog.
11745      * @hide
11746      */
11747     public static final String EXTRA_DIALOG_POSITIVE_BUTTON_TEXT =
11748             "android.net.wifi.extra.DIALOG_POSITIVE_BUTTON_TEXT";
11749 
11750     /**
11751      * Extra String indicating the negative button text of a simple dialog.
11752      * @hide
11753      */
11754     public static final String EXTRA_DIALOG_NEGATIVE_BUTTON_TEXT =
11755             "android.net.wifi.extra.DIALOG_NEGATIVE_BUTTON_TEXT";
11756 
11757     /**
11758      * Extra String indicating the neutral button text of a simple dialog.
11759      * @hide
11760      */
11761     public static final String EXTRA_DIALOG_NEUTRAL_BUTTON_TEXT =
11762             "android.net.wifi.extra.DIALOG_NEUTRAL_BUTTON_TEXT";
11763 
11764     /**
11765      * Extra long indicating the timeout in milliseconds of a dialog.
11766      * @hide
11767      */
11768     public static final String EXTRA_DIALOG_TIMEOUT_MS = "android.net.wifi.extra.DIALOG_TIMEOUT_MS";
11769 
11770     /**
11771      * Extra String indicating a P2P device name for a P2P Invitation Sent/Received dialog.
11772      * @hide
11773      */
11774     public static final String EXTRA_P2P_DEVICE_NAME = "android.net.wifi.extra.P2P_DEVICE_NAME";
11775 
11776     /**
11777      * Extra boolean indicating that a PIN is requested for a P2P Invitation Received dialog.
11778      * @hide
11779      */
11780     public static final String EXTRA_P2P_PIN_REQUESTED = "android.net.wifi.extra.P2P_PIN_REQUESTED";
11781 
11782     /**
11783      * Extra String indicating the PIN to be displayed for a P2P Invitation Sent/Received dialog.
11784      * @hide
11785      */
11786     public static final String EXTRA_P2P_DISPLAY_PIN = "android.net.wifi.extra.P2P_DISPLAY_PIN";
11787 
11788     /**
11789      * Extra boolean indicating ACTION_CLOSE_SYSTEM_DIALOGS should not close the Wi-Fi dialogs.
11790      * @hide
11791      */
11792     public static final String EXTRA_CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI =
11793             "android.net.wifi.extra.CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI";
11794 
11795     /**
11796      * Returns a set of packages that aren't DO or PO but should be able to manage WiFi networks.
11797      * @hide
11798      */
11799     @SystemApi
11800     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
11801     @NonNull
getOemPrivilegedWifiAdminPackages()11802     public Set<String> getOemPrivilegedWifiAdminPackages() {
11803         try {
11804             return new ArraySet<>(mService.getOemPrivilegedWifiAdminPackages());
11805         } catch (RemoteException e) {
11806             throw e.rethrowFromSystemServer();
11807         }
11808     }
11809 
11810     /**
11811      * Method for WifiDialog to notify the framework of a reply to a simple dialog.
11812      * @param dialogId id of the replying dialog.
11813      * @param reply reply of the dialog.
11814      * @hide
11815      */
replyToSimpleDialog(int dialogId, @DialogReply int reply)11816     public void replyToSimpleDialog(int dialogId, @DialogReply int reply) {
11817         if (mVerboseLoggingEnabled) {
11818             Log.v(TAG, "replyToWifiEnableRequestDialog: dialogId=" + dialogId
11819                     + " reply=" + reply);
11820         }
11821         try {
11822             mService.replyToSimpleDialog(dialogId, reply);
11823         } catch (RemoteException e) {
11824             throw e.rethrowFromSystemServer();
11825         }
11826     }
11827 
11828     /**
11829      * Method for WifiDialog to notify the framework of a reply to a P2P Invitation Received dialog.
11830      * @param dialogId id of the replying dialog.
11831      * @param accepted Whether the invitation was accepted.
11832      * @param optionalPin PIN of the reply, or {@code null} if none was supplied.
11833      * @hide
11834      */
replyToP2pInvitationReceivedDialog( int dialogId, boolean accepted, @Nullable String optionalPin)11835     public void replyToP2pInvitationReceivedDialog(
11836             int dialogId, boolean accepted, @Nullable String optionalPin) {
11837         if (mVerboseLoggingEnabled) {
11838             Log.v(TAG, "replyToP2pInvitationReceivedDialog: "
11839                     + "dialogId=" + dialogId
11840                     + ", accepted=" + accepted
11841                     + ", pin=" + optionalPin);
11842         }
11843         try {
11844             mService.replyToP2pInvitationReceivedDialog(dialogId, accepted, optionalPin);
11845         } catch (RemoteException e) {
11846             throw e.rethrowFromSystemServer();
11847         }
11848     }
11849 
11850     /**
11851      * Specify a list of DHCP options to use for any network whose SSID is specified and which
11852      * transmits vendor-specific information elements (VSIEs) using the specified Organizationally
11853      * Unique Identifier (OUI). If the AP transmits VSIEs for multiple specified OUIs then all
11854      * matching DHCP options will be used. The allowlist for DHCP options in
11855      * {@link android.net.ip.IpClient} gates whether the DHCP options will actually be used.
11856      * When DHCP options are used: if the option value {@link android.net.DhcpOption#getValue()}
11857      * is null, the option type {@link android.net.DhcpOption#getType()} will be put in the
11858      * Parameter Request List in the DHCP packets; otherwise, the option will be included in the
11859      * options section in the DHCP packets. Use {@link #removeCustomDhcpOptions(Object, Object)}
11860      * to remove the specified DHCP options.
11861      *
11862      * @param ssid the network SSID.
11863      * @param oui the 3-byte OUI.
11864      * @param options the list of {@link android.net.DhcpOption}.
11865      *
11866      * @hide
11867      */
11868     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
11869     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11870     @RequiresPermission(anyOf = {
11871             android.Manifest.permission.NETWORK_SETTINGS,
11872             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
11873     })
addCustomDhcpOptions(@onNull WifiSsid ssid, @NonNull byte[] oui, @NonNull List<DhcpOption> options)11874     public void addCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui,
11875             @NonNull List<DhcpOption> options) {
11876         try {
11877             mService.addCustomDhcpOptions(ssid, oui, new ParceledListSlice<>(options));
11878         } catch (RemoteException e) {
11879             throw e.rethrowFromSystemServer();
11880         }
11881     }
11882 
11883     /**
11884      * Remove custom DHCP options specified by {@link #addCustomDhcpOptions(Object, Object, List)}.
11885      *
11886      * @param ssid the network SSID.
11887      * @param oui the 3-byte OUI.
11888      *
11889      * @hide
11890      */
11891     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
11892     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11893     @RequiresPermission(anyOf = {
11894             android.Manifest.permission.NETWORK_SETTINGS,
11895             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
11896     })
removeCustomDhcpOptions(@onNull WifiSsid ssid, @NonNull byte[] oui)11897     public void removeCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui) {
11898         try {
11899             mService.removeCustomDhcpOptions(ssid, oui);
11900         } catch (RemoteException e) {
11901             throw e.rethrowFromSystemServer();
11902         }
11903     }
11904 
11905     /**
11906      * Wi-Fi interface of type STA (station/client Wi-Fi infrastructure device).
11907      */
11908     public static final int WIFI_INTERFACE_TYPE_STA = 0;
11909 
11910     /**
11911      * Wi-Fi interface of type AP (access point Wi-Fi infrastructure device).
11912      */
11913     public static final int WIFI_INTERFACE_TYPE_AP = 1;
11914 
11915     /**
11916      * Wi-Fi interface of type Wi-Fi Aware (aka NAN).
11917      */
11918     public static final int WIFI_INTERFACE_TYPE_AWARE = 2;
11919 
11920     /**
11921      * Wi-Fi interface of type Wi-Fi Direct (aka P2P).
11922      */
11923     public static final int WIFI_INTERFACE_TYPE_DIRECT = 3;
11924 
11925     /** @hide */
11926     @IntDef(prefix = { "WIFI_INTERFACE_TYPE_" }, value = {
11927             WIFI_INTERFACE_TYPE_STA,
11928             WIFI_INTERFACE_TYPE_AP,
11929             WIFI_INTERFACE_TYPE_AWARE,
11930             WIFI_INTERFACE_TYPE_DIRECT,
11931     })
11932     @Retention(RetentionPolicy.SOURCE)
11933     public @interface WifiInterfaceType {}
11934 
11935     /**
11936      * Class describing an impact of interface creation - returned by
11937      * {@link #reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)}. Due to Wi-Fi
11938      * concurrency limitations certain interfaces may have to be torn down. Each of these
11939      * interfaces was requested by a set of applications who could potentially be impacted.
11940      *
11941      * This class contain the information for a single interface: the interface type with
11942      * {@link InterfaceCreationImpact#getInterfaceType()} and the set of impacted packages
11943      * with {@link InterfaceCreationImpact#getPackages()}.
11944      */
11945     public static class InterfaceCreationImpact {
11946         private final int mInterfaceType;
11947         private final Set<String> mPackages;
11948 
InterfaceCreationImpact(@ifiInterfaceType int interfaceType, @NonNull Set<String> packages)11949         public InterfaceCreationImpact(@WifiInterfaceType int interfaceType,
11950                 @NonNull Set<String> packages) {
11951             mInterfaceType = interfaceType;
11952             mPackages = packages;
11953         }
11954 
11955         /**
11956          * @return The interface type which will be torn down to make room for the interface
11957          * requested in {@link #reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)}.
11958          */
getInterfaceType()11959         public @WifiInterfaceType int getInterfaceType() {
11960             return mInterfaceType;
11961         }
11962 
11963         /**
11964          * @return The list of potentially impacted packages due to tearing down the interface
11965          * specified in {@link #getInterfaceType()}.
11966          */
getPackages()11967         public @NonNull Set<String> getPackages() {
11968             return mPackages;
11969         }
11970 
11971         @Override
hashCode()11972         public int hashCode() {
11973             return Objects.hash(mInterfaceType, mPackages);
11974         }
11975 
11976         @Override
equals(Object that)11977         public boolean equals(Object that) {
11978             if (this == that) return true;
11979             if (!(that instanceof InterfaceCreationImpact)) return false;
11980             InterfaceCreationImpact thatInterfaceCreationImpact = (InterfaceCreationImpact) that;
11981 
11982             return this.mInterfaceType == thatInterfaceCreationImpact.mInterfaceType
11983                     && Objects.equals(this.mPackages, thatInterfaceCreationImpact.mPackages);
11984         }
11985     }
11986 
11987     /**
11988      * Queries the framework to determine whether the specified interface can be created, and if
11989      * so - what other interfaces would be torn down by the framework to allow this creation if
11990      * it were requested. The result is returned via the specified {@link BiConsumer} callback
11991      * which returns two arguments:
11992      * <li>First argument: a {@code boolean} - indicating whether or not the interface can be
11993      * created.</li>
11994      * <li>Second argument: a {@code Set<InterfaceCreationImpact>} - if the interface can be
11995      * created (first argument is {@code true} then this is the set of interface types which
11996      * will be removed and the packages which requested them. Possibly an empty set. If the
11997      * first argument is {@code false}, then an empty set will be returned here.</li>
11998      * <p>
11999      * Interfaces, input and output, are specified using the {@code WIFI_INTERFACE_*} constants:
12000      * {@link #WIFI_INTERFACE_TYPE_STA}, {@link #WIFI_INTERFACE_TYPE_AP},
12001      * {@link #WIFI_INTERFACE_TYPE_AWARE}, or {@link #WIFI_INTERFACE_TYPE_DIRECT}.
12002      * <p>
12003      * This method does not actually create the interface. That operation is handled by the
12004      * framework when a particular service method is called. E.g. a Wi-Fi Direct interface may be
12005      * created when various methods of {@link android.net.wifi.p2p.WifiP2pManager} are called,
12006      * similarly for Wi-Fi Aware and {@link android.net.wifi.aware.WifiAwareManager}.
12007      * <p>
12008      * Note: the information returned via this method is the current snapshot of the system. It may
12009      * change due to actions of the framework or other apps.
12010      *
12011      * @param interfaceType The interface type whose possible creation is being queried.
12012      * @param requireNewInterface Indicates that the query is for a new interface of the specified
12013      *                             type - an existing interface won't meet the query. Some
12014      *                             operations (such as Wi-Fi Direct and Wi-Fi Aware are a shared
12015      *                             resource and so may not need a new interface).
12016      * @param executor An {@link Executor} on which to return the result.
12017      * @param resultCallback The asynchronous callback which will return two argument: a
12018      * {@code boolean} (whether the interface can be created), and a
12019      * {@code Set<InterfaceCreationImpact>} (a set of {@link InterfaceCreationImpact}:
12020      *                       interfaces which will be destroyed when the interface is created
12021      *                       and the packages which requested them and thus may be impacted).
12022      */
12023     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
12024     @RequiresPermission(allOf = {android.Manifest.permission.MANAGE_WIFI_INTERFACES,
12025             ACCESS_WIFI_STATE})
reportCreateInterfaceImpact(@ifiInterfaceType int interfaceType, boolean requireNewInterface, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<Boolean, Set<InterfaceCreationImpact>> resultCallback)12026     public void reportCreateInterfaceImpact(@WifiInterfaceType int interfaceType,
12027             boolean requireNewInterface,
12028             @NonNull @CallbackExecutor Executor executor,
12029             @NonNull BiConsumer<Boolean, Set<InterfaceCreationImpact>> resultCallback) {
12030         Objects.requireNonNull(executor, "Non-null executor required");
12031         Objects.requireNonNull(resultCallback, "Non-null resultCallback required");
12032         try {
12033             mService.reportCreateInterfaceImpact(mContext.getOpPackageName(), interfaceType,
12034                     requireNewInterface, new IInterfaceCreationInfoCallback.Stub() {
12035                         @Override
12036                         public void onResults(boolean canCreate, int[] interfacesToDelete,
12037                                 String[] packagesForInterfaces) {
12038                             Binder.clearCallingIdentity();
12039                             if ((interfacesToDelete == null && packagesForInterfaces != null)
12040                                     || (interfacesToDelete != null
12041                                     && packagesForInterfaces == null) || (canCreate && (
12042                                     interfacesToDelete == null || interfacesToDelete.length
12043                                             != packagesForInterfaces.length))) {
12044                                 Log.e(TAG,
12045                                         "reportImpactToCreateIfaceRequest: Invalid callback "
12046                                                 + "parameters - canCreate="
12047                                                 + canCreate + ", interfacesToDelete="
12048                                                 + Arrays.toString(interfacesToDelete)
12049                                                 + ", worksourcesForInterfaces="
12050                                                 + Arrays.toString(packagesForInterfaces));
12051                                 return;
12052                             }
12053 
12054                             final Set<InterfaceCreationImpact> finalSet =
12055                                     (canCreate && interfacesToDelete.length > 0) ? new ArraySet<>()
12056                                             : Collections.emptySet();
12057                             if (canCreate) {
12058                                 for (int i = 0; i < interfacesToDelete.length; ++i) {
12059                                     finalSet.add(
12060                                             new InterfaceCreationImpact(interfacesToDelete[i],
12061                                                     packagesForInterfaces[i] == null
12062                                                             ? Collections.emptySet()
12063                                                             : new ArraySet<>(
12064                                                                     packagesForInterfaces[i]
12065                                                                             .split(","))));
12066                                 }
12067                             }
12068                             executor.execute(() -> resultCallback.accept(canCreate, finalSet));
12069                         }
12070                     });
12071         } catch (RemoteException e) {
12072             throw e.rethrowFromSystemServer();
12073         }
12074     }
12075 
12076     /**
12077      * Returns the max number of channels that is allowed to be set on a
12078      * {@link WifiNetworkSpecifier}.
12079      * @see WifiNetworkSpecifier.Builder#setPreferredChannelsFrequenciesMhz(int[])
12080      *
12081      * @return The max number of channels can be set on a request.
12082      */
12083 
getMaxNumberOfChannelsPerNetworkSpecifierRequest()12084     public int getMaxNumberOfChannelsPerNetworkSpecifierRequest() {
12085         try {
12086             return mService.getMaxNumberOfChannelsPerRequest();
12087         } catch (RemoteException e) {
12088             throw e.rethrowFromSystemServer();
12089         }
12090     }
12091 
12092     /**
12093      * Add a list of new application-initiated QoS policies.
12094      *
12095      * Note: Policies are managed using a policy ID, which can be retrieved using
12096      *       {@link QosPolicyParams#getPolicyId()}. This ID can be used when removing a policy via
12097      *       {@link #removeQosPolicies(int[])}. The caller is in charge of assigning and managing
12098      *       the policy IDs for any requested policies.
12099      *
12100      * Note: Policies with duplicate IDs are not allowed. To update an existing policy, first
12101      *       remove it using {@link #removeQosPolicies(int[])}, and then re-add it using this API.
12102      *
12103      * Note: All policies in a single request must have the same {@link QosPolicyParams.Direction}.
12104      *
12105      * Note: Support for the {@link QosPolicyParams#DIRECTION_UPLINK} direction is added in
12106      *       {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}. For earlier releases,
12107      *       only the {@link QosPolicyParams#DIRECTION_DOWNLINK} direction is supported.
12108      *
12109      * @param policyParamsList List of {@link QosPolicyParams} objects describing the requested
12110      *                         policies. Must have a maximum length of
12111      *                         {@link #getMaxNumberOfPoliciesPerQosRequest()}.
12112      * @param executor The executor on which callback will be invoked.
12113      * @param resultsCallback An asynchronous callback that will return a list of integer status
12114      *                        codes from {@link QosRequestStatus}. Result list will be the same
12115      *                        length as the input list, and each status code will correspond to
12116      *                        the policy at that index in the input list.
12117      *
12118      * @throws SecurityException if caller does not have the required permissions.
12119      * @throws NullPointerException if the caller provided a null input.
12120      * @throws UnsupportedOperationException if the feature is not enabled.
12121      * @throws IllegalArgumentException if the input list is invalid.
12122      * @hide
12123      */
12124     @SystemApi
12125     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12126     @RequiresPermission(anyOf = {
12127             android.Manifest.permission.NETWORK_SETTINGS,
12128             MANAGE_WIFI_NETWORK_SELECTION
12129     })
addQosPolicies(@onNull List<QosPolicyParams> policyParamsList, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<List<Integer>> resultsCallback)12130     public void addQosPolicies(@NonNull List<QosPolicyParams> policyParamsList,
12131             @NonNull @CallbackExecutor Executor executor,
12132             @NonNull Consumer<List<Integer>> resultsCallback) {
12133         Objects.requireNonNull(policyParamsList, "policyParamsList cannot be null");
12134         Objects.requireNonNull(executor, "executor cannot be null");
12135         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12136         try {
12137             mService.addQosPolicies(new ParceledListSlice<>(policyParamsList),
12138                     new Binder(), mContext.getOpPackageName(),
12139                     new IListListener.Stub() {
12140                         @Override
12141                         public void onResult(List value) {
12142                             Binder.clearCallingIdentity();
12143                             executor.execute(() -> {
12144                                 resultsCallback.accept(value);
12145                             });
12146                         }
12147                     });
12148         } catch (RemoteException e) {
12149             throw e.rethrowFromSystemServer();
12150         }
12151     }
12152 
12153     /**
12154      * Remove a list of existing application-initiated QoS policies, previously added via
12155      * {@link #addQosPolicies(List, Executor, Consumer)}.
12156      *
12157      * Note: Policies are identified by their policy IDs, which are assigned by the caller. The ID
12158      *       for a given policy can be retrieved using {@link QosPolicyParams#getPolicyId()}.
12159      *
12160      * @param policyIdList List of policy IDs corresponding to the policies to remove. Must have
12161      *                     a maximum length of {@link #getMaxNumberOfPoliciesPerQosRequest()}.
12162      * @throws SecurityException if caller does not have the required permissions.
12163      * @throws NullPointerException if the caller provided a null input.
12164      * @throws IllegalArgumentException if the input list is invalid.
12165      * @hide
12166      */
12167     @SystemApi
12168     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12169     @RequiresPermission(anyOf = {
12170             android.Manifest.permission.NETWORK_SETTINGS,
12171             MANAGE_WIFI_NETWORK_SELECTION
12172     })
removeQosPolicies(@onNull int[] policyIdList)12173     public void removeQosPolicies(@NonNull int[] policyIdList) {
12174         Objects.requireNonNull(policyIdList, "policyIdList cannot be null");
12175         try {
12176             mService.removeQosPolicies(policyIdList, mContext.getOpPackageName());
12177         } catch (RemoteException e) {
12178             throw e.rethrowFromSystemServer();
12179         }
12180     }
12181 
12182     /**
12183      * Remove all application-initiated QoS policies requested by this caller,
12184      * previously added via {@link #addQosPolicies(List, Executor, Consumer)}.
12185      *
12186      * @throws SecurityException if caller does not have the required permissions.
12187      * @hide
12188      */
12189     @SystemApi
12190     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12191     @RequiresPermission(anyOf = {
12192             android.Manifest.permission.NETWORK_SETTINGS,
12193             MANAGE_WIFI_NETWORK_SELECTION
12194     })
removeAllQosPolicies()12195     public void removeAllQosPolicies() {
12196         try {
12197             mService.removeAllQosPolicies(mContext.getOpPackageName());
12198         } catch (RemoteException e) {
12199             throw e.rethrowFromSystemServer();
12200         }
12201     }
12202 
12203     /**
12204      * Set the link layer stats polling interval, in milliseconds.
12205      *
12206      * @param intervalMs a non-negative integer, for the link layer stats polling interval
12207      *                   in milliseconds.
12208      *                   To set a fixed interval, use a positive value.
12209      *                   For automatic handling of the interval, use value 0
12210      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
12211      * @throws SecurityException if the caller does not have permission.
12212      * @throws IllegalArgumentException if input is invalid.
12213      * @hide
12214      */
12215     @SystemApi
12216     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
12217     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
setLinkLayerStatsPollingInterval(@ntRange from = 0) int intervalMs)12218     public void setLinkLayerStatsPollingInterval(@IntRange (from = 0) int intervalMs) {
12219         try {
12220             mService.setLinkLayerStatsPollingInterval(intervalMs);
12221         } catch (RemoteException e) {
12222             throw e.rethrowFromSystemServer();
12223         }
12224     }
12225 
12226     /**
12227      * Get the link layer stats polling interval, in milliseconds.
12228      *
12229      * @param executor The executor on which callback will be invoked.
12230      * @param resultsCallback An asynchronous callback that will return current
12231      *                        link layer stats polling interval in milliseconds.
12232      *
12233      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
12234      * @throws SecurityException if the caller does not have permission.
12235      * @throws NullPointerException if the caller provided invalid inputs.
12236      * @hide
12237      */
12238     @SystemApi
12239     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
12240     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
getLinkLayerStatsPollingInterval(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12241     public void getLinkLayerStatsPollingInterval(@NonNull @CallbackExecutor Executor executor,
12242             @NonNull Consumer<Integer> resultsCallback) {
12243         Objects.requireNonNull(executor, "executor cannot be null");
12244         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12245         try {
12246             mService.getLinkLayerStatsPollingInterval(
12247                     new IIntegerListener.Stub() {
12248                         @Override
12249                         public void onResult(int value) {
12250                             Binder.clearCallingIdentity();
12251                             executor.execute(() -> {
12252                                 resultsCallback.accept(value);
12253                             });
12254                         }
12255                     });
12256         } catch (RemoteException e) {
12257             throw e.rethrowFromSystemServer();
12258         }
12259     }
12260 
12261     /**
12262      * This API allows a privileged application to set Multi-Link Operation mode.
12263      *
12264      * Multi-link operation (MLO) will allow Wi-Fi devices to operate on multiple links at the same
12265      * time through a single connection, aiming to support applications that require lower latency,
12266      * and higher capacity. Chip vendors have algorithms that run on the chip to use available links
12267      * based on incoming traffic and various inputs. This API allows system application to give a
12268      * suggestion to such algorithms on its preference using {@link MloMode}.
12269      *
12270      *
12271      * @param mode Refer {@link MloMode} for supported modes.
12272      * @param executor The executor on which callback will be invoked.
12273      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
12274      *                        whether the MLO mode is successfully set or not.
12275      * @throws IllegalArgumentException if mode value is not in {@link MloMode}.
12276      * @throws NullPointerException if the caller provided a null input.
12277      * @throws SecurityException if caller does not have the required permissions.
12278      * @throws UnsupportedOperationException if the set operation is not supported on this SDK.
12279      * @hide
12280      */
12281     @SystemApi
12282     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12283     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
setMloMode(@loMode int mode, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)12284     public void setMloMode(@MloMode int mode, @NonNull @CallbackExecutor Executor executor,
12285             @NonNull Consumer<Boolean> resultsCallback) {
12286 
12287         if (mode < MLO_MODE_DEFAULT || mode > MLO_MODE_LOW_POWER) {
12288             throw new IllegalArgumentException("invalid mode: " + mode);
12289         }
12290         Objects.requireNonNull(executor, "executor cannot be null");
12291         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12292         try {
12293             mService.setMloMode(mode, new IBooleanListener.Stub() {
12294                 @Override
12295                 public void onResult(boolean value) {
12296                     Binder.clearCallingIdentity();
12297                     executor.execute(() -> {
12298                         resultsCallback.accept(value);
12299                     });
12300                 }
12301             });
12302         } catch (RemoteException e) {
12303             throw e.rethrowFromSystemServer();
12304         }
12305     }
12306 
12307     /**
12308      * This API allows a privileged application to get Multi-Link Operation mode. Refer
12309      * {@link WifiManager#setMloMode(int, Executor, Consumer)}  for more details.
12310      *
12311      * @param executor The executor on which callback will be invoked.
12312      * @param resultsCallback An asynchronous callback that will return current MLO mode. Returns
12313      *                        {@link MloMode#MLO_MODE_DEFAULT} if information is not available,
12314      *                        e.g. if the driver/firmware doesn't provide this information.
12315      * @throws NullPointerException if the caller provided a null input.
12316      * @throws SecurityException if caller does not have the required permissions.
12317      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
12318      * @hide
12319      */
12320     @SystemApi
12321     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12322     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMloMode(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12323     public void getMloMode(@NonNull @CallbackExecutor Executor executor,
12324             @NonNull Consumer<Integer> resultsCallback) {
12325         Objects.requireNonNull(executor, "executor cannot be null");
12326         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12327         try {
12328             mService.getMloMode(new IIntegerListener.Stub() {
12329                 @Override
12330                 public void onResult(int value) {
12331                     Binder.clearCallingIdentity();
12332                     executor.execute(() -> {
12333                         resultsCallback.accept(value);
12334                     });
12335                 }
12336             });
12337         } catch (RemoteException e) {
12338             throw e.rethrowFromSystemServer();
12339         }
12340     }
12341 
12342     /**
12343      * Get the maximum number of links supported by the chip for MLO association. e.g. if the Wi-Fi
12344      * chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous Transmit and
12345      * Receive) with following capabilities,
12346      * - Max MLO assoc link count = 3.
12347      * - Max MLO STR link count   = 2. See
12348      * {@link WifiManager#getMaxMloStrLinkCount(Executor, Consumer)}
12349      * One of the possible configuration is - STR (2.4 GHz , eMLSR(5 GHz, 6 GHz)), provided the
12350      * radio combination of the chip supports it.
12351      *
12352      * @param executor        The executor on which callback will be invoked.
12353      * @param resultsCallback An asynchronous callback that will return maximum MLO association link
12354      *                        count supported by the chip or -1 if error or not available.
12355      * @throws NullPointerException          if the caller provided a null input.
12356      * @throws SecurityException             if caller does not have the required permissions.
12357      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
12358      * @hide
12359      */
12360     @SystemApi
12361     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12362     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12363     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMaxMloAssociationLinkCount(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12364     public void getMaxMloAssociationLinkCount(@NonNull @CallbackExecutor Executor executor,
12365             @NonNull Consumer<Integer> resultsCallback) {
12366         Objects.requireNonNull(executor, "executor cannot be null");
12367         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12368         try {
12369             Bundle extras = new Bundle();
12370             if (SdkLevel.isAtLeastS()) {
12371                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12372                         mContext.getAttributionSource());
12373             }
12374             mService.getMaxMloAssociationLinkCount(new IIntegerListener.Stub() {
12375                 @Override
12376                 public void onResult(int value) {
12377                     Binder.clearCallingIdentity();
12378                     executor.execute(() -> {
12379                         resultsCallback.accept(value);
12380                     });
12381                 }
12382             }, extras);
12383         } catch (RemoteException e) {
12384             throw e.rethrowFromSystemServer();
12385         }
12386     }
12387 
12388     /**
12389      * Get the maximum number of STR links used in Multi-Link Operation. The maximum number of STR
12390      * links used for MLO can be different from the number of radios supported by the chip. e.g. if
12391      * the Wi-Fi chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous
12392      * Transmit and Receive) with following capabilities,
12393      * - Max MLO assoc link count = 3. See
12394      *   {@link WifiManager#getMaxMloAssociationLinkCount(Executor, Consumer)}.
12395      * - Max MLO STR link count   = 2.
12396      * One of the possible configuration is - STR (2.4 GHz, eMLSR(5 GHz, 6 GHz)), provided the radio
12397      * combination of the chip supports it.
12398      *
12399      * @param executor The executor on which callback will be invoked.
12400      * @param resultsCallback An asynchronous callback that will return maximum STR link count
12401      *                       supported by the chip in MLO mode or -1 if error or not available.
12402      * @throws NullPointerException if the caller provided a null input.
12403      * @throws SecurityException if caller does not have the required permissions.
12404      * @throws UnsupportedOperationException if the get operation is not supported on this SDK
12405      * @hide
12406      */
12407     @SystemApi
12408     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12409     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12410     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMaxMloStrLinkCount(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12411     public void getMaxMloStrLinkCount(@NonNull @CallbackExecutor Executor executor,
12412             @NonNull Consumer<Integer> resultsCallback) {
12413         Objects.requireNonNull(executor, "executor cannot be null");
12414         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12415         try {
12416             Bundle extras = new Bundle();
12417             if (SdkLevel.isAtLeastS()) {
12418                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12419                         mContext.getAttributionSource());
12420             }
12421             mService.getMaxMloStrLinkCount(new IIntegerListener.Stub() {
12422                 @Override
12423                 public void onResult(int value) {
12424                     Binder.clearCallingIdentity();
12425                     executor.execute(() -> {
12426                         resultsCallback.accept(value);
12427                     });
12428                 }
12429             }, extras);
12430         } catch (RemoteException e) {
12431             throw e.rethrowFromSystemServer();
12432         }
12433     }
12434 
12435     /**
12436      * Get the set of band combinations supported simultaneously by the Wi-Fi Chip.
12437      *
12438      * Note: This method returns simultaneous band operation combination and not multichannel
12439      * concurrent operation (MCC) combination.
12440      *
12441      * @param executor The executor on which callback will be invoked.
12442      * @param resultsCallback An asynchronous callback that will return a list of possible
12443      *                        simultaneous band combinations supported by the chip or empty list if
12444      *                        not available. Band value is defined in {@link WifiScanner.WifiBand}.
12445      * @throws NullPointerException if the caller provided a null input.
12446      * @throws SecurityException if caller does not have the required permissions.
12447      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
12448      * @hide
12449      */
12450     @SystemApi
12451     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12452     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12453     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getSupportedSimultaneousBandCombinations( @onNull @allbackExecutor Executor executor, @NonNull Consumer<List<int[]>> resultsCallback)12454     public void getSupportedSimultaneousBandCombinations(
12455             @NonNull @CallbackExecutor Executor executor,
12456             @NonNull Consumer<List<int[]>> resultsCallback) {
12457         Objects.requireNonNull(executor, "executor cannot be null");
12458         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12459         try {
12460             Bundle extras = new Bundle();
12461             if (SdkLevel.isAtLeastS()) {
12462                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12463                         mContext.getAttributionSource());
12464             }
12465             mService.getSupportedSimultaneousBandCombinations(new IWifiBandsListener.Stub() {
12466                 @Override
12467                 public void onResult(WifiBands[] supportedBands) {
12468                     Binder.clearCallingIdentity();
12469                     List<int[]> bandCombinations = new ArrayList<>();
12470                     for (WifiBands wifiBands : supportedBands) {
12471                         bandCombinations.add(wifiBands.bands);
12472                     }
12473                     executor.execute(() -> {
12474                         resultsCallback.accept(bandCombinations);
12475                     });
12476                 }
12477             }, extras);
12478         } catch (RemoteException e) {
12479             throw e.rethrowFromSystemServer();
12480         }
12481     }
12482 
12483     /**
12484      * This API allows a privileged application to set whether or not this device allows
12485      * connections to Wi-Fi WEP networks.
12486      *
12487      * Note: The WEP connections may not work even if caller invokes this method with {@code true}
12488      * because device may NOT support connections to Wi-Fi WEP networks.
12489      * See: {@link #isWepSupported()}.
12490      *
12491      * @param isAllowed whether or not the user allow connections to Wi-Fi WEP networks.
12492      * @throws SecurityException if the caller does not have permission.
12493      * @hide
12494      */
12495     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12496     @SystemApi
12497     @RequiresPermission(anyOf = {
12498             android.Manifest.permission.NETWORK_SETTINGS,
12499             android.Manifest.permission.NETWORK_SETUP_WIZARD
12500     })
setWepAllowed(boolean isAllowed)12501     public void setWepAllowed(boolean isAllowed) {
12502         try {
12503             mService.setWepAllowed(isAllowed);
12504         } catch (RemoteException e) {
12505             throw e.rethrowFromSystemServer();
12506         }
12507     }
12508 
12509     /**
12510      * Query whether or not this device is configured to allow connections to Wi-Fi WEP networks.
12511      * @see #setWepAllowed(boolean)
12512      *
12513      * Note: The WEP connections may not work even if this method returns {@code true} in the
12514      * result callback because device may NOT support connections to Wi-Fi WEP networks.
12515      * See: {@link #isWepSupported()}.
12516      *
12517      * @param executor The executor on which callback will be invoked.
12518      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
12519      *                        whether wep network support is enabled/disabled.
12520      *
12521      * @throws SecurityException if the caller does not have permission.
12522      * @hide
12523      */
12524     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12525     @SystemApi
12526     @RequiresPermission(anyOf = {
12527             android.Manifest.permission.NETWORK_SETTINGS,
12528             android.Manifest.permission.NETWORK_SETUP_WIZARD
12529     })
queryWepAllowed(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)12530     public void queryWepAllowed(@NonNull @CallbackExecutor Executor executor,
12531             @NonNull Consumer<Boolean> resultsCallback) {
12532         Objects.requireNonNull(executor, "executor cannot be null");
12533         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12534         try {
12535             mService.queryWepAllowed(
12536                     new IBooleanListener.Stub() {
12537                         @Override
12538                         public void onResult(boolean value) {
12539                             Binder.clearCallingIdentity();
12540                             executor.execute(() -> {
12541                                 resultsCallback.accept(value);
12542                             });
12543                         }
12544                     });
12545         } catch (RemoteException e) {
12546             throw e.rethrowFromSystemServer();
12547         }
12548     }
12549 
12550     /**
12551      * Enable Mirrored Stream Classification Service (MSCS) and configure using
12552      * the provided configuration values.
12553      *
12554      * If MSCS has already been enabled/configured, this will override the
12555      * existing configuration.
12556      *
12557      * Refer to Section 11.25.3 of the IEEE 802.11-2020 standard for more information.
12558      *
12559      * @param mscsParams {@link MscsParams} object containing the configuration parameters.
12560      * @hide
12561      */
12562     @SystemApi
12563     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12564     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12565     @RequiresPermission(anyOf = {MANAGE_WIFI_NETWORK_SELECTION})
enableMscs(@onNull MscsParams mscsParams)12566     public void enableMscs(@NonNull MscsParams mscsParams) {
12567         Objects.requireNonNull(mscsParams);
12568         try {
12569             mService.enableMscs(mscsParams);
12570         } catch (RemoteException e) {
12571             throw e.rethrowFromSystemServer();
12572         }
12573     }
12574 
12575     /**
12576      * Disable Mirrored Stream Classification Service (MSCS).
12577      *
12578      * If MSCS is enabled/configured, this will send a remove request to the AP.
12579      *
12580      * Refer to Section 11.25.3 of the IEEE 802.11-2020 standard for more information.
12581      * @hide
12582      */
12583     @SystemApi
12584     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12585     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12586     @RequiresPermission(anyOf = {MANAGE_WIFI_NETWORK_SELECTION})
disableMscs()12587     public void disableMscs() {
12588         try {
12589             mService.disableMscs();
12590         } catch (RemoteException e) {
12591             throw e.rethrowFromSystemServer();
12592         }
12593     }
12594 
12595     /**
12596      * Do not send the DHCP hostname to open networks.
12597      */
12598     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12599     public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN = 1 << 0;
12600 
12601     /**
12602      * Do not send the DHCP hostname to secure network.
12603      */
12604     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12605     public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE = 1 << 1;
12606 
12607     /** @hide */
12608     @IntDef(flag = true, prefix = { "FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_" }, value = {
12609             FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN,
12610             FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE,
12611     })
12612     @Retention(RetentionPolicy.SOURCE)
12613     public @interface SendDhcpHostnameRestriction {}
12614 
12615     /**
12616      * Sets the global restrictions on which networks to send the device hostname to during DHCP.
12617      *
12618      * @param restriction Bitmask of {@link SendDhcpHostnameRestriction}, or none to indicate no
12619      *                    restriction.
12620      * @throws IllegalArgumentException if input is invalid
12621      * @throws SecurityException if the calling app is not a Device Owner (DO), or a privileged app
12622      *                           that has one of the permissions required by this API.
12623      */
12624     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12625     @RequiresPermission(anyOf = {
12626             android.Manifest.permission.NETWORK_SETTINGS,
12627             android.Manifest.permission.NETWORK_SETUP_WIZARD
12628     })
setSendDhcpHostnameRestriction(@endDhcpHostnameRestriction int restriction)12629     public void setSendDhcpHostnameRestriction(@SendDhcpHostnameRestriction int restriction) {
12630         try {
12631             mService.setSendDhcpHostnameRestriction(mContext.getOpPackageName(), restriction);
12632         } catch (RemoteException e) {
12633             throw e.rethrowFromSystemServer();
12634         }
12635     }
12636 
12637     /**
12638      * Query the global restriction on which networks to send the device hostname to during DHCP.
12639      * @see #setSendDhcpHostnameRestriction(int)
12640      *
12641      * @param executor The executor on which callback will be invoked.
12642      * @param resultsCallback An asynchronous callback that will return a bitmask of
12643      *                        {@link SendDhcpHostnameRestriction}.
12644      *
12645      * @throws SecurityException if the calling app is not a Device Owner (DO), or a privileged app
12646      *                           that has one of the permissions required by this API.
12647      */
12648     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12649     @RequiresPermission(anyOf = {
12650             android.Manifest.permission.NETWORK_SETTINGS,
12651             android.Manifest.permission.NETWORK_SETUP_WIZARD
12652     })
querySendDhcpHostnameRestriction(@onNull @allbackExecutor Executor executor, @NonNull IntConsumer resultsCallback)12653     public void querySendDhcpHostnameRestriction(@NonNull @CallbackExecutor Executor executor,
12654             @NonNull IntConsumer resultsCallback) {
12655         Objects.requireNonNull(executor, "executor cannot be null");
12656         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12657         try {
12658             mService.querySendDhcpHostnameRestriction(mContext.getOpPackageName(),
12659                     new IIntegerListener.Stub() {
12660                         @Override
12661                         public void onResult(int value) {
12662                             Binder.clearCallingIdentity();
12663                             executor.execute(() -> {
12664                                 resultsCallback.accept(value);
12665                             });
12666                         }
12667                     });
12668         } catch (RemoteException e) {
12669             throw e.rethrowFromSystemServer();
12670         }
12671     }
12672 
12673     /**
12674      * @return true if this device supports Aggressive roaming mode
12675      * {@link #setPerSsidRoamingMode(WifiSsid, int)}
12676      */
12677     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isAggressiveRoamingModeSupported()12678     public boolean isAggressiveRoamingModeSupported() {
12679         return isFeatureSupported(WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT);
12680     }
12681 
12682     /**
12683      * This API allows a privileged application to set roaming mode per SSID.
12684      *
12685      * Available for Device Owner (DO) and profile owner of an organization owned device.
12686      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
12687      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
12688      *
12689      * @param ssid SSID to be mapped to apply roaming policy
12690      * @param roamingMode One of the {@code ROAMING_MODE_} values.
12691      * @throws IllegalArgumentException if input is invalid.
12692      * @throws NullPointerException if the caller provided a null input.
12693      * @throws SecurityException if caller does not have the required permission.
12694      * @throws UnsupportedOperationException if the API is not supported on this SDK version or
12695      *                                       {@link #isAggressiveRoamingModeSupported()} returns
12696      *                                       false, but input roaming mode is
12697      *                                       {@code ROAMING_MODE_AGGRESSIVE}.
12698      */
12699     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12700     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12701     @SuppressLint("RequiresPermission")
setPerSsidRoamingMode(@onNull WifiSsid ssid, @RoamingMode int roamingMode)12702     public void setPerSsidRoamingMode(@NonNull WifiSsid ssid, @RoamingMode int roamingMode) {
12703         if (roamingMode < ROAMING_MODE_NONE || roamingMode > ROAMING_MODE_AGGRESSIVE) {
12704             throw new IllegalArgumentException("invalid roaming mode: " + roamingMode);
12705         }
12706         Objects.requireNonNull(ssid, "ssid cannot be null");
12707         try {
12708             mService.setPerSsidRoamingMode(ssid, roamingMode, mContext.getOpPackageName());
12709         } catch (RemoteException e) {
12710             throw e.rethrowFromSystemServer();
12711         }
12712     }
12713 
12714     /**
12715      * This API allows a privileged application to remove roaming mode policy
12716      * configured using the {@link #setPerSsidRoamingMode(WifiSsid, int)}.
12717      *
12718      * Available for Device Owner (DO) and profile owner of an organization owned device.
12719      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
12720      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
12721      *
12722      * @param ssid SSID to be removed from the roaming mode policy.
12723      * @throws NullPointerException if the caller provided a null input.
12724      * @throws SecurityException if caller does not have the required permission.
12725      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
12726      */
12727     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12728     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12729     @SuppressLint("RequiresPermission")
removePerSsidRoamingMode(@onNull WifiSsid ssid)12730     public void removePerSsidRoamingMode(@NonNull WifiSsid ssid) {
12731         Objects.requireNonNull(ssid, "ssid cannot be null");
12732         try {
12733             mService.removePerSsidRoamingMode(ssid, mContext.getOpPackageName());
12734         } catch (RemoteException e) {
12735             throw e.rethrowFromSystemServer();
12736         }
12737     }
12738 
12739     /**
12740      * This API allows a privileged application to get roaming mode policies
12741      * configured using the {@link #setPerSsidRoamingMode(WifiSsid, int)}.
12742      *
12743      * Available for Device Owner (DO) and profile owner of an organization owned device.
12744      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
12745      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
12746      *
12747      * @param executor The executor on which callback will be invoked.
12748      * @param resultsCallback An asynchronous callback that will return the corresponding
12749      *                        roaming policies for the API caller.
12750      * @throws SecurityException if caller does not have the required permission.
12751      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
12752      */
12753     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12754     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12755     @SuppressLint("RequiresPermission")
getPerSsidRoamingModes(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Map<String, Integer>> resultsCallback)12756     public void getPerSsidRoamingModes(@NonNull @CallbackExecutor Executor executor,
12757             @NonNull Consumer<Map<String, Integer>> resultsCallback) {
12758         Objects.requireNonNull(executor, "executor cannot be null");
12759         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12760         try {
12761             mService.getPerSsidRoamingModes(mContext.getOpPackageName(), new IMapListener.Stub() {
12762                 @Override
12763                 public void onResult(Map roamingPolicies) {
12764                     Binder.clearCallingIdentity();
12765                     executor.execute(() -> {
12766                         resultsCallback.accept(roamingPolicies);
12767                     });
12768                 }
12769             });
12770         } catch (RemoteException e) {
12771             throw e.rethrowFromSystemServer();
12772         }
12773     }
12774 
12775     /**
12776      * Bundle key to check target wake time requester mode supported or not
12777      * @hide
12778      */
12779     @SystemApi
12780     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12781     public static final String TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER =
12782             "key_requester";
12783 
12784     /**
12785      * Bundle key to get minimum wake duration supported in microseconds
12786      * @hide
12787      */
12788     @SystemApi
12789     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12790     public static final String TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS =
12791             "key_min_wake_duration";
12792     /**
12793      * Bundle key to get maximum wake duration supported in microseconds
12794      * @hide
12795      */
12796     @SystemApi
12797     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12798     public static final String TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS =
12799             "key_max_wake_duration";
12800     /**
12801      * Bundle key to get minimum wake interval supported in microseconds
12802      * @hide
12803      */
12804     @SystemApi
12805     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12806     public static final String TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS =
12807             "key_min_wake_interval";
12808     /**
12809      * Bundle key to get maximum wake interval supported in microseconds
12810      * @hide
12811      */
12812     @SystemApi
12813     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12814     public static final String TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS =
12815             "key_max_wake_interval";
12816 
12817     /** @hide */
12818     @StringDef(prefix = { "TWT_CAPABILITIES_KEY_"}, value = {
12819             TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER,
12820             TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS,
12821             TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS,
12822             TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS,
12823             TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS,
12824     })
12825     @Retention(RetentionPolicy.SOURCE)
12826     public @interface TwtCapabilities {}
12827 
12828     /**
12829      * Get target wake time (TWT) capabilities of the primary station interface.
12830      *
12831      * Note: Target wake time feature is only supported for primary station. If Wi-Fi is off or the
12832      * capability is not available the asynchronous callback will be called with the bundle
12833      * with values { false, -1, -1, -1, -1 }.
12834      *
12835      * @param executor Executor to execute listener callback
12836      * @param resultCallback An asynchronous callback that will return a bundle for target wake time
12837      *                       capabilities. See {@link TwtCapabilities} for the string keys for
12838      *                       the bundle.
12839      * @throws SecurityException if the caller does not have permission.
12840      * @throws NullPointerException if the caller provided null inputs.
12841      * @throws UnsupportedOperationException if the API is not supported.
12842      * @hide
12843      */
12844     @SystemApi
12845     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12846     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
12847     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
getTwtCapabilities(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Bundle> resultCallback)12848     public void getTwtCapabilities(@NonNull @CallbackExecutor Executor executor,
12849             @NonNull Consumer<Bundle> resultCallback) {
12850         Objects.requireNonNull(executor, "executor cannot be null");
12851         Objects.requireNonNull(resultCallback, "resultCallback cannot be null");
12852         if (!SdkLevel.isAtLeastV()) {
12853             throw new UnsupportedOperationException();
12854         }
12855         try {
12856             Bundle extras = new Bundle();
12857             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12858                     mContext.getAttributionSource());
12859             mService.getTwtCapabilities(
12860                     new ITwtCapabilitiesListener.Stub() {
12861                         @Override
12862                         public void onResult(Bundle value) {
12863                             Binder.clearCallingIdentity();
12864                             executor.execute(() -> {
12865                                 resultCallback.accept(value);
12866                             });
12867                         }
12868                     }, extras);
12869         } catch (RemoteException e) {
12870             throw e.rethrowFromSystemServer();
12871         }
12872     }
12873 
12874     private class TwtCallbackProxy extends ITwtCallback.Stub {
12875         private final Executor mExecutor;
12876         private final TwtSessionCallback mCallback;
12877 
TwtCallbackProxy(Executor executor, TwtSessionCallback callback)12878         private TwtCallbackProxy(Executor executor, TwtSessionCallback callback) {
12879             mExecutor = executor;
12880             mCallback = callback;
12881         }
12882 
12883         @Override
onFailure(@wtSessionCallback.TwtErrorCode int errorCode)12884         public void onFailure(@TwtSessionCallback.TwtErrorCode int errorCode)
12885                 throws RemoteException {
12886             if (mVerboseLoggingEnabled) {
12887                 Log.v(TAG, "TwtCallbackProxy: onFailure(errorCode = " + errorCode + " )");
12888             }
12889             Binder.clearCallingIdentity();
12890             mExecutor.execute(() -> mCallback.onFailure(errorCode));
12891         }
12892 
12893         @Override
onTeardown(@wtSessionCallback.TwtReasonCode int reasonCode)12894         public void onTeardown(@TwtSessionCallback.TwtReasonCode int reasonCode)
12895                 throws RemoteException {
12896             if (mVerboseLoggingEnabled) {
12897                 Log.v(TAG, "TwtCallbackProxy: onTeardown(errorCode = " + reasonCode + " )");
12898             }
12899             Binder.clearCallingIdentity();
12900             mExecutor.execute(() -> mCallback.onTeardown(reasonCode));
12901         }
12902 
12903         @Override
onCreate(int wakeDuration, long wakeInterval, int mloLinkId, int owner, int sessionId)12904         public void onCreate(int wakeDuration, long wakeInterval, int mloLinkId, int owner,
12905                 int sessionId) throws RemoteException {
12906             if (mVerboseLoggingEnabled) {
12907                 Log.v(TAG, "TwtCallbackProxy: onCreate " + sessionId);
12908             }
12909 
12910             WifiTwtSession wifiTwtSession = new WifiTwtSession(WifiManager.this, wakeDuration,
12911                     wakeInterval, mloLinkId, owner, sessionId);
12912             Binder.clearCallingIdentity();
12913             mExecutor.execute(() -> mCallback.onCreate(wifiTwtSession));
12914         }
12915     }
12916 
12917     /**
12918      * Set up a TWT session with a TWT responder capable AP. Only supported for primary connected
12919      * station which is a TWT requester. See {@link #getTwtCapabilities(Executor, Consumer)} and
12920      * {@link ScanResult#isTwtResponder()} to check station and AP support.
12921      *
12922      * Following callbacks are invoked,
12923      *  - {@link TwtSessionCallback#onFailure(int)} upon error with error code.
12924      *  - {@link TwtSessionCallback#onCreate(TwtSession)} upon TWT session creation.
12925      *  - {@link TwtSessionCallback#onTeardown(int)} upon TWT session teardown.
12926      *
12927      * Note: {@link #getTwtCapabilities(Executor, Consumer)} gives {@link TwtCapabilities} which can
12928      * be used to fill in the valid TWT wake interval and duration ranges for {@link TwtRequest}.
12929      *
12930      * @param twtRequest TWT request
12931      * @param executor Executor to execute listener callback on
12932      * @param callback Callback to register
12933      * @throws SecurityException if the caller does not have permission.
12934      * @throws NullPointerException if the caller provided null inputs.
12935      * @throws UnsupportedOperationException if the API is not supported.
12936      * @hide
12937      */
12938     @SystemApi
12939     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12940     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
12941     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
setupTwtSession(@onNull TwtRequest twtRequest, @NonNull @CallbackExecutor Executor executor, @NonNull TwtSessionCallback callback)12942     public void setupTwtSession(@NonNull TwtRequest twtRequest,
12943             @NonNull @CallbackExecutor Executor executor, @NonNull TwtSessionCallback callback) {
12944         Objects.requireNonNull(executor, "executor cannot be null");
12945         Objects.requireNonNull(callback, "callback cannot be null");
12946         Objects.requireNonNull(twtRequest, "twtRequest cannot be null");
12947         if (!SdkLevel.isAtLeastV()) {
12948             throw new UnsupportedOperationException();
12949         }
12950         try {
12951             ITwtCallback.Stub binderCallback = new TwtCallbackProxy(executor, callback);
12952             Bundle extras = new Bundle();
12953             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12954                     mContext.getAttributionSource());
12955             mService.setupTwtSession(twtRequest, binderCallback, extras);
12956         } catch (RemoteException e) {
12957             throw e.rethrowFromSystemServer();
12958         }
12959     }
12960 
12961     /**
12962      * Get stats of the target wake time session.
12963      *
12964      * Note: For Internal use only. Expected to be called through
12965      * {@link TwtSession#getStats(Executor, Consumer)}. If the command fails, -1 will be returned
12966      * for all stats values.
12967      *
12968      * @param sessionId TWT session id
12969      * @param executor The executor on which callback will be invoked.
12970      * @param resultCallback The asynchronous callback that will return bundle with key string
12971      *                       {@link TwtSession.TwtStats}.
12972      *
12973      * @throws SecurityException if the caller does not have permission.
12974      * @throws NullPointerException if the caller provided null inputs.
12975      * @throws UnsupportedOperationException if the API is not supported or primary station is
12976      * not connected.
12977      * @hide
12978      */
getStatsTwtSession(@onNull int sessionId, @NonNull Executor executor, @NonNull Consumer<Bundle> resultCallback)12979     public void getStatsTwtSession(@NonNull int sessionId, @NonNull Executor executor,
12980             @NonNull Consumer<Bundle> resultCallback) {
12981         Objects.requireNonNull(executor, "executor cannot be null");
12982         Objects.requireNonNull(resultCallback, "resultsCallback cannot be null");
12983         if (!SdkLevel.isAtLeastV()) {
12984             throw new UnsupportedOperationException();
12985         }
12986         try {
12987             Bundle extras = new Bundle();
12988             if (SdkLevel.isAtLeastS()) {
12989                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12990                         mContext.getAttributionSource());
12991             }
12992             mService.getStatsTwtSession(sessionId,
12993                     new ITwtStatsListener.Stub() {
12994                         @Override
12995                         public void onResult(Bundle value) {
12996                             Binder.clearCallingIdentity();
12997                             executor.execute(() -> {
12998                                 resultCallback.accept(value);
12999                             });
13000                         }
13001                     }, extras);
13002         } catch (RemoteException e) {
13003             throw e.rethrowFromSystemServer();
13004         }
13005     }
13006 
13007     /**
13008      * Teardown the target wake time session. Only owner can teardown the session.
13009      *
13010      * Note: For internal use only. Expected to be called through
13011      * {@link TwtSessionCallback#onTeardown(int)}.
13012      *
13013      * @param sessionId TWT session id
13014      * @throws SecurityException if the caller does not have permission.
13015      * @throws UnsupportedOperationException if the API is not supported or primary station is not
13016      * connected.
13017      * @hide
13018      */
teardownTwtSession(int sessionId)13019     public void teardownTwtSession(int sessionId) {
13020         if (!SdkLevel.isAtLeastV()) {
13021             throw new UnsupportedOperationException();
13022         }
13023         try {
13024             Bundle extras = new Bundle();
13025             if (SdkLevel.isAtLeastS()) {
13026                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
13027                         mContext.getAttributionSource());
13028             }
13029             mService.teardownTwtSession(sessionId, extras);
13030         } catch (RemoteException e) {
13031             throw e.rethrowFromSystemServer();
13032         }
13033     }
13034 
13035     /**
13036      * Allows a privileged application to set whether or not this device allows
13037      * device-to-device connections when infra STA is disabled. Callers can use
13038      * {@link #queryD2dAllowedWhenInfraStaDisabled(Executor, Consumer)} to check the currently
13039      * set value.
13040      *
13041      * Note: This functionality is supported only when the device support device-to-device
13042      * when infra STA is disabled. Use {@link #isD2dSupportedWhenInfraStaDisabled()} to
13043      * know if device supported device-to-device when infra STA is disabled.
13044      *
13045      * @param isAllowed whether or not the device allows to device-to-device connectivity when
13046      *                  infra STA is disabled.
13047      * @throws SecurityException if the caller does not have permission.
13048      * @hide
13049      */
13050     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
13051     @SystemApi
13052     @RequiresPermission(anyOf = {
13053             android.Manifest.permission.NETWORK_SETTINGS,
13054             android.Manifest.permission.NETWORK_SETUP_WIZARD
13055     })
13056     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setD2dAllowedWhenInfraStaDisabled(boolean isAllowed)13057     public void setD2dAllowedWhenInfraStaDisabled(boolean isAllowed) {
13058         try {
13059             mService.setD2dAllowedWhenInfraStaDisabled(isAllowed);
13060         } catch (RemoteException e) {
13061             throw e.rethrowFromSystemServer();
13062         }
13063     }
13064 
13065     /**
13066      * Query whether or not this device is configured to allow D2d connection when
13067      * infra STA is disabled.
13068      * see: {@link #setD2dAllowedWhenInfraStaDisabled(boolean)}.
13069      *
13070      *
13071      * @param executor The executor on which callback will be invoked.
13072      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
13073      *                        whether device-to-device connection is allowed or disallowed
13074      *                        when infra STA is disabled.
13075      * @hide
13076      */
13077     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
13078     @SystemApi
queryD2dAllowedWhenInfraStaDisabled(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)13079     public void queryD2dAllowedWhenInfraStaDisabled(@NonNull @CallbackExecutor Executor executor,
13080             @NonNull Consumer<Boolean> resultsCallback) {
13081         Objects.requireNonNull(executor, "executor cannot be null");
13082         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
13083         try {
13084             mService.queryD2dAllowedWhenInfraStaDisabled(
13085                     new IBooleanListener.Stub() {
13086                         @Override
13087                         public void onResult(boolean value) {
13088                             Binder.clearCallingIdentity();
13089                             executor.execute(() -> {
13090                                 resultsCallback.accept(value);
13091                             });
13092                         }
13093                     });
13094         } catch (RemoteException e) {
13095             throw e.rethrowFromSystemServer();
13096         }
13097     }
13098 
13099     /**
13100      * Disallow Wi-Fi autojoin on ScanResults matching the selected security types.
13101      * This does not restrict manual connections.
13102      *
13103      * @param restrictions An array of {@code WifiInfo.SECURITY_TYPE_*} values to disallow autojoin.
13104      *                     An empty array will clear all restrictions. Note, certain combinations of
13105      *                     restricted security types are not valid.
13106      *                     1. restrictions contains WifiInfo.SECURITY_TYPE_OWE,
13107      *                        but not WifiInfo.SECURITY_TYPE_OPEN.
13108      *                     2. restrictions contains WifiInfo.SECURITY_TYPE_SAE,
13109      *                        but not WifiInfo.SECURITY_TYPE_PSK.
13110      *                     3. restrictions contains WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
13111      *                        but not WifiInfo.SECURITY_TYPE_EAP.
13112      *
13113      * Usage example:
13114      * <pre>
13115      *                     To disallow autojoin to Wi-Fi networks with security type, OPEN, WEP
13116      *                     or OWE, use following argument.
13117      *
13118      *                     {@code
13119      *                         int[] restrictions = {
13120      *                                 WifiInfo.SECURITY_TYPE_OPEN,
13121      *                                 WifiInfo.SECURITY_TYPE_WEP,
13122      *                                 WifiInfo.SECURITY_TYPE_OWE };
13123      *                         wifiManager.setAutojoinDisallowedSecurityTypes(restrictions);
13124      *                     }
13125      *
13126      *                     To clear autojoin restriction on all security types, use following
13127      *                     argument.
13128      *
13129      *                     {@code
13130      *                         wifiManager.setAutojoinDisallowedSecurityTypes(new int[0]);
13131      *                     }
13132      * </pre>
13133      * @throws UnsupportedOperationException if the API is not supported.
13134      * @hide
13135      */
13136     @SystemApi
13137     @FlaggedApi(Flags.FLAG_AUTOJOIN_RESTRICTION_SECURITY_TYPES_API)
13138     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
13139     @RequiresPermission(anyOf = {
13140             android.Manifest.permission.NETWORK_SETTINGS,
13141             MANAGE_WIFI_NETWORK_SELECTION
13142     })
setAutojoinDisallowedSecurityTypes( @onNull @ifiAnnotations.SecurityType int[] restrictions)13143     public void setAutojoinDisallowedSecurityTypes(
13144             @NonNull @WifiAnnotations.SecurityType int[] restrictions) {
13145         if (!SdkLevel.isAtLeastT()) {
13146             throw new UnsupportedOperationException();
13147         }
13148         Objects.requireNonNull(restrictions, "restrictions cannot be null");
13149         try {
13150             Bundle extras = new Bundle();
13151             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
13152                     mContext.getAttributionSource());
13153             int restrictionBitmap = 0;
13154             for (int securityType : restrictions) {
13155                 restrictionBitmap |= 0x1 << securityType;
13156             }
13157             mService.setAutojoinDisallowedSecurityTypes(restrictionBitmap, extras);
13158         } catch (RemoteException e) {
13159             throw e.rethrowFromSystemServer();
13160         }
13161     }
13162 
13163     /**
13164      * Retrieves the autojoin disallowed Wi-Fi security types currently set for the device.
13165      *
13166      * @param executor The executor to run the callback on.
13167      * @param resultsCallback The callback to receive the result. It will be called with an array
13168      *                        of autojoin disallowedse security types from
13169      *                        {@code WifiInfo.SECURITY_TYPE_*}.
13170      * @throws UnsupportedOperationException if the API is not supported.
13171      * @hide
13172      */
13173     @SystemApi
13174     @FlaggedApi(Flags.FLAG_AUTOJOIN_RESTRICTION_SECURITY_TYPES_API)
13175     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
13176     @RequiresPermission(anyOf = {
13177             android.Manifest.permission.NETWORK_SETTINGS,
13178             MANAGE_WIFI_NETWORK_SELECTION
13179     })
getAutojoinDisallowedSecurityTypes(@onNull @allbackExecutor Executor executor, @NonNull Consumer<int[]> resultsCallback)13180     public void getAutojoinDisallowedSecurityTypes(@NonNull @CallbackExecutor Executor executor,
13181             @NonNull Consumer<int[]> resultsCallback) {
13182         if (!SdkLevel.isAtLeastT()) {
13183             throw new UnsupportedOperationException();
13184         }
13185         Objects.requireNonNull(executor, "executor cannot be null");
13186         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
13187         try {
13188             Bundle extras = new Bundle();
13189             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
13190                     mContext.getAttributionSource());
13191             mService.getAutojoinDisallowedSecurityTypes(new IIntegerListener.Stub() {
13192                 @Override
13193                 public void onResult(int value) {
13194                     Binder.clearCallingIdentity();
13195                     executor.execute(() -> {
13196                         List<Integer> restrictions = new ArrayList<>();
13197                         for (int i = 0; i < Integer.SIZE; i++) {
13198                             if (((0x1 << i) & value) != 0) {
13199                                 restrictions.add(i);
13200                             }
13201                         }
13202                         int[] results = new int[restrictions.size()];
13203                         for (int i = 0; i < restrictions.size(); i++) {
13204                             results[i] = restrictions.get(i);
13205                         }
13206                         resultsCallback.accept(results);
13207                     });
13208                 }
13209             }, extras);
13210         } catch (RemoteException e) {
13211             throw e.rethrowFromSystemServer();
13212         }
13213     }
13214 
13215     /**
13216      * Indicates what {@link AdvancedProtectionFeature} are supported over Wi-Fi.
13217      *
13218      * The {@link AdvancedProtectionFeature} is the advanced protection feature
13219      * providing protections which works when Android Advanced Protection Mode (AAPM)
13220      * is enabled.
13221      *
13222      * @return a list of the supported features.
13223      * @hide
13224      */
13225     @SystemApi
13226     @FlaggedApi(android.security.Flags.FLAG_AAPM_API)
13227     @RequiresApi(Build.VERSION_CODES.BAKLAVA)
13228     @NonNull
13229     @SuppressLint("NewApi")
getAvailableAdvancedProtectionFeatures()13230     public List<AdvancedProtectionFeature> getAvailableAdvancedProtectionFeatures() {
13231         if (!Environment.isSdkAtLeastB()) {
13232             throw new UnsupportedOperationException();
13233         }
13234         List<AdvancedProtectionFeature> features = new ArrayList<>();
13235         if (Flags.wepDisabledInApm() && android.security.Flags.aapmApi()) {
13236             features.add(new AdvancedProtectionFeature(
13237                     AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP));
13238         }
13239         return features;
13240     }
13241 
13242     /**
13243      * When the device is connected to a network suggested by calling app
13244      * {@link #addNetworkSuggestions(List)}, this API provide a way to avoid the current connection
13245      * without {@link #removeNetworkSuggestions(List)}. The disallowed network will be disconnected
13246      * or roam to other networks.
13247      * App can only use this API to control the current connected network
13248      * which was suggested by this app.
13249      *
13250      * @param blockingOption Option to change for the network blocking {@link BlockingOption}
13251      */
13252     @FlaggedApi(Flags.FLAG_BSSID_BLOCKLIST_FOR_SUGGESTION)
13253     @RequiresPermission(CHANGE_WIFI_STATE)
disallowCurrentSuggestedNetwork(@onNull BlockingOption blockingOption)13254     public void disallowCurrentSuggestedNetwork(@NonNull BlockingOption blockingOption) {
13255         Objects.requireNonNull(blockingOption, "blockingOption cannot be null");
13256         try {
13257             mService.disallowCurrentSuggestedNetwork(blockingOption, mContext.getOpPackageName());
13258         } catch (RemoteException e) {
13259             throw e.rethrowFromSystemServer();
13260         }
13261     }
13262 
13263     /**
13264      * Return whether Unsynchronized Service Discovery (USD) subscriber is supported or not.
13265      * @hide
13266      */
13267     @android.annotation.RequiresApi(Build.VERSION_CODES.BAKLAVA)
13268     @SystemApi
13269     @FlaggedApi(android.net.wifi.flags.Flags.FLAG_USD)
13270     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
isUsdSubscriberSupported()13271     public boolean isUsdSubscriberSupported() {
13272         if (!Environment.isSdkAtLeastB()) {
13273             throw new UnsupportedOperationException();
13274         }
13275         try {
13276             return mService.isUsdSubscriberSupported();
13277         } catch (RemoteException e) {
13278             throw e.rethrowFromSystemServer();
13279         }
13280     }
13281 
13282     /**
13283      * Return whether Unsynchronized Service Discovery (USD) publisher is supported or not.
13284      * <p>
13285      * The USD publisher support is controlled by an overlay config_wifiUsdPublisherSupported.
13286      * By default, the feature will be disabled because the publisher operation impacts other
13287      * concurrency operation such as Station. The USD publisher switches channels and dwells a
13288      * longer time (500 milliseconds to 1 second) on non-home channel which disrupts other
13289      * concurrency operation.
13290      *
13291      * @return true if publisher feature is supported, otherwise false.
13292      * @hide
13293      */
13294     @android.annotation.RequiresApi(Build.VERSION_CODES.BAKLAVA)
13295     @SystemApi
13296     @FlaggedApi(android.net.wifi.flags.Flags.FLAG_USD)
13297     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
isUsdPublisherSupported()13298     public boolean isUsdPublisherSupported() {
13299         if (!Environment.isSdkAtLeastB()) {
13300             throw new UnsupportedOperationException();
13301         }
13302         try {
13303             return mService.isUsdPublisherSupported();
13304         } catch (RemoteException e) {
13305             throw e.rethrowFromSystemServer();
13306         }
13307     }
13308 }
13309