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.net.ConnectivityManager;
50 import android.net.ConnectivityManager.NetworkCallback;
51 import android.net.DhcpInfo;
52 import android.net.DhcpOption;
53 import android.net.LinkProperties;
54 import android.net.MacAddress;
55 import android.net.Network;
56 import android.net.NetworkCapabilities;
57 import android.net.NetworkRequest;
58 import android.net.NetworkStack;
59 import android.net.TetheringManager;
60 import android.net.Uri;
61 import android.net.wifi.hotspot2.IProvisioningCallback;
62 import android.net.wifi.hotspot2.OsuProvider;
63 import android.net.wifi.hotspot2.PasspointConfiguration;
64 import android.net.wifi.hotspot2.ProvisioningCallback;
65 import android.net.wifi.p2p.WifiP2pConfig;
66 import android.net.wifi.p2p.WifiP2pDiscoveryConfig;
67 import android.net.wifi.p2p.WifiP2pManager;
68 import android.net.wifi.twt.TwtRequest;
69 import android.net.wifi.twt.TwtSession;
70 import android.net.wifi.twt.TwtSessionCallback;
71 import android.os.Binder;
72 import android.os.Build;
73 import android.os.Bundle;
74 import android.os.Handler;
75 import android.os.IBinder;
76 import android.os.Looper;
77 import android.os.Parcel;
78 import android.os.Parcelable;
79 import android.os.RemoteException;
80 import android.os.WorkSource;
81 import android.os.connectivity.WifiActivityEnergyInfo;
82 import android.telephony.SubscriptionInfo;
83 import android.text.TextUtils;
84 import android.util.ArraySet;
85 import android.util.CloseGuard;
86 import android.util.Log;
87 import android.util.Pair;
88 import android.util.SparseArray;
89 
90 import androidx.annotation.RequiresApi;
91 
92 import com.android.internal.annotations.GuardedBy;
93 import com.android.internal.annotations.VisibleForTesting;
94 import com.android.modules.utils.HandlerExecutor;
95 import com.android.modules.utils.ParceledListSlice;
96 import com.android.modules.utils.build.SdkLevel;
97 import com.android.wifi.flags.Flags;
98 
99 import java.lang.annotation.Retention;
100 import java.lang.annotation.RetentionPolicy;
101 import java.lang.ref.Reference;
102 import java.lang.ref.WeakReference;
103 import java.net.InetAddress;
104 import java.time.Duration;
105 import java.util.ArrayList;
106 import java.util.Arrays;
107 import java.util.Collections;
108 import java.util.HashMap;
109 import java.util.List;
110 import java.util.Map;
111 import java.util.Objects;
112 import java.util.Set;
113 import java.util.StringTokenizer;
114 import java.util.concurrent.Executor;
115 import java.util.function.BiConsumer;
116 import java.util.function.Consumer;
117 import java.util.function.IntConsumer;
118 
119 /**
120  * This class provides the primary API for managing all aspects of Wi-Fi
121  * connectivity.
122  * <p>
123  * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
124  * should only be obtained from an {@linkplain Context#getApplicationContext()
125  * application context}, and not from any other derived context to avoid memory
126  * leaks within the calling process.
127  * <p>
128  * It deals with several categories of items:
129  * </p>
130  * <ul>
131  * <li>The list of configured networks. The list can be viewed and updated, and
132  * attributes of individual entries can be modified.</li>
133  * <li>The currently active Wi-Fi network, if any. Connectivity can be
134  * established or torn down, and dynamic information about the state of the
135  * network can be queried.</li>
136  * <li>Results of access point scans, containing enough information to make
137  * decisions about what access point to connect to.</li>
138  * <li>It defines the names of various Intent actions that are broadcast upon
139  * any sort of change in Wi-Fi state.
140  * </ul>
141  * <p>
142  * This is the API to use when performing Wi-Fi specific operations. To perform
143  * operations that pertain to network connectivity at an abstract level, use
144  * {@link android.net.ConnectivityManager}.
145  * </p>
146  */
147 @SystemService(Context.WIFI_SERVICE)
148 public class WifiManager {
149 
150     private static final String TAG = "WifiManager";
151 
152     /**
153      * Local networks should not be modified by B&R since the user may have
154      * updated it with the latest configurations.
155      * @hide
156      */
157     @ChangeId
158     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
159     public static final long NOT_OVERRIDE_EXISTING_NETWORKS_ON_RESTORE = 234793325L;
160 
161     // Supplicant error codes:
162     /**
163      * The error code if there was a problem authenticating.
164      * @deprecated This is no longer supported.
165      */
166     @Deprecated
167     public static final int ERROR_AUTHENTICATING = 1;
168 
169     /**
170      * The reason code if there is no error during authentication.
171      * It could also imply that there no authentication in progress,
172      * this reason code also serves as a reset value.
173      * @deprecated This is no longer supported.
174      * @hide
175      */
176     @Deprecated
177     public static final int ERROR_AUTH_FAILURE_NONE = 0;
178 
179     /**
180      * The reason code if there was a timeout authenticating.
181      * @deprecated This is no longer supported.
182      * @hide
183      */
184     @Deprecated
185     public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
186 
187     /**
188      * The reason code if there was a wrong password while
189      * authenticating.
190      * @deprecated This is no longer supported.
191      * @hide
192      */
193     @Deprecated
194     public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
195 
196     /**
197      * The reason code if there was EAP failure while
198      * authenticating.
199      * @deprecated This is no longer supported.
200      * @hide
201      */
202     @Deprecated
203     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
204 
205     /** @hide */
206     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM = 256;
207 
208     /** @hide */
209     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM = 1024;
210 
211     /**
212      * Reason code if all of the network suggestions were successfully added or removed.
213      */
214     public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0;
215 
216     /**
217      * Reason code if there was an internal error in the platform while processing the addition or
218      * removal of suggestions.
219      */
220     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1;
221 
222     /**
223      * Reason code if the user has disallowed "android:change_wifi_state" app-ops from the app.
224      * @see android.app.AppOpsManager#unsafeCheckOp(String, int, String).
225      */
226     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2;
227 
228     /**
229      * Reason code if one or more of the network suggestions added already exists in platform's
230      * database.
231      * Note: this code will not be returned with Android 11 as in-place modification is allowed,
232      * please check {@link #addNetworkSuggestions(List)}.
233      * @see WifiNetworkSuggestion#equals(Object)
234      */
235     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
236 
237     /**
238      * Reason code if the number of network suggestions provided by the app crosses the max
239      * threshold set per app.
240      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} if
241      * the total size exceeds the limit.
242      * @see #getMaxNumberOfNetworkSuggestionsPerApp()
243      */
244     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
245 
246     /**
247      * Reason code if one or more of the network suggestions removed does not exist in platform's
248      * database.
249      * The framework won't remove any suggestions if one or more of suggestions provided
250      * by {@link #removeNetworkSuggestions(List)} does not exist in database.
251      * @see WifiNetworkSuggestion#equals(Object)
252      */
253     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
254 
255     /**
256      * Reason code if one or more of the network suggestions added is not allowed.
257      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
258      * if one or more of them is not allowed.
259      * This error may be caused by suggestion is using SIM-based encryption method, but calling app
260      * is not carrier privileged.
261      */
262     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6;
263 
264     /**
265      * Reason code if one or more of the network suggestions added is invalid. Framework will reject
266      * all the suggestions in the list.
267      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
268      * if one or more of them is invalid.
269      * Please use {@link WifiNetworkSuggestion.Builder} to create network suggestions.
270      */
271     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7;
272 
273     /**
274      * Reason code if {@link android.os.UserManager#DISALLOW_ADD_WIFI_CONFIG} user restriction
275      * is set and calling app is restricted by device admin.
276      */
277     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_RESTRICTED_BY_ADMIN = 8;
278 
279     /** @hide */
280     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
281             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
282             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
283             STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED,
284             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
285             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
286             STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
287             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED,
288             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
289             STATUS_NETWORK_SUGGESTIONS_ERROR_RESTRICTED_BY_ADMIN,
290     })
291     @Retention(RetentionPolicy.SOURCE)
292     public @interface NetworkSuggestionsStatusCode {}
293 
294     /**
295      * Reason code if suggested network connection attempt failed with an unknown failure.
296      */
297     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN = 0;
298     /**
299      * Reason code if suggested network connection attempt failed with association failure.
300      */
301     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1;
302     /**
303      * Reason code if suggested network connection attempt failed with an authentication failure.
304      */
305     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2;
306     /**
307      * Reason code if suggested network connection attempt failed with an IP provision failure.
308      */
309     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3;
310 
311     /** @hide */
312     @IntDef(prefix = {"STATUS_SUGGESTION_CONNECTION_FAILURE_"},
313             value = {STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN,
314                     STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION,
315                     STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION,
316                     STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING
317     })
318     @Retention(RetentionPolicy.SOURCE)
319     public @interface SuggestionConnectionStatusCode {}
320 
321     /**
322      * Reason code if local-only network connection attempt failed with an unknown failure.
323      */
324     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_UNKNOWN = 0;
325     /**
326      * Reason code if local-only network connection attempt failed with association failure.
327      */
328     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_ASSOCIATION = 1;
329     /**
330      * Reason code if local-only network connection attempt failed with an authentication failure.
331      */
332     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION = 2;
333     /**
334      * Reason code if local-only network connection attempt failed with an IP provisioning failure.
335      */
336     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_IP_PROVISIONING = 3;
337     /**
338      * Reason code if local-only network connection attempt failed with AP not in range.
339      */
340     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NOT_FOUND = 4;
341     /**
342      * Reason code if local-only network connection attempt failed with AP not responding
343      */
344     public static final int STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NO_RESPONSE = 5;
345 
346     /** @hide */
347     @IntDef(prefix = {"STATUS_LOCAL_ONLY_CONNECTION_FAILURE_"},
348             value = {STATUS_LOCAL_ONLY_CONNECTION_FAILURE_UNKNOWN,
349                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_ASSOCIATION,
350                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_AUTHENTICATION,
351                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_IP_PROVISIONING,
352                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NOT_FOUND,
353                     STATUS_LOCAL_ONLY_CONNECTION_FAILURE_NO_RESPONSE
354             })
355     @Retention(RetentionPolicy.SOURCE)
356     public @interface LocalOnlyConnectionStatusCode {}
357 
358     /**
359      * Status code if suggestion approval status is unknown, an App which hasn't made any
360      * suggestions will get this code.
361      */
362     public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0;
363 
364     /**
365      * Status code if the calling app is still pending user approval for suggestions.
366      */
367     public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1;
368 
369     /**
370      * Status code if the calling app got the user approval for suggestions.
371      */
372     public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2;
373 
374     /**
375      * Status code if the calling app suggestions were rejected by the user.
376      */
377     public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3;
378 
379     /**
380      * Status code if the calling app was approved by virtue of being a carrier privileged app.
381      *
382      * @see android.telephony.TelephonyManager#hasCarrierPrivileges()
383      */
384     public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4;
385 
386     /** @hide */
387     @IntDef(prefix = {"STATUS_SUGGESTION_APPROVAL_"},
388             value = {STATUS_SUGGESTION_APPROVAL_UNKNOWN,
389                     STATUS_SUGGESTION_APPROVAL_PENDING,
390                     STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
391                     STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER,
392                     STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE
393             })
394     @Retention(RetentionPolicy.SOURCE)
395     public @interface SuggestionUserApprovalStatus {}
396 
397     /**
398      * Disable PNO scan until device reboot.
399      * @hide
400      */
401     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
402     @SystemApi
403     public static final int PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT = 0;
404 
405     /**
406      * Disable PNO scan until device reboot or Wi-Fi is toggled.
407      * @hide
408      */
409     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
410     @SystemApi
411     public static final int PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE = 1;
412 
413     /**
414      * Enable PNO scan.
415      * @hide
416      */
417     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
418     @SystemApi
419     public static final int PNO_SCAN_STATE_ENABLED = 2;
420 
421     /** @hide */
422     @IntDef(prefix = {"PNO_SCAN_STATE_"},
423             value = {PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT,
424                     PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE,
425                     PNO_SCAN_STATE_ENABLED
426             })
427     @Retention(RetentionPolicy.SOURCE)
428     public @interface PnoScanState {}
429 
430     /**
431      * If one of the removed suggestions is currently connected, that network will be disconnected
432      * after a short delay as opposed to immediately (which will be done by
433      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT}). The {@link ConnectivityManager} may call the
434      * {@link NetworkCallback#onLosing(Network, int)} on such networks.
435      */
436     public static final int ACTION_REMOVE_SUGGESTION_LINGER = 1;
437 
438     /**
439      * If one of the removed suggestions is currently connected, trigger an immediate disconnect
440      * after suggestions removal
441      */
442     public static final int ACTION_REMOVE_SUGGESTION_DISCONNECT = 2;
443 
444     /** @hide */
445     @IntDef(prefix = {"ACTION_REMOVE_SUGGESTION_"},
446             value = {ACTION_REMOVE_SUGGESTION_LINGER,
447                     ACTION_REMOVE_SUGGESTION_DISCONNECT
448             })
449     @Retention(RetentionPolicy.SOURCE)
450     public @interface ActionAfterRemovingSuggestion {}
451 
452     /**
453      * Only available on Android S or later.
454      * @hide
455      **/
456     public static final String EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE =
457             "EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE";
458 
459     /**
460      * Broadcast intent action indicating whether Wi-Fi scanning is currently available.
461      * Available extras:
462      * - {@link #EXTRA_SCAN_AVAILABLE}
463      */
464     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
465     public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED =
466             "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
467 
468     /**
469      * A boolean extra indicating whether scanning is currently available.
470      * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABILITY_CHANGED}.
471      * Its value is true if scanning is currently available, false otherwise.
472      */
473     public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
474 
475     /**
476      * Broadcast intent action indicating that the credential of a Wi-Fi network
477      * has been changed. One extra provides the ssid of the network. Another
478      * extra provides the event type, whether the credential is saved or forgot.
479      * @hide
480      */
481     @SystemApi
482     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
483             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
484     /** @hide */
485     @SystemApi
486     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
487     /** @hide */
488     @SystemApi
489     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
490     /** @hide */
491     @SystemApi
492     public static final int WIFI_CREDENTIAL_SAVED = 0;
493     /** @hide */
494     @SystemApi
495     public static final int WIFI_CREDENTIAL_FORGOT = 1;
496 
497     /** @hide */
498     @SystemApi
499     public static final int PASSPOINT_HOME_NETWORK = 0;
500 
501     /** @hide */
502     @SystemApi
503     public static final int PASSPOINT_ROAMING_NETWORK = 1;
504 
505     /** @hide */
506     @Retention(RetentionPolicy.SOURCE)
507     @IntDef(value = {
508             API_SCANNING_ENABLED,
509             API_WIFI_ENABLED,
510             API_SOFT_AP,
511             API_TETHERED_HOTSPOT,
512             API_AUTOJOIN_GLOBAL,
513             API_SET_SCAN_SCHEDULE,
514             API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY,
515             API_SET_NETWORK_SELECTION_CONFIG,
516             API_SET_THIRD_PARTY_APPS_ENABLING_WIFI_CONFIRMATION_DIALOG,
517             API_ADD_NETWORK,
518             API_UPDATE_NETWORK,
519             API_ALLOW_AUTOJOIN,
520             API_CONNECT_CONFIG,
521             API_CONNECT_NETWORK_ID,
522             API_DISABLE_NETWORK,
523             API_ENABLE_NETWORK,
524             API_FORGET,
525             API_SAVE,
526             API_START_SCAN,
527             API_START_LOCAL_ONLY_HOTSPOT,
528             API_P2P_DISCOVER_PEERS,
529             API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS,
530             API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY,
531             API_P2P_STOP_PEER_DISCOVERY,
532             API_P2P_CONNECT,
533             API_P2P_CANCEL_CONNECT,
534             API_P2P_CREATE_GROUP,
535             API_P2P_CREATE_GROUP_P2P_CONFIG,
536             API_P2P_REMOVE_GROUP,
537             API_P2P_START_LISTENING,
538             API_P2P_STOP_LISTENING,
539             API_P2P_SET_CHANNELS,
540             API_WIFI_SCANNER_START_SCAN,
541             API_SET_TDLS_ENABLED,
542             API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS,
543             API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS
544     })
545     public @interface ApiType {}
546 
547     /**
548      * A constant used in
549      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
550      * Tracks usage of {@link WifiScanner#setScanningEnabled(boolean)}
551      * @hide
552      */
553     @SystemApi
554     public static final int API_SCANNING_ENABLED = 1;
555     /**
556      * A constant used in
557      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
558      * Tracks usage of {@link WifiManager#setWifiEnabled(boolean)} .
559      * @hide
560      */
561     @SystemApi
562     public static final int API_WIFI_ENABLED = 2;
563     /**
564      * A constant used in
565      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
566      * Tracks usage of {@link WifiManager#startSoftAp(WifiConfiguration)} and
567      * {@link WifiManager#stopSoftAp()}.
568      * @hide
569      */
570     @SystemApi
571     public static final int API_SOFT_AP = 3;
572     /**
573      * A constant used in
574      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
575      * Tracks usage of {@link WifiManager#startTetheredHotspot(SoftApConfiguration)}.
576      * @hide
577      */
578     @SystemApi
579     public static final int API_TETHERED_HOTSPOT = 4;
580     /**
581      * A constant used in
582      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
583      * Tracks usage of {@link WifiManager#allowAutojoinGlobal(boolean)}.
584      * @hide
585      */
586     @SystemApi
587     public static final int API_AUTOJOIN_GLOBAL = 5;
588     /**
589      * A constant used in
590      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
591      * Tracks usage of {@link WifiManager#setScreenOnScanSchedule(List)}.
592      * @hide
593      */
594     @SystemApi
595     public static final int API_SET_SCAN_SCHEDULE = 6;
596 
597     /**
598      * A constant used in
599      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
600      * Tracks usage of {@link WifiManager#setOneShotScreenOnConnectivityScanDelayMillis(int)}.
601      * @hide
602      */
603     @SystemApi
604     public static final int API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY = 7;
605 
606     /**
607      * A constant used in
608      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
609      * Tracks usage of
610      * {@link WifiManager#setNetworkSelectionConfig(WifiNetworkSelectionConfig)}
611      * @hide
612      */
613     @SystemApi
614     public static final int API_SET_NETWORK_SELECTION_CONFIG = 8;
615 
616     /**
617      * A constant used in
618      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
619      * Tracks usage of
620      * {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)}
621      * @hide
622      */
623     @SystemApi
624     public static final int API_SET_THIRD_PARTY_APPS_ENABLING_WIFI_CONFIRMATION_DIALOG = 9;
625 
626     /**
627      * A constant used in
628      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
629      * Tracks usage of
630      * {@link WifiManager#addNetwork(WifiConfiguration)}
631      * @hide
632      */
633     @SystemApi
634     public static final int API_ADD_NETWORK = 10;
635 
636     /**
637      * A constant used in
638      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
639      * Tracks usage of
640      * {@link WifiManager#updateNetwork(WifiConfiguration)}
641      * @hide
642      */
643     @SystemApi
644     public static final int API_UPDATE_NETWORK = 11;
645 
646     /**
647      * A constant used in
648      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
649      * Tracks usage of
650      * {@link WifiManager#allowAutojoin(int, boolean)}
651      * @hide
652      */
653     @SystemApi
654     public static final int API_ALLOW_AUTOJOIN = 12;
655 
656     /**
657      * A constant used in
658      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
659      * Tracks usage of
660      * {@link WifiManager#connect(WifiConfiguration, ActionListener)}
661      * @hide
662      */
663     @SystemApi
664     public static final int API_CONNECT_CONFIG = 13;
665 
666     /**
667      * A constant used in
668      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
669      * Tracks usage of
670      * {@link WifiManager#connect(int, ActionListener)}
671      * @hide
672      */
673     @SystemApi
674     public static final int API_CONNECT_NETWORK_ID = 14;
675 
676     /**
677      * A constant used in
678      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
679      * Tracks usage of
680      * {@link WifiManager#disableNetwork(int)}
681      * @hide
682      */
683     @SystemApi
684     public static final int API_DISABLE_NETWORK = 15;
685 
686     /**
687      * A constant used in
688      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
689      * Tracks usage of
690      * {@link WifiManager#enableNetwork(int, boolean)}
691      * @hide
692      */
693     @SystemApi
694     public static final int API_ENABLE_NETWORK = 16;
695 
696     /**
697      * A constant used in
698      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
699      * Tracks usage of
700      * {@link WifiManager#forget(int, ActionListener)}
701      * @hide
702      */
703     @SystemApi
704     public static final int API_FORGET = 17;
705 
706     /**
707      * A constant used in
708      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
709      * Tracks usage of
710      * {@link WifiManager#save(WifiConfiguration, ActionListener)}
711      * @hide
712      */
713     @SystemApi
714     public static final int API_SAVE = 18;
715 
716     /**
717      * A constant used in
718      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
719      * Tracks usage of
720      * {@link WifiManager#startScan()}
721      * @hide
722      */
723     @SystemApi
724     public static final int API_START_SCAN = 19;
725 
726     /**
727      * A constant used in
728      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
729      * Tracks usage of
730      * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}
731      * @hide
732      */
733     @SystemApi
734     public static final int API_START_LOCAL_ONLY_HOTSPOT = 20;
735 
736     /**
737      * A constant used in
738      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
739      * Tracks usage of
740      * {@link WifiP2pManager#discoverPeers(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
741      * @hide
742      */
743     @SystemApi
744     public static final int API_P2P_DISCOVER_PEERS = 21;
745 
746     /**
747      * A constant used in
748      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
749      * Tracks usage of
750      * {@link WifiP2pManager#discoverPeersOnSocialChannels(WifiP2pManager.Channel,
751      * WifiP2pManager.ActionListener)}
752      * @hide
753      */
754     @SystemApi
755     public static final int API_P2P_DISCOVER_PEERS_ON_SOCIAL_CHANNELS = 22;
756 
757     /**
758      * A constant used in
759      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
760      * Tracks usage of
761      * {@link WifiP2pManager#discoverPeersOnSpecificFrequency(WifiP2pManager.Channel, int,
762      * WifiP2pManager.ActionListener)}
763      * @hide
764      */
765     @SystemApi
766     public static final int API_P2P_DISCOVER_PEERS_ON_SPECIFIC_FREQUENCY = 23;
767 
768     /**
769      * A constant used in
770      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
771      * Tracks usage of
772      * {@link WifiP2pManager#stopPeerDiscovery(WifiP2pManager.Channel,
773      * WifiP2pManager.ActionListener)}
774      * @hide
775      */
776     @SystemApi
777     public static final int API_P2P_STOP_PEER_DISCOVERY = 24;
778 
779     /**
780      * A constant used in
781      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
782      * Tracks usage of
783      * {@link WifiP2pManager#connect(WifiP2pManager.Channel, WifiP2pConfig,
784      * WifiP2pManager.ActionListener)}
785      * @hide
786      */
787     @SystemApi
788     public static final int API_P2P_CONNECT = 25;
789 
790     /**
791      * A constant used in
792      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
793      * Tracks usage of
794      * {@link WifiP2pManager#cancelConnect(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
795      * @hide
796      */
797     @SystemApi
798     public static final int API_P2P_CANCEL_CONNECT = 26;
799 
800     /**
801      * A constant used in
802      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
803      * Tracks usage of
804      * {@link WifiP2pManager#createGroup(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
805      * @hide
806      */
807     @SystemApi
808     public static final int API_P2P_CREATE_GROUP = 27;
809 
810     /**
811      * A constant used in
812      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
813      * Tracks usage of
814      * {@link WifiP2pManager#createGroup(WifiP2pManager.Channel, WifiP2pConfig,
815      * WifiP2pManager.ActionListener)}
816      * @hide
817      */
818     @SystemApi
819     public static final int API_P2P_CREATE_GROUP_P2P_CONFIG = 28;
820 
821     /**
822      * A constant used in
823      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
824      * Tracks usage of
825      * {@link WifiP2pManager#removeGroup(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
826      * @hide
827      */
828     @SystemApi
829     public static final int API_P2P_REMOVE_GROUP = 29;
830 
831     /**
832      * A constant used in
833      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
834      * Tracks usage of
835      * {@link WifiP2pManager#startListening(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
836      * @hide
837      */
838     @SystemApi
839     public static final int API_P2P_START_LISTENING = 30;
840 
841     /**
842      * A constant used in
843      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
844      * Tracks usage of
845      * {@link WifiP2pManager#stopListening(WifiP2pManager.Channel, WifiP2pManager.ActionListener)}
846      * @hide
847      */
848     @SystemApi
849     public static final int API_P2P_STOP_LISTENING = 31;
850 
851     /**
852      * A constant used in
853      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
854      * Tracks usage of
855      * {@link WifiP2pManager#setWifiP2pChannels(WifiP2pManager.Channel, int, int,
856      * WifiP2pManager.ActionListener)}
857      * @hide
858      */
859     @SystemApi
860     public static final int API_P2P_SET_CHANNELS = 32;
861 
862     /**
863      * A constant used in
864      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
865      * Tracks usage of
866      * {@link WifiScanner#startScan(WifiScanner.ScanSettings, WifiScanner.ScanListener)}
867      * @hide
868      */
869     @SystemApi
870     public static final int API_WIFI_SCANNER_START_SCAN = 33;
871 
872     /**
873      * A constant used in
874      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
875      * Tracks usage of
876      * {@link WifiManager#setTdlsEnabled(InetAddress, boolean)} and
877      * {@link WifiManager#setTdlsEnabled(InetAddress, boolean, Executor, Consumer)}
878      * @hide
879      */
880     @SystemApi
881     public static final int API_SET_TDLS_ENABLED = 34;
882 
883     /**
884      * A constant used in
885      * {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
886      * Tracks usage of
887      * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean)} and
888      * {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
889      * @hide
890      */
891     @SystemApi
892     public static final int API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS = 35;
893 
894     /**
895      * A constant used in {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
896      * Tracks usage of {@link WifiManager#setPnoScanState(int)}
897      *
898      * @hide
899      */
900     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
901     @SystemApi
902     public static final int API_SET_PNO_SCAN_ENABLED = 36;
903 
904     /**
905      * A constant used in {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}
906      * Tracks usage of {@link WifiP2pManager#discoverPeersWithConfigParams(
907      * WifiP2pManager.Channel, WifiP2pDiscoveryConfig, WifiP2pManager.ActionListener)}
908      *
909      * @hide
910      */
911     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
912     @SystemApi
913     public static final int API_P2P_DISCOVER_PEERS_WITH_CONFIG_PARAMS = 37;
914 
915     /**
916      * Used internally to keep track of boundary.
917      * @hide
918      */
919     public static final int API_MAX = 38;
920 
921     /**
922      * Broadcast intent action indicating that a Passpoint provider icon has been received.
923      *
924      * Included extras:
925      * {@link #EXTRA_BSSID_LONG}
926      * {@link #EXTRA_FILENAME}
927      * {@link #EXTRA_ICON}
928      *
929      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
930      *
931      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
932      * components will be launched.
933      *
934      * @hide
935      */
936     public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
937     /**
938      * BSSID of an AP in long representation.  The {@link #EXTRA_BSSID} contains BSSID in
939      * String representation.
940      *
941      * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}.
942      *
943      * @hide
944      */
945     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
946     /**
947      * Icon data.
948      *
949      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
950      * {@link android.graphics.drawable.Icon}.
951      *
952      * @hide
953      */
954     public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
955     /**
956      * Name of a file.
957      *
958      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
959      *
960      * @hide
961      */
962     public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
963 
964     /**
965      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
966      *
967      * Included extras:
968      * {@link #EXTRA_BSSID_LONG}
969      * {@link #EXTRA_ANQP_ELEMENT_DATA}
970      *
971      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
972      *
973      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
974      * components will be launched.
975      *
976      * @hide
977      */
978     public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
979             "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
980     /**
981      * Raw binary data of an ANQP (Access Network Query Protocol) element.
982      *
983      * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}.
984      *
985      * @hide
986      */
987     public static final String EXTRA_ANQP_ELEMENT_DATA =
988             "android.net.wifi.extra.ANQP_ELEMENT_DATA";
989 
990     /**
991      * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
992      *
993      * Included extras:
994      * {@link #EXTRA_BSSID_LONG}
995      * {@link #EXTRA_ESS}
996      * {@link #EXTRA_DELAY}
997      * {@link #EXTRA_URL}
998      *
999      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1000      *
1001      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
1002      * components will be launched.
1003      *
1004      * @hide
1005      */
1006     public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
1007             "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
1008     /**
1009      * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to
1010      * {@code true} for ESS.
1011      *
1012      * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}.
1013      *
1014      * @hide
1015      */
1016     public static final String EXTRA_ESS = "android.net.wifi.extra.ESS";
1017     /**
1018      * Delay in seconds.
1019      *
1020      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
1021      *
1022      * @hide
1023      */
1024     public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
1025 
1026     /**
1027      * Broadcast intent action indicating a Passpoint subscription remediation frame has been
1028      * received.
1029      *
1030      * Included extras:
1031      * {@link #EXTRA_BSSID_LONG}
1032      * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD}
1033      * {@link #EXTRA_URL}
1034      *
1035      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1036      *
1037      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
1038      * components will be launched.
1039      *
1040      * @hide
1041      */
1042     public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
1043             "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
1044     /**
1045      * The protocol supported by the subscription remediation server. The possible values are:
1046      * 0 - OMA DM
1047      * 1 - SOAP XML SPP
1048      *
1049      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
1050      *
1051      * @hide
1052      */
1053     public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD =
1054             "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
1055 
1056     /**
1057      * Activity Action: Receiver should launch Passpoint OSU (Online Sign Up) view.
1058      * Included extras:
1059      *
1060      * {@link #EXTRA_OSU_NETWORK}: {@link Network} instance associated with OSU AP.
1061      * {@link #EXTRA_URL}: String representation of a server URL used for OSU process.
1062      *
1063      * @hide
1064      */
1065     @SystemApi
1066     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1067     public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW =
1068             "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
1069 
1070     /**
1071      * The lookup key for a {@link android.net.Network} associated with a Passpoint OSU server.
1072      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
1073      *
1074      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1075      *
1076      * @hide
1077      */
1078     @SystemApi
1079     public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
1080 
1081     /**
1082      * String representation of an URL for Passpoint OSU.
1083      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
1084      *
1085      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
1086      *
1087      * @hide
1088      */
1089     @SystemApi
1090     public static final String EXTRA_URL = "android.net.wifi.extra.URL";
1091 
1092     /**
1093      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
1094      * enabling, disabling, or unknown. One extra provides this state as an int.
1095      * Another extra provides the previous state, if available.  No network-related
1096      * permissions are required to subscribe to this broadcast.
1097      *
1098      * <p class="note">This broadcast is not delivered to manifest receivers in
1099      * applications that target API version 26 or later.
1100      *
1101      * @see #EXTRA_WIFI_STATE
1102      * @see #EXTRA_PREVIOUS_WIFI_STATE
1103      */
1104     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1105     public static final String WIFI_STATE_CHANGED_ACTION =
1106         "android.net.wifi.WIFI_STATE_CHANGED";
1107     /**
1108      * The lookup key for an int that indicates whether Wi-Fi is enabled,
1109      * disabled, enabling, disabling, or unknown.  Retrieve it with
1110      * {@link android.content.Intent#getIntExtra(String,int)}.
1111      *
1112      * @see #WIFI_STATE_DISABLED
1113      * @see #WIFI_STATE_DISABLING
1114      * @see #WIFI_STATE_ENABLED
1115      * @see #WIFI_STATE_ENABLING
1116      * @see #WIFI_STATE_UNKNOWN
1117      */
1118     public static final String EXTRA_WIFI_STATE = "wifi_state";
1119     /**
1120      * The previous Wi-Fi state.
1121      *
1122      * @see #EXTRA_WIFI_STATE
1123      */
1124     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
1125 
1126     /**
1127      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
1128      * it finishes successfully.
1129      *
1130      * @see #WIFI_STATE_CHANGED_ACTION
1131      * @see #getWifiState()
1132      */
1133     public static final int WIFI_STATE_DISABLING = 0;
1134     /**
1135      * Wi-Fi is disabled.
1136      *
1137      * @see #WIFI_STATE_CHANGED_ACTION
1138      * @see #getWifiState()
1139      */
1140     public static final int WIFI_STATE_DISABLED = 1;
1141     /**
1142      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
1143      * it finishes successfully.
1144      *
1145      * @see #WIFI_STATE_CHANGED_ACTION
1146      * @see #getWifiState()
1147      */
1148     public static final int WIFI_STATE_ENABLING = 2;
1149     /**
1150      * Wi-Fi is enabled.
1151      *
1152      * @see #WIFI_STATE_CHANGED_ACTION
1153      * @see #getWifiState()
1154      */
1155     public static final int WIFI_STATE_ENABLED = 3;
1156     /**
1157      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
1158      * or disabling.
1159      *
1160      * @see #WIFI_STATE_CHANGED_ACTION
1161      * @see #getWifiState()
1162      */
1163     public static final int WIFI_STATE_UNKNOWN = 4;
1164 
1165     /**
1166      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
1167      * enabling, disabling, or failed.
1168      *
1169      * @hide
1170      */
1171     @SystemApi
1172     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
1173     public static final String WIFI_AP_STATE_CHANGED_ACTION =
1174         "android.net.wifi.WIFI_AP_STATE_CHANGED";
1175 
1176     /**
1177      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
1178      * disabled, enabling, disabling, or failed.  Retrieve it with
1179      * {@link android.content.Intent#getIntExtra(String,int)}.
1180      *
1181      * @see #WIFI_AP_STATE_DISABLED
1182      * @see #WIFI_AP_STATE_DISABLING
1183      * @see #WIFI_AP_STATE_ENABLED
1184      * @see #WIFI_AP_STATE_ENABLING
1185      * @see #WIFI_AP_STATE_FAILED
1186      *
1187      * @hide
1188      */
1189     @SystemApi
1190     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
1191 
1192     /**
1193      * An extra containing the int error code for Soft AP start failure.
1194      * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
1195      * {@link android.content.Intent#getIntExtra}.
1196      * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
1197      * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
1198      *
1199      * The error code will be one of:
1200      * {@link #SAP_START_FAILURE_GENERAL},
1201      * {@link #SAP_START_FAILURE_NO_CHANNEL},
1202      * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
1203      * {@link #SAP_START_FAILURE_USER_REJECTED}
1204      *
1205      * @hide
1206      */
1207     @SystemApi
1208     public static final String EXTRA_WIFI_AP_FAILURE_REASON =
1209             "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
1210     /**
1211      * The previous Wi-Fi state.
1212      *
1213      * @see #EXTRA_WIFI_AP_STATE
1214      *
1215      * @hide
1216      */
1217     @SystemApi
1218     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
1219     /**
1220      * The lookup key for a String extra that stores the interface name used for the Soft AP.
1221      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
1222      * Retrieve its value with {@link android.content.Intent#getStringExtra(String)}.
1223      *
1224      * @hide
1225      */
1226     @SystemApi
1227     public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
1228             "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
1229     /**
1230      * The lookup key for an int extra that stores the intended IP mode for this Soft AP.
1231      * One of {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
1232      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
1233      * Retrieve its value with {@link android.content.Intent#getIntExtra(String, int)}.
1234      *
1235      * @hide
1236      */
1237     @SystemApi
1238     public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
1239 
1240     /** @hide */
1241     @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
1242         WIFI_AP_STATE_DISABLING,
1243         WIFI_AP_STATE_DISABLED,
1244         WIFI_AP_STATE_ENABLING,
1245         WIFI_AP_STATE_ENABLED,
1246         WIFI_AP_STATE_FAILED,
1247     })
1248     @Retention(RetentionPolicy.SOURCE)
1249     public @interface WifiApState {}
1250 
1251     /**
1252      * Wi-Fi AP is currently being disabled. The state will change to
1253      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
1254      *
1255      * @see #WIFI_AP_STATE_CHANGED_ACTION
1256      * @see #getWifiApState()
1257      *
1258      * @hide
1259      */
1260     @SystemApi
1261     public static final int WIFI_AP_STATE_DISABLING = 10;
1262     /**
1263      * Wi-Fi AP is disabled.
1264      *
1265      * @see #WIFI_AP_STATE_CHANGED_ACTION
1266      * @see #getWifiState()
1267      *
1268      * @hide
1269      */
1270     @SystemApi
1271     public static final int WIFI_AP_STATE_DISABLED = 11;
1272     /**
1273      * Wi-Fi AP is currently being enabled. The state will change to
1274      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
1275      *
1276      * @see #WIFI_AP_STATE_CHANGED_ACTION
1277      * @see #getWifiApState()
1278      *
1279      * @hide
1280      */
1281     @SystemApi
1282     public static final int WIFI_AP_STATE_ENABLING = 12;
1283     /**
1284      * Wi-Fi AP is enabled.
1285      *
1286      * @see #WIFI_AP_STATE_CHANGED_ACTION
1287      * @see #getWifiApState()
1288      *
1289      * @hide
1290      */
1291     @SystemApi
1292     public static final int WIFI_AP_STATE_ENABLED = 13;
1293     /**
1294      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
1295      * enabling or disabling
1296      *
1297      * @see #WIFI_AP_STATE_CHANGED_ACTION
1298      * @see #getWifiApState()
1299      *
1300      * @hide
1301      */
1302     @SystemApi
1303     public static final int WIFI_AP_STATE_FAILED = 14;
1304 
1305     /** @hide */
1306     @IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = {
1307         SAP_START_FAILURE_GENERAL,
1308         SAP_START_FAILURE_NO_CHANNEL,
1309         SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION,
1310         SAP_START_FAILURE_USER_REJECTED,
1311     })
1312     @Retention(RetentionPolicy.SOURCE)
1313     public @interface SapStartFailure {}
1314 
1315     /**
1316      *  All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL},
1317      *  {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}, and
1318      *  {@link #SAP_START_FAILURE_USER_REJECTED}.
1319      *
1320      *  @hide
1321      */
1322     @SystemApi
1323     public static final int SAP_START_FAILURE_GENERAL= 0;
1324 
1325     /**
1326      *  If Wi-Fi AP start failed, this reason code means that no legal channel exists on user
1327      *  selected band due to regulatory constraints.
1328      *
1329      *  @hide
1330      */
1331     @SystemApi
1332     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
1333 
1334     /**
1335      *  If Wi-Fi AP start failed, this reason code means that the specified configuration
1336      *  is not supported by the current HAL version.
1337      *
1338      *  @hide
1339      */
1340     @SystemApi
1341     public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2;
1342 
1343     /**
1344      *  If Wi-Fi AP start failed, this reason code means that the user was asked for confirmation to
1345      *  create the AP and the user declined.
1346      *
1347      *  @hide
1348      */
1349     @SystemApi
1350     public static final int SAP_START_FAILURE_USER_REJECTED = 3;
1351 
1352     /** @hide */
1353     @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = {
1354         SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER,
1355         SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS,
1356     })
1357     @Retention(RetentionPolicy.SOURCE)
1358     public @interface SapClientBlockedReason {}
1359 
1360     /**
1361      *  If Soft Ap client is blocked, this reason code means that client doesn't exist in the
1362      *  specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
1363      *  and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
1364      *  and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
1365      *  is configured as well.
1366      *  @hide
1367      */
1368     @SystemApi
1369     public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0;
1370 
1371     /**
1372      *  If Soft Ap client is blocked, this reason code means that no more clients can be
1373      *  associated to this AP since it reached maximum capacity. The maximum capacity is
1374      *  the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and
1375      *  {@link SoftApCapability#getMaxSupportedClients} which get from
1376      *  {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}.
1377      *
1378      *  @hide
1379      */
1380     @SystemApi
1381     public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1;
1382 
1383     /**
1384      * Client disconnected for unspecified reason. This could for example be because the AP is being
1385      * shut down.
1386      * @hide
1387      */
1388     public static final int SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED = 2;
1389 
1390     /** @hide */
1391     @Retention(RetentionPolicy.SOURCE)
1392     @IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
1393             IFACE_IP_MODE_UNSPECIFIED,
1394             IFACE_IP_MODE_CONFIGURATION_ERROR,
1395             IFACE_IP_MODE_TETHERED,
1396             IFACE_IP_MODE_LOCAL_ONLY})
1397     public @interface IfaceIpMode {}
1398 
1399     /**
1400      * Interface IP mode unspecified.
1401      *
1402      * @see #updateInterfaceIpState(String, int)
1403      *
1404      * @hide
1405      */
1406     @SystemApi
1407     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
1408 
1409     /**
1410      * Interface IP mode for configuration error.
1411      *
1412      * @see #updateInterfaceIpState(String, int)
1413      *
1414      * @hide
1415      */
1416     @SystemApi
1417     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
1418 
1419     /**
1420      * Interface IP mode for tethering.
1421      *
1422      * @see #updateInterfaceIpState(String, int)
1423      *
1424      * @hide
1425      */
1426     @SystemApi
1427     public static final int IFACE_IP_MODE_TETHERED = 1;
1428 
1429     /**
1430      * Interface IP mode for Local Only Hotspot.
1431      *
1432      * @see #updateInterfaceIpState(String, int)
1433      *
1434      * @hide
1435      */
1436     @SystemApi
1437     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
1438 
1439     /**
1440      * Broadcast intent action indicating that the wifi network settings
1441      * had been reset.
1442      *
1443      * Note: This intent is sent as a directed broadcast to each manifest registered receiver.
1444      * Intent will not be received by dynamically registered receivers.
1445      * @hide
1446      */
1447     @SystemApi
1448     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
1449     public static final String ACTION_NETWORK_SETTINGS_RESET =
1450             "android.net.wifi.action.NETWORK_SETTINGS_RESET";
1451 
1452     /**
1453      * Broadcast intent action indicating that the wifi network profiles provisioned
1454      * may need refresh.
1455      *
1456      * Note: This intent is sent as a directed broadcast to each manifest registered receiver;
1457      * And restricted to those apps which have the NETWORK_CARRIER_PROVISIONING permission.
1458      * Intent will not be received by dynamically registered receivers.
1459      * @hide
1460      */
1461     @SystemApi
1462     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
1463     public static final String ACTION_REFRESH_USER_PROVISIONING =
1464             "android.net.wifi.action.REFRESH_USER_PROVISIONING";
1465 
1466     /**
1467      * Broadcast intent action indicating that a connection to the supplicant has
1468      * been established (and it is now possible
1469      * to perform Wi-Fi operations) or the connection to the supplicant has been
1470      * lost. One extra provides the connection state as a boolean, where {@code true}
1471      * means CONNECTED.
1472      * @deprecated This is no longer supported.
1473      * @see #EXTRA_SUPPLICANT_CONNECTED
1474      */
1475     @Deprecated
1476     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1477     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
1478         "android.net.wifi.supplicant.CONNECTION_CHANGE";
1479     /**
1480      * The lookup key for a boolean that indicates whether a connection to
1481      * the supplicant daemon has been gained or lost. {@code true} means
1482      * a connection now exists.
1483      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
1484      * @deprecated This is no longer supported.
1485      */
1486     @Deprecated
1487     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
1488     /**
1489      * Broadcast intent action indicating that the state of Wi-Fi connectivity
1490      * has changed. An extra provides the new state
1491      * in the form of a {@link android.net.NetworkInfo} object.  No network-related
1492      * permissions are required to subscribe to this broadcast.
1493      *
1494      * <p class="note">This broadcast is not delivered to manifest receivers in
1495      * applications that target API version 26 or later.
1496      * @see #EXTRA_NETWORK_INFO
1497      */
1498     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1499     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
1500     /**
1501      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
1502      * Wi-Fi network. Retrieve with
1503      * {@link android.content.Intent#getParcelableExtra(String)}.
1504      */
1505     public static final String EXTRA_NETWORK_INFO = "networkInfo";
1506     /**
1507      * The lookup key for a String giving the BSSID of the access point to which
1508      * we are connected. No longer used.
1509      */
1510     @Deprecated
1511     public static final String EXTRA_BSSID = "bssid";
1512     /**
1513      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
1514      * information about the access point to which we are connected.
1515      * No longer used.
1516      */
1517     @Deprecated
1518     public static final String EXTRA_WIFI_INFO = "wifiInfo";
1519     /**
1520      * Broadcast intent action indicating that the state of establishing a connection to
1521      * an access point has changed.One extra provides the new
1522      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
1523      * is not generally the most useful thing to look at if you are just interested in
1524      * the overall state of connectivity.
1525      * @see #EXTRA_NEW_STATE
1526      * @see #EXTRA_SUPPLICANT_ERROR
1527      * @deprecated This is no longer supported.
1528      */
1529     @Deprecated
1530     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1531     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
1532         "android.net.wifi.supplicant.STATE_CHANGE";
1533     /**
1534      * The lookup key for a {@link SupplicantState} describing the new state
1535      * Retrieve with
1536      * {@link android.content.Intent#getParcelableExtra(String)}.
1537      * @deprecated This is no longer supported.
1538      */
1539     @Deprecated
1540     public static final String EXTRA_NEW_STATE = "newState";
1541 
1542     /**
1543      * The lookup key for a {@link SupplicantState} describing the supplicant
1544      * error code if any
1545      * Retrieve with
1546      * {@link android.content.Intent#getIntExtra(String, int)}.
1547      * @see #ERROR_AUTHENTICATING
1548      * @deprecated This is no longer supported.
1549      */
1550     @Deprecated
1551     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
1552 
1553     /**
1554      * The lookup key for a {@link SupplicantState} describing the supplicant
1555      * error reason if any
1556      * Retrieve with
1557      * {@link android.content.Intent#getIntExtra(String, int)}.
1558      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
1559      * @deprecated This is no longer supported.
1560      * @hide
1561      */
1562     @Deprecated
1563     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
1564 
1565     /**
1566      * Broadcast intent action indicating that the configured networks changed.
1567      * This can be as a result of adding/updating/deleting a network.
1568      * <br />
1569      * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
1570      * {@link #EXTRA_WIFI_CONFIGURATION} is never set beginning in
1571      * {@link android.os.Build.VERSION_CODES#R}.
1572      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
1573      * its value is always true beginning in {@link android.os.Build.VERSION_CODES#R}, even if only
1574      * a single network changed.
1575      * <br />
1576      * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
1577      * required to receive this broadcast.
1578      *
1579      * @hide
1580      */
1581     @SystemApi
1582     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
1583         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
1584     /**
1585      * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
1586      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
1587      * broadcast is sent.
1588      * @deprecated This extra is never set beginning in {@link android.os.Build.VERSION_CODES#R},
1589      * regardless of the target SDK version. Use {@link #getConfiguredNetworks} to get the full list
1590      * of configured networks.
1591      * @hide
1592      */
1593     @Deprecated
1594     @SystemApi
1595     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
1596     /**
1597      * Multiple network configurations have changed.
1598      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
1599      * @deprecated This extra's value is always true beginning in
1600      * {@link android.os.Build.VERSION_CODES#R}, regardless of the target SDK version.
1601      * @hide
1602      */
1603     @Deprecated
1604     @SystemApi
1605     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
1606     /**
1607      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
1608      * has changed. One of {@link #CHANGE_REASON_ADDED}, {@link #CHANGE_REASON_REMOVED},
1609      * {@link #CHANGE_REASON_CONFIG_CHANGE}.
1610      *
1611      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
1612      * @hide
1613      */
1614     @SystemApi
1615     public static final String EXTRA_CHANGE_REASON = "changeReason";
1616     /**
1617      * The configuration is new and was added.
1618      * @hide
1619      */
1620     @SystemApi
1621     public static final int CHANGE_REASON_ADDED = 0;
1622     /**
1623      * The configuration was removed and is no longer present in the system's list of
1624      * configured networks.
1625      * @hide
1626      */
1627     @SystemApi
1628     public static final int CHANGE_REASON_REMOVED = 1;
1629     /**
1630      * The configuration has changed as a result of explicit action or because the system
1631      * took an automated action such as disabling a malfunctioning configuration.
1632      * @hide
1633      */
1634     @SystemApi
1635     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
1636     /**
1637      * An access point scan has completed, and results are available.
1638      * Call {@link #getScanResults()} to obtain the results.
1639      * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
1640      * and a {@code boolean} value indicating if the scan was successful.
1641      */
1642     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1643     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
1644 
1645     /**
1646      * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
1647      * representing if the scan was successful or not.
1648      * Scans may fail for multiple reasons, these may include:
1649      * <ol>
1650      * <li>An app requested too many scans in a certain period of time.
1651      * This may lead to additional scan request rejections via "scan throttling" for both
1652      * foreground and background apps.
1653      * Note: Apps holding android.Manifest.permission.NETWORK_SETTINGS permission are
1654      * exempted from scan throttling.
1655      * </li>
1656      * <li>The device is idle and scanning is disabled.</li>
1657      * <li>Wifi hardware reported a scan failure.</li>
1658      * </ol>
1659      * @return true scan was successful, results are updated
1660      * @return false scan was not successful, results haven't been updated since previous scan
1661      */
1662     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
1663 
1664     /**
1665      * A batch of access point scans has been completed and the results areavailable.
1666      * Call {@link #getBatchedScanResults()} to obtain the results.
1667      * @deprecated This API is nolonger supported.
1668      * Use {@link WifiScanner} API
1669      * @hide
1670      */
1671     @Deprecated
1672     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1673     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
1674             "android.net.wifi.BATCHED_RESULTS";
1675 
1676     /**
1677      * The RSSI (signal strength) has changed.
1678      *
1679      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1680      * @see #EXTRA_NEW_RSSI
1681      */
1682     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1683     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
1684     /**
1685      * The lookup key for an {@code int} giving the new RSSI in dBm.
1686      */
1687     public static final String EXTRA_NEW_RSSI = "newRssi";
1688 
1689     /**
1690      * @see #ACTION_LINK_CONFIGURATION_CHANGED
1691      * @hide
1692      */
1693     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1694     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
1695             "android.net.wifi.LINK_CONFIGURATION_CHANGED";
1696 
1697     /**
1698      * Broadcast intent action indicating that the link configuration changed on wifi.
1699      * <br /> No permissions are required to listen to this broadcast.
1700      * @hide
1701      */
1702     @SystemApi
1703     public static final String ACTION_LINK_CONFIGURATION_CHANGED =
1704             // should be android.net.wifi.action.LINK_CONFIGURATION_CHANGED, but due to
1705             // @UnsupportedAppUsage leaving it as android.net.wifi.LINK_CONFIGURATION_CHANGED.
1706             LINK_CONFIGURATION_CHANGED_ACTION;
1707 
1708     /**
1709      * The lookup key for a {@link android.net.LinkProperties} object associated with the
1710      * Wi-Fi network.
1711      * Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
1712      *
1713      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1714      *
1715      * @deprecated this extra is no longer populated.
1716      *
1717      * @hide
1718      */
1719     @Deprecated
1720     @SystemApi
1721     public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
1722 
1723     /**
1724      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
1725      * Wi-Fi network. Retrieve with
1726      * {@link android.content.Intent#getParcelableExtra(String)}.
1727      * @hide
1728      */
1729     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
1730 
1731     /**
1732      * The network IDs of the configured networks could have changed.
1733      */
1734     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1735     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
1736 
1737     /**
1738      * Activity Action: Show a system activity that allows the user to enable
1739      * scans to be available even with Wi-Fi turned off.
1740      *
1741      * <p>Notification of the result of this activity is posted using the
1742      * {@link android.app.Activity#onActivityResult} callback. The
1743      * <code>resultCode</code>
1744      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
1745      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
1746      * has rejected the request or an error has occurred.
1747      */
1748     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1749     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
1750             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
1751 
1752     /**
1753      * Activity Action: Pick a Wi-Fi network to connect to.
1754      * <p>Input: Nothing.
1755      * <p>Output: Nothing.
1756      */
1757     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1758     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
1759 
1760     /**
1761      * Activity Action: Receiver should show UI to get user approval to enable WiFi.
1762      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1763      *           the name of the app requesting the action.
1764      * <p>Output: Nothing.
1765      * <p>No permissions are required to send this action.
1766      * @hide
1767      */
1768     @SystemApi
1769     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1770     public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
1771 
1772     /**
1773      * Activity Action: Receiver should show UI to get user approval to disable WiFi.
1774      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1775      *           the name of the app requesting the action.
1776      * <p>Output: Nothing.
1777      * <p>No permissions are required to send this action.
1778      * @hide
1779      */
1780     @SystemApi
1781     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1782     public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
1783 
1784     /**
1785      * Directed broadcast intent action indicating that the device has connected to one of the
1786      * network suggestions provided by the app. This will be sent post connection to a network
1787      * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
1788      * boolean)}
1789      * flag set.
1790      * <p>
1791      * Note: The broadcast is sent to the app only if it holds
1792      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
1793      *
1794      * @see #EXTRA_NETWORK_SUGGESTION
1795      */
1796     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1797     public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION =
1798             "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
1799     /**
1800      * Sent as as a part of {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} that holds
1801      * an instance of {@link WifiNetworkSuggestion} corresponding to the connected network.
1802      */
1803     public static final String EXTRA_NETWORK_SUGGESTION =
1804             "android.net.wifi.extra.NETWORK_SUGGESTION";
1805 
1806     /**
1807      * Internally used Wi-Fi lock mode representing the case were no locks are held.
1808      * @hide
1809      */
1810     public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
1811 
1812     /**
1813      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1814      * and will behave normally, i.e., it will attempt to automatically
1815      * establish a connection to a remembered access point that is
1816      * within range, and will do periodic scans if there are remembered
1817      * access points but none are in range.
1818      *
1819      * @deprecated This API is non-functional and will have no impact.
1820      */
1821     @Deprecated
1822     public static final int WIFI_MODE_FULL = 1;
1823 
1824     /**
1825      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1826      * but the only operation that will be supported is initiation of
1827      * scans, and the subsequent reporting of scan results. No attempts
1828      * will be made to automatically connect to remembered access points,
1829      * nor will periodic scans be automatically performed looking for
1830      * remembered access points. Scans must be explicitly requested by
1831      * an application in this mode.
1832      *
1833      * @deprecated This API is non-functional and will have no impact.
1834      */
1835     @Deprecated
1836     public static final int WIFI_MODE_SCAN_ONLY = 2;
1837 
1838     /**
1839      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
1840      * This results in operating with low packet latency.
1841      * The lock is only active when the device is connected to an access point.
1842      * The lock is active even when the device screen is off or the acquiring application is
1843      * running in the background.
1844      * This mode will consume more power and hence should be used only
1845      * when there is a need for this tradeoff.
1846      * <p>
1847      * An example use case is when a voice connection needs to be
1848      * kept active even after the device screen goes off.
1849      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
1850      * duration of the voice call may improve the call quality.
1851      * <p>
1852      * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
1853      * lock will have no impact.
1854      *
1855      * @deprecated The {@code WIFI_MODE_FULL_HIGH_PERF} is deprecated and is automatically replaced
1856      * with {@link #WIFI_MODE_FULL_LOW_LATENCY} with all the restrictions documented on that lock.
1857      * I.e. any request to the {@code WIFI_MODE_FULL_HIGH_PERF} will now obtain a
1858      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock instead.
1859      * Deprecation is due to the impact of {@code WIFI_MODE_FULL_HIGH_PERF} on power dissipation.
1860      * The {@link #WIFI_MODE_FULL_LOW_LATENCY} provides much of the same desired functionality with
1861      * less impact on power dissipation.
1862      */
1863     @Deprecated
1864     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
1865 
1866     /**
1867      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
1868      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock has the following limitations:
1869      * <ol>
1870      * <li>The lock is only active when the device is connected to an access point.</li>
1871      * <li>The lock is only active when the screen is on.</li>
1872      * <li>The lock is only active when the acquiring app is running in the foreground.</li>
1873      * </ol>
1874      * Low latency mode optimizes for reduced packet latency,
1875      * and as a result other performance measures may suffer when there are trade-offs to make:
1876      * <ol>
1877      * <li>Battery life may be reduced.</li>
1878      * <li>Throughput may be reduced.</li>
1879      * <li>Frequency of Wi-Fi scanning may be reduced. This may result in: </li>
1880      * <ul>
1881      * <li>The device may not roam or switch to the AP with highest signal quality.</li>
1882      * <li>Location accuracy may be reduced.</li>
1883      * </ul>
1884      * </ol>
1885      * <p>
1886      * Example use cases are real time gaming or virtual reality applications where
1887      * low latency is a key factor for user experience.
1888      * <p>
1889      * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and
1890      * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY}
1891      * lock will be effective when app is running in foreground and screen is on,
1892      * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
1893      */
1894     public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
1895 
1896 
1897     /** Anything worse than or equal to this will show 0 bars. */
1898     @UnsupportedAppUsage
1899     private static final int MIN_RSSI = -100;
1900 
1901     /** Anything better than or equal to this will show the max bars. */
1902     @UnsupportedAppUsage
1903     private static final int MAX_RSSI = -55;
1904 
1905     /**
1906      * Number of RSSI levels used in the framework to initiate {@link #RSSI_CHANGED_ACTION}
1907      * broadcast, where each level corresponds to a range of RSSI values.
1908      * The {@link #RSSI_CHANGED_ACTION} broadcast will only fire if the RSSI
1909      * change is significant enough to change the RSSI signal level.
1910      * @hide
1911      */
1912     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1913     public static final int RSSI_LEVELS = 5;
1914 
1915     //TODO (b/146346676): This needs to be removed, not used in the code.
1916     /**
1917      * Auto settings in the driver. The driver could choose to operate on both
1918      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
1919      * @hide
1920      */
1921     @UnsupportedAppUsage
1922     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
1923 
1924     /**
1925      * Operation on 5 GHz alone
1926      * @hide
1927      */
1928     @UnsupportedAppUsage
1929     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
1930 
1931     /**
1932      * Operation on 2.4 GHz alone
1933      * @hide
1934      */
1935     @UnsupportedAppUsage
1936     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
1937 
1938     /** @hide */
1939     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
1940 
1941     /**
1942      * Maximum number of active locks we allow.
1943      * This limit was added to prevent apps from creating a ridiculous number
1944      * of locks and crashing the system by overflowing the global ref table.
1945      */
1946     private static final int MAX_ACTIVE_LOCKS = 50;
1947 
1948     /** Indicates an invalid SSID. */
1949     public static final String UNKNOWN_SSID = "<unknown ssid>";
1950 
1951     /** @hide */
1952     public static final MacAddress ALL_ZEROS_MAC_ADDRESS =
1953             MacAddress.fromString("00:00:00:00:00:00");
1954 
1955     /** @hide */
1956     @IntDef(flag = false, prefix = { "WIFI_MULTI_INTERNET_MODE_" }, value = {
1957         WIFI_MULTI_INTERNET_MODE_DISABLED,
1958         WIFI_MULTI_INTERNET_MODE_DBS_AP,
1959         WIFI_MULTI_INTERNET_MODE_MULTI_AP,
1960     })
1961     @Retention(RetentionPolicy.SOURCE)
1962     public @interface WifiMultiInternetMode {}
1963 
1964     /**
1965      * Wi-Fi simultaneous connection to multiple internet-providing Wi-Fi networks (APs) is
1966      * disabled.
1967      *
1968      * @see #getStaConcurrencyForMultiInternetMode()
1969      *
1970      */
1971     public static final int WIFI_MULTI_INTERNET_MODE_DISABLED = 0;
1972     /**
1973      * Wi-Fi simultaneous connection to multiple internet-providing Wi-FI networks (APs) is enabled
1974      * and restricted to a single network on different bands (e.g. a DBS AP).
1975      *
1976      * @see #getStaConcurrencyForMultiInternetMode()
1977      *
1978      */
1979     public static final int WIFI_MULTI_INTERNET_MODE_DBS_AP = 1;
1980     /**
1981      * Wi-Fi simultaneous connection to multiple internet-providing Wi-Fi networks (APs) is enabled.
1982      * The device can connect to any networks/APs - it is just restricted to using different bands
1983      * for individual connections.
1984      *
1985      * @see #getStaConcurrencyForMultiInternetMode()
1986      *
1987      */
1988     public static final int WIFI_MULTI_INTERNET_MODE_MULTI_AP = 2;
1989 
1990     /**
1991      * The bundle key string for the channel frequency in MHz.
1992      * See {@link #getChannelData(Executor, Consumer)}
1993      */
1994     public static final String CHANNEL_DATA_KEY_FREQUENCY_MHZ = "CHANNEL_DATA_KEY_FREQUENCY_MHZ";
1995     /**
1996      * The bundle key for the number of APs found on the corresponding channel specified by
1997      * {@link WifiManager#CHANNEL_DATA_KEY_FREQUENCY_MHZ}.
1998      * See {@link #getChannelData(Executor, Consumer)}
1999      */
2000     public static final String CHANNEL_DATA_KEY_NUM_AP = "CHANNEL_DATA_KEY_NUM_AP";
2001 
2002     /**
2003      * This policy is being tracked by the Wifi service.
2004      * Indicates success for {@link #addQosPolicies(List, Executor, Consumer)}.
2005      * @hide
2006      */
2007     @SystemApi
2008     public static final int QOS_REQUEST_STATUS_TRACKING = 0;
2009 
2010     /**
2011      * A policy with the same policy ID is already being tracked.
2012      * @hide
2013      */
2014     @SystemApi
2015     public static final int QOS_REQUEST_STATUS_ALREADY_ACTIVE = 1;
2016 
2017     /**
2018      * There are insufficient resources to handle this request at this time.
2019      * @hide
2020      */
2021     @SystemApi
2022     public static final int QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES = 2;
2023 
2024     /**
2025      * The parameters in the policy request are invalid.
2026      * @hide
2027      */
2028     @SystemApi
2029     public static final int QOS_REQUEST_STATUS_INVALID_PARAMETERS = 3;
2030 
2031     /**
2032      * An unspecified failure occurred while processing this request.
2033      * @hide
2034      */
2035     @SystemApi
2036     public static final int QOS_REQUEST_STATUS_FAILURE_UNKNOWN = 4;
2037 
2038     /** @hide */
2039     @Retention(RetentionPolicy.SOURCE)
2040     @IntDef(prefix = {"QOS_REQUEST_STATUS_"}, value = {
2041             QOS_REQUEST_STATUS_TRACKING,
2042             QOS_REQUEST_STATUS_ALREADY_ACTIVE,
2043             QOS_REQUEST_STATUS_INSUFFICIENT_RESOURCES,
2044             QOS_REQUEST_STATUS_INVALID_PARAMETERS,
2045             QOS_REQUEST_STATUS_FAILURE_UNKNOWN})
2046     public @interface QosRequestStatus {}
2047 
2048     /**
2049      * Maximum number of policies that can be included in a QoS add/remove request.
2050      */
2051     private static final int MAX_POLICIES_PER_QOS_REQUEST = 16;
2052 
2053     /**
2054      * Get the maximum number of policies that can be included in a request to
2055      * {@link #addQosPolicies(List, Executor, Consumer)} or {@link #removeQosPolicies(int[])}.
2056      * @hide
2057      */
2058     @SystemApi
getMaxNumberOfPoliciesPerQosRequest()2059     public static int getMaxNumberOfPoliciesPerQosRequest() {
2060         return MAX_POLICIES_PER_QOS_REQUEST;
2061     }
2062 
2063     /* Number of currently active WifiLocks and MulticastLocks */
2064     @UnsupportedAppUsage
2065     private int mActiveLockCount;
2066 
2067     private Context mContext;
2068     @UnsupportedAppUsage
2069     IWifiManager mService;
2070     private final int mTargetSdkVersion;
2071 
2072     private Looper mLooper;
2073     private boolean mVerboseLoggingEnabled = false;
2074 
2075     private final Object mLock = new Object(); // lock guarding access to the following vars
2076     @GuardedBy("mLock")
2077     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
2078     @GuardedBy("mLock")
2079     private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
2080 
2081     private static final SparseArray<IOnWifiUsabilityStatsListener>
2082             sOnWifiUsabilityStatsListenerMap = new SparseArray();
2083     private static final SparseArray<ISuggestionConnectionStatusListener>
2084             sSuggestionConnectionStatusListenerMap = new SparseArray();
2085     private static final SparseArray<ISuggestionUserApprovalStatusListener>
2086             sSuggestionUserApprovalStatusListenerMap = new SparseArray();
2087     private static final SparseArray<IWifiVerboseLoggingStatusChangedListener>
2088             sWifiVerboseLoggingStatusChangedListenerMap = new SparseArray();
2089     private static final SparseArray<INetworkRequestMatchCallback>
2090             sNetworkRequestMatchCallbackMap = new SparseArray();
2091     private static final SparseArray<ITrafficStateCallback>
2092             sTrafficStateCallbackMap = new SparseArray();
2093     private static final SparseArray<ISoftApCallback> sSoftApCallbackMap = new SparseArray();
2094     private static final SparseArray<IOnWifiDriverCountryCodeChangedListener>
2095             sActiveCountryCodeChangedCallbackMap = new SparseArray();
2096     private static final SparseArray<ISoftApCallback>
2097             sLocalOnlyHotspotSoftApCallbackMap = new SparseArray();
2098     private static final SparseArray<ILocalOnlyConnectionStatusListener>
2099             sLocalOnlyConnectionStatusListenerMap = new SparseArray();
2100     private static final SparseArray<IWifiNetworkStateChangedListener>
2101             sOnWifiNetworkStateChangedListenerMap = new SparseArray<>();
2102     private static final SparseArray<IWifiLowLatencyLockListener>
2103             sWifiLowLatencyLockListenerMap = new SparseArray<>();
2104 
2105     /**
2106      * Multi-link operation (MLO) will allow Wi-Fi devices to operate on multiple links at the same
2107      * time through a single connection, aiming to support applications that require lower latency,
2108      * and higher capacity. Chip vendors have algorithms that run on the chip to use available links
2109      * based on incoming traffic and various inputs. Below is a list of Multi-Link Operation modes
2110      * that applications can suggest to be accommodated in the algorithm.
2111      *
2112      * The default MLO mode is for chip vendors to use algorithms to select the optimum links to
2113      * operate on, without any guidance from the calling app.
2114      *
2115      * @hide
2116      */
2117     @SystemApi
2118     public static final int MLO_MODE_DEFAULT = 0;
2119 
2120     /**
2121      * Low latency mode for Multi-link operation. In this mode, the chip vendor's algorithm
2122      * should select MLO links that will achieve low latency.
2123      *
2124      * @hide
2125      */
2126     @SystemApi
2127     public static final int MLO_MODE_LOW_LATENCY = 1;
2128 
2129     /**
2130      * High throughput mode for Multi-link operation. In this mode, the chip vendor's algorithm
2131      * should select MLO links that will achieve higher throughput.
2132      *
2133      * @hide
2134      */
2135     @SystemApi
2136     public static final int MLO_MODE_HIGH_THROUGHPUT = 2;
2137 
2138     /**
2139      * Low power mode for Multi-link operation. In this mode, the chip vendor's algorithm
2140      * should select MLO links that will achieve low power.
2141      *
2142      * @hide
2143      */
2144     @SystemApi
2145     public static final int MLO_MODE_LOW_POWER = 3;
2146 
2147     /** @hide */
2148     @Retention(RetentionPolicy.SOURCE)
2149     @IntDef(prefix = {"MLO_MODE_"}, value = {
2150             MLO_MODE_DEFAULT,
2151             MLO_MODE_LOW_LATENCY,
2152             MLO_MODE_HIGH_THROUGHPUT,
2153             MLO_MODE_LOW_POWER})
2154     public @interface MloMode {
2155     }
2156 
2157     /**
2158      * Roaming is disabled.
2159      */
2160     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
2161     public static final int ROAMING_MODE_NONE = 0;
2162 
2163     /**
2164      * Chipset has roaming trigger capability based on the score calculated
2165      * using multiple parameters. If device is configured to this mode then it
2166      * will be using chipset's normal (default) roaming.
2167      */
2168     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
2169     public static final int ROAMING_MODE_NORMAL = 1;
2170 
2171     /**
2172      * Allows the device to roam more quickly than the normal roaming mode.
2173      * Used in cases such as where APs are installed in a high density.
2174      */
2175     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
2176     public static final int ROAMING_MODE_AGGRESSIVE = 2;
2177 
2178     /**
2179      * @hide
2180      */
2181     @Retention(RetentionPolicy.SOURCE)
2182     @IntDef(prefix = {"ROAMING_MODE_"}, value = {
2183             ROAMING_MODE_NONE,
2184             ROAMING_MODE_NORMAL,
2185             ROAMING_MODE_AGGRESSIVE})
2186     public @interface RoamingMode {
2187     }
2188 
2189     /**
2190      * Create a new WifiManager instance.
2191      * Applications will almost always want to use
2192      * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve
2193      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
2194      *
2195      * @param context the application context
2196      * @param service the Binder interface
2197      * @param looper the Looper used to deliver callbacks
2198      * @hide - hide this because it takes in a parameter of type IWifiManager, which
2199      * is a system private class.
2200      */
WifiManager(@onNull Context context, @NonNull IWifiManager service, @NonNull Looper looper)2201     public WifiManager(@NonNull Context context, @NonNull IWifiManager service,
2202         @NonNull Looper looper) {
2203         mContext = context;
2204         mService = service;
2205         mLooper = looper;
2206         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
2207         updateVerboseLoggingEnabledFromService();
2208     }
2209 
2210     /**
2211      * Return a list of all the networks configured for the current foreground
2212      * user.
2213      *
2214      * Not all fields of WifiConfiguration are returned. Only the following
2215      * fields are filled in:
2216      * <ul>
2217      * <li>networkId</li>
2218      * <li>SSID</li>
2219      * <li>BSSID</li>
2220      * <li>priority</li>
2221      * <li>allowedProtocols</li>
2222      * <li>allowedKeyManagement</li>
2223      * <li>allowedAuthAlgorithms</li>
2224      * <li>allowedPairwiseCiphers</li>
2225      * <li>allowedGroupCiphers</li>
2226      * <li>status</li>
2227      * </ul>
2228      * @return a list of network configurations in the form of a list
2229      * of {@link WifiConfiguration} objects.
2230      *
2231      * @deprecated
2232      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2233      * mechanism to trigger connection to a Wi-Fi network.
2234      * b) See {@link #addNetworkSuggestions(List)},
2235      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2236      * when auto-connecting to wifi.
2237      * <b>Compatibility Note:</b> For applications targeting
2238      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return an
2239      * empty list.
2240      * <p>
2241      * Deprecation Exemptions:
2242      * <ul>
2243      * <li>Device Owner (DO), Profile Owner (PO) and system apps will have access to the full list.
2244      * <li>Callers with Carrier privilege will receive a restricted list only containing
2245      * configurations which they created.
2246      * </ul>
2247      */
2248     @Deprecated
2249     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
getConfiguredNetworks()2250     public List<WifiConfiguration> getConfiguredNetworks() {
2251         try {
2252             ParceledListSlice<WifiConfiguration> parceledList =
2253                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
2254                             mContext.getAttributionTag(), false);
2255             if (parceledList == null) {
2256                 return Collections.emptyList();
2257             }
2258             return parceledList.getList();
2259         } catch (RemoteException e) {
2260             throw e.rethrowFromSystemServer();
2261         }
2262     }
2263 
2264     /**
2265      * Return a list of all the networks previously configured by the calling app. Can
2266      * be called by Device Owner (DO), Profile Owner (PO), Callers with Carrier privilege and
2267      * system apps.
2268      *
2269      * @return a list of network configurations in the form of a list
2270      * of {@link WifiConfiguration} objects.
2271      * @throws SecurityException if the caller is not allowed to call this API
2272      */
2273     @RequiresPermission(ACCESS_WIFI_STATE)
2274     @NonNull
getCallerConfiguredNetworks()2275     public List<WifiConfiguration> getCallerConfiguredNetworks() {
2276         try {
2277             ParceledListSlice<WifiConfiguration> parceledList =
2278                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
2279                             mContext.getAttributionTag(), true);
2280             if (parceledList == null) {
2281                 return Collections.emptyList();
2282             }
2283             return parceledList.getList();
2284         } catch (RemoteException e) {
2285             throw e.rethrowFromSystemServer();
2286         }
2287     }
2288 
2289 
2290     /**
2291      * Applications targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later need to have
2292      * the following permissions: {@link android.Manifest.permission#NEARBY_WIFI_DEVICES},
2293      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
2294      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2295      * Applications targeting {@link Build.VERSION_CODES#S} or prior SDK levels need to have the
2296      * following permissions: {@link android.Manifest.permission#ACCESS_FINE_LOCATION},
2297      * {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
2298      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2299      * <p> See {@link #getPrivilegedConnectedNetwork()} to get the WifiConfiguration for only the
2300      * connected network that's providing internet by default.
2301      *
2302      * @hide
2303      **/
2304     @SystemApi
2305     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, NEARBY_WIFI_DEVICES, ACCESS_WIFI_STATE,
2306             READ_WIFI_CREDENTIAL},
2307             conditional = true)
getPrivilegedConfiguredNetworks()2308     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
2309         try {
2310             Bundle extras = new Bundle();
2311             if (SdkLevel.isAtLeastS()) {
2312                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
2313                         mContext.getAttributionSource());
2314             }
2315             ParceledListSlice<WifiConfiguration> parceledList =
2316                     mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
2317                             mContext.getAttributionTag(), extras);
2318             if (parceledList == null) {
2319                 return Collections.emptyList();
2320             }
2321             return parceledList.getList();
2322         } catch (RemoteException e) {
2323             throw e.rethrowFromSystemServer();
2324         }
2325     }
2326 
2327     /**
2328      * Gets the {@link WifiConfiguration} with credentials of the connected wifi network
2329      * that's providing internet by default.
2330      * <p>
2331      * On {@link android.os.Build.VERSION_CODES#TIRAMISU} or later SDKs, the caller need to have
2332      * the following permissions: {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} with
2333      * android:usesPermissionFlags="neverForLocation",
2334      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and
2335      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}. If the app does not have
2336      * android:usesPermissionFlags="neverForLocation", then it must also have
2337      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
2338      * <p>
2339      * On {@link Build.VERSION_CODES#S} or prior SDKs, the caller need to have the
2340      * following permissions: {@link android.Manifest.permission#ACCESS_FINE_LOCATION},
2341      * {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
2342      * {@link android.Manifest.permission#READ_WIFI_CREDENTIAL}.
2343      *
2344      * @return The WifiConfiguration representation of the connected wifi network providing
2345      * internet, or null if wifi is not connected.
2346      *
2347      * @throws SecurityException if caller does not have the required permissions
2348      * @hide
2349      **/
2350     @SystemApi
2351     @RequiresPermission(allOf = {NEARBY_WIFI_DEVICES, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL},
2352             conditional = true)
2353     @Nullable
getPrivilegedConnectedNetwork()2354     public WifiConfiguration getPrivilegedConnectedNetwork() {
2355         try {
2356             Bundle extras = new Bundle();
2357             if (SdkLevel.isAtLeastS()) {
2358                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
2359                         mContext.getAttributionSource());
2360             }
2361             return mService.getPrivilegedConnectedNetwork(mContext.getOpPackageName(),
2362                     mContext.getAttributionTag(), extras);
2363         } catch (RemoteException e) {
2364             throw e.rethrowFromSystemServer();
2365         }
2366     }
2367 
2368     /**
2369      * Returns a list of all matching WifiConfigurations of PasspointConfiguration for a given list
2370      * of ScanResult.
2371      *
2372      * An empty list will be returned when no PasspointConfiguration are installed or if no
2373      * PasspointConfiguration match the ScanResult.
2374      *
2375      * @param scanResults a list of scanResult that represents the BSSID
2376      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
2377      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
2378      * @hide
2379      */
2380     @SystemApi
2381     @RequiresPermission(anyOf = {
2382             android.Manifest.permission.NETWORK_SETTINGS,
2383             android.Manifest.permission.NETWORK_SETUP_WIZARD
2384     })
2385     @NonNull
getAllMatchingWifiConfigs( @onNull List<ScanResult> scanResults)2386     public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
2387             @NonNull List<ScanResult> scanResults) {
2388         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
2389         try {
2390             Map<String, Map<Integer, List<ScanResult>>> results =
2391                     mService.getAllMatchingPasspointProfilesForScanResults(scanResults);
2392             if (results.isEmpty()) {
2393                 return configs;
2394             }
2395             List<WifiConfiguration> wifiConfigurations =
2396                     mService.getWifiConfigsForPasspointProfiles(
2397                             new ArrayList<>(results.keySet()));
2398             for (WifiConfiguration configuration : wifiConfigurations) {
2399                 Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
2400                         results.get(configuration.getProfileKey());
2401                 if (scanResultsPerNetworkType != null) {
2402                     configs.add(Pair.create(configuration, scanResultsPerNetworkType));
2403                 }
2404             }
2405         } catch (RemoteException e) {
2406             throw e.rethrowFromSystemServer();
2407         }
2408 
2409         return configs;
2410     }
2411 
2412     /**
2413      * To be used with setScreenOnScanSchedule.
2414      * @hide
2415      */
2416     @SystemApi
2417     public static class ScreenOnScanSchedule {
2418         private final Duration mScanInterval;
2419         private final int mScanType;
2420 
2421         /**
2422          * Creates a ScreenOnScanSchedule.
2423          * @param scanInterval Interval between framework-initiated connectivity scans.
2424          * @param scanType One of the {@code WifiScanner.SCAN_TYPE_} values.
2425          */
ScreenOnScanSchedule(@onNull Duration scanInterval, @WifiAnnotations.ScanType int scanType)2426         public ScreenOnScanSchedule(@NonNull Duration scanInterval,
2427                 @WifiAnnotations.ScanType int scanType) {
2428             if (scanInterval == null) {
2429                 throw new IllegalArgumentException("scanInterval can't be null");
2430             }
2431             mScanInterval = scanInterval;
2432             mScanType = scanType;
2433         }
2434 
2435         /**
2436          * Gets the interval between framework-initiated connectivity scans.
2437          */
getScanInterval()2438         public @NonNull Duration getScanInterval() {
2439             return mScanInterval;
2440         }
2441 
2442         /**
2443          * Gets the type of scan to be used. One of the {@code WifiScanner.SCAN_TYPE_} values.
2444          */
getScanType()2445         public @WifiAnnotations.ScanType int getScanType() {
2446             return mScanType;
2447         }
2448     }
2449 
2450     /**
2451      * This API allows a privileged app to customize the wifi framework's network selection logic.
2452      * To revert to default behavior, call this API with a {@link WifiNetworkSelectionConfig}
2453      * created from a default {@link WifiNetworkSelectionConfig.Builder}.
2454      *
2455      * Use {@link WifiManager#getNetworkSelectionConfig(Executor, Consumer)} to get the current
2456      * network selection configuration.
2457      * <P>
2458      * @param nsConfig an Object representing the network selection configuration being programmed.
2459      *                 This should be created with a {@link WifiNetworkSelectionConfig.Builder}.
2460      *
2461      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2462      * @throws IllegalArgumentException if input is invalid.
2463      * @throws SecurityException if the caller does not have permission.
2464      * @hide
2465      */
2466     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2467     @RequiresPermission(anyOf = {
2468             android.Manifest.permission.NETWORK_SETTINGS,
2469             MANAGE_WIFI_NETWORK_SELECTION
2470     })
2471     @SystemApi
setNetworkSelectionConfig(@onNull WifiNetworkSelectionConfig nsConfig)2472     public void setNetworkSelectionConfig(@NonNull WifiNetworkSelectionConfig nsConfig) {
2473         try {
2474             if (nsConfig == null) {
2475                 throw new IllegalArgumentException("nsConfig can not be null");
2476             }
2477             mService.setNetworkSelectionConfig(nsConfig);
2478         } catch (RemoteException e) {
2479             throw e.rethrowFromSystemServer();
2480         }
2481     }
2482 
2483     /**
2484      * This API allows a privileged app to retrieve the {@link WifiNetworkSelectionConfig}
2485      * currently being used by the network selector.
2486      *
2487      * Use {@link WifiManager#setNetworkSelectionConfig(WifiNetworkSelectionConfig)} to set a
2488      * new network selection configuration.
2489      * <P>
2490      * @param executor The executor on which callback will be invoked.
2491      * @param resultsCallback An asynchronous callback that will return
2492      *                        {@link WifiNetworkSelectionConfig}
2493      *
2494      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2495      * @throws SecurityException if the caller does not have permission.
2496      * @throws NullPointerException if the caller provided invalid inputs.
2497      * @hide
2498      */
2499     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2500     @RequiresPermission(anyOf = {
2501             android.Manifest.permission.NETWORK_SETTINGS,
2502             MANAGE_WIFI_NETWORK_SELECTION
2503     })
2504     @SystemApi
getNetworkSelectionConfig(@onNull @allbackExecutor Executor executor, @NonNull Consumer<WifiNetworkSelectionConfig> resultsCallback)2505     public void getNetworkSelectionConfig(@NonNull @CallbackExecutor Executor executor,
2506             @NonNull Consumer<WifiNetworkSelectionConfig> resultsCallback) {
2507         Objects.requireNonNull(executor, "executor cannot be null");
2508         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
2509         try {
2510             mService.getNetworkSelectionConfig(
2511                     new IWifiNetworkSelectionConfigListener.Stub() {
2512                         @Override
2513                         public void onResult(WifiNetworkSelectionConfig value) {
2514                             Binder.clearCallingIdentity();
2515                             executor.execute(() -> {
2516                                 resultsCallback.accept(value);
2517                             });
2518                         }
2519                     });
2520         } catch (RemoteException e) {
2521             throw e.rethrowFromSystemServer();
2522         }
2523     }
2524 
2525     /**
2526      * Allows a privileged app to enable/disable whether a confirmation dialog should be displayed
2527      * when third-party apps attempt to turn on WiFi.
2528      *
2529      * Use {@link #isThirdPartyAppEnablingWifiConfirmationDialogEnabled()} to get the
2530      * currently configured value.
2531      *
2532      * Note: Only affects behavior for apps with targetSDK < Q, since third party apps are not
2533      * allowed to enable wifi on targetSDK >= Q.
2534      *
2535      * This overrides the overlay value |config_showConfirmationDialogForThirdPartyAppsEnablingWifi|
2536      * <P>
2537      * @param enable true to enable the confirmation dialog, false otherwise
2538      *
2539      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2540      * @throws SecurityException if the caller does not have permission.
2541      * @hide
2542      */
2543     @RequiresPermission(anyOf = {
2544             android.Manifest.permission.NETWORK_SETTINGS,
2545             android.Manifest.permission.NETWORK_SETUP_WIZARD
2546     })
2547     @SystemApi
setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable)2548     public void setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable) {
2549         try {
2550             mService.setThirdPartyAppEnablingWifiConfirmationDialogEnabled(enable);
2551         } catch (RemoteException e) {
2552             throw e.rethrowFromSystemServer();
2553         }
2554     }
2555 
2556     /**
2557      * Check whether the wifi configuration indicates that a confirmation dialog should be displayed
2558      * when third-party apps attempt to turn on WiFi.
2559      *
2560      * Use {@link #setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)} to set this
2561      * value.
2562      *
2563      * Note: This setting only affects behavior for apps with targetSDK < Q, since third party apps
2564      *       are not allowed to enable wifi on targetSDK >= Q.
2565      *
2566      * <P>
2567      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2568      * @throws SecurityException if the caller does not have permission.
2569      * @return true if dialog should be displayed, false otherwise.
2570      * @hide
2571      */
2572     @RequiresPermission(anyOf = {
2573             android.Manifest.permission.NETWORK_SETTINGS,
2574             android.Manifest.permission.NETWORK_SETUP_WIZARD
2575     })
2576     @SystemApi
isThirdPartyAppEnablingWifiConfirmationDialogEnabled()2577     public boolean isThirdPartyAppEnablingWifiConfirmationDialogEnabled() {
2578         try {
2579             return mService.isThirdPartyAppEnablingWifiConfirmationDialogEnabled();
2580         } catch (RemoteException e) {
2581             throw e.rethrowFromSystemServer();
2582         }
2583     }
2584 
2585     /**
2586      * Allows a privileged app to customize the screen-on scan behavior. When a non-null schedule
2587      * is set via this API, it will always get used instead of the scan schedules defined in the
2588      * overlay. When a null schedule is set via this API, the wifi subsystem will go back to using
2589      * the scan schedules defined in the overlay. Also note, the scan schedule will be truncated
2590      * (rounded down) to the nearest whole second.
2591      * <p>
2592      * Example usage:
2593      * The following call specifies that first scheduled scan should be in 20 seconds using
2594      * {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, and all
2595      * scheduled scans later should happen every 40 seconds using
2596      * {@link WifiScanner#SCAN_TYPE_LOW_POWER}.
2597      * <pre>
2598      * List<ScreenOnScanSchedule> schedule = new ArrayList<>();
2599      * schedule.add(new ScreenOnScanSchedule(Duration.ofSeconds(20),
2600      *         WifiScanner.SCAN_TYPE_HIGH_ACCURACY));
2601      * schedule.add(new ScreenOnScanSchedule(Duration.ofSeconds(40),
2602      *         WifiScanner.SCAN_TYPE_LOW_POWER));
2603      * wifiManager.setScreenOnScanSchedule(schedule);
2604      * </pre>
2605      * @param screenOnScanSchedule defines the screen-on scan schedule and the corresponding
2606      *                             scan type. Set to null to clear any previously set value.
2607      *
2608      * @throws IllegalStateException if input is invalid
2609      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2610      * @throws SecurityException if the caller does not have permission.
2611      * @hide
2612      */
2613     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2614     @RequiresPermission(anyOf = {
2615             android.Manifest.permission.NETWORK_SETTINGS,
2616             MANAGE_WIFI_NETWORK_SELECTION
2617     })
2618     @SystemApi
setScreenOnScanSchedule(@ullable List<ScreenOnScanSchedule> screenOnScanSchedule)2619     public void setScreenOnScanSchedule(@Nullable List<ScreenOnScanSchedule> screenOnScanSchedule) {
2620         try {
2621             if (screenOnScanSchedule == null) {
2622                 mService.setScreenOnScanSchedule(null, null);
2623                 return;
2624             }
2625             if (screenOnScanSchedule.isEmpty()) {
2626                 throw new IllegalArgumentException("The input should either be null or a non-empty"
2627                         + " list");
2628             }
2629             int[] scanSchedule = new int[screenOnScanSchedule.size()];
2630             int[] scanType = new int[screenOnScanSchedule.size()];
2631             for (int i = 0; i < screenOnScanSchedule.size(); i++) {
2632                 scanSchedule[i] = (int) screenOnScanSchedule.get(i).getScanInterval().toSeconds();
2633                 scanType[i] = screenOnScanSchedule.get(i).getScanType();
2634             }
2635             mService.setScreenOnScanSchedule(scanSchedule, scanType);
2636         } catch (RemoteException e) {
2637             throw e.rethrowFromSystemServer();
2638         }
2639     }
2640 
2641     /**
2642      * The Wi-Fi framework may trigger connectivity scans in response to the screen turning on for
2643      * network selection purposes. This API allows a privileged app to set a delay to the next
2644      * connectivity scan triggered by the Wi-Fi framework in response to the next screen-on event.
2645      * This gives a window for the privileged app to issue their own custom scans to influence Wi-Fi
2646      * network selection. The expected usage is the privileged app monitor for the screen turning
2647      * off, and then call this API if it believes delaying the next screen-on connectivity scan is
2648      * needed.
2649      * <p>
2650      * Note that this API will only delay screen-on connectivity scans once. This API will need to
2651      * be called again if further screen-on scan delays are needed after it resolves.
2652      * @param delayMs defines the time in milliseconds to delay the next screen-on connectivity
2653      *                scan. Setting this to 0 will remove the delay.
2654      *
2655      * @throws IllegalStateException if input is invalid
2656      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
2657      * @throws SecurityException if the caller does not have permission.
2658      * @hide
2659      */
2660     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2661     @RequiresPermission(anyOf = {
2662             android.Manifest.permission.NETWORK_SETTINGS,
2663             MANAGE_WIFI_NETWORK_SELECTION
2664     })
2665     @SystemApi
setOneShotScreenOnConnectivityScanDelayMillis(@ntRangefrom = 0) int delayMs)2666     public void setOneShotScreenOnConnectivityScanDelayMillis(@IntRange(from = 0) int delayMs) {
2667         try {
2668             mService.setOneShotScreenOnConnectivityScanDelayMillis(delayMs);
2669         } catch (RemoteException e) {
2670             throw e.rethrowFromSystemServer();
2671         }
2672     }
2673 
2674     /**
2675      * Retrieve a list of {@link WifiConfiguration} for available {@link WifiNetworkSuggestion}
2676      * matching the given list of {@link ScanResult}.
2677      *
2678      * An available {@link WifiNetworkSuggestion} must satisfy:
2679      * <ul>
2680      * <li> Matching one of the {@link ScanResult} from the given list.
2681      * <li> and {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} set
2682      * to true.
2683      * </ul>
2684      *
2685      * @param scanResults a list of scanResult.
2686      * @return a list of @link WifiConfiguration} for available {@link WifiNetworkSuggestion}
2687      * @hide
2688      */
2689     @SystemApi
2690     @RequiresPermission(anyOf = {
2691             android.Manifest.permission.NETWORK_SETTINGS,
2692             android.Manifest.permission.NETWORK_SETUP_WIZARD
2693     })
2694     @NonNull
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( @onNull List<ScanResult> scanResults)2695     public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
2696             @NonNull List<ScanResult> scanResults) {
2697         try {
2698             return mService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults);
2699         } catch (RemoteException e) {
2700             throw e.rethrowAsRuntimeException();
2701         }
2702     }
2703 
2704     /**
2705      * Specify a set of SSIDs that will not get disabled internally by the Wi-Fi subsystem when
2706      * connection issues occur. To clear the list, call this API with an empty Set.
2707      * <p>
2708      * {@link #getSsidsAllowlist()} can be used to check the SSIDs that have been set.
2709      * @param ssids - list of WifiSsid that will not get disabled internally
2710      * @throws SecurityException if the calling app is not a Device Owner (DO), Profile Owner (PO),
2711      *                           or a privileged app that has one of the permissions required by
2712      *                           this API.
2713      * @throws IllegalArgumentException if the input is null.
2714      * @hide
2715      */
2716     @SystemApi
2717     @RequiresPermission(anyOf = {
2718             android.Manifest.permission.NETWORK_SETTINGS,
2719             android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional = true)
setSsidsAllowlist(@onNull Set<WifiSsid> ssids)2720     public void setSsidsAllowlist(@NonNull Set<WifiSsid> ssids) {
2721         if (ssids == null) {
2722             throw new IllegalArgumentException(TAG + ": ssids can not be null");
2723         }
2724         try {
2725             mService.setSsidsAllowlist(mContext.getOpPackageName(), new ArrayList<>(ssids));
2726         } catch (RemoteException e) {
2727             throw e.rethrowFromSystemServer();
2728         }
2729     }
2730 
2731     /**
2732      * Get the Set of SSIDs that will not get disabled internally by the Wi-Fi subsystem when
2733      * connection issues occur.
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      * @hide
2738      */
2739     @SystemApi
2740     @RequiresPermission(anyOf = {
2741             android.Manifest.permission.NETWORK_SETTINGS,
2742             android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION}, conditional = true)
getSsidsAllowlist()2743     public @NonNull Set<WifiSsid> getSsidsAllowlist() {
2744         try {
2745             return new ArraySet<WifiSsid>(
2746                     mService.getSsidsAllowlist(mContext.getOpPackageName()));
2747         } catch (RemoteException e) {
2748             throw e.rethrowFromSystemServer();
2749         }
2750     }
2751 
2752     /**
2753      * Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
2754      * list of ScanResult.
2755      *
2756      * An empty list will be returned if no match is found.
2757      *
2758      * @param scanResults a list of ScanResult
2759      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
2760      * @hide
2761      */
2762     @SystemApi
2763     @RequiresPermission(anyOf = {
2764             android.Manifest.permission.NETWORK_SETTINGS,
2765             android.Manifest.permission.NETWORK_SETUP_WIZARD
2766     })
2767     @NonNull
getMatchingOsuProviders( @ullable List<ScanResult> scanResults)2768     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
2769             @Nullable List<ScanResult> scanResults) {
2770         if (scanResults == null) {
2771             return new HashMap<>();
2772         }
2773         try {
2774             return mService.getMatchingOsuProviders(scanResults);
2775         } catch (RemoteException e) {
2776             throw e.rethrowFromSystemServer();
2777         }
2778     }
2779 
2780     /**
2781      * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers.
2782      *
2783      * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2
2784      * configurations in the device.
2785      * An empty map will be returned when there is no matching Passpoint R2 configuration for the
2786      * given OsuProviders.
2787      *
2788      * @param osuProviders a set of {@link OsuProvider}
2789      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
2790      * @hide
2791      */
2792     @SystemApi
2793     @RequiresPermission(anyOf = {
2794             android.Manifest.permission.NETWORK_SETTINGS,
2795             android.Manifest.permission.NETWORK_SETUP_WIZARD
2796     })
2797     @NonNull
getMatchingPasspointConfigsForOsuProviders( @onNull Set<OsuProvider> osuProviders)2798     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
2799             @NonNull Set<OsuProvider> osuProviders) {
2800         try {
2801             return mService.getMatchingPasspointConfigsForOsuProviders(
2802                     new ArrayList<>(osuProviders));
2803         } catch (RemoteException e) {
2804             throw e.rethrowFromSystemServer();
2805         }
2806     }
2807 
2808     /**
2809      * Add a new network description to the set of configured networks.
2810      * The {@code networkId} field of the supplied configuration object
2811      * is ignored.
2812      * <p/>
2813      * The new network will be marked DISABLED by default. To enable it,
2814      * called {@link #enableNetwork}.
2815      *
2816      * @param config the set of variables that describe the configuration,
2817      *            contained in a {@link WifiConfiguration} object.
2818      *            If the {@link WifiConfiguration} has an Http Proxy set
2819      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
2820      * @return the ID of the newly created network description. This is used in
2821      *         other operations to specified the network to be acted upon.
2822      *         Returns {@code -1} on failure.
2823      *
2824      * @deprecated
2825      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2826      * mechanism to trigger connection to a Wi-Fi network.
2827      * b) See {@link #addNetworkSuggestions(List)},
2828      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2829      * when auto-connecting to wifi.
2830      * <b>Compatibility Note:</b> For applications targeting
2831      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2832      * {@code -1}.
2833      * <p>
2834      * Deprecation Exemptions:
2835      * <ul>
2836      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2837      * </ul>
2838      */
2839     @Deprecated
addNetwork(WifiConfiguration config)2840     public int addNetwork(WifiConfiguration config) {
2841         if (config == null) {
2842             return -1;
2843         }
2844         config.networkId = -1;
2845         return addOrUpdateNetwork(config);
2846     }
2847 
2848     /**
2849      * This is a new version of {@link #addNetwork(WifiConfiguration)} which returns more detailed
2850      * failure codes. The usage of this API is limited to Device Owner (DO), Profile Owner (PO),
2851      * system app, and privileged apps.
2852      * <p>
2853      * Add a new network description to the set of configured networks. The {@code networkId}
2854      * field of the supplied configuration object is ignored. The new network will be marked
2855      * DISABLED by default. To enable it, call {@link #enableNetwork}.
2856      * <p>
2857      * @param config the set of variables that describe the configuration,
2858      *            contained in a {@link WifiConfiguration} object.
2859      *            If the {@link WifiConfiguration} has an Http Proxy set
2860      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
2861      * @return A {@link AddNetworkResult} Object.
2862      * @throws SecurityException if the calling app is not a Device Owner (DO),
2863      *                           Profile Owner (PO), system app, or a privileged app that has one of
2864      *                           the permissions required by this API.
2865      * @throws IllegalArgumentException if the input configuration is null or if the
2866      *            security type in input configuration is not supported.
2867      */
2868     @RequiresPermission(anyOf = {
2869             android.Manifest.permission.NETWORK_SETTINGS,
2870             android.Manifest.permission.NETWORK_STACK,
2871             android.Manifest.permission.NETWORK_SETUP_WIZARD,
2872             android.Manifest.permission.NETWORK_MANAGED_PROVISIONING
2873             }, conditional = true)
2874     @NonNull
addNetworkPrivileged(@onNull WifiConfiguration config)2875     public AddNetworkResult addNetworkPrivileged(@NonNull WifiConfiguration config) {
2876         if (config == null) throw new IllegalArgumentException("config cannot be null");
2877         if (config.isSecurityType(WifiInfo.SECURITY_TYPE_DPP)
2878                 && !isFeatureSupported(WIFI_FEATURE_DPP_AKM)) {
2879             throw new IllegalArgumentException("dpp akm is not supported");
2880         }
2881         config.networkId = -1;
2882         try {
2883             return mService.addOrUpdateNetworkPrivileged(config, mContext.getOpPackageName());
2884         } catch (RemoteException e) {
2885             throw e.rethrowFromSystemServer();
2886         }
2887     }
2888 
2889     /**
2890      * Provides the results of a call to {@link #addNetworkPrivileged(WifiConfiguration)}
2891      */
2892     public static final class AddNetworkResult implements Parcelable {
2893         /**
2894          * The operation has completed successfully.
2895          */
2896         public static final int STATUS_SUCCESS = 0;
2897         /**
2898          * The operation has failed due to an unknown reason.
2899          */
2900         public static final int STATUS_FAILURE_UNKNOWN = 1;
2901         /**
2902          * The calling app does not have permission to call this API.
2903          */
2904         public static final int STATUS_NO_PERMISSION = 2;
2905         /**
2906          * Generic failure code for adding a passpoint network.
2907          */
2908         public static final int STATUS_ADD_PASSPOINT_FAILURE = 3;
2909         /**
2910          * Generic failure code for adding a non-passpoint network.
2911          */
2912         public static final int STATUS_ADD_WIFI_CONFIG_FAILURE = 4;
2913         /**
2914          * The network configuration is invalid.
2915          */
2916         public static final int STATUS_INVALID_CONFIGURATION = 5;
2917         /**
2918          * The calling app has no permission to modify the configuration.
2919          */
2920         public static final int STATUS_NO_PERMISSION_MODIFY_CONFIG = 6;
2921         /**
2922          * The calling app has no permission to modify the proxy setting.
2923          */
2924         public static final int STATUS_NO_PERMISSION_MODIFY_PROXY_SETTING = 7;
2925         /**
2926          * The calling app has no permission to modify the MAC randomization setting.
2927          */
2928         public static final int STATUS_NO_PERMISSION_MODIFY_MAC_RANDOMIZATION = 8;
2929         /**
2930          * Internal failure in updating network keys..
2931          */
2932         public static final int STATUS_FAILURE_UPDATE_NETWORK_KEYS = 9;
2933         /**
2934          * The enterprise network is missing either the root CA or domain name.
2935          */
2936         public static final int STATUS_INVALID_CONFIGURATION_ENTERPRISE = 10;
2937 
2938         /** @hide */
2939         @IntDef(prefix = { "STATUS_" }, value = {
2940                 STATUS_SUCCESS,
2941                 STATUS_FAILURE_UNKNOWN,
2942                 STATUS_NO_PERMISSION,
2943                 STATUS_ADD_PASSPOINT_FAILURE,
2944                 STATUS_ADD_WIFI_CONFIG_FAILURE,
2945                 STATUS_INVALID_CONFIGURATION,
2946                 STATUS_NO_PERMISSION_MODIFY_CONFIG,
2947                 STATUS_NO_PERMISSION_MODIFY_PROXY_SETTING,
2948                 STATUS_NO_PERMISSION_MODIFY_MAC_RANDOMIZATION,
2949                 STATUS_FAILURE_UPDATE_NETWORK_KEYS,
2950                 STATUS_INVALID_CONFIGURATION_ENTERPRISE,
2951         })
2952         @Retention(RetentionPolicy.SOURCE)
2953         public @interface AddNetworkStatusCode {}
2954 
2955         @Override
describeContents()2956         public int describeContents() {
2957             return 0;
2958         }
2959 
2960         @Override
writeToParcel(@onNull Parcel dest, int flags)2961         public void writeToParcel(@NonNull Parcel dest, int flags) {
2962             dest.writeInt(statusCode);
2963             dest.writeInt(networkId);
2964         }
2965 
2966         /** Implement the Parcelable interface */
2967         public static final @android.annotation.NonNull Creator<AddNetworkResult> CREATOR =
2968                 new Creator<AddNetworkResult>() {
2969                     public AddNetworkResult createFromParcel(Parcel in) {
2970                         return new AddNetworkResult(in.readInt(), in.readInt());
2971                     }
2972 
2973                     public AddNetworkResult[] newArray(int size) {
2974                         return new AddNetworkResult[size];
2975                     }
2976                 };
2977 
2978         /**
2979          * One of the {@code STATUS_} values. If the operation is successful this field
2980          * will be set to {@code STATUS_SUCCESS}.
2981          */
2982         public final @AddNetworkStatusCode int statusCode;
2983         /**
2984          * The identifier of the added network, which could be used in other operations. This field
2985          * will be set to {@code -1} if the operation failed.
2986          */
2987         public final int networkId;
2988 
AddNetworkResult(@ddNetworkStatusCode int statusCode, int networkId)2989         public AddNetworkResult(@AddNetworkStatusCode int statusCode, int networkId) {
2990             this.statusCode = statusCode;
2991             this.networkId = networkId;
2992         }
2993     }
2994 
2995     /**
2996      * Update the network description of an existing configured network.
2997      *
2998      * @param config the set of variables that describe the configuration,
2999      *            contained in a {@link WifiConfiguration} object. It may
3000      *            be sparse, so that only the items that are being changed
3001      *            are non-<code>null</code>. The {@code networkId} field
3002      *            must be set to the ID of the existing network being updated.
3003      *            If the {@link WifiConfiguration} has an Http Proxy set
3004      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
3005      * @return Returns the {@code networkId} of the supplied
3006      *         {@code WifiConfiguration} on success.
3007      *         <br/>
3008      *         Returns {@code -1} on failure, including when the {@code networkId}
3009      *         field of the {@code WifiConfiguration} does not refer to an
3010      *         existing network.
3011      *
3012      * @deprecated
3013      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3014      * mechanism to trigger connection to a Wi-Fi network.
3015      * b) See {@link #addNetworkSuggestions(List)},
3016      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3017      * when auto-connecting to wifi.
3018      * <b>Compatibility Note:</b> For applications targeting
3019      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3020      * {@code -1}.
3021      * <p>
3022      * Deprecation Exemptions:
3023      * <ul>
3024      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3025      * </ul>
3026      */
3027     @Deprecated
updateNetwork(WifiConfiguration config)3028     public int updateNetwork(WifiConfiguration config) {
3029         if (config == null || config.networkId < 0) {
3030             return -1;
3031         }
3032         return addOrUpdateNetwork(config);
3033     }
3034 
3035     /**
3036      * Internal method for doing the RPC that creates a new network description
3037      * or updates an existing one.
3038      *
3039      * @param config The possibly sparse object containing the variables that
3040      *         are to set or updated in the network description.
3041      * @return the ID of the network on success, {@code -1} on failure.
3042      */
addOrUpdateNetwork(WifiConfiguration config)3043     private int addOrUpdateNetwork(WifiConfiguration config) {
3044         Bundle extras = new Bundle();
3045         if (SdkLevel.isAtLeastS()) {
3046             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
3047                     mContext.getAttributionSource());
3048         }
3049 
3050         try {
3051             return mService.addOrUpdateNetwork(config, mContext.getOpPackageName(), extras);
3052         } catch (RemoteException e) {
3053             throw e.rethrowFromSystemServer();
3054         }
3055     }
3056 
3057     /**
3058      * Interface for indicating user selection from the list of networks presented in the
3059      * {@link NetworkRequestMatchCallback#onMatch(List)}.
3060      *
3061      * The platform will implement this callback and pass it along with the
3062      * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
3063      * NetworkRequestUserSelectionCallback)}. The UI component handling
3064      * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
3065      * {@link #reject()} to return the user's selection back to the platform via this callback.
3066      * @hide
3067      */
3068     @SystemApi
3069     public interface NetworkRequestUserSelectionCallback {
3070         /**
3071          * User selected this network to connect to.
3072          * @param wifiConfiguration WifiConfiguration object corresponding to the network
3073          *                          user selected.
3074          */
3075         @SuppressLint("CallbackMethodName")
select(@onNull WifiConfiguration wifiConfiguration)3076         default void select(@NonNull WifiConfiguration wifiConfiguration) {}
3077 
3078         /**
3079          * User rejected the app's request.
3080          */
3081         @SuppressLint("CallbackMethodName")
reject()3082         default void reject() {}
3083     }
3084 
3085     /**
3086      * Interface for network request callback. Should be implemented by applications and passed when
3087      * calling {@link #registerNetworkRequestMatchCallback(Executor,
3088      * WifiManager.NetworkRequestMatchCallback)}.
3089      *
3090      * This is meant to be implemented by a UI component to present the user with a list of networks
3091      * matching the app's request. The user is allowed to pick one of these networks to connect to
3092      * or reject the request by the app.
3093      * @hide
3094      */
3095     @SystemApi
3096     public interface NetworkRequestMatchCallback {
3097         /**
3098          * Invoked to register a callback to be invoked to convey user selection. The callback
3099          * object passed in this method is to be invoked by the UI component after the service sends
3100          * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
3101          * from that list.
3102          *
3103          * @param userSelectionCallback Callback object to send back the user selection.
3104          */
onUserSelectionCallbackRegistration( @onNull NetworkRequestUserSelectionCallback userSelectionCallback)3105         default void onUserSelectionCallbackRegistration(
3106                 @NonNull NetworkRequestUserSelectionCallback userSelectionCallback) {}
3107 
3108         /**
3109          * Invoked when the active network request is aborted, either because
3110          * <li> The app released the request, OR</li>
3111          * <li> Request was overridden by a new request</li>
3112          * This signals the end of processing for the current request and should stop the UI
3113          * component. No subsequent calls from the UI component will be handled by the platform.
3114          */
onAbort()3115         default void onAbort() {}
3116 
3117         /**
3118          * Invoked when a network request initiated by an app matches some networks in scan results.
3119          * This may be invoked multiple times for a single network request as the platform finds new
3120          * matching networks in scan results.
3121          *
3122          * @param scanResults List of {@link ScanResult} objects corresponding to the networks
3123          *                    matching the request.
3124          */
onMatch(@onNull List<ScanResult> scanResults)3125         default void onMatch(@NonNull List<ScanResult> scanResults) {}
3126 
3127         /**
3128          * Invoked on a successful connection with the network that the user selected
3129          * via {@link NetworkRequestUserSelectionCallback}.
3130          *
3131          * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
3132          *                          user selected.
3133          */
onUserSelectionConnectSuccess(@onNull WifiConfiguration wifiConfiguration)3134         default void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration) {}
3135 
3136         /**
3137          * Invoked on failure to establish connection with the network that the user selected
3138          * via {@link NetworkRequestUserSelectionCallback}.
3139          *
3140          * @param wifiConfiguration WifiConfiguration object corresponding to the network
3141          *                          user selected.
3142          */
onUserSelectionConnectFailure(@onNull WifiConfiguration wifiConfiguration)3143         default void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration) {}
3144     }
3145 
3146     /**
3147      * Callback proxy for NetworkRequestUserSelectionCallback objects.
3148      * @hide
3149      */
3150     private class NetworkRequestUserSelectionCallbackProxy implements
3151             NetworkRequestUserSelectionCallback {
3152         private final INetworkRequestUserSelectionCallback mCallback;
3153 
NetworkRequestUserSelectionCallbackProxy( INetworkRequestUserSelectionCallback callback)3154         NetworkRequestUserSelectionCallbackProxy(
3155                 INetworkRequestUserSelectionCallback callback) {
3156             mCallback = callback;
3157         }
3158 
3159         @Override
select(@onNull WifiConfiguration wifiConfiguration)3160         public void select(@NonNull WifiConfiguration wifiConfiguration) {
3161             if (mVerboseLoggingEnabled) {
3162                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
3163                         + "wificonfiguration: " + wifiConfiguration);
3164             }
3165             try {
3166                 mCallback.select(wifiConfiguration);
3167             } catch (RemoteException e) {
3168                 Log.e(TAG, "Failed to invoke onSelected", e);
3169                 throw e.rethrowFromSystemServer();
3170             }
3171         }
3172 
3173         @Override
reject()3174         public void reject() {
3175             if (mVerboseLoggingEnabled) {
3176                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
3177             }
3178             try {
3179                 mCallback.reject();
3180             } catch (RemoteException e) {
3181                 Log.e(TAG, "Failed to invoke onRejected", e);
3182                 throw e.rethrowFromSystemServer();
3183             }
3184         }
3185     }
3186 
3187     /**
3188      * Callback proxy for NetworkRequestMatchCallback objects.
3189      * @hide
3190      */
3191     private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
3192         private final Executor mExecutor;
3193         private final NetworkRequestMatchCallback mCallback;
3194 
NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback)3195         NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback) {
3196             mExecutor = executor;
3197             mCallback = callback;
3198         }
3199 
3200         @Override
onUserSelectionCallbackRegistration( INetworkRequestUserSelectionCallback userSelectionCallback)3201         public void onUserSelectionCallbackRegistration(
3202                 INetworkRequestUserSelectionCallback userSelectionCallback) {
3203             if (mVerboseLoggingEnabled) {
3204                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
3205                         + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
3206             }
3207             Binder.clearCallingIdentity();
3208             mExecutor.execute(() -> {
3209                 mCallback.onUserSelectionCallbackRegistration(
3210                         new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
3211             });
3212         }
3213 
3214         @Override
onAbort()3215         public void onAbort() {
3216             if (mVerboseLoggingEnabled) {
3217                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onAbort");
3218             }
3219             Binder.clearCallingIdentity();
3220             mExecutor.execute(() -> {
3221                 mCallback.onAbort();
3222             });
3223         }
3224 
3225         @Override
onMatch(List<ScanResult> scanResults)3226         public void onMatch(List<ScanResult> scanResults) {
3227             if (mVerboseLoggingEnabled) {
3228                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch scanResults: "
3229                         + scanResults);
3230             }
3231             Binder.clearCallingIdentity();
3232             mExecutor.execute(() -> {
3233                 mCallback.onMatch(scanResults);
3234             });
3235         }
3236 
3237         @Override
onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration)3238         public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
3239             if (mVerboseLoggingEnabled) {
3240                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
3241                         + " wificonfiguration: " + wifiConfiguration);
3242             }
3243             Binder.clearCallingIdentity();
3244             mExecutor.execute(() -> {
3245                 mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
3246             });
3247         }
3248 
3249         @Override
onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration)3250         public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
3251             if (mVerboseLoggingEnabled) {
3252                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
3253                         + " wificonfiguration: " + wifiConfiguration);
3254             }
3255             Binder.clearCallingIdentity();
3256             mExecutor.execute(() -> {
3257                 mCallback.onUserSelectionConnectFailure(wifiConfiguration);
3258             });
3259         }
3260     }
3261 
3262     /**
3263      * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
3264      * Caller can unregister a previously registered callback using
3265      * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
3266      * <p>
3267      * Applications should have the
3268      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
3269      * without the permission will trigger a {@link java.lang.SecurityException}.
3270      * <p>
3271      *
3272      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
3273      *                 object.
3274      * @param callback Callback for network match events to register.
3275      * @hide
3276      */
3277     @SystemApi
3278     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerNetworkRequestMatchCallback(@onNull @allbackExecutor Executor executor, @NonNull NetworkRequestMatchCallback callback)3279     public void registerNetworkRequestMatchCallback(@NonNull @CallbackExecutor Executor executor,
3280             @NonNull NetworkRequestMatchCallback callback) {
3281         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
3282         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3283         Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
3284                 + ", executor=" + executor);
3285 
3286         try {
3287             synchronized (sNetworkRequestMatchCallbackMap) {
3288                 INetworkRequestMatchCallback.Stub binderCallback =
3289                         new NetworkRequestMatchCallbackProxy(executor, callback);
3290                 sNetworkRequestMatchCallbackMap.put(System.identityHashCode(callback),
3291                         binderCallback);
3292                 mService.registerNetworkRequestMatchCallback(binderCallback);
3293             }
3294         } catch (RemoteException e) {
3295             throw e.rethrowFromSystemServer();
3296         }
3297     }
3298 
3299     /**
3300      * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
3301      * <p>
3302      * Applications should have the
3303      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
3304      * without the permission will trigger a {@link java.lang.SecurityException}.
3305      * <p>
3306      *
3307      * @param callback Callback for network match events to unregister.
3308      * @hide
3309      */
3310     @SystemApi
3311     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterNetworkRequestMatchCallback( @onNull NetworkRequestMatchCallback callback)3312     public void unregisterNetworkRequestMatchCallback(
3313             @NonNull NetworkRequestMatchCallback callback) {
3314         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3315         Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
3316 
3317         try {
3318             synchronized (sNetworkRequestMatchCallbackMap) {
3319                 int callbackIdentifier = System.identityHashCode(callback);
3320                 if (!sNetworkRequestMatchCallbackMap.contains(callbackIdentifier)) {
3321                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
3322                     return;
3323                 }
3324                 mService.unregisterNetworkRequestMatchCallback(
3325                         sNetworkRequestMatchCallbackMap.get(callbackIdentifier));
3326                 sNetworkRequestMatchCallbackMap.remove(callbackIdentifier);
3327             }
3328         } catch (RemoteException e) {
3329             throw e.rethrowFromSystemServer();
3330         }
3331     }
3332 
3333     /**
3334      * Privileged API to revoke all app state from wifi stack (equivalent to operations that the
3335      * wifi stack performs to clear state for an app that was uninstalled.
3336      * This removes:
3337      * <li> All saved networks or passpoint profiles added by the app </li>
3338      * <li> All previously approved peer to peer connection to access points initiated by the app
3339      * using {@link WifiNetworkSpecifier}</li>
3340      * <li> All network suggestions and approvals provided using {@link WifiNetworkSuggestion}</li>
3341      * <p>
3342      * @param targetAppUid UID of the app.
3343      * @param targetAppPackageName Package name of the app.
3344      * @hide
3345      */
3346     @SystemApi
3347     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
removeAppState(int targetAppUid, @NonNull String targetAppPackageName)3348     public void removeAppState(int targetAppUid, @NonNull String targetAppPackageName) {
3349         try {
3350             mService.removeAppState(targetAppUid, targetAppPackageName);
3351         } catch (RemoteException e) {
3352             throw e.rethrowAsRuntimeException();
3353         }
3354     }
3355 
3356     /**
3357      * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
3358      * for a detailed explanation of the parameters.
3359      * When the device decides to connect to one of the provided network suggestions, platform sends
3360      * a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
3361      * the network was created with
3362      * {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(boolean)} flag set and the
3363      * app holds {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
3364      * permission.
3365      *<p>
3366      * NOTE:
3367      * <ul>
3368      * <li> These networks are just a suggestion to the platform. The platform will ultimately
3369      * decide on which network the device connects to. </li>
3370      * <li> When an app is uninstalled or disabled, all its suggested networks are discarded.
3371      * If the device is currently connected to a suggested network which is being removed then the
3372      * device will disconnect from that network.</li>
3373      * <li> If user reset network settings, all added suggestions will be discarded. Apps can use
3374      * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
3375      * <li> In-place modification of existing suggestions are allowed.</li>
3376      * <ul>
3377      * <li> If the provided suggestions include any previously provided suggestions by the app,
3378      * previous suggestions will be updated.</li>
3379      * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and
3380      * the device is currently connected to that suggested network, then the device will disconnect
3381      * from that network. The system will immediately re-evaluate all the network candidates
3382      * and possibly reconnect back to the same suggestion. This disconnect is to make sure that any
3383      * traffic flowing over unmetered networks isn't accidentally continued over a metered network.
3384      * </li>
3385      * <li>
3386      * On {@link android.os.Build.VERSION_CODES#TIRAMISU} or above If one of the provided
3387      * suggestions marks a previously trusted suggestion as untrusted and the device is currently
3388      * connected to that suggested network, then the device will disconnect from that network. The
3389      * system will immediately re-evaluate all the network candidates. This disconnect is to make
3390      * sure device will not remain connected to an untrusted network without a related
3391      * {@link android.net.NetworkRequest}.
3392      * </li>
3393      * </ul>
3394      * </ul>
3395      *
3396      * @param networkSuggestions List of network suggestions provided by the app.
3397      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
3398      * @throws SecurityException if the caller is missing required permissions.
3399      * @see WifiNetworkSuggestion#equals(Object)
3400      */
3401     @RequiresPermission(CHANGE_WIFI_STATE)
addNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)3402     public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
3403             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
3404         try {
3405             return mService.addNetworkSuggestions(
3406                     networkSuggestions, mContext.getOpPackageName(), mContext.getAttributionTag());
3407         } catch (RemoteException e) {
3408             throw e.rethrowFromSystemServer();
3409         }
3410     }
3411 
3412     /**
3413      * Remove some or all of the network suggestions that were previously provided by the app.
3414      * If one of the suggestions being removed was used to establish connection to the current
3415      * network, then the device will immediately disconnect from that network. This method is same
3416      * as {@link #removeNetworkSuggestions(List, int)} with
3417      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT}
3418      *
3419      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
3420      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
3421      * <p></
3422      * Note: Use {@link #removeNetworkSuggestions(List, int)}. An {@code action} of
3423      * {@link #ACTION_REMOVE_SUGGESTION_DISCONNECT} is equivalent to the current behavior.
3424      *
3425      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
3426      *                           to remove all the previous suggestions provided by the app.
3427      * @return Status code for the operation. One of the {@code STATUS_NETWORK_SUGGESTIONS_*}
3428      * values. Any matching suggestions are removed from the device and will not be considered for
3429      * any further connection attempts.
3430      */
3431     @RequiresPermission(CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)3432     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
3433             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
3434         return removeNetworkSuggestions(networkSuggestions, ACTION_REMOVE_SUGGESTION_DISCONNECT);
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 specified action will be executed.
3441      *
3442      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
3443      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
3444      *
3445      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
3446      *                           to remove all the previous suggestions provided by the app.
3447      * @param action Desired action to execute after removing the suggestion. One of
3448      *               {@code ACTION_REMOVE_SUGGESTION_*}
3449      * @return Status code for the operation. One of the {@code STATUS_NETWORK_SUGGESTIONS_*}
3450      * values. Any matching suggestions are removed from the device and will not be considered for
3451      * further connection attempts.
3452      */
3453     @RequiresPermission(CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions, @ActionAfterRemovingSuggestion int action)3454     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
3455             @NonNull List<WifiNetworkSuggestion> networkSuggestions,
3456             @ActionAfterRemovingSuggestion int action) {
3457         try {
3458             return mService.removeNetworkSuggestions(networkSuggestions,
3459                     mContext.getOpPackageName(), action);
3460         } catch (RemoteException e) {
3461             throw e.rethrowFromSystemServer();
3462         }
3463     }
3464 
3465     /**
3466      * Get all network suggestions provided by the calling app.
3467      * See {@link #addNetworkSuggestions(List)}
3468      * See {@link #removeNetworkSuggestions(List)}
3469      * @return a list of {@link WifiNetworkSuggestion}
3470      */
3471     @RequiresPermission(ACCESS_WIFI_STATE)
getNetworkSuggestions()3472     public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
3473         try {
3474             return mService.getNetworkSuggestions(mContext.getOpPackageName());
3475         } catch (RemoteException e) {
3476             throw e.rethrowAsRuntimeException();
3477         }
3478     }
3479 
3480     /**
3481      * Returns the max number of network suggestions that are allowed per app on the device.
3482      * @see #addNetworkSuggestions(List)
3483      * @see #removeNetworkSuggestions(List)
3484      */
getMaxNumberOfNetworkSuggestionsPerApp()3485     public int getMaxNumberOfNetworkSuggestionsPerApp() {
3486         return getMaxNumberOfNetworkSuggestionsPerApp(
3487                 mContext.getSystemService(ActivityManager.class).isLowRamDevice());
3488     }
3489 
3490     /** @hide */
getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice)3491     public static int getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice) {
3492         return isLowRamDevice
3493                 ? NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM
3494                 : NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM;
3495     }
3496 
3497     /**
3498      * Add or update a Passpoint configuration.  The configuration provides a credential
3499      * for connecting to Passpoint networks that are operated by the Passpoint
3500      * service provider specified in the configuration.
3501      *
3502      * Each configuration is uniquely identified by a unique key which depends on the contents of
3503      * the configuration. This allows the caller to install multiple profiles with the same FQDN
3504      * (Fully qualified domain name). Therefore, in order to update an existing profile, it is
3505      * first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
3506      * Otherwise, a new profile will be added with both configuration.
3507      *
3508      * Deprecated for general app usage - except DO/PO apps.
3509      * See {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} to
3510      * create a passpoint suggestion.
3511      * See {@link #addNetworkSuggestions(List)}, {@link #removeNetworkSuggestions(List)} for new
3512      * API to add Wi-Fi networks for consideration when auto-connecting to wifi.
3513      * <b>Compatibility Note:</b> For applications targeting
3514      * {@link android.os.Build.VERSION_CODES#R} or above, this API will always fail and throw
3515      * {@link IllegalArgumentException}.
3516      * <p>
3517      * Deprecation Exemptions:
3518      * <ul>
3519      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3520      * </ul>
3521      *
3522      * @param config The Passpoint configuration to be added
3523      * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
3524      *                                  the device.
3525      */
addOrUpdatePasspointConfiguration(PasspointConfiguration config)3526     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
3527         try {
3528             if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
3529                 throw new IllegalArgumentException();
3530             }
3531         } catch (RemoteException e) {
3532             throw e.rethrowFromSystemServer();
3533         }
3534     }
3535 
3536     /**
3537      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name) added
3538      * by the caller.
3539      *
3540      * @param fqdn The FQDN of the Passpoint configuration added by the caller to be removed
3541      * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
3542      *                                  Passpoint is not enabled on the device.
3543      * @deprecated This will be non-functional in a future release.
3544      * <br>
3545      * Requires {@code android.Manifest.permission.NETWORK_SETTINGS} or
3546      * {@code android.Manifest.permission.NETWORK_CARRIER_PROVISIONING}.
3547      */
3548     @Deprecated
removePasspointConfiguration(String fqdn)3549     public void removePasspointConfiguration(String fqdn) {
3550         try {
3551             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
3552                 throw new IllegalArgumentException();
3553             }
3554         } catch (RemoteException e) {
3555             throw e.rethrowFromSystemServer();
3556         }
3557     }
3558 
3559     /**
3560      * Return the list of installed Passpoint configurations added by the caller.
3561      *
3562      * An empty list will be returned when no configurations are installed.
3563      *
3564      * @return A list of {@link PasspointConfiguration} added by the caller
3565      * @deprecated This will be non-functional in a future release.
3566      * <br>
3567      * Requires {@code android.Manifest.permission.NETWORK_SETTINGS} or
3568      * {@code android.Manifest.permission.NETWORK_SETUP_WIZARD}.
3569      */
3570     @Deprecated
getPasspointConfigurations()3571     public List<PasspointConfiguration> getPasspointConfigurations() {
3572         try {
3573             return mService.getPasspointConfigurations(mContext.getOpPackageName());
3574         } catch (RemoteException e) {
3575             throw e.rethrowFromSystemServer();
3576         }
3577     }
3578 
3579     /**
3580      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
3581      * will be broadcasted once the request is completed.  The presence of the intent extra
3582      * {@link #EXTRA_ICON} will indicate the result of the request.
3583      * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
3584      *
3585      * @param bssid The BSSID of the AP
3586      * @param fileName Name of the icon file (remote file) to query from the AP
3587      *
3588      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
3589      * @hide
3590      */
queryPasspointIcon(long bssid, String fileName)3591     public void queryPasspointIcon(long bssid, String fileName) {
3592         try {
3593             mService.queryPasspointIcon(bssid, fileName);
3594         } catch (RemoteException e) {
3595             throw e.rethrowFromSystemServer();
3596         }
3597     }
3598 
3599     /**
3600      * Match the currently associated network against the SP matching the given FQDN
3601      * @param fqdn FQDN of the SP
3602      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
3603      * @hide
3604      */
matchProviderWithCurrentNetwork(String fqdn)3605     public int matchProviderWithCurrentNetwork(String fqdn) {
3606         try {
3607             return mService.matchProviderWithCurrentNetwork(fqdn);
3608         } catch (RemoteException e) {
3609             throw e.rethrowFromSystemServer();
3610         }
3611     }
3612 
3613     /**
3614      * Remove the specified network from the list of configured networks.
3615      * This may result in the asynchronous delivery of state change
3616      * events.
3617      *
3618      * Applications are not allowed to remove networks created by other
3619      * applications.
3620      *
3621      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3622      *        #getConfiguredNetworks}.
3623      * @return {@code true} if the operation succeeded
3624      *
3625      * @deprecated
3626      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3627      * mechanism to trigger connection to a Wi-Fi network.
3628      * b) See {@link #addNetworkSuggestions(List)},
3629      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3630      * when auto-connecting to wifi.
3631      * <b>Compatibility Note:</b> For applications targeting
3632      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3633      * {@code false}.
3634      * <p>
3635      * Deprecation Exemptions:
3636      * <ul>
3637      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3638      * </ul>
3639      */
3640     @Deprecated
removeNetwork(int netId)3641     public boolean removeNetwork(int netId) {
3642         try {
3643             return mService.removeNetwork(netId, mContext.getOpPackageName());
3644         } catch (RemoteException e) {
3645             throw e.rethrowFromSystemServer();
3646         }
3647     }
3648 
3649     /**
3650      * Remove all configured networks that were not created by the calling app. Can only
3651      * be called by a Device Owner (DO) app.
3652      *
3653      * @return {@code true} if at least one network is removed, {@code false} otherwise
3654      * @throws SecurityException if the caller is not a Device Owner app
3655      */
3656     @RequiresPermission(CHANGE_WIFI_STATE)
removeNonCallerConfiguredNetworks()3657     public boolean removeNonCallerConfiguredNetworks() {
3658         try {
3659             return mService.removeNonCallerConfiguredNetworks(mContext.getOpPackageName());
3660         } catch (RemoteException e) {
3661             throw e.rethrowFromSystemServer();
3662         }
3663     }
3664     /**
3665      * Allow a previously configured network to be associated with. If
3666      * <code>attemptConnect</code> is true, an attempt to connect to the selected
3667      * network is initiated. This may result in the asynchronous delivery
3668      * of state change events.
3669      * <p>
3670      * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
3671      * traffic may instead be sent through another network, such as cellular data,
3672      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
3673      * Wi-Fi network that does not provide Internet access (e.g. a wireless
3674      * printer), if another network that does offer Internet access (e.g.
3675      * cellular data) is available. Applications that need to ensure that their
3676      * network traffic uses Wi-Fi should use APIs such as
3677      * {@link Network#bindSocket(java.net.Socket)},
3678      * {@link Network#openConnection(java.net.URL)}, or
3679      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
3680      *
3681      * Applications are not allowed to enable networks created by other
3682      * applications.
3683      *
3684      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3685      *        #getConfiguredNetworks}.
3686      * @param attemptConnect The way to select a particular network to connect to is specify
3687      *        {@code true} for this parameter.
3688      * @return {@code true} if the operation succeeded
3689      *
3690      * @deprecated
3691      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3692      * mechanism to trigger connection to a Wi-Fi network.
3693      * b) See {@link #addNetworkSuggestions(List)},
3694      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3695      * when auto-connecting to wifi.
3696      * <b>Compatibility Note:</b> For applications targeting
3697      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3698      * {@code false}.
3699      * Deprecation Exemptions:
3700      * <ul>
3701      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3702      * </ul>
3703      */
3704     @Deprecated
enableNetwork(int netId, boolean attemptConnect)3705     public boolean enableNetwork(int netId, boolean attemptConnect) {
3706         try {
3707             return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
3708         } catch (RemoteException e) {
3709             throw e.rethrowFromSystemServer();
3710         }
3711     }
3712 
3713     /**
3714      * Disable a configured network. The specified network will not be
3715      * a candidate for associating. This may result in the asynchronous
3716      * delivery of state change events.
3717      *
3718      * Applications are not allowed to disable networks created by other
3719      * applications.
3720      *
3721      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
3722      *        #getConfiguredNetworks}.
3723      * @return {@code true} if the operation succeeded
3724      *
3725      * @deprecated
3726      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3727      * mechanism to trigger connection to a Wi-Fi network.
3728      * b) See {@link #addNetworkSuggestions(List)},
3729      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3730      * when auto-connecting to wifi.
3731      * <b>Compatibility Note:</b> For applications targeting
3732      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3733      * {@code false}.
3734      * <p>
3735      * Deprecation Exemptions:
3736      * <ul>
3737      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3738      * </ul>
3739      */
3740     @Deprecated
disableNetwork(int netId)3741     public boolean disableNetwork(int netId) {
3742         try {
3743             return mService.disableNetwork(netId, mContext.getOpPackageName());
3744         } catch (RemoteException e) {
3745             throw e.rethrowFromSystemServer();
3746         }
3747     }
3748 
3749     /**
3750      * Disassociate from the currently active access point. This may result
3751      * in the asynchronous delivery of state change events.
3752      * @return {@code true} if the operation succeeded
3753      *
3754      * @deprecated
3755      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3756      * mechanism to trigger connection to a Wi-Fi network.
3757      * b) See {@link #addNetworkSuggestions(List)},
3758      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3759      * when auto-connecting to wifi.
3760      * <b>Compatibility Note:</b> For applications targeting
3761      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3762      * {@code false}.
3763      * <p>
3764      * Deprecation Exemptions:
3765      * <ul>
3766      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3767      * </ul>
3768      */
3769     @Deprecated
disconnect()3770     public boolean disconnect() {
3771         try {
3772             return mService.disconnect(mContext.getOpPackageName());
3773         } catch (RemoteException e) {
3774             throw e.rethrowFromSystemServer();
3775         }
3776     }
3777 
3778     /**
3779      * Reconnect to the currently active access point, if we are currently
3780      * disconnected. This may result in the asynchronous delivery of state
3781      * change events.
3782      * @return {@code true} if the operation succeeded
3783      *
3784      * @deprecated
3785      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3786      * mechanism to trigger connection to a Wi-Fi network.
3787      * b) See {@link #addNetworkSuggestions(List)},
3788      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3789      * when auto-connecting to wifi.
3790      * <b>Compatibility Note:</b> For applications targeting
3791      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
3792      * {@code false}.
3793      * <p>
3794      * Deprecation Exemptions:
3795      * <ul>
3796      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
3797      * </ul>
3798      */
3799     @Deprecated
reconnect()3800     public boolean reconnect() {
3801         try {
3802             return mService.reconnect(mContext.getOpPackageName());
3803         } catch (RemoteException e) {
3804             throw e.rethrowFromSystemServer();
3805         }
3806     }
3807 
3808     /**
3809      * Reconnect to the currently active access point, even if we are already
3810      * connected. This may result in the asynchronous delivery of state
3811      * change events.
3812      * @return {@code true} if the operation succeeded
3813      *
3814      * @deprecated
3815      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
3816      * mechanism to trigger connection to a Wi-Fi network.
3817      * b) See {@link #addNetworkSuggestions(List)},
3818      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
3819      * when auto-connecting to wifi.
3820      * <b>Compatibility Note:</b> For applications targeting
3821      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
3822      */
3823     @Deprecated
reassociate()3824     public boolean reassociate() {
3825         try {
3826             return mService.reassociate(mContext.getOpPackageName());
3827         } catch (RemoteException e) {
3828             throw e.rethrowFromSystemServer();
3829         }
3830     }
3831 
3832     /**
3833      * Check that the supplicant daemon is responding to requests.
3834      * @return {@code true} if we were able to communicate with the supplicant and
3835      * it returned the expected response to the PING message.
3836      * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
3837      */
3838     @Deprecated
pingSupplicant()3839     public boolean pingSupplicant() {
3840         return isWifiEnabled();
3841     }
3842 
3843     /** @hide */
3844     public static final long WIFI_FEATURE_INFRA            = 1L << 0;  // Basic infrastructure mode
3845     /** @hide */
3846     public static final long WIFI_FEATURE_PASSPOINT        = 1L << 2;  // Support for GAS/ANQP
3847     /** @hide */
3848     public static final long WIFI_FEATURE_P2P              = 1L << 3;  // Wifi-Direct
3849     /** @hide */
3850     public static final long WIFI_FEATURE_MOBILE_HOTSPOT   = 1L << 4;  // Soft AP
3851     /** @hide */
3852     public static final long WIFI_FEATURE_SCANNER          = 1L << 5;  // WifiScanner APIs
3853     /** @hide */
3854     public static final long WIFI_FEATURE_AWARE            = 1L << 6;  // Wi-Fi Aware networking
3855     /** @hide */
3856     public static final long WIFI_FEATURE_D2D_RTT          = 1L << 7;  // Device-to-device RTT
3857     /** @hide */
3858     public static final long WIFI_FEATURE_D2AP_RTT         = 1L << 8;  // Device-to-AP RTT
3859     /** @hide */
3860     public static final long WIFI_FEATURE_PNO              = 1L << 10;  // Preferred network offload
3861     /** @hide */
3862     public static final long WIFI_FEATURE_TDLS             = 1L << 12; // Tunnel directed link setup
3863     /** @hide */
3864     public static final long WIFI_FEATURE_TDLS_OFFCHANNEL  = 1L << 13; // TDLS off channel
3865     /** @hide */
3866     public static final long WIFI_FEATURE_AP_STA           = 1L << 15; // AP STA Concurrency
3867     /** @hide */
3868     public static final long WIFI_FEATURE_LINK_LAYER_STATS = 1L << 16; // Link layer stats
3869     /** @hide */
3870     public static final long WIFI_FEATURE_LOGGER           = 1L << 17; // WiFi Logger
3871     /** @hide */
3872     public static final long WIFI_FEATURE_RSSI_MONITOR     = 1L << 19; // RSSI Monitor
3873     /** @hide */
3874     public static final long WIFI_FEATURE_MKEEP_ALIVE      = 1L << 20; // mkeep_alive
3875     /** @hide */
3876     public static final long WIFI_FEATURE_CONFIG_NDO       = 1L << 21; // ND offload
3877     /** @hide */
3878     public static final long WIFI_FEATURE_CONTROL_ROAMING  = 1L << 23; // Control firmware roaming
3879     /** @hide */
3880     public static final long WIFI_FEATURE_IE_WHITELIST     = 1L << 24; // Probe IE white listing
3881     /** @hide */
3882     public static final long WIFI_FEATURE_SCAN_RAND        = 1L << 25; // Random MAC & Probe seq
3883     /** @hide */
3884     public static final long WIFI_FEATURE_TX_POWER_LIMIT   = 1L << 26; // Set Tx power limit
3885     /** @hide */
3886     public static final long WIFI_FEATURE_WPA3_SAE         = 1L << 27; // WPA3-Personal SAE
3887     /** @hide */
3888     public static final long WIFI_FEATURE_WPA3_SUITE_B     = 1L << 28; // WPA3-Enterprise Suite-B
3889     /** @hide */
3890     public static final long WIFI_FEATURE_OWE              = 1L << 29; // Enhanced Open
3891     /** @hide */
3892     public static final long WIFI_FEATURE_LOW_LATENCY      = 1L << 30; // Low Latency modes
3893     /** @hide */
3894     public static final long WIFI_FEATURE_DPP              = 1L << 31; // DPP (Easy-Connect)
3895     /** @hide */
3896     public static final long WIFI_FEATURE_P2P_RAND_MAC     = 1L << 32; // Random P2P MAC
3897     /** @hide */
3898     public static final long WIFI_FEATURE_CONNECTED_RAND_MAC    = 1L << 33; // Random STA MAC
3899     /** @hide */
3900     public static final long WIFI_FEATURE_AP_RAND_MAC      = 1L << 34; // Random AP MAC
3901     /** @hide */
3902     public static final long WIFI_FEATURE_MBO              = 1L << 35; // MBO Support
3903     /** @hide */
3904     public static final long WIFI_FEATURE_OCE              = 1L << 36; // OCE Support
3905     /** @hide */
3906     public static final long WIFI_FEATURE_WAPI             = 1L << 37; // WAPI
3907 
3908     /** @hide */
3909     public static final long WIFI_FEATURE_FILS_SHA256      = 1L << 38; // FILS-SHA256
3910 
3911     /** @hide */
3912     public static final long WIFI_FEATURE_FILS_SHA384      = 1L << 39; // FILS-SHA384
3913 
3914     /** @hide */
3915     public static final long WIFI_FEATURE_SAE_PK           = 1L << 40; // SAE-PK
3916 
3917     /** @hide */
3918     public static final long WIFI_FEATURE_STA_BRIDGED_AP   = 1L << 41; // STA + Bridged AP
3919 
3920     /** @hide */
3921     public static final long WIFI_FEATURE_BRIDGED_AP       = 1L << 42; // Bridged AP
3922 
3923     /** @hide */
3924     public static final long WIFI_FEATURE_INFRA_60G        = 1L << 43; // 60 GHz Band Support
3925 
3926     /**
3927      * Support for 2 STA's for the local-only (peer to peer) connection + internet connection
3928      * concurrency.
3929      * @hide
3930      */
3931     public static final long WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY = 1L << 44;
3932 
3933     /**
3934      * Support for 2 STA's for the make before break concurrency.
3935      * @hide
3936      */
3937     public static final long WIFI_FEATURE_ADDITIONAL_STA_MBB = 1L << 45;
3938 
3939     /**
3940      * Support for 2 STA's for the restricted connection + internet connection concurrency.
3941      * @hide
3942      */
3943     public static final long WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED = 1L << 46;
3944 
3945     /**
3946      * DPP (Easy-Connect) Enrollee Responder mode support
3947      * @hide
3948      */
3949     public static final long WIFI_FEATURE_DPP_ENROLLEE_RESPONDER = 1L << 47;
3950 
3951     /**
3952      * Passpoint Terms and Conditions feature support
3953      * @hide
3954      */
3955     public static final long WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS = 1L << 48;
3956 
3957      /** @hide */
3958     public static final long WIFI_FEATURE_SAE_H2E          = 1L << 49; // Hash-to-Element
3959 
3960      /** @hide */
3961     public static final long WIFI_FEATURE_WFD_R2           = 1L << 50; // Wi-Fi Display R2
3962 
3963     /**
3964      * RFC 7542 decorated identity support
3965      * @hide */
3966     public static final long WIFI_FEATURE_DECORATED_IDENTITY = 1L << 51;
3967 
3968     /**
3969      * Trust On First Use support for WPA Enterprise network
3970      * @hide
3971      */
3972     public static final long WIFI_FEATURE_TRUST_ON_FIRST_USE = 1L << 52;
3973 
3974     /**
3975      * Support for 2 STA's multi internet concurrency.
3976      * @hide
3977      */
3978     public static final long WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET = 1L << 53;
3979 
3980     /**
3981      * Support for DPP (Easy-Connect) AKM.
3982      * @hide
3983      */
3984     public static final long WIFI_FEATURE_DPP_AKM = 1L << 54;
3985 
3986     /**
3987      * Support for setting TLS minimum version.
3988      * @hide
3989      */
3990     public static final long WIFI_FEATURE_SET_TLS_MINIMUM_VERSION = 1L << 55;
3991 
3992     /**
3993      * Support for TLS v.13.
3994      * @hide
3995      */
3996     public static final long WIFI_FEATURE_TLS_V1_3 = 1L << 56;
3997 
3998     /**
3999      * Support for Dual Band Simultaneous (DBS) operation.
4000      * @hide
4001      */
4002     public static final long WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS = 1L << 57;
4003 
4004     /**
4005      * Support for TID-To-Link Mapping negotiation.
4006      * @hide
4007      */
4008     public static final long WIFI_FEATURE_T2LM_NEGOTIATION = 1L << 58;
4009 
4010     /**
4011      * Support for WEP Wi-Fi Network
4012      * @hide
4013      */
4014     public static final long WIFI_FEATURE_WEP = 1L << 59;
4015 
4016     /**
4017      * Support for WPA PERSONAL Wi-Fi Network
4018      * @hide
4019      */
4020     public static final long WIFI_FEATURE_WPA_PERSONAL = 1L << 60;
4021 
4022     /**
4023      * Support for Roaming Mode
4024      * @hide
4025      */
4026     public static final long WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT = 1L << 61;
4027 
4028     /**
4029      * Supports device-to-device connections when infra STA is disabled.
4030      * @hide
4031      */
4032     public static final long WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED = 1L << 62;
4033 
getSupportedFeatures()4034     private long getSupportedFeatures() {
4035         try {
4036             return mService.getSupportedFeatures();
4037         } catch (RemoteException e) {
4038             throw e.rethrowFromSystemServer();
4039         }
4040     }
4041 
isFeatureSupported(long feature)4042     private boolean isFeatureSupported(long feature) {
4043         return (getSupportedFeatures() & feature) == feature;
4044     }
4045 
4046     /**
4047      * @return true if this adapter supports Passpoint
4048      * @hide
4049      */
isPasspointSupported()4050     public boolean isPasspointSupported() {
4051         return isFeatureSupported(WIFI_FEATURE_PASSPOINT);
4052     }
4053 
4054     /**
4055      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
4056      */
isP2pSupported()4057     public boolean isP2pSupported() {
4058         return isFeatureSupported(WIFI_FEATURE_P2P);
4059     }
4060 
4061     /**
4062      * @return true if this adapter supports portable Wi-Fi hotspot
4063      * @hide
4064      */
4065     @SystemApi
isPortableHotspotSupported()4066     public boolean isPortableHotspotSupported() {
4067         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
4068     }
4069 
4070     /**
4071      * @return true if this adapter supports WifiScanner APIs
4072      * @hide
4073      */
4074     @SystemApi
isWifiScannerSupported()4075     public boolean isWifiScannerSupported() {
4076         return isFeatureSupported(WIFI_FEATURE_SCANNER);
4077     }
4078 
4079     /**
4080      * @return true if this adapter supports Neighbour Awareness Network APIs
4081      * @hide
4082      */
isWifiAwareSupported()4083     public boolean isWifiAwareSupported() {
4084         return isFeatureSupported(WIFI_FEATURE_AWARE);
4085     }
4086 
4087     /**
4088      * Query whether or not the device supports Station (STA) + Access point (AP) concurrency.
4089      *
4090      * @return true if this device supports STA + AP concurrency, false otherwise.
4091      */
isStaApConcurrencySupported()4092     public boolean isStaApConcurrencySupported() {
4093         return isFeatureSupported(WIFI_FEATURE_AP_STA);
4094     }
4095 
4096     /**
4097      * Query whether or not the device supports concurrent station (STA) connections for local-only
4098      * connections using {@link WifiNetworkSpecifier}.
4099      *
4100      * @return true if this device supports multiple STA concurrency for this use-case, false
4101      * otherwise.
4102      */
isStaConcurrencyForLocalOnlyConnectionsSupported()4103     public boolean isStaConcurrencyForLocalOnlyConnectionsSupported() {
4104         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY);
4105     }
4106 
4107     /**
4108      * Query whether or not the device supports concurrent station (STA) connections for
4109      * make-before-break wifi to wifi switching.
4110      *
4111      * Note: This is an internal feature which is not available to apps.
4112      *
4113      * @return true if this device supports multiple STA concurrency for this use-case, false
4114      * otherwise.
4115      */
isMakeBeforeBreakWifiSwitchingSupported()4116     public boolean isMakeBeforeBreakWifiSwitchingSupported() {
4117         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_MBB);
4118     }
4119 
4120     /**
4121      * Query whether or not the device supports concurrent station (STA) connections for multi
4122      * internet connections.
4123      *
4124      * @return true if this device supports multiple STA concurrency for this use-case, false
4125      * otherwise.
4126      */
4127     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
isStaConcurrencyForMultiInternetSupported()4128     public boolean isStaConcurrencyForMultiInternetSupported() {
4129         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_MULTI_INTERNET);
4130     }
4131 
4132     /**
4133      * Query whether or not the device supports concurrent station (STA) connections for restricted
4134      * connections using {@link WifiNetworkSuggestion.Builder#setOemPaid(boolean)} /
4135      * {@link WifiNetworkSuggestion.Builder#setOemPrivate(boolean)}.
4136      *
4137      * @return true if this device supports multiple STA concurrency for this use-case, false
4138      * otherwise.
4139      * @hide
4140      */
4141     @SystemApi
isStaConcurrencyForRestrictedConnectionsSupported()4142     public boolean isStaConcurrencyForRestrictedConnectionsSupported() {
4143         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED);
4144     }
4145 
4146     /**
4147      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
4148      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
4149      * {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
4150      *
4151      * @return true if this adapter supports Device-to-device RTT
4152      * @hide
4153      */
4154     @Deprecated
4155     @SystemApi
isDeviceToDeviceRttSupported()4156     public boolean isDeviceToDeviceRttSupported() {
4157         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
4158     }
4159 
4160     /**
4161      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
4162      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT}.
4163      *
4164      * @return true if this adapter supports Device-to-AP RTT
4165      */
4166     @Deprecated
isDeviceToApRttSupported()4167     public boolean isDeviceToApRttSupported() {
4168         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
4169     }
4170 
4171     /**
4172      * @return true if this adapter supports offloaded connectivity scan
4173      */
isPreferredNetworkOffloadSupported()4174     public boolean isPreferredNetworkOffloadSupported() {
4175         try {
4176             return mService.isPnoSupported();
4177         } catch (RemoteException e) {
4178             throw e.rethrowFromSystemServer();
4179         }
4180     }
4181 
4182     /**
4183      * @return true if this adapter supports Tunnel Directed Link Setup
4184      */
isTdlsSupported()4185     public boolean isTdlsSupported() {
4186         return isFeatureSupported(WIFI_FEATURE_TDLS);
4187     }
4188 
4189     /**
4190      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
4191      * @hide
4192      */
isOffChannelTdlsSupported()4193     public boolean isOffChannelTdlsSupported() {
4194         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
4195     }
4196 
4197     /**
4198      * @return true if this adapter supports advanced power/performance counters
4199      */
isEnhancedPowerReportingSupported()4200     public boolean isEnhancedPowerReportingSupported() {
4201         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
4202     }
4203 
4204     /**
4205      * @return true if this device supports connected MAC randomization.
4206      * @hide
4207      */
4208     @SystemApi
isConnectedMacRandomizationSupported()4209     public boolean isConnectedMacRandomizationSupported() {
4210         return isFeatureSupported(WIFI_FEATURE_CONNECTED_RAND_MAC);
4211     }
4212 
4213     /**
4214      * @return true if this device supports AP MAC randomization.
4215      * @hide
4216      */
4217     @SystemApi
isApMacRandomizationSupported()4218     public boolean isApMacRandomizationSupported() {
4219         return isFeatureSupported(WIFI_FEATURE_AP_RAND_MAC);
4220     }
4221 
4222     /**
4223      * @return true if this device supports Low latency mode.
4224      * @hide
4225      */
4226     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
4227     @SystemApi
isLowLatencyModeSupported()4228     public boolean isLowLatencyModeSupported() {
4229         return isFeatureSupported(WIFI_FEATURE_LOW_LATENCY);
4230     }
4231 
4232     /**
4233      * Check if the chipset supports 2.4GHz band.
4234      * @return {@code true} if supported, {@code false} otherwise.
4235      */
is24GHzBandSupported()4236     public boolean is24GHzBandSupported() {
4237         try {
4238             return mService.is24GHzBandSupported();
4239         } catch (RemoteException e) {
4240             throw e.rethrowFromSystemServer();
4241         }
4242     }
4243 
4244     /**
4245      * Check if the chipset supports 5GHz band.
4246      * @return {@code true} if supported, {@code false} otherwise.
4247      */
is5GHzBandSupported()4248     public boolean is5GHzBandSupported() {
4249         try {
4250             return mService.is5GHzBandSupported();
4251         } catch (RemoteException e) {
4252             throw e.rethrowFromSystemServer();
4253         }
4254     }
4255 
4256     /**
4257      * Check if the chipset supports the 60GHz frequency band.
4258      *
4259      * @return {@code true} if supported, {@code false} otherwise.
4260      */
4261     @RequiresApi(Build.VERSION_CODES.S)
is60GHzBandSupported()4262     public boolean is60GHzBandSupported() {
4263         try {
4264             return mService.is60GHzBandSupported();
4265         } catch (RemoteException e) {
4266             throw e.rethrowFromSystemServer();
4267         }
4268     }
4269 
4270     /**
4271      * Check if the chipset supports 6GHz band.
4272      * @return {@code true} if supported, {@code false} otherwise.
4273      */
is6GHzBandSupported()4274     public boolean is6GHzBandSupported() {
4275         try {
4276             return mService.is6GHzBandSupported();
4277         } catch (RemoteException e) {
4278             throw e.rethrowFromSystemServer();
4279         }
4280     }
4281 
4282     /**
4283      * Check if the chipset supports a certain Wi-Fi standard.
4284      * @param standard the IEEE 802.11 standard to check on.
4285      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
4286      * @return {@code true} if supported, {@code false} otherwise.
4287      */
isWifiStandardSupported(@ifiAnnotations.WifiStandard int standard)4288     public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
4289         try {
4290             return mService.isWifiStandardSupported(standard);
4291         } catch (RemoteException e) {
4292             throw e.rethrowFromSystemServer();
4293         }
4294     }
4295 
4296     /**
4297      * Query whether or not the device supports concurrency of Station (STA) + multiple access
4298      * points (AP) (where the APs bridged together).
4299      *
4300      * @return true if this device supports concurrency of STA + multiple APs which are bridged
4301      *         together, false otherwise.
4302      */
isStaBridgedApConcurrencySupported()4303     public boolean isStaBridgedApConcurrencySupported() {
4304         return isFeatureSupported(WIFI_FEATURE_STA_BRIDGED_AP);
4305     }
4306 
4307     /**
4308      * Query whether or not the device supports multiple Access point (AP) which are bridged
4309      * together.
4310      *
4311      * @return true if this device supports concurrency of multiple AP which bridged together,
4312      *         false otherwise.
4313      */
isBridgedApConcurrencySupported()4314     public boolean isBridgedApConcurrencySupported() {
4315         return isFeatureSupported(WIFI_FEATURE_BRIDGED_AP);
4316     }
4317 
4318     /**
4319      * @return true if this devices supports device-to-device (D2d) Wi-Fi use-cases
4320      * such as Wi-Fi Direct when infra station (STA) is disabled.
4321      */
4322     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isD2dSupportedWhenInfraStaDisabled()4323     public boolean isD2dSupportedWhenInfraStaDisabled() {
4324         return isFeatureSupported(WIFI_FEATURE_D2D_WHEN_INFRA_STA_DISABLED);
4325     }
4326 
4327     /**
4328      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
4329      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
4330      *
4331      * @hide
4332      */
4333     @SystemApi
4334     public interface OnWifiActivityEnergyInfoListener {
4335         /**
4336          * Called when Wi-Fi activity energy info is available.
4337          * Note: this listener is triggered at most once for each call to
4338          * {@link #getWifiActivityEnergyInfoAsync}.
4339          *
4340          * @param info the latest {@link WifiActivityEnergyInfo}, or null if unavailable.
4341          */
onWifiActivityEnergyInfo(@ullable WifiActivityEnergyInfo info)4342         void onWifiActivityEnergyInfo(@Nullable WifiActivityEnergyInfo info);
4343     }
4344 
4345     private static class OnWifiActivityEnergyInfoProxy
4346             extends IOnWifiActivityEnergyInfoListener.Stub {
4347         private final Object mLock = new Object();
4348         @Nullable @GuardedBy("mLock") private Executor mExecutor;
4349         @Nullable @GuardedBy("mLock") private OnWifiActivityEnergyInfoListener mListener;
4350 
OnWifiActivityEnergyInfoProxy(Executor executor, OnWifiActivityEnergyInfoListener listener)4351         OnWifiActivityEnergyInfoProxy(Executor executor,
4352                 OnWifiActivityEnergyInfoListener listener) {
4353             mExecutor = executor;
4354             mListener = listener;
4355         }
4356 
4357         @Override
onWifiActivityEnergyInfo(WifiActivityEnergyInfo info)4358         public void onWifiActivityEnergyInfo(WifiActivityEnergyInfo info) {
4359             Executor executor;
4360             OnWifiActivityEnergyInfoListener listener;
4361             synchronized (mLock) {
4362                 if (mExecutor == null || mListener == null) {
4363                     return;
4364                 }
4365                 executor = mExecutor;
4366                 listener = mListener;
4367                 // null out to allow garbage collection, prevent triggering listener more than once
4368                 mExecutor = null;
4369                 mListener = null;
4370             }
4371             Binder.clearCallingIdentity();
4372             executor.execute(() -> listener.onWifiActivityEnergyInfo(info));
4373         }
4374     }
4375 
4376     /**
4377      * Request to get the current {@link WifiActivityEnergyInfo} asynchronously.
4378      * Note: This method will return null if {@link #isEnhancedPowerReportingSupported()} returns
4379      * false.
4380      *
4381      * @param executor the executor that the listener will be invoked on
4382      * @param listener the listener that will receive the {@link WifiActivityEnergyInfo} object
4383      *                 when it becomes available. The listener will be triggered at most once for
4384      *                 each call to this method.
4385      *
4386      * @hide
4387      */
4388     @SystemApi
4389     @RequiresPermission(ACCESS_WIFI_STATE)
getWifiActivityEnergyInfoAsync( @onNull @allbackExecutor Executor executor, @NonNull OnWifiActivityEnergyInfoListener listener)4390     public void getWifiActivityEnergyInfoAsync(
4391             @NonNull @CallbackExecutor Executor executor,
4392             @NonNull OnWifiActivityEnergyInfoListener listener) {
4393         Objects.requireNonNull(executor, "executor cannot be null");
4394         Objects.requireNonNull(listener, "listener cannot be null");
4395         try {
4396             mService.getWifiActivityEnergyInfoAsync(
4397                     new OnWifiActivityEnergyInfoProxy(executor, listener));
4398         } catch (RemoteException e) {
4399             throw e.rethrowFromSystemServer();
4400         }
4401     }
4402 
4403     /**
4404      * Request a scan for access points. Returns immediately. The availability
4405      * of the results is made known later by means of an asynchronous event sent
4406      * on completion of the scan.
4407      * <p>
4408      * To initiate a Wi-Fi scan, declare the
4409      * {@link android.Manifest.permission#CHANGE_WIFI_STATE}
4410      * permission in the manifest, and perform these steps:
4411      * </p>
4412      * <ol style="1">
4413      * <li>Invoke the following method:
4414      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>
4415      * <li>
4416      * Register a BroadcastReceiver to listen to
4417      * {@code SCAN_RESULTS_AVAILABLE_ACTION}.</li>
4418      * <li>When a broadcast is received, call:
4419      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>
4420      * </ol>
4421      * @return {@code true} if the operation succeeded, i.e., the scan was initiated.
4422      * @deprecated The ability for apps to trigger scan requests will be removed in a future
4423      * release.
4424      */
4425     @Deprecated
startScan()4426     public boolean startScan() {
4427         return startScan(null);
4428     }
4429 
4430     /** @hide */
4431     @SystemApi
4432     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
startScan(WorkSource workSource)4433     public boolean startScan(WorkSource workSource) {
4434         try {
4435             String packageName = mContext.getOpPackageName();
4436             String attributionTag = mContext.getAttributionTag();
4437             return mService.startScan(packageName, attributionTag);
4438         } catch (RemoteException e) {
4439             throw e.rethrowFromSystemServer();
4440         }
4441     }
4442 
4443     /**
4444      * WPS has been deprecated from Client mode operation.
4445      *
4446      * @return null
4447      * @hide
4448      * @deprecated This API is deprecated
4449      */
getCurrentNetworkWpsNfcConfigurationToken()4450     public String getCurrentNetworkWpsNfcConfigurationToken() {
4451         return null;
4452     }
4453 
4454     /**
4455      * Return dynamic information about the current Wi-Fi connection, if any is active.
4456      * <p>
4457      *
4458      * @return the Wi-Fi information, contained in {@link WifiInfo}.
4459      *
4460      * @deprecated Starting with {@link Build.VERSION_CODES#S}, WifiInfo retrieval is moved to
4461      * {@link ConnectivityManager} API surface. WifiInfo is attached in
4462      * {@link NetworkCapabilities#getTransportInfo()} which is available via callback in
4463      * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} or on-demand from
4464      * {@link ConnectivityManager#getNetworkCapabilities(Network)}.
4465      *
4466      *</p>
4467      * Usage example:
4468      * <pre>
4469      * final NetworkRequest request =
4470      *      new NetworkRequest.Builder()
4471      *      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
4472      *      .build();
4473      * final ConnectivityManager connectivityManager =
4474      *      context.getSystemService(ConnectivityManager.class);
4475      * final NetworkCallback networkCallback = new NetworkCallback() {
4476      *      ...
4477      *      &#64;Override
4478      *      void onAvailable(Network network) {}
4479      *
4480      *      &#64;Override
4481      *      void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
4482      *          WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
4483      *      }
4484      *      // etc.
4485      * };
4486      * connectivityManager.requestNetwork(request, networkCallback); // For request
4487      * connectivityManager.registerNetworkCallback(request, networkCallback); // For listen
4488      * </pre>
4489      * <p>
4490      * <b>Compatibility Notes:</b>
4491      * <li>Apps can continue using this API, however newer features
4492      * such as ability to mask out location sensitive data in WifiInfo will not be supported
4493      * via this API. </li>
4494      * <li>On devices supporting concurrent connections (indicated via
4495      * {@link #isStaConcurrencyForLocalOnlyConnectionsSupported()}, etc) this API will return
4496      * the details of the internet providing connection (if any) to all apps, except for the apps
4497      * that triggered the creation of the concurrent connection. For such apps, this API will return
4498      * the details of the connection they created. e.g. apps using {@link WifiNetworkSpecifier} will
4499      * trigger a concurrent connection on supported devices and hence this API will provide
4500      * details of their peer to peer connection (not the internet providing connection). This
4501      * is to maintain backwards compatibility with behavior on single STA devices.</li>
4502      * </p>
4503      */
4504     @Deprecated
4505     @RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION}, conditional = true)
getConnectionInfo()4506     public WifiInfo getConnectionInfo() {
4507         try {
4508             return mService.getConnectionInfo(mContext.getOpPackageName(),
4509                     mContext.getAttributionTag());
4510         } catch (RemoteException e) {
4511             throw e.rethrowFromSystemServer();
4512         }
4513     }
4514 
4515     /**
4516      * Return the results of the latest access point scan.
4517      * @return the list of access points found in the most recent scan. An app must hold
4518      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
4519      * and {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission
4520      * in order to get valid results.
4521      *
4522      * <p>
4523      * When an Access Point’s beacon or probe response includes a Multi-BSSID Element, the
4524      * returned scan results should include separate scan result for each BSSID within the
4525      * Multi-BSSID Information Element. This includes both transmitted and non-transmitted BSSIDs.
4526      * Original Multi-BSSID Element will be included in the Information Elements attached to
4527      * each of the scan results.
4528      * Note: This is the expected behavior for devices supporting 11ax (WiFi-6) and above, and an
4529      * optional requirement for devices running with older WiFi generations.
4530      * </p>
4531      */
4532     @RequiresPermission(allOf = {ACCESS_WIFI_STATE, ACCESS_FINE_LOCATION})
getScanResults()4533     public List<ScanResult> getScanResults() {
4534         try {
4535             ParceledListSlice<ScanResult> parceledList = mService
4536                     .getScanResults(mContext.getOpPackageName(), mContext.getAttributionTag());
4537             if (parceledList == null) {
4538                 return Collections.emptyList();
4539             }
4540             return parceledList.getList();
4541         } catch (RemoteException e) {
4542             throw e.rethrowFromSystemServer();
4543         }
4544     }
4545 
4546     /**
4547      * Get the filtered ScanResults which match the network configurations specified by the
4548      * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
4549      * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
4550      * use the matching rules of Hotspot 2.0.
4551      * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
4552      * These may or may not be suggestions which are installed on the device.
4553      * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
4554      * the Wi-Fi service will use the most recent scan results which the system has.
4555      * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
4556      * corresponding to networks which match them.
4557      * @hide
4558      */
4559     @SystemApi
4560     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
4561     @NonNull
getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestionsToMatch, @Nullable List<ScanResult> scanResults)4562     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
4563             @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
4564             @Nullable List<ScanResult> scanResults) {
4565         if (networkSuggestionsToMatch == null) {
4566             throw new IllegalArgumentException("networkSuggestions must not be null.");
4567         }
4568         try {
4569             return mService.getMatchingScanResults(
4570                     networkSuggestionsToMatch, scanResults,
4571                     mContext.getOpPackageName(), mContext.getAttributionTag());
4572         } catch (RemoteException e) {
4573             throw e.rethrowFromSystemServer();
4574         }
4575     }
4576 
4577     /**
4578      * Set if scanning is always available.
4579      *
4580      * If set to {@code true}, apps can issue {@link #startScan} and fetch scan results
4581      * even when Wi-Fi is turned off.
4582      *
4583      * @param isAvailable true to enable, false to disable.
4584      * @hide
4585      * @see #isScanAlwaysAvailable()
4586      */
4587     @SystemApi
4588     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanAlwaysAvailable(boolean isAvailable)4589     public void setScanAlwaysAvailable(boolean isAvailable) {
4590         try {
4591             mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName());
4592         } catch (RemoteException e) {
4593             throw e.rethrowFromSystemServer();
4594         }
4595     }
4596 
4597     /**
4598      * Check if scanning is always available.
4599      *
4600      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
4601      * even when Wi-Fi is turned off.
4602      *
4603      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
4604      * @deprecated The ability for apps to trigger scan requests will be removed in a future
4605      * release.
4606      */
4607     @Deprecated
isScanAlwaysAvailable()4608     public boolean isScanAlwaysAvailable() {
4609         try {
4610             return mService.isScanAlwaysAvailable();
4611         } catch (RemoteException e) {
4612             throw e.rethrowFromSystemServer();
4613         }
4614     }
4615 
4616     /**
4617      * Get channel data such as the number of APs found on each channel from the most recent scan.
4618      * App requires {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}
4619      *
4620      * @param executor        The executor on which callback will be invoked.
4621      * @param resultsCallback A callback that will return {@code List<Bundle>} containing channel
4622      *                       data such as the number of APs found on each channel.
4623      *                       {@link WifiManager#CHANNEL_DATA_KEY_FREQUENCY_MHZ} and
4624      *                       {@link WifiManager#CHANNEL_DATA_KEY_NUM_AP} are used to get
4625      *                       the frequency (Mhz) and number of APs.
4626      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
4627      * @throws SecurityException             if the caller does not have permission.
4628      * @throws NullPointerException          if the caller provided invalid inputs.
4629      */
4630     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4631     @RequiresPermission(NEARBY_WIFI_DEVICES)
getChannelData(@onNull @allbackExecutor Executor executor, @NonNull Consumer<List<Bundle>> resultsCallback)4632     public void getChannelData(@NonNull @CallbackExecutor Executor executor,
4633             @NonNull Consumer<List<Bundle>> resultsCallback) {
4634         Objects.requireNonNull(executor, "executor cannot be null");
4635         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
4636         try {
4637             Bundle extras = new Bundle();
4638             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
4639                     mContext.getAttributionSource());
4640             mService.getChannelData(new IListListener.Stub() {
4641                 @Override
4642                 public void onResult(List value) {
4643                     Binder.clearCallingIdentity();
4644                     executor.execute(() -> {
4645                         resultsCallback.accept(value);
4646                     });
4647                 }
4648             }, mContext.getOpPackageName(), extras);
4649         } catch (RemoteException e) {
4650             throw e.rethrowFromSystemServer();
4651         }
4652     }
4653 
4654     /**
4655      * Tell the device to persist the current list of configured networks.
4656      * <p>
4657      * Note: It is possible for this method to change the network IDs of
4658      * existing networks. You should assume the network IDs can be different
4659      * after calling this method.
4660      *
4661      * @return {@code false}.
4662      * @deprecated There is no need to call this method -
4663      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
4664      * and {@link #removeNetwork(int)} already persist the configurations automatically.
4665      */
4666     @Deprecated
saveConfiguration()4667     public boolean saveConfiguration() {
4668         return false;
4669     }
4670 
4671     /**
4672      * Helper class to support driver country code changed listener.
4673      */
4674     private static class OnDriverCountryCodeChangedProxy
4675             extends IOnWifiDriverCountryCodeChangedListener.Stub {
4676 
4677         @NonNull private Executor mExecutor;
4678         @NonNull private ActiveCountryCodeChangedCallback mCallback;
4679 
OnDriverCountryCodeChangedProxy(@onNull Executor executor, @NonNull ActiveCountryCodeChangedCallback callback)4680         OnDriverCountryCodeChangedProxy(@NonNull Executor executor,
4681                 @NonNull ActiveCountryCodeChangedCallback callback) {
4682             Objects.requireNonNull(executor);
4683             Objects.requireNonNull(callback);
4684             mExecutor = executor;
4685             mCallback = callback;
4686         }
4687 
4688         @Override
onDriverCountryCodeChanged(String countryCode)4689         public void onDriverCountryCodeChanged(String countryCode) {
4690             Log.i(TAG, "OnDriverCountryCodeChangedProxy: receive onDriverCountryCodeChanged: "
4691                     + countryCode);
4692             Binder.clearCallingIdentity();
4693             if (countryCode != null) {
4694                 mExecutor.execute(() -> mCallback.onActiveCountryCodeChanged(countryCode));
4695             } else {
4696                 mExecutor.execute(() -> mCallback.onCountryCodeInactive());
4697             }
4698         }
4699     }
4700 
4701     /**
4702      * Interface used to listen the active country code changed event.
4703      * @hide
4704      */
4705     @SystemApi
4706     public interface ActiveCountryCodeChangedCallback {
4707         /**
4708          * Called when the country code used by the Wi-Fi subsystem has changed.
4709          *
4710          * @param countryCode An ISO-3166-alpha2 country code which is 2-Character alphanumeric.
4711          */
onActiveCountryCodeChanged(@onNull String countryCode)4712         void onActiveCountryCodeChanged(@NonNull String countryCode);
4713 
4714         /**
4715          * Called when the Wi-Fi subsystem does not have an active country code.
4716          * This can happen when Wi-Fi is disabled.
4717          */
onCountryCodeInactive()4718         void onCountryCodeInactive();
4719     }
4720 
4721     /**
4722      * Add the provided callback for the active country code changed event.
4723      * Caller will receive either
4724      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}
4725      * or {@link WifiManager.ActiveCountryCodeChangedCallback#onCountryCodeInactive()}
4726      * on registration.
4727      *
4728      * Note: When the global location setting is off or the caller does not have runtime location
4729      * permission, caller will not receive the callback even if caller register callback succeeded.
4730      *
4731      *
4732      * Caller can remove a previously registered callback using
4733      * {@link WifiManager#unregisterActiveCountryCodeChangedCallback(
4734      * ActiveCountryCodeChangedCallback)}.
4735      *
4736      * <p>
4737      * Note:
4738      * The value provided by
4739      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}
4740      * may be different from the returned value from {@link WifiManager#getCountryCode()} even if
4741      * the Wi-Fi subsystem is active. See: {@link WifiManager#getCountryCode()} for details.
4742      * </p>
4743      *
4744      * @param executor The Executor on which to execute the callbacks.
4745      * @param callback callback for the driver country code changed events.
4746      * @hide
4747      */
4748     @SystemApi
4749     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4750     @RequiresPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
registerActiveCountryCodeChangedCallback( @onNull @allbackExecutor Executor executor, @NonNull ActiveCountryCodeChangedCallback callback)4751     public void registerActiveCountryCodeChangedCallback(
4752             @NonNull @CallbackExecutor Executor executor,
4753             @NonNull ActiveCountryCodeChangedCallback callback) {
4754         if (!SdkLevel.isAtLeastT()) {
4755             throw new UnsupportedOperationException();
4756         }
4757         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
4758         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
4759         if (mVerboseLoggingEnabled) {
4760             Log.d(TAG, "registerActiveCountryCodeChangedCallback: callback=" + callback
4761                     + ", executor=" + executor);
4762         }
4763         final int callbackIdentifier = System.identityHashCode(callback);
4764         synchronized (sActiveCountryCodeChangedCallbackMap) {
4765             try {
4766                 IOnWifiDriverCountryCodeChangedListener.Stub binderListener =
4767                         new OnDriverCountryCodeChangedProxy(executor, callback);
4768                 sActiveCountryCodeChangedCallbackMap.put(callbackIdentifier,
4769                         binderListener);
4770                 mService.registerDriverCountryCodeChangedListener(binderListener,
4771                         mContext.getOpPackageName(), mContext.getAttributionTag());
4772             } catch (RemoteException e) {
4773                 sActiveCountryCodeChangedCallbackMap.remove(callbackIdentifier);
4774                 throw e.rethrowFromSystemServer();
4775             }
4776         }
4777     }
4778 
4779     /**
4780      * Allow callers to remove a previously registered listener. After calling this method,
4781      * applications will no longer receive the active country code changed events through that
4782      * callback.
4783      *
4784      * @param callback Callback to remove the active country code changed events.
4785      *
4786      * @hide
4787      */
4788     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
4789     @SystemApi
unregisterActiveCountryCodeChangedCallback( @onNull ActiveCountryCodeChangedCallback callback)4790     public void unregisterActiveCountryCodeChangedCallback(
4791             @NonNull ActiveCountryCodeChangedCallback callback) {
4792         if (!SdkLevel.isAtLeastT()) {
4793             throw new UnsupportedOperationException();
4794         }
4795         if (callback == null) throw new IllegalArgumentException("Callback cannot be null");
4796         if (mVerboseLoggingEnabled) {
4797             Log.d(TAG, "unregisterActiveCountryCodeChangedCallback: callback=" + callback);
4798         }
4799         final int callbackIdentifier = System.identityHashCode(callback);
4800         synchronized (sActiveCountryCodeChangedCallbackMap) {
4801             try {
4802                 if (!sActiveCountryCodeChangedCallbackMap.contains(callbackIdentifier)) {
4803                     Log.w(TAG, "Unknown external listener " + callbackIdentifier);
4804                     return;
4805                 }
4806                 mService.unregisterDriverCountryCodeChangedListener(
4807                         sActiveCountryCodeChangedCallbackMap.get(callbackIdentifier));
4808             } catch (RemoteException e) {
4809                 throw e.rethrowFromSystemServer();
4810             } finally {
4811                 sActiveCountryCodeChangedCallbackMap.remove(callbackIdentifier);
4812             }
4813         }
4814     }
4815 
4816     /**
4817      * Interface used to listen to changes in current network state.
4818      * @hide
4819      */
4820     @SystemApi
4821     public interface WifiNetworkStateChangedListener {
4822         /** @hide */
4823         @Retention(RetentionPolicy.SOURCE)
4824         @IntDef(prefix = {"WIFI_ROLE_CLIENT_"}, value = {
4825                 WIFI_ROLE_CLIENT_PRIMARY,
4826                 WIFI_ROLE_CLIENT_SECONDARY_INTERNET,
4827                 WIFI_ROLE_CLIENT_SECONDARY_LOCAL_ONLY
4828         })
4829         @interface WifiClientModeRole {}
4830 
4831         /**
4832          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4833          * Represents the primary Client Mode Manager which is mostly used for internet, but could
4834          * also be used for other use-cases such as local only connections.
4835          **/
4836         int WIFI_ROLE_CLIENT_PRIMARY = 1;
4837         /**
4838          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4839          * Represents a Client Mode Manager dedicated for the secondary internet use-case.
4840          **/
4841         int WIFI_ROLE_CLIENT_SECONDARY_INTERNET = 2;
4842         /**
4843          * A client mode role returned by {@link #onWifiNetworkStateChanged(int, int)}.
4844          * Represents a Client Mode Manager dedicated for the local only connection use-case.
4845          **/
4846         int WIFI_ROLE_CLIENT_SECONDARY_LOCAL_ONLY = 3;
4847 
4848         /** @hide */
4849         @Retention(RetentionPolicy.SOURCE)
4850         @IntDef(prefix = {"WIFI_NETWORK_STATUS_"}, value = {
4851                 WIFI_NETWORK_STATUS_IDLE,
4852                 WIFI_NETWORK_STATUS_SCANNING,
4853                 WIFI_NETWORK_STATUS_CONNECTING,
4854                 WIFI_NETWORK_STATUS_AUTHENTICATING,
4855                 WIFI_NETWORK_STATUS_OBTAINING_IPADDR,
4856                 WIFI_NETWORK_STATUS_CONNECTED,
4857                 WIFI_NETWORK_STATUS_DISCONNECTED,
4858                 WIFI_NETWORK_STATUS_FAILED
4859         })
4860         @interface WifiNetworkState {}
4861 
4862         /**
4863          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4864          * Supplicant is in uninitialized state.
4865          **/
4866         int WIFI_NETWORK_STATUS_IDLE = 1;
4867         /**
4868          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4869          * Supplicant is scanning.
4870          **/
4871         int WIFI_NETWORK_STATUS_SCANNING = 2;
4872         /**
4873          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4874          * L2 connection is in progress.
4875          **/
4876         int WIFI_NETWORK_STATUS_CONNECTING = 3;
4877         /**
4878          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4879          * L2 connection 4 way handshake.
4880          **/
4881         int WIFI_NETWORK_STATUS_AUTHENTICATING = 4;
4882         /**
4883          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4884          * L2 connection complete. Obtaining IP address.
4885          **/
4886         int WIFI_NETWORK_STATUS_OBTAINING_IPADDR = 5;
4887         /**
4888          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4889          * L3 connection is complete.
4890          **/
4891         int WIFI_NETWORK_STATUS_CONNECTED = 6;
4892         /**
4893          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4894          * Network disconnected.
4895          **/
4896         int WIFI_NETWORK_STATUS_DISCONNECTED = 7;
4897         /**
4898          * A state returned by {@link #onWifiNetworkStateChanged(int, int)}.
4899          * A pseudo-state that should normally never be seen.
4900          **/
4901         int WIFI_NETWORK_STATUS_FAILED = 8;
4902 
4903 
4904         /**
4905          * Provides network state changes per client mode role.
4906          * @param cmmRole the role of the wifi client mode manager having the state change.
4907          *                One of {@link WifiClientModeRole}.
4908          * @param state the wifi network state specified by one of {@link WifiNetworkState}.
4909          */
onWifiNetworkStateChanged(@ifiClientModeRole int cmmRole, @WifiNetworkState int state)4910         void onWifiNetworkStateChanged(@WifiClientModeRole int cmmRole,
4911                 @WifiNetworkState int state);
4912     }
4913 
4914     /**
4915      * Helper class to support wifi network state changed listener.
4916      */
4917     private static class OnWifiNetworkStateChangedProxy
4918             extends IWifiNetworkStateChangedListener.Stub {
4919 
4920         @NonNull private Executor mExecutor;
4921         @NonNull private WifiNetworkStateChangedListener mListener;
4922 
OnWifiNetworkStateChangedProxy(@onNull Executor executor, @NonNull WifiNetworkStateChangedListener listener)4923         OnWifiNetworkStateChangedProxy(@NonNull Executor executor,
4924                 @NonNull WifiNetworkStateChangedListener listener) {
4925             Objects.requireNonNull(executor);
4926             Objects.requireNonNull(listener);
4927             mExecutor = executor;
4928             mListener = listener;
4929         }
4930 
4931         @Override
onWifiNetworkStateChanged(int cmmRole, int state)4932         public void onWifiNetworkStateChanged(int cmmRole, int state) {
4933             Log.i(TAG, "OnWifiNetworkStateChangedProxy: onWifiNetworkStateChanged: "
4934                     + cmmRole + ", " + state);
4935             Binder.clearCallingIdentity();
4936             mExecutor.execute(() -> mListener.onWifiNetworkStateChanged(cmmRole, state));
4937         }
4938     }
4939 
4940     /**
4941      * Add a listener to listen to Wi-Fi network state changes on available client mode roles
4942      * specified in {@link WifiNetworkStateChangedListener.WifiClientModeRole}.
4943      * When wifi state changes such as connected/disconnect happens, results will be delivered via
4944      * {@link WifiNetworkStateChangedListener#onWifiNetworkStateChanged(int, int)}.
4945      *
4946      * @param executor The Executor on which to execute the callbacks.
4947      * @param listener listener for the network status updates.
4948      * @throws SecurityException if the caller is missing required permissions.
4949      * @throws IllegalArgumentException if incorrect input arguments are provided.
4950      * @hide
4951      */
4952     @SystemApi
4953     @RequiresPermission(Manifest.permission.NETWORK_SETTINGS)
addWifiNetworkStateChangedListener(@onNull @allbackExecutor Executor executor, @NonNull WifiNetworkStateChangedListener listener)4954     public void addWifiNetworkStateChangedListener(@NonNull @CallbackExecutor Executor executor,
4955             @NonNull WifiNetworkStateChangedListener listener) {
4956         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
4957         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
4958         if (mVerboseLoggingEnabled) {
4959             Log.d(TAG, "addWifiNetworkStateChangedListener: listener=" + listener
4960                     + ", executor=" + executor);
4961         }
4962         final int listenerIdentifier = System.identityHashCode(listener);
4963         synchronized (sOnWifiNetworkStateChangedListenerMap) {
4964             try {
4965                 IWifiNetworkStateChangedListener.Stub listenerProxy =
4966                         new OnWifiNetworkStateChangedProxy(executor, listener);
4967                 sOnWifiNetworkStateChangedListenerMap.put(listenerIdentifier,
4968                         listenerProxy);
4969                 mService.addWifiNetworkStateChangedListener(listenerProxy);
4970             } catch (RemoteException e) {
4971                 sOnWifiNetworkStateChangedListenerMap.remove(listenerIdentifier);
4972                 throw e.rethrowFromSystemServer();
4973             }
4974         }
4975     }
4976 
4977     /**
4978      * Remove a listener added using
4979      * {@link #addWifiNetworkStateChangedListener(Executor, WifiNetworkStateChangedListener)}.
4980      * @param listener the listener to be removed.
4981      * @throws IllegalArgumentException if incorrect input arguments are provided.
4982      * @hide
4983      */
4984     @SystemApi
4985     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
removeWifiNetworkStateChangedListener( @onNull WifiNetworkStateChangedListener listener)4986     public void removeWifiNetworkStateChangedListener(
4987             @NonNull WifiNetworkStateChangedListener listener) {
4988         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
4989         if (mVerboseLoggingEnabled) {
4990             Log.d(TAG, "removeWifiNetworkStateChangedListener: listener=" + listener);
4991         }
4992         final int listenerIdentifier = System.identityHashCode(listener);
4993         synchronized (sOnWifiNetworkStateChangedListenerMap) {
4994             try {
4995                 if (!sOnWifiNetworkStateChangedListenerMap.contains(listenerIdentifier)) {
4996                     Log.w(TAG, "Unknown external listener " + listenerIdentifier);
4997                     return;
4998                 }
4999                 mService.removeWifiNetworkStateChangedListener(
5000                         sOnWifiNetworkStateChangedListenerMap.get(listenerIdentifier));
5001             } catch (RemoteException e) {
5002                 throw e.rethrowFromSystemServer();
5003             } finally {
5004                 sOnWifiNetworkStateChangedListenerMap.remove(listenerIdentifier);
5005             }
5006         }
5007     }
5008 
5009     /**
5010      * Get the country code as resolved by the Wi-Fi framework.
5011      * The Wi-Fi framework uses multiple sources to resolve a country code
5012      * - in order of priority (high to low):
5013      * 1. Override country code set by {@link WifiManager#setOverrideCountryCode(String)}
5014      * and cleared by {@link WifiManager#clearOverrideCountryCode()}. Typically only used
5015      * for testing.
5016      * 2. Country code supplied by the telephony module. Typically provided from the
5017      * current network or from emergency cell information.
5018      * 3. Country code supplied by the wifi driver module. (802.11d)
5019      * 4. Default country code set either via {@code ro.boot.wificountrycode}
5020      * or the {@link WifiManager#setDefaultCountryCode(String)}.
5021      *
5022      * <p>
5023      * Note:
5024      * This method returns the Country Code value used by the framework - even if not currently
5025      * used by the Wi-Fi subsystem. I.e. the returned value from this API may be different from the
5026      * value provided by
5027      * {@link WifiManager.ActiveCountryCodeChangedCallback#onActiveCountryCodeChanged(String)}.
5028      * Such a difference may happen when there is an ongoing network connection (STA, AP, Direct,
5029      * or Aware) and the Wi-Fi subsystem does not support dynamic updates - at that point the
5030      * framework may defer setting the Country Code to the Wi-Fi subsystem.
5031      * </p>
5032      * @return the country code in ISO 3166 alpha-2 (2-letter) upper format,
5033      * or null if there is no country code configured.
5034      *
5035      * @hide
5036      */
5037     @Nullable
5038     @SystemApi
5039     @RequiresPermission(anyOf = {
5040             android.Manifest.permission.NETWORK_SETTINGS,
5041             android.Manifest.permission.ACCESS_COARSE_LOCATION
5042     })
getCountryCode()5043     public String getCountryCode() {
5044         try {
5045             return mService.getCountryCode(mContext.getOpPackageName(),
5046                     mContext.getAttributionTag());
5047         } catch (RemoteException e) {
5048             throw e.rethrowFromSystemServer();
5049         }
5050     }
5051 
5052     /**
5053      * Set the override country code - may be used for testing. See the country code resolution
5054      * order and format in {@link #getCountryCode()}.
5055      * @param country A 2-Character alphanumeric country code.
5056      * @see #getCountryCode().
5057      *
5058      * @hide
5059      */
5060     @RequiresApi(Build.VERSION_CODES.S)
5061     @SystemApi
5062     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
setOverrideCountryCode(@onNull String country)5063     public void setOverrideCountryCode(@NonNull String country) {
5064         try {
5065             mService.setOverrideCountryCode(country);
5066         } catch (RemoteException e) {
5067             throw e.rethrowFromSystemServer();
5068         }
5069     }
5070 
5071     /**
5072      * This clears the override country code which was previously set by
5073      * {@link WifiManager#setOverrideCountryCode(String)} method.
5074      * @see #getCountryCode().
5075      *
5076      * @hide
5077      */
5078     @RequiresApi(Build.VERSION_CODES.S)
5079     @SystemApi
5080     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
clearOverrideCountryCode()5081     public void clearOverrideCountryCode() {
5082         try {
5083             mService.clearOverrideCountryCode();
5084         } catch (RemoteException e) {
5085             throw e.rethrowFromSystemServer();
5086         }
5087     }
5088     /**
5089      * Used to configure the default country code. See {@link #getCountryCode()} for resolution
5090      * method of the country code.
5091      * @param country A 2-character alphanumeric country code.
5092      * @see #getCountryCode().
5093      *
5094      * @hide
5095      */
5096     @RequiresApi(Build.VERSION_CODES.S)
5097     @SystemApi
5098     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_COUNTRY_CODE)
setDefaultCountryCode(@onNull String country)5099     public void setDefaultCountryCode(@NonNull String country) {
5100         try {
5101             mService.setDefaultCountryCode(country);
5102         } catch (RemoteException e) {
5103             throw e.rethrowFromSystemServer();
5104         }
5105     }
5106 
5107     /**
5108      * Return the DHCP-assigned addresses from the last successful DHCP request,
5109      * if any.
5110      *
5111      * @return the DHCP information
5112      *
5113      * @deprecated Use the methods on {@link android.net.LinkProperties} which can be obtained
5114      * either via {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)} or
5115      * {@link ConnectivityManager#getLinkProperties(Network)}.
5116      *
5117      * <p>
5118      * <b>Compatibility Notes:</b>
5119      * <li>On devices supporting concurrent connections (indicated via
5120      * {@link #isStaConcurrencyForLocalOnlyConnectionsSupported()}, etc), this API will return
5121      * the details of the internet providing connection (if any) to all apps, except for the apps
5122      * that triggered the creation of the concurrent connection. For such apps, this API will return
5123      * the details of the connection they created. e.g. apps using {@link WifiNetworkSpecifier} will
5124      * trigger a concurrent connection on supported devices and hence this API will provide
5125      * details of their peer to peer connection (not the internet providing connection). This
5126      * is to maintain backwards compatibility with behavior on single STA devices.</li>
5127      * </p>
5128      */
5129     @Deprecated
getDhcpInfo()5130     public DhcpInfo getDhcpInfo() {
5131         try {
5132             return mService.getDhcpInfo(mContext.getOpPackageName());
5133         } catch (RemoteException e) {
5134             throw e.rethrowFromSystemServer();
5135         }
5136     }
5137 
5138     /**
5139      * Enable or disable Wi-Fi.
5140      * <p>
5141      * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
5142      * permission to toggle wifi.
5143      *
5144      * @param enabled {@code true} to enable, {@code false} to disable.
5145      * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
5146      *         either already in the requested state, or in progress toward the requested state.
5147      * @throws  SecurityException if the caller is missing required permissions.
5148      *
5149      * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
5150      * enable/disable Wi-Fi.
5151      * <b>Compatibility Note:</b> For applications targeting
5152      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
5153      * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
5154      * or below), they can continue to use this API.
5155      * <p>
5156      * Deprecation Exemptions:
5157      * <ul>
5158      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
5159      * </ul>
5160      *
5161      * Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, DO/COPE may set
5162      * a user restriction (DISALLOW_CHANGE_WIFI_STATE) to only allow DO/PO to use this API.
5163      */
5164     @Deprecated
setWifiEnabled(boolean enabled)5165     public boolean setWifiEnabled(boolean enabled) {
5166         try {
5167             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
5168         } catch (RemoteException e) {
5169             throw e.rethrowFromSystemServer();
5170         }
5171     }
5172 
5173     /**
5174      * Abstract callback class for applications to receive updates about the Wi-Fi subsystem
5175      * restarting. The Wi-Fi subsystem can restart due to internal recovery mechanisms or via user
5176      * action.
5177      */
5178     @RequiresApi(Build.VERSION_CODES.S)
5179     public abstract static class SubsystemRestartTrackingCallback {
5180         private final SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy mProxy;
5181 
SubsystemRestartTrackingCallback()5182         public SubsystemRestartTrackingCallback() {
5183             mProxy = new SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy();
5184         }
5185 
5186         /*package*/ @NonNull
getProxy()5187         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy getProxy() {
5188             return mProxy;
5189         }
5190 
5191         /**
5192          * Indicates that the Wi-Fi subsystem is about to restart.
5193          */
onSubsystemRestarting()5194         public abstract void onSubsystemRestarting();
5195 
5196         /**
5197          * Indicates that the Wi-Fi subsystem has restarted.
5198          */
onSubsystemRestarted()5199         public abstract void onSubsystemRestarted();
5200 
5201         private static class SubsystemRestartCallbackProxy extends ISubsystemRestartCallback.Stub {
5202             private final Object mLock = new Object();
5203             @Nullable
5204             @GuardedBy("mLock")
5205             private Executor mExecutor;
5206             @Nullable
5207             @GuardedBy("mLock")
5208             private SubsystemRestartTrackingCallback mCallback;
5209 
SubsystemRestartCallbackProxy()5210             SubsystemRestartCallbackProxy() {
5211                 mExecutor = null;
5212                 mCallback = null;
5213             }
5214 
initProxy(@onNull Executor executor, @NonNull SubsystemRestartTrackingCallback callback)5215             /*package*/ void initProxy(@NonNull Executor executor,
5216                     @NonNull SubsystemRestartTrackingCallback callback) {
5217                 synchronized (mLock) {
5218                     mExecutor = executor;
5219                     mCallback = callback;
5220                 }
5221             }
5222 
cleanUpProxy()5223             /*package*/ void cleanUpProxy() {
5224                 synchronized (mLock) {
5225                     mExecutor = null;
5226                     mCallback = null;
5227                 }
5228             }
5229 
5230             @Override
onSubsystemRestarting()5231             public void onSubsystemRestarting() {
5232                 Executor executor;
5233                 SubsystemRestartTrackingCallback callback;
5234                 synchronized (mLock) {
5235                     executor = mExecutor;
5236                     callback = mCallback;
5237                 }
5238                 if (executor == null || callback == null) {
5239                     return;
5240                 }
5241                 Binder.clearCallingIdentity();
5242                 executor.execute(callback::onSubsystemRestarting);
5243             }
5244 
5245             @Override
onSubsystemRestarted()5246             public void onSubsystemRestarted() {
5247                 Executor executor;
5248                 SubsystemRestartTrackingCallback callback;
5249                 synchronized (mLock) {
5250                     executor = mExecutor;
5251                     callback = mCallback;
5252                 }
5253                 if (executor == null || callback == null) {
5254                     return;
5255                 }
5256                 Binder.clearCallingIdentity();
5257                 executor.execute(callback::onSubsystemRestarted);
5258             }
5259         }
5260     }
5261 
5262     /**
5263      * Registers a {@link SubsystemRestartTrackingCallback} to listen to Wi-Fi subsystem restarts.
5264      * The subsystem may restart due to internal recovery mechanisms or via user action.
5265      *
5266      * @see #unregisterSubsystemRestartTrackingCallback(SubsystemRestartTrackingCallback)
5267      *
5268      * @param executor Executor to execute callback on
5269      * @param callback {@link SubsystemRestartTrackingCallback} to register
5270      */
5271     @RequiresApi(Build.VERSION_CODES.S)
5272     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
registerSubsystemRestartTrackingCallback( @onNull @allbackExecutor Executor executor, @NonNull SubsystemRestartTrackingCallback callback)5273     public void registerSubsystemRestartTrackingCallback(
5274             @NonNull @CallbackExecutor Executor executor,
5275             @NonNull SubsystemRestartTrackingCallback callback) {
5276         if (executor == null) throw new IllegalArgumentException("executor must not be null");
5277         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5278         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy proxy = callback.getProxy();
5279         proxy.initProxy(executor, callback);
5280         try {
5281             mService.registerSubsystemRestartCallback(proxy);
5282         } catch (RemoteException e) {
5283             proxy.cleanUpProxy();
5284             throw e.rethrowFromSystemServer();
5285         }
5286     }
5287 
5288     /**
5289      * Unregisters a {@link SubsystemRestartTrackingCallback} registered with
5290      * {@link #registerSubsystemRestartTrackingCallback(Executor, SubsystemRestartTrackingCallback)}
5291      *
5292      * @param callback {@link SubsystemRestartTrackingCallback} to unregister
5293      */
5294     @RequiresApi(Build.VERSION_CODES.S)
5295     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
unregisterSubsystemRestartTrackingCallback( @onNull SubsystemRestartTrackingCallback callback)5296     public void unregisterSubsystemRestartTrackingCallback(
5297             @NonNull SubsystemRestartTrackingCallback callback) {
5298         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5299         SubsystemRestartTrackingCallback.SubsystemRestartCallbackProxy proxy = callback.getProxy();
5300         try {
5301             mService.unregisterSubsystemRestartCallback(proxy);
5302         } catch (RemoteException e) {
5303             throw e.rethrowFromSystemServer();
5304         } finally {
5305             proxy.cleanUpProxy();
5306         }
5307     }
5308 
5309     /**
5310      * Restart the Wi-Fi subsystem.
5311      *
5312      * Restarts the Wi-Fi subsystem - effectively disabling it and re-enabling it. All existing
5313      * Access Point (AP) associations are torn down, all Soft APs are disabled, Wi-Fi Direct and
5314      * Wi-Fi Aware are disabled.
5315      *
5316      * The state of the system after restart is not guaranteed to match its state before the API is
5317      * called - for instance the device may associate to a different Access Point (AP), and tethered
5318      * hotspots may or may not be restored.
5319      *
5320      * Use the
5321      * {@link #registerSubsystemRestartTrackingCallback(Executor, SubsystemRestartTrackingCallback)}
5322      * to track the operation.
5323      *
5324      * @hide
5325      */
5326     @RequiresApi(Build.VERSION_CODES.S)
5327     @SystemApi
5328     @RequiresPermission(android.Manifest.permission.RESTART_WIFI_SUBSYSTEM)
restartWifiSubsystem()5329     public void restartWifiSubsystem() {
5330         try {
5331             mService.restartWifiSubsystem();
5332         } catch (RemoteException e) {
5333             throw e.rethrowFromSystemServer();
5334         }
5335     }
5336 
5337     /**
5338      * Gets the Wi-Fi enabled state.
5339      * @return One of {@link #WIFI_STATE_DISABLED},
5340      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
5341      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
5342      * @see #isWifiEnabled()
5343      */
getWifiState()5344     public int getWifiState() {
5345         try {
5346             return mService.getWifiEnabledState();
5347         } catch (RemoteException e) {
5348             throw e.rethrowFromSystemServer();
5349         }
5350     }
5351 
5352     /**
5353      * Return whether Wi-Fi is enabled or disabled.
5354      * @return {@code true} if Wi-Fi is enabled
5355      * @see #getWifiState()
5356      */
isWifiEnabled()5357     public boolean isWifiEnabled() {
5358         return getWifiState() == WIFI_STATE_ENABLED;
5359     }
5360 
5361     /**
5362      * Calculates the level of the signal. This should be used any time a signal
5363      * is being shown.
5364      *
5365      * @param rssi The power of the signal measured in RSSI.
5366      * @param numLevels The number of levels to consider in the calculated level.
5367      * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive).
5368      * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the
5369      * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level
5370      * themselves using their own formula.
5371      */
5372     @Deprecated
calculateSignalLevel(int rssi, int numLevels)5373     public static int calculateSignalLevel(int rssi, int numLevels) {
5374         if (rssi <= MIN_RSSI) {
5375             return 0;
5376         } else if (rssi >= MAX_RSSI) {
5377             return numLevels - 1;
5378         } else {
5379             float inputRange = (MAX_RSSI - MIN_RSSI);
5380             float outputRange = (numLevels - 1);
5381             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
5382         }
5383     }
5384 
5385     /**
5386      * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI
5387      * quality rating thresholds.
5388      * @param rssi a raw RSSI value, in dBm, usually between -55 and -90
5389      * @return the RSSI signal quality rating, in the range
5390      * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
5391      * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
5392      */
5393     @IntRange(from = 0)
calculateSignalLevel(int rssi)5394     public int calculateSignalLevel(int rssi) {
5395         try {
5396             return mService.calculateSignalLevel(rssi);
5397         } catch (RemoteException e) {
5398             throw e.rethrowFromSystemServer();
5399         }
5400     }
5401 
5402     /**
5403      * Get the system default maximum signal level.
5404      * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
5405      */
5406     @IntRange(from = 0)
getMaxSignalLevel()5407     public int getMaxSignalLevel() {
5408         return calculateSignalLevel(Integer.MAX_VALUE);
5409     }
5410 
5411     /**
5412      * Compares two signal strengths.
5413      *
5414      * @param rssiA The power of the first signal measured in RSSI.
5415      * @param rssiB The power of the second signal measured in RSSI.
5416      * @return Returns <0 if the first signal is weaker than the second signal,
5417      *         0 if the two signals have the same strength, and >0 if the first
5418      *         signal is stronger than the second signal.
5419      */
compareSignalLevel(int rssiA, int rssiB)5420     public static int compareSignalLevel(int rssiA, int rssiB) {
5421         return rssiA - rssiB;
5422     }
5423 
5424     /**
5425      * Call allowing ConnectivityService to update WifiService with interface mode changes.
5426      *
5427      * @param ifaceName String name of the updated interface, or null to represent all interfaces
5428      * @param mode int representing the new mode, one of:
5429      *             {@link #IFACE_IP_MODE_TETHERED},
5430      *             {@link #IFACE_IP_MODE_LOCAL_ONLY},
5431      *             {@link #IFACE_IP_MODE_CONFIGURATION_ERROR},
5432      *             {@link #IFACE_IP_MODE_UNSPECIFIED}
5433      *
5434      * @hide
5435      */
5436     @SystemApi
5437     @RequiresPermission(anyOf = {
5438             android.Manifest.permission.NETWORK_STACK,
5439             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5440     })
updateInterfaceIpState(@ullable String ifaceName, @IfaceIpMode int mode)5441     public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
5442         try {
5443             mService.updateInterfaceIpState(ifaceName, mode);
5444         } catch (RemoteException e) {
5445             throw e.rethrowFromSystemServer();
5446         }
5447     }
5448 
5449     /* Wi-Fi/Cellular Coex */
5450 
5451     /**
5452      * Mandatory coex restriction flag for Wi-Fi Direct.
5453      *
5454      * @see #setCoexUnsafeChannels(List, int)
5455      *
5456      * @hide
5457      */
5458     @SystemApi
5459     @RequiresApi(Build.VERSION_CODES.S)
5460     public static final int COEX_RESTRICTION_WIFI_DIRECT = 0x1 << 0;
5461 
5462     /**
5463      * Mandatory coex restriction flag for SoftAP
5464      *
5465      * @see #setCoexUnsafeChannels(List, int)
5466      *
5467      * @hide
5468      */
5469     @SystemApi
5470     @RequiresApi(Build.VERSION_CODES.S)
5471     public static final int COEX_RESTRICTION_SOFTAP = 0x1 << 1;
5472 
5473     /**
5474      * Mandatory coex restriction flag for Wi-Fi Aware.
5475      *
5476      * @see #setCoexUnsafeChannels(List, int)
5477      *
5478      * @hide
5479      */
5480     @SystemApi
5481     @RequiresApi(Build.VERSION_CODES.S)
5482     public static final int COEX_RESTRICTION_WIFI_AWARE = 0x1 << 2;
5483 
5484     /** @hide */
5485     @RequiresApi(Build.VERSION_CODES.S)
5486     @Retention(RetentionPolicy.SOURCE)
5487     @IntDef(flag = true, prefix = {"COEX_RESTRICTION_"}, value = {
5488             COEX_RESTRICTION_WIFI_DIRECT,
5489             COEX_RESTRICTION_SOFTAP,
5490             COEX_RESTRICTION_WIFI_AWARE
5491     })
5492     public @interface CoexRestriction {}
5493 
5494     /**
5495      * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
5496      *
5497      * @hide
5498      */
isDefaultCoexAlgorithmEnabled()5499     public boolean isDefaultCoexAlgorithmEnabled() {
5500         try {
5501             return mService.isDefaultCoexAlgorithmEnabled();
5502         } catch (RemoteException e) {
5503             throw e.rethrowFromSystemServer();
5504         }
5505     }
5506 
5507     /**
5508      * Specify the list of {@link CoexUnsafeChannel} to propagate through the framework for
5509      * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
5510      * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
5511      *
5512      * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
5513      * @param restrictions Bitmap of {@code COEX_RESTRICTION_*} constants specifying the mode
5514      *                     restrictions on the specified channels. If any restrictions are set,
5515      *                     then the supplied CoexUnsafeChannels should be completely avoided for
5516      *                     the specified modes, rather than be avoided with best effort.
5517      *
5518      * @hide
5519      */
5520     @SystemApi
5521     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS)
5522     @RequiresApi(Build.VERSION_CODES.S)
setCoexUnsafeChannels( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5523     public void setCoexUnsafeChannels(
5524             @NonNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions) {
5525         if (unsafeChannels == null) {
5526             throw new IllegalArgumentException("unsafeChannels must not be null");
5527         }
5528         try {
5529             mService.setCoexUnsafeChannels(unsafeChannels, restrictions);
5530         } catch (RemoteException e) {
5531             throw e.rethrowFromSystemServer();
5532         }
5533     }
5534 
5535     /**
5536      * Registers a CoexCallback to listen on the current CoexUnsafeChannels and restrictions being
5537      * used for Wi-Fi/cellular coex channel avoidance. The callback method
5538      * {@link CoexCallback#onCoexUnsafeChannelsChanged(List, int)} will be called immediately after
5539      * registration to return the current values.
5540      *
5541      * @param executor Executor to execute listener callback on
5542      * @param callback CoexCallback to register
5543      *
5544      * @hide
5545      */
5546     @SystemApi
5547     @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
5548     @RequiresApi(Build.VERSION_CODES.S)
registerCoexCallback( @onNull @allbackExecutor Executor executor, @NonNull CoexCallback callback)5549     public void registerCoexCallback(
5550             @NonNull @CallbackExecutor Executor executor, @NonNull CoexCallback callback) {
5551         if (executor == null) throw new IllegalArgumentException("executor must not be null");
5552         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5553         CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
5554         proxy.initProxy(executor, callback);
5555         try {
5556             mService.registerCoexCallback(proxy);
5557         } catch (RemoteException e) {
5558             throw e.rethrowFromSystemServer();
5559         }
5560     }
5561 
5562     /**
5563      * Unregisters a CoexCallback from listening on the current CoexUnsafeChannels and restrictions
5564      * being used for Wi-Fi/cellular coex channel avoidance.
5565      * @param callback CoexCallback to unregister
5566      *
5567      * @hide
5568      */
5569     @SystemApi
5570     @RequiresPermission(android.Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS)
5571     @RequiresApi(Build.VERSION_CODES.S)
unregisterCoexCallback(@onNull CoexCallback callback)5572     public void unregisterCoexCallback(@NonNull CoexCallback callback) {
5573         if (callback == null) throw new IllegalArgumentException("callback must not be null");
5574         CoexCallback.CoexCallbackProxy proxy = callback.getProxy();
5575         try {
5576             mService.unregisterCoexCallback(proxy);
5577         } catch (RemoteException e) {
5578             throw e.rethrowFromSystemServer();
5579         } finally {
5580             proxy.cleanUpProxy();
5581         }
5582     }
5583 
5584     /**
5585      * Abstract callback class for applications to receive updates about current CoexUnsafeChannels
5586      * for Wi-Fi/Cellular coex channel avoidance.
5587      *
5588      * @hide
5589      */
5590     @SystemApi
5591     @RequiresApi(Build.VERSION_CODES.S)
5592     public abstract static class CoexCallback {
5593         private final CoexCallbackProxy mCoexCallbackProxy;
5594 
CoexCallback()5595         public CoexCallback() {
5596             if (!SdkLevel.isAtLeastS()) {
5597                 throw new UnsupportedOperationException();
5598             }
5599             mCoexCallbackProxy = new CoexCallbackProxy();
5600         }
5601 
5602         /*package*/ @NonNull
getProxy()5603         CoexCallbackProxy getProxy() {
5604             return mCoexCallbackProxy;
5605         }
5606 
5607         /**
5608          * This indicates the current CoexUnsafeChannels and restrictions calculated by the default
5609          * coex algorithm if config_wifiCoexDefaultAlgorithmEnabled is {@code true}. Otherwise, the
5610          * values will match the ones supplied to {@link #setCoexUnsafeChannels(List, int)}.
5611          *
5612          * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
5613          * @param restrictions Bitmap of {@code COEX_RESTRICTION_*} constants specifying the mode
5614          *                     restrictions on the specified channels. If any restrictions are set,
5615          *                     then the supplied CoexUnsafeChannels should be completely avoided for
5616          *                     the specified modes, rather than be avoided with best effort.
5617          */
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5618         public abstract void onCoexUnsafeChannelsChanged(
5619                 @NonNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions);
5620 
5621         /**
5622          * Callback proxy for CoexCallback objects.
5623          */
5624         private static class CoexCallbackProxy extends ICoexCallback.Stub {
5625             private final Object mLock = new Object();
5626             @Nullable @GuardedBy("mLock") private Executor mExecutor;
5627             @Nullable @GuardedBy("mLock") private CoexCallback mCallback;
5628 
CoexCallbackProxy()5629             CoexCallbackProxy() {
5630                 mExecutor = null;
5631                 mCallback = null;
5632             }
5633 
initProxy(@onNull Executor executor, @NonNull CoexCallback callback)5634             /*package*/ void initProxy(@NonNull Executor executor,
5635                     @NonNull CoexCallback callback) {
5636                 synchronized (mLock) {
5637                     mExecutor = executor;
5638                     mCallback = callback;
5639                 }
5640             }
5641 
cleanUpProxy()5642             /*package*/ void cleanUpProxy() {
5643                 synchronized (mLock) {
5644                     mExecutor = null;
5645                     mCallback = null;
5646                 }
5647             }
5648 
5649             @Override
onCoexUnsafeChannelsChanged( @onNull List<CoexUnsafeChannel> unsafeChannels, @CoexRestriction int restrictions)5650             public void onCoexUnsafeChannelsChanged(
5651                     @NonNull List<CoexUnsafeChannel> unsafeChannels,
5652                     @CoexRestriction int restrictions) {
5653                 Executor executor;
5654                 CoexCallback callback;
5655                 synchronized (mLock) {
5656                     executor = mExecutor;
5657                     callback = mCallback;
5658                 }
5659                 if (executor == null || callback == null) {
5660                     return;
5661                 }
5662                 Binder.clearCallingIdentity();
5663                 executor.execute(() ->
5664                         callback.onCoexUnsafeChannelsChanged(unsafeChannels, restrictions));
5665             }
5666         }
5667     }
5668 
5669     /**
5670      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
5671      * Note that starting Soft AP mode may disable station mode operation if the device does not
5672      * support concurrency.
5673      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
5674      *                   use the persisted Soft AP configuration that was previously set using
5675      *                   {@link #setWifiApConfiguration(WifiConfiguration)}.
5676      * @return {@code true} if the operation succeeded, {@code false} otherwise
5677      *
5678      * @hide
5679      */
5680     @RequiresPermission(anyOf = {
5681             android.Manifest.permission.NETWORK_STACK,
5682             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5683     })
startSoftAp(@ullable WifiConfiguration wifiConfig)5684     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
5685         try {
5686             return mService.startSoftAp(wifiConfig, mContext.getOpPackageName());
5687         } catch (RemoteException e) {
5688             throw e.rethrowFromSystemServer();
5689         }
5690     }
5691 
5692     /**
5693      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
5694      * Note that starting Soft AP mode may disable station mode operation if the device does not
5695      * support concurrency.
5696      *
5697      * Note: Call {@link WifiManager#validateSoftApConfiguration(SoftApConfiguration)} to avoid
5698      * unexpected error due to invalid configuration.
5699      *
5700      * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP, or
5701      *                     null to use the persisted Soft AP configuration that was previously set
5702      *                     using {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}.
5703      * @return {@code true} if the operation succeeded, {@code false} otherwise
5704      *
5705      * @deprecated Use {@link #startTetheredHotspot(TetheringManager.TetheringRequest)}
5706      *             instead.
5707      * @hide
5708      */
5709     @SystemApi
5710     @RequiresPermission(anyOf = {
5711             android.Manifest.permission.NETWORK_STACK,
5712             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5713     })
5714     @Deprecated
startTetheredHotspot(@ullable SoftApConfiguration softApConfig)5715     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
5716         try {
5717             return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
5718         } catch (RemoteException e) {
5719             throw e.rethrowFromSystemServer();
5720         }
5721     }
5722 
5723     /**
5724      * Start Soft AP (hotspot) mode for tethering purposes with the specified TetheringRequest.
5725      * Note that starting Soft AP mode may disable station mode operation if the device does not
5726      * support concurrency.
5727      *
5728      * @param request  A valid TetheringRequest specifying the configuration of the SAP.
5729      * @param executor Executor to run the callback on.
5730      * @param callback Callback to listen on state changes for this specific request.
5731      * @hide
5732      */
5733     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
5734     @SystemApi
5735     @RequiresPermission(anyOf = {
5736             android.Manifest.permission.NETWORK_STACK,
5737             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5738     })
startTetheredHotspot(@onNull TetheringManager.TetheringRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull SoftApCallback callback)5739     public void startTetheredHotspot(@NonNull TetheringManager.TetheringRequest request,
5740             @NonNull @CallbackExecutor Executor executor, @NonNull SoftApCallback callback) {
5741         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5742         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5743         ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
5744                 IFACE_IP_MODE_TETHERED);
5745         try {
5746             mService.startTetheredHotspotRequest(request, binderCallback,
5747                     mContext.getOpPackageName());
5748         } catch (RemoteException e) {
5749             throw e.rethrowFromSystemServer();
5750         }
5751     }
5752 
5753     /**
5754      * Stop SoftAp mode.
5755      * Note that stopping softap mode will restore the previous wifi mode.
5756      * @return {@code true} if the operation succeeds, {@code false} otherwise
5757      *
5758      * @hide
5759      */
5760     @SystemApi
5761     @RequiresPermission(anyOf = {
5762             android.Manifest.permission.NETWORK_STACK,
5763             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
5764     })
stopSoftAp()5765     public boolean stopSoftAp() {
5766         try {
5767             return mService.stopSoftAp();
5768         } catch (RemoteException e) {
5769             throw e.rethrowFromSystemServer();
5770         }
5771     }
5772 
5773     /**
5774      * Check if input configuration is valid.
5775      *
5776      * @param config a configuration would like to be checked.
5777      * @return true if config is valid, otherwise false.
5778      */
validateSoftApConfiguration(@onNull SoftApConfiguration config)5779     public boolean validateSoftApConfiguration(@NonNull SoftApConfiguration config) {
5780         if (config == null) {
5781             throw new IllegalArgumentException(TAG + ": config can not be null");
5782         }
5783         try {
5784             return mService.validateSoftApConfiguration(config);
5785         } catch (RemoteException e) {
5786             throw e.rethrowFromSystemServer();
5787         }
5788     }
5789 
5790     /**
5791      * Request a local only hotspot that an application can use to communicate between co-located
5792      * devices connected to the created WiFi hotspot.  The network created by this method will not
5793      * have Internet access.  Each application can make a single request for the hotspot, but
5794      * multiple applications could be requesting the hotspot at the same time.  When multiple
5795      * applications have successfully registered concurrently, they will be sharing the underlying
5796      * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called
5797      * when the hotspot is ready for use by the application.
5798      * <p>
5799      * Each application can make a single active call to this method. The {@link
5800      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
5801      * requestor with a {@link LocalOnlyHotspotReservation} that contains a
5802      * {@link SoftApConfiguration} with the SSID, security type and credentials needed to connect
5803      * to the hotspot.  Communicating this information is up to the application.
5804      * <p>
5805      * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
5806      * method will be called. Example failures include errors bringing up the network or if
5807      * there is an incompatible operating mode.  For example, if the user is currently using Wifi
5808      * Tethering to provide an upstream to another device, LocalOnlyHotspot may not start due to
5809      * an incompatible mode. The possible error codes include:
5810      * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL},
5811      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC},
5812      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and
5813      * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}.
5814      * <p>
5815      * Internally, requests will be tracked to prevent the hotspot from being torn down while apps
5816      * are still using it.  The {@link LocalOnlyHotspotReservation} object passed in the  {@link
5817      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when
5818      * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}.
5819      * Since the hotspot may be shared among multiple applications, removing the final registered
5820      * application request will trigger the hotspot teardown.  This means that applications should
5821      * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after
5822      * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is
5823      * called, applications will not receive callbacks of any kind.
5824      * <p>
5825      * Applications should be aware that the user may also stop the LocalOnlyHotspot through the
5826      * Settings UI; it is not guaranteed to stay up as long as there is a requesting application.
5827      * The requestors will be notified of this case via
5828      * {@link LocalOnlyHotspotCallback#onStopped()}.  Other cases may arise where the hotspot is
5829      * torn down (Emergency mode, etc).  Application developers should be aware that it can stop
5830      * unexpectedly, but they will receive a notification if they have properly registered.
5831      * <p>
5832      * Applications should also be aware that this network will be shared with other applications.
5833      * Applications are responsible for protecting their data on this network (e.g. TLS).
5834      * <p>
5835      * Applications targeting {@link android.os.Build.VERSION_CODES#TIRAMISU} or later need to have
5836      * the following permissions: {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
5837      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES}.
5838      * Applications targeting {@link Build.VERSION_CODES#S} or prior SDK levels need to have the
5839      * following permissions: {@link android.Manifest.permission#CHANGE_WIFI_STATE} and
5840      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
5841      * Callers without
5842      * the permissions will trigger a {@link java.lang.SecurityException}.
5843      * <p>
5844      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
5845      * operating status.
5846      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
5847      * main thread will be used.
5848      */
5849     @RequiresPermission(allOf = {CHANGE_WIFI_STATE, ACCESS_FINE_LOCATION, NEARBY_WIFI_DEVICES},
5850             conditional = true)
startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler)5851     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
5852             @Nullable Handler handler) {
5853         Executor executor = handler == null ? null : new HandlerExecutor(handler);
5854         startLocalOnlyHotspotInternal(null, executor, callback);
5855     }
5856 
5857     /**
5858      * Starts a local-only hotspot with a specific configuration applied. See
5859      * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
5860      *
5861      * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD},
5862      * {@link android.Manifest.permission#NETWORK_SETTINGS} or
5863      * {@link android.Manifest.permission#NEARBY_WIFI_DEVICES} to call this method.
5864      *
5865      * Since custom configuration settings may be incompatible with each other, the hotspot started
5866      * through this method cannot coexist with another hotspot created through
5867      * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others
5868      * receive {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
5869      * {@link LocalOnlyHotspotCallback#onFailed}.
5870      *
5871      * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
5872      * @param executor Executor to run callback methods on, or null to use the main thread.
5873      * @param callback Callback object for updates about hotspot status, or null for no updates.
5874      * @hide
5875      */
5876     @SystemApi
5877     @RequiresPermission(anyOf = {
5878             android.Manifest.permission.NETWORK_SETTINGS,
5879             android.Manifest.permission.NETWORK_SETUP_WIZARD,
5880             NEARBY_WIFI_DEVICES})
startLocalOnlyHotspot(@onNull SoftApConfiguration config, @Nullable @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)5881     public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config,
5882             @Nullable @CallbackExecutor Executor executor,
5883             @Nullable LocalOnlyHotspotCallback callback) {
5884         Objects.requireNonNull(config);
5885         startLocalOnlyHotspotInternal(config, executor, callback);
5886     }
5887 
5888     /**
5889      * Common implementation of both configurable and non-configurable LOHS.
5890      *
5891      * @param config App-specified configuration, or null. When present, additional privileges are
5892      *               required, and the hotspot cannot be shared with other clients.
5893      * @param executor Executor to run callback methods on, or null to use the main thread.
5894      * @param callback Callback object for updates about hotspot status, or null for no updates.
5895      */
startLocalOnlyHotspotInternal( @ullable SoftApConfiguration config, @Nullable @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)5896     private void startLocalOnlyHotspotInternal(
5897             @Nullable SoftApConfiguration config,
5898             @Nullable @CallbackExecutor Executor executor,
5899             @Nullable LocalOnlyHotspotCallback callback) {
5900         if (executor == null) {
5901             executor = mContext.getMainExecutor();
5902         }
5903         synchronized (mLock) {
5904             LocalOnlyHotspotCallbackProxy proxy =
5905                     new LocalOnlyHotspotCallbackProxy(this, executor, callback);
5906             try {
5907                 String packageName = mContext.getOpPackageName();
5908                 String featureId = mContext.getAttributionTag();
5909                 Bundle extras = new Bundle();
5910                 if (SdkLevel.isAtLeastS()) {
5911                     extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
5912                             mContext.getAttributionSource());
5913                 }
5914                 int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
5915                         config, extras);
5916                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
5917                     // Send message to the proxy to make sure we call back on the correct thread
5918                     proxy.onHotspotFailed(returnCode);
5919                     return;
5920                 }
5921                 mLOHSCallbackProxy = proxy;
5922             } catch (RemoteException e) {
5923                 throw e.rethrowFromSystemServer();
5924             }
5925         }
5926     }
5927 
5928     /**
5929      * Cancels a pending local only hotspot request.  This can be used by the calling application to
5930      * cancel the existing request if the provided callback has not been triggered.  Calling this
5931      * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not
5932      * explicitly required.
5933      * <p>
5934      * When cancelling this request, application developers should be aware that there may still be
5935      * outstanding local only hotspot requests and the hotspot may still start, or continue running.
5936      * Additionally, if a callback was registered, it will no longer be triggered after calling
5937      * cancel.
5938      *
5939      * @hide
5940      */
5941     @UnsupportedAppUsage
cancelLocalOnlyHotspotRequest()5942     public void cancelLocalOnlyHotspotRequest() {
5943         synchronized (mLock) {
5944             stopLocalOnlyHotspot();
5945         }
5946     }
5947 
5948     /**
5949      *  Method used to inform WifiService that the LocalOnlyHotspot is no longer needed.  This
5950      *  method is used by WifiManager to release LocalOnlyHotspotReservations held by calling
5951      *  applications and removes the internal tracking for the hotspot request.  When all requesting
5952      *  applications are finished using the hotspot, it will be stopped and WiFi will return to the
5953      *  previous operational mode.
5954      *
5955      *  This method should not be called by applications.  Instead, they should call the close()
5956      *  method on their LocalOnlyHotspotReservation.
5957      */
stopLocalOnlyHotspot()5958     private void stopLocalOnlyHotspot() {
5959         synchronized (mLock) {
5960             if (mLOHSCallbackProxy == null) {
5961                 // nothing to do, the callback was already cleaned up.
5962                 return;
5963             }
5964             mLOHSCallbackProxy = null;
5965             try {
5966                 mService.stopLocalOnlyHotspot();
5967             } catch (RemoteException e) {
5968                 throw e.rethrowFromSystemServer();
5969             }
5970         }
5971     }
5972 
5973     /**
5974      * Registers a callback for local only hotspot. See {@link SoftApCallback}. Caller will receive
5975      * the following callbacks on registration:
5976      * <ul>
5977      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
5978      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
5979      * <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
5980      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
5981      * </ul>
5982      *
5983      * Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
5984      * if there are any clients connected to a specific bridged instance of this AP
5985      * (if bridged AP is enabled).
5986      *
5987      * Note: Caller will receive the callback
5988      * {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)}
5989      * on registration when there are clients connected to AP.
5990      *
5991      * These will be dispatched on registration to provide the caller with the current state
5992      * (and are not an indication of any current change). Note that receiving an immediate
5993      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
5994      * soft AP has failed. Caller can unregister a previously registered callback using
5995      * {@link #unregisterLocalOnlyHotspotSoftApCallback}
5996      * <p>
5997      *
5998      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
5999      *                 object.
6000      * @param callback Callback for local only hotspot events
6001      * @hide
6002      */
6003     @SystemApi
6004     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
6005     @RequiresPermission(NEARBY_WIFI_DEVICES)
registerLocalOnlyHotspotSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)6006     public void registerLocalOnlyHotspotSoftApCallback(@NonNull @CallbackExecutor Executor executor,
6007             @NonNull SoftApCallback callback) {
6008         if (!SdkLevel.isAtLeastT()) {
6009             throw new UnsupportedOperationException();
6010         }
6011         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
6012         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
6013         Log.v(TAG, "registerLocalOnlyHotspotSoftApCallback: callback=" + callback + ", executor="
6014                 + executor);
6015         try {
6016             synchronized (sLocalOnlyHotspotSoftApCallbackMap) {
6017                 ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
6018                         IFACE_IP_MODE_LOCAL_ONLY);
6019                 sLocalOnlyHotspotSoftApCallbackMap.put(System.identityHashCode(callback),
6020                         binderCallback);
6021                 Bundle extras = new Bundle();
6022                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
6023                         mContext.getAttributionSource());
6024                 mService.registerLocalOnlyHotspotSoftApCallback(binderCallback, extras);
6025             }
6026         } catch (RemoteException e) {
6027             throw e.rethrowFromSystemServer();
6028         }
6029     }
6030 
6031     /**
6032      * Allow callers to unregister a previously registered callback. After calling this method,
6033      * applications will no longer receive local only hotspot events.
6034      *
6035      * <p>
6036      *
6037      * @param callback Callback to unregister for soft AP events
6038      *
6039      * @hide
6040      */
6041     @SystemApi
6042     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
6043     @RequiresPermission(NEARBY_WIFI_DEVICES)
unregisterLocalOnlyHotspotSoftApCallback(@onNull SoftApCallback callback)6044     public void unregisterLocalOnlyHotspotSoftApCallback(@NonNull SoftApCallback callback) {
6045         if (!SdkLevel.isAtLeastT()) {
6046             throw new UnsupportedOperationException();
6047         }
6048         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
6049         Log.v(TAG, "unregisterLocalOnlyHotspotSoftApCallback: callback=" + callback);
6050 
6051         try {
6052             synchronized (sLocalOnlyHotspotSoftApCallbackMap) {
6053                 int callbackIdentifier = System.identityHashCode(callback);
6054                 if (!sLocalOnlyHotspotSoftApCallbackMap.contains(callbackIdentifier)) {
6055                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
6056                     return;
6057                 }
6058                 Bundle extras = new Bundle();
6059                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
6060                         mContext.getAttributionSource());
6061                 mService.unregisterLocalOnlyHotspotSoftApCallback(
6062                         sLocalOnlyHotspotSoftApCallbackMap.get(callbackIdentifier), extras);
6063                 sLocalOnlyHotspotSoftApCallbackMap.remove(callbackIdentifier);
6064             }
6065         } catch (RemoteException e) {
6066             throw e.rethrowFromSystemServer();
6067         }
6068     }
6069 
6070     /**
6071      * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes.  Callers will
6072      * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
6073      * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
6074      * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(SoftApConfiguration)} and
6075      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
6076      * <p>
6077      * Applications should have the
6078      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
6079      * permission.  Callers without the permission will trigger a
6080      * {@link java.lang.SecurityException}.
6081      * <p>
6082      * @param observer LocalOnlyHotspotObserver callback.
6083      * @param handler Handler to use for callbacks
6084      *
6085      * @hide
6086      */
watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, @Nullable Handler handler)6087     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
6088             @Nullable Handler handler) {
6089         Executor executor = handler == null ? mContext.getMainExecutor()
6090                 : new HandlerExecutor(handler);
6091         synchronized (mLock) {
6092             mLOHSObserverProxy =
6093                     new LocalOnlyHotspotObserverProxy(this, executor, observer);
6094             try {
6095                 mService.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
6096                 mLOHSObserverProxy.registered();
6097             } catch (RemoteException e) {
6098                 mLOHSObserverProxy = null;
6099                 throw e.rethrowFromSystemServer();
6100             }
6101         }
6102     }
6103 
6104     /**
6105      * Allow callers to stop watching LocalOnlyHotspot state changes.  After calling this method,
6106      * applications will no longer receive callbacks.
6107      *
6108      * @hide
6109      */
unregisterLocalOnlyHotspotObserver()6110     public void unregisterLocalOnlyHotspotObserver() {
6111         synchronized (mLock) {
6112             if (mLOHSObserverProxy == null) {
6113                 // nothing to do, the callback was already cleaned up
6114                 return;
6115             }
6116             mLOHSObserverProxy = null;
6117             try {
6118                 mService.stopWatchLocalOnlyHotspot();
6119             } catch (RemoteException e) {
6120                 throw e.rethrowFromSystemServer();
6121             }
6122         }
6123     }
6124 
6125     /**
6126      * Gets the tethered Wi-Fi hotspot enabled state.
6127      * @return One of {@link #WIFI_AP_STATE_DISABLED},
6128      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
6129      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
6130      * @see #isWifiApEnabled()
6131      *
6132      * @hide
6133      */
6134     @SystemApi
6135     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getWifiApState()6136     public int getWifiApState() {
6137         try {
6138             return mService.getWifiApEnabledState();
6139         } catch (RemoteException e) {
6140             throw e.rethrowFromSystemServer();
6141         }
6142     }
6143 
6144     /**
6145      * Return whether tethered Wi-Fi AP is enabled or disabled.
6146      * @return {@code true} if tethered  Wi-Fi AP is enabled
6147      * @see #getWifiApState()
6148      *
6149      * @hide
6150      */
6151     @SystemApi
6152     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiApEnabled()6153     public boolean isWifiApEnabled() {
6154         return getWifiApState() == WIFI_AP_STATE_ENABLED;
6155     }
6156 
6157     /**
6158      * Gets the tethered Wi-Fi AP Configuration.
6159      * @return AP details in WifiConfiguration
6160      *
6161      * Note that AP detail may contain configuration which is cannot be represented
6162      * by the legacy WifiConfiguration, in such cases a null will be returned.
6163      *
6164      * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
6165      * @hide
6166      */
6167     @Nullable
6168     @SystemApi
6169     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
6170     @Deprecated
getWifiApConfiguration()6171     public WifiConfiguration getWifiApConfiguration() {
6172         try {
6173             return mService.getWifiApConfiguration();
6174         } catch (RemoteException e) {
6175             throw e.rethrowFromSystemServer();
6176         }
6177     }
6178 
6179     /**
6180      * Gets the Wi-Fi tethered AP Configuration.
6181      * @return AP details in {@link SoftApConfiguration}
6182      *
6183      * @hide
6184      */
6185     @NonNull
6186     @SystemApi
6187     @RequiresPermission(anyOf = {
6188             android.Manifest.permission.NETWORK_SETTINGS,
6189             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6190     })
getSoftApConfiguration()6191     public SoftApConfiguration getSoftApConfiguration() {
6192         try {
6193             return mService.getSoftApConfiguration();
6194         } catch (RemoteException e) {
6195             throw e.rethrowFromSystemServer();
6196         }
6197     }
6198 
6199     /**
6200      * Gets the last configured Wi-Fi tethered AP passphrase.
6201      *
6202      * Note: It may be null when there is no passphrase changed since
6203      * device boot.
6204      *
6205      * @param executor The executor on which callback will be invoked.
6206      * @param resultCallback An asynchronous callback that will return the last configured
6207      *                       Wi-Fi tethered AP passphrase.
6208      *
6209      * @throws SecurityException if the caller does not have permission.
6210      * @throws NullPointerException if the caller provided invalid inputs.
6211      *
6212      * @hide
6213      */
6214     @Nullable
6215     @SystemApi
6216     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
queryLastConfiguredTetheredApPassphraseSinceBoot( @onNull @allbackExecutor Executor executor, @NonNull Consumer<String> resultCallback)6217     public void queryLastConfiguredTetheredApPassphraseSinceBoot(
6218             @NonNull @CallbackExecutor Executor executor,
6219             @NonNull Consumer<String> resultCallback) {
6220         Objects.requireNonNull(executor, "executor cannot be null");
6221         Objects.requireNonNull(resultCallback, "resultsCallback cannot be null");
6222         try {
6223             mService.queryLastConfiguredTetheredApPassphraseSinceBoot(
6224                     new IStringListener.Stub() {
6225                         @Override
6226                         public void onResult(String value) {
6227                             Binder.clearCallingIdentity();
6228                             executor.execute(() -> {
6229                                 resultCallback.accept(value);
6230                             });
6231                         }
6232                     });
6233         } catch (RemoteException e) {
6234             throw e.rethrowFromSystemServer();
6235         }
6236     }
6237 
6238     /**
6239      * Sets the tethered Wi-Fi AP Configuration.
6240      * @return {@code true} if the operation succeeded, {@code false} otherwise
6241      *
6242      * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
6243      * instead.
6244      * @hide
6245      */
6246     @SystemApi
6247     @RequiresPermission(CHANGE_WIFI_STATE)
6248     @Deprecated
setWifiApConfiguration(WifiConfiguration wifiConfig)6249     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
6250         try {
6251             return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
6252         } catch (RemoteException e) {
6253             throw e.rethrowFromSystemServer();
6254         }
6255     }
6256 
6257     /**
6258      * Sets the tethered Wi-Fi AP Configuration.
6259      *
6260      * If the API is called while the tethered soft AP is enabled, the configuration will apply to
6261      * the current soft AP if the new configuration only includes
6262      * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
6263      * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
6264      * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
6265      * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
6266      * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
6267      * or {@link SoftApConfiguration.Builder#setAutoShutdownEnabled(boolean)}
6268      * or {@link SoftApConfiguration.Builder#setBridgedModeOpportunisticShutdownEnabled(boolean)}
6269      *
6270      * Otherwise, the configuration changes will be applied when the Soft AP is next started
6271      * (the framework will not stop/start the AP).
6272      *
6273      * Note: Call {@link WifiManager#validateSoftApConfiguration(SoftApConfiguration)} to avoid
6274      * unexpected error due to invalid configuration.
6275      *
6276      * @param softApConfig  A valid SoftApConfiguration specifying the configuration of the SAP.
6277      * @return {@code true} if the operation succeeded, {@code false} otherwise
6278      *
6279      * @hide
6280      */
6281     @SystemApi
6282     @RequiresPermission(anyOf = {
6283             android.Manifest.permission.NETWORK_SETTINGS,
6284             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6285     })
setSoftApConfiguration(@onNull SoftApConfiguration softApConfig)6286     public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
6287         try {
6288             return mService.setSoftApConfiguration(
6289                     softApConfig, mContext.getOpPackageName());
6290         } catch (RemoteException e) {
6291             throw e.rethrowFromSystemServer();
6292         }
6293     }
6294 
6295     /**
6296      * Enable/Disable TDLS on a specific local route.
6297      *
6298      * <p>
6299      * TDLS enables two wireless endpoints to talk to each other directly
6300      * without going through the access point that is managing the local
6301      * network. It saves bandwidth and improves quality of the link.
6302      * </p>
6303      * <p>
6304      * This API enables/disables the option of using TDLS. If enabled, the
6305      * underlying hardware is free to use TDLS or a hop through the access
6306      * point. If disabled, existing TDLS session is torn down and
6307      * hardware is restricted to use access point for transferring wireless
6308      * packets. Default value for all routes is 'disabled', meaning restricted
6309      * to use access point for transferring packets.
6310      * </p>
6311      *
6312      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
6313      * @param enable true = setup and false = tear down TDLS
6314      */
setTdlsEnabled(InetAddress remoteIPAddress, boolean enable)6315     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
6316         try {
6317             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
6318         } catch (RemoteException e) {
6319             throw e.rethrowFromSystemServer();
6320         }
6321     }
6322 
6323     /**
6324      * Enable/Disable TDLS on a specific local route.
6325      *
6326      * Similar to {@link #setTdlsEnabled(InetAddress, boolean)}, except
6327      * this version sends the result of the Enable/Disable request.
6328      *
6329      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
6330      * @param enable true = setup and false = tear down TDLS
6331      * @param executor The executor on which callback will be invoked.
6332      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6333      *                        whether TDLS was successfully enabled or disabled.
6334      *                        {@code true} for success, {@code false} for failure.
6335      *
6336      * @throws NullPointerException if the caller provided invalid inputs.
6337      */
setTdlsEnabled(@onNull InetAddress remoteIPAddress, boolean enable, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6338     public void setTdlsEnabled(@NonNull InetAddress remoteIPAddress, boolean enable,
6339             @NonNull @CallbackExecutor Executor executor,
6340             @NonNull Consumer<Boolean> resultsCallback) {
6341         Objects.requireNonNull(executor, "executor cannot be null");
6342         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6343         Objects.requireNonNull(remoteIPAddress, "remote IP address cannot be null");
6344         try {
6345             mService.enableTdlsWithRemoteIpAddress(remoteIPAddress.getHostAddress(), enable,
6346                     new IBooleanListener.Stub() {
6347                         @Override
6348                         public void onResult(boolean value) {
6349                             Binder.clearCallingIdentity();
6350                             executor.execute(() -> {
6351                                 resultsCallback.accept(value);
6352                             });
6353                         }
6354                     });
6355         } catch (RemoteException e) {
6356             throw e.rethrowFromSystemServer();
6357         }
6358     }
6359 
6360     /**
6361      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
6362      * this version allows you to specify remote endpoint with a MAC address.
6363      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
6364      * @param enable true = setup and false = tear down TDLS
6365      */
setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable)6366     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
6367         try {
6368             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
6369         } catch (RemoteException e) {
6370             throw e.rethrowFromSystemServer();
6371         }
6372     }
6373 
6374     /**
6375      * Enable/Disable TDLS with a specific peer Mac Address.
6376      *
6377      * Similar to {@link #setTdlsEnabledWithMacAddress(String, boolean)}, except
6378      * this version sends the result of the Enable/Disable request.
6379      *
6380      * @param remoteMacAddress Mac address of the endpoint to setup TDLS with
6381      * @param enable true = setup and false = tear down TDLS
6382      * @param executor The executor on which callback will be invoked.
6383      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6384      *                        whether TDLS was successfully enabled or disabled.
6385      *                        {@code true} for success, {@code false} for failure.
6386      *
6387      * @throws NullPointerException if the caller provided invalid inputs.
6388      */
setTdlsEnabledWithMacAddress(@onNull String remoteMacAddress, boolean enable, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6389     public void setTdlsEnabledWithMacAddress(@NonNull String remoteMacAddress, boolean enable,
6390             @NonNull @CallbackExecutor Executor executor,
6391             @NonNull Consumer<Boolean> resultsCallback) {
6392         Objects.requireNonNull(executor, "executor cannot be null");
6393         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6394         Objects.requireNonNull(remoteMacAddress, "remote Mac address cannot be null");
6395         try {
6396             mService.enableTdlsWithRemoteMacAddress(remoteMacAddress, enable,
6397                     new IBooleanListener.Stub() {
6398                         @Override
6399                         public void onResult(boolean value) {
6400                             Binder.clearCallingIdentity();
6401                             executor.execute(() -> {
6402                                 resultsCallback.accept(value);
6403                             });
6404                         }
6405                     });
6406         } catch (RemoteException e) {
6407             throw e.rethrowFromSystemServer();
6408         }
6409     }
6410 
6411     /**
6412      * Check if a TDLS session can be established at this time via
6413      * {@link #setTdlsEnabled(InetAddress, boolean)} or
6414      * {@link #setTdlsEnabledWithMacAddress(String, boolean)} or
6415      * {@link #setTdlsEnabled(InetAddress, boolean, Executor, Consumer)} or
6416      * {@link #setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
6417      *
6418      * Internally framework checks the STA connected state, device support for TDLS and
6419      * the number of TDLS sessions available in driver/firmware.
6420      *
6421      * @param executor The executor on which callback will be invoked.
6422      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
6423      *                        whether a TDLS session can be established at this time.
6424      *                        {@code true} for available, {@code false} for not available.
6425      *
6426      * @throws NullPointerException if the caller provided invalid inputs.
6427      */
isTdlsOperationCurrentlyAvailable(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)6428     public void isTdlsOperationCurrentlyAvailable(@NonNull @CallbackExecutor Executor executor,
6429             @NonNull Consumer<Boolean> resultsCallback) {
6430         Objects.requireNonNull(executor, "executor cannot be null");
6431         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6432         try {
6433             mService.isTdlsOperationCurrentlyAvailable(
6434                     new IBooleanListener.Stub() {
6435                         @Override
6436                         public void onResult(boolean value) {
6437                             Binder.clearCallingIdentity();
6438                             executor.execute(() -> {
6439                                 resultsCallback.accept(value);
6440                             });
6441                         }
6442                     });
6443         } catch (RemoteException e) {
6444             throw e.rethrowFromSystemServer();
6445         }
6446     }
6447 
6448     /**
6449      * Return the maximum number of concurrent TDLS sessions supported by the device.
6450      *
6451      * @param executor The executor on which callback will be invoked.
6452      * @param resultsCallback An asynchronous callback that will return the maximum number of
6453      *                        concurrent TDLS sessions supported by the device. Returns
6454      *                        {@code -1} if information is not available,
6455      *                        e.g. if the driver/firmware doesn't provide this information.
6456      *
6457      * @throws NullPointerException if the caller provided invalid inputs.
6458      * @throws UnsupportedOperationException if the feature is not available.
6459      */
6460     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
getMaxSupportedConcurrentTdlsSessions(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)6461     public void getMaxSupportedConcurrentTdlsSessions(@NonNull @CallbackExecutor Executor executor,
6462             @NonNull Consumer<Integer> resultsCallback) {
6463         Objects.requireNonNull(executor, "executor cannot be null");
6464         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6465         try {
6466             mService.getMaxSupportedConcurrentTdlsSessions(
6467                     new IIntegerListener.Stub() {
6468                         @Override
6469                         public void onResult(int value) {
6470                             Binder.clearCallingIdentity();
6471                             executor.execute(() -> {
6472                                 resultsCallback.accept(value);
6473                             });
6474                         }
6475                     });
6476         } catch (RemoteException e) {
6477             throw e.rethrowFromSystemServer();
6478         }
6479     }
6480 
6481     /**
6482      * Return the number of currently enabled TDLS sessions.
6483      *
6484      * Tracks the number of peers enabled for TDLS session via
6485      * {@link #setTdlsEnabled(InetAddress, boolean) },
6486      * {@link #setTdlsEnabledWithMacAddress(String, boolean) },
6487      * {@link #setTdlsEnabled(InetAddress, boolean, Executor, Consumer) } and
6488      * {@link #setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer) }
6489      *
6490      * @param executor The executor on which callback will be invoked.
6491      * @param resultsCallback An asynchronous callback that will return the number of Peer
6492      *                        Mac addresses configured in the driver for TDLS session.
6493      *
6494      * @throws NullPointerException if the caller provided invalid inputs.
6495      */
getNumberOfEnabledTdlsSessions(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)6496     public void getNumberOfEnabledTdlsSessions(@NonNull @CallbackExecutor Executor executor,
6497             @NonNull Consumer<Integer> resultsCallback) {
6498         Objects.requireNonNull(executor, "executor cannot be null");
6499         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
6500         try {
6501             mService.getNumberOfEnabledTdlsSessions(
6502                     new IIntegerListener.Stub() {
6503                         @Override
6504                         public void onResult(int value) {
6505                             Binder.clearCallingIdentity();
6506                             executor.execute(() -> {
6507                                 resultsCallback.accept(value);
6508                             });
6509                         }
6510                     });
6511         } catch (RemoteException e) {
6512             throw e.rethrowFromSystemServer();
6513         }
6514     }
6515 
6516     /** @hide */
6517     @Retention(RetentionPolicy.SOURCE)
6518     @IntDef({ActionListener.FAILURE_INTERNAL_ERROR,
6519             ActionListener.FAILURE_IN_PROGRESS,
6520             ActionListener.FAILURE_BUSY,
6521             ActionListener.FAILURE_INVALID_ARGS,
6522             ActionListener.FAILURE_NOT_AUTHORIZED})
6523     public @interface ActionListenerFailureReason {}
6524 
6525     /* WPS specific errors */
6526     /** WPS overlap detected
6527      * @deprecated This is deprecated
6528      */
6529     public static final int WPS_OVERLAP_ERROR           = 3;
6530     /** WEP on WPS is prohibited
6531      * @deprecated This is deprecated
6532      */
6533     public static final int WPS_WEP_PROHIBITED          = 4;
6534     /** TKIP only prohibited
6535      * @deprecated This is deprecated
6536      */
6537     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
6538     /** Authentication failure on WPS
6539      * @deprecated This is deprecated
6540      */
6541     public static final int WPS_AUTH_FAILURE            = 6;
6542     /** WPS timed out
6543      * @deprecated This is deprecated
6544      */
6545     public static final int WPS_TIMED_OUT               = 7;
6546 
6547     /**
6548      * Interface for callback invocation on an application action.
6549      * @hide
6550      */
6551     @SystemApi
6552     public interface ActionListener {
6553         /**
6554          * Passed with {@link #onFailure}.
6555          * Indicates that the operation failed due to an internal error.
6556          */
6557         int FAILURE_INTERNAL_ERROR = 0;
6558 
6559         /**
6560          * Passed with {@link #onFailure}.
6561          * Indicates that the operation is already in progress.
6562          */
6563         int FAILURE_IN_PROGRESS = 1;
6564 
6565         /**
6566          * Passed with {@link #onFailure}.
6567          * Indicates that the operation failed because the framework is busy and is unable to
6568          * service the request.
6569          */
6570         int FAILURE_BUSY = 2;
6571 
6572         /**
6573          * Passed with {@link #onFailure}.
6574          * Indicates that the operation failed due to invalid inputs.
6575          */
6576         int FAILURE_INVALID_ARGS = 3;
6577 
6578         /**
6579          * Passed with {@link #onFailure}.
6580          * Indicates that the operation failed due to insufficient user permissions.
6581          */
6582         int FAILURE_NOT_AUTHORIZED = 4;
6583 
6584         /**
6585          * The operation succeeded.
6586          */
onSuccess()6587         void onSuccess();
6588         /**
6589          * The operation failed.
6590          * @param reason The reason for failure depends on the operation.
6591          */
onFailure(@ctionListenerFailureReason int reason)6592         void onFailure(@ActionListenerFailureReason int reason);
6593     }
6594 
6595     /** Interface for callback invocation on a start WPS action
6596      * @deprecated This is deprecated
6597      */
6598     public static abstract class WpsCallback {
6599 
6600         /** WPS start succeeded
6601          * @deprecated This API is deprecated
6602          */
onStarted(String pin)6603         public abstract void onStarted(String pin);
6604 
6605         /** WPS operation completed successfully
6606          * @deprecated This API is deprecated
6607          */
onSucceeded()6608         public abstract void onSucceeded();
6609 
6610         /**
6611          * WPS operation failed
6612          * @param reason The reason for failure could be one of
6613          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
6614          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
6615          * and some generic errors.
6616          * @deprecated This API is deprecated
6617          */
onFailed(int reason)6618         public abstract void onFailed(int reason);
6619     }
6620 
6621     /**
6622      * Base class for soft AP callback. Should be extended by applications and set when calling
6623      * {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
6624      *
6625      * @hide
6626      */
6627     @SystemApi
6628     public interface SoftApCallback {
6629         /**
6630          * Called when soft AP state changes.
6631          *
6632          * @param state         the new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
6633          *                      {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
6634          *                      {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
6635          * @param failureReason reason when in failed state. One of
6636          *                      {@link #SAP_START_FAILURE_GENERAL},
6637          *                      {@link #SAP_START_FAILURE_NO_CHANNEL},
6638          *                      {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION},
6639          *                      {@link #SAP_START_FAILURE_USER_REJECTED}
6640          */
onStateChanged(@ifiApState int state, @SapStartFailure int failureReason)6641         default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
6642 
6643         /**
6644          * Called when soft AP state changes.
6645          * <p>
6646          * This provides the same state and failure reason as {@link #onStateChanged(int, int)}, but
6647          * also provides extra information such as interface name and TetheringRequest in order to
6648          * replace usage of the WIFI_AP_STATE_CHANGED_ACTION broadcast. If this method is overridden
6649          * then {@link #onStateChanged(int, int)} will no longer be called.
6650          *
6651          * @param state the new state.
6652          */
6653         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onStateChanged(@onNull SoftApState state)6654         default void onStateChanged(@NonNull SoftApState state) {
6655             onStateChanged(state.mState, state.mFailureReason);
6656         }
6657 
6658         /**
6659          * Called when the connected clients to soft AP changes.
6660          *
6661          * @param clients the currently connected clients
6662          *
6663          * @deprecated This API is deprecated.
6664          * Use {@link #onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} instead.
6665          */
6666         @Deprecated
onConnectedClientsChanged(@onNull List<WifiClient> clients)6667         default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
6668 
6669 
6670         /**
6671          * Called when the connected clients for a soft AP instance change.
6672          *
6673          * When the Soft AP is configured in single AP mode, this callback is invoked
6674          * with the same {@link SoftApInfo} for all connected clients changes.
6675          * When the Soft AP is configured as multiple Soft AP instances (using
6676          * {@link SoftApConfiguration.Builder#setBands(int[])} or
6677          * {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)}), this
6678          * callback is invoked with the corresponding {@link SoftApInfo} for the instance in which
6679          * the connected clients changed.
6680          *
6681          * @param info The {@link SoftApInfo} of the AP.
6682          * @param clients The currently connected clients on the AP instance specified by
6683          *                {@code info}.
6684          */
onConnectedClientsChanged(@onNull SoftApInfo info, @NonNull List<WifiClient> clients)6685         default void onConnectedClientsChanged(@NonNull SoftApInfo info,
6686                 @NonNull List<WifiClient> clients) {}
6687 
6688         /**
6689          * Called when the Soft AP information changes.
6690          *
6691          * Note: this API remains valid only when the Soft AP is configured as a single AP -
6692          * not as multiple Soft APs (which are bridged to each other). When multiple Soft APs are
6693          * configured (using {@link SoftApConfiguration.Builder#setBands(int[])} or
6694          * {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)})
6695          * this callback will not be triggered -  use the
6696          * {@link #onInfoChanged(List<SoftApInfo>)} callback in that case.
6697          *
6698          * @param softApInfo is the Soft AP information. {@link SoftApInfo}
6699          *
6700          * @deprecated This API is deprecated. Use {@link #onInfoChanged(List<SoftApInfo>)}
6701          * instead.
6702          */
6703         @Deprecated
onInfoChanged(@onNull SoftApInfo softApInfo)6704         default void onInfoChanged(@NonNull SoftApInfo softApInfo) {
6705             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
6706         }
6707 
6708         /**
6709          * Called when the Soft AP information changes.
6710          *
6711          * Returns information on all configured Soft AP instances. The number of the elements in
6712          * the list depends on Soft AP configuration and state:
6713          * <ul>
6714          * <li>An empty list will be returned when the Soft AP is disabled.
6715          * <li>One information element will be returned in the list when the Soft AP is configured
6716          *     as a single AP or when a single Soft AP remains active.
6717          * <li>Two information elements will be returned in the list when the multiple Soft APs are
6718          *     configured and are active.
6719          *     (configured using {@link SoftApConfiguration.Builder#setBands(int[])} or
6720          *     {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)}).
6721          * </ul>
6722          *
6723          * Note: When multiple Soft AP instances are configured, one of the Soft APs may
6724          * be shut down independently of the other by the framework. This can happen if no devices
6725          * are connected to it for some duration. In that case, one information element will be
6726          * returned.
6727          *
6728          * See {@link #isBridgedApConcurrencySupported()} for support info of multiple (bridged) AP.
6729          *
6730          * @param softApInfoList is the list of the Soft AP information elements -
6731          *        {@link SoftApInfo}.
6732          */
onInfoChanged(@onNull List<SoftApInfo> softApInfoList)6733         default void onInfoChanged(@NonNull List<SoftApInfo> softApInfoList) {
6734             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
6735         }
6736 
6737         /**
6738          * Called when capability of Soft AP changes.
6739          *
6740          * @param softApCapability is the Soft AP capability. {@link SoftApCapability}
6741          */
onCapabilityChanged(@onNull SoftApCapability softApCapability)6742         default void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
6743             // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported
6744             // client number) to the UI.
6745         }
6746 
6747         /**
6748          * Called when client trying to connect but device blocked the client with specific reason.
6749          *
6750          * Can be used to ask user to update client to allowed list or blocked list
6751          * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or
6752          * indicate the block due to maximum supported client number limitation when reason is
6753          * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}.
6754          *
6755          * @param client the currently blocked client.
6756          * @param blockedReason one of blocked reason from {@link SapClientBlockedReason}
6757          */
onBlockedClientConnecting(@onNull WifiClient client, @SapClientBlockedReason int blockedReason)6758         default void onBlockedClientConnecting(@NonNull WifiClient client,
6759                 @SapClientBlockedReason int blockedReason) {
6760             // Do nothing: can be used to ask user to update client to allowed list or blocked list.
6761         }
6762     }
6763 
6764     /**
6765      * Callback proxy for SoftApCallback objects.
6766      *
6767      * @hide
6768      */
6769     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
6770         private final Executor mExecutor;
6771         private final SoftApCallback mCallback;
6772         // Either {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
6773         private final int mIpMode;
6774         private Map<String, List<WifiClient>> mCurrentClients = new HashMap<>();
6775         private Map<String, SoftApInfo> mCurrentInfos = new HashMap<>();
6776 
getConnectedClientList(Map<String, List<WifiClient>> clientsMap)6777         private List<WifiClient> getConnectedClientList(Map<String, List<WifiClient>> clientsMap) {
6778             List<WifiClient> connectedClientList = new ArrayList<>();
6779             for (List<WifiClient> it : clientsMap.values()) {
6780                 connectedClientList.addAll(it);
6781             }
6782             return connectedClientList;
6783         }
6784 
SoftApCallbackProxy(Executor executor, SoftApCallback callback, int mode)6785         SoftApCallbackProxy(Executor executor, SoftApCallback callback, int mode) {
6786             mExecutor = executor;
6787             mCallback = callback;
6788             mIpMode = mode;
6789         }
6790 
6791         @Override
onStateChanged(SoftApState state)6792         public void onStateChanged(SoftApState state) {
6793             if (mVerboseLoggingEnabled) {
6794                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6795                         + ", onStateChanged: " + state);
6796             }
6797 
6798             Binder.clearCallingIdentity();
6799             mExecutor.execute(() -> {
6800                 mCallback.onStateChanged(state);
6801             });
6802         }
6803 
6804         @Override
onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration)6805         public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
6806                 Map<String, List<WifiClient>> clients, boolean isBridged, boolean isRegistration) {
6807             if (mVerboseLoggingEnabled) {
6808                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6809                         + ", onConnectedClientsOrInfoChanged: clients: "
6810                         + clients + ", infos: " + infos + ", isBridged is " + isBridged
6811                         + ", isRegistration is " + isRegistration);
6812             }
6813 
6814             List<SoftApInfo> changedInfoList = new ArrayList<>(infos.values());
6815             Map<SoftApInfo, List<WifiClient>> changedInfoClients = new HashMap<>();
6816             // Some devices may not support infos callback, allow them to support client
6817             // connection changed callback.
6818             boolean areClientsChangedWithoutInfosChanged =
6819                     infos.size() == 0 && getConnectedClientList(clients).size()
6820                     != getConnectedClientList(mCurrentClients).size();
6821             boolean isInfoChanged = infos.size() != mCurrentInfos.size();
6822 
6823             if (isRegistration) {
6824                 // Check if there are clients connected, put it to changedInfoClients
6825                 for (SoftApInfo currentInfo : infos.values()) {
6826                     String instance = currentInfo.getApInstanceIdentifier();
6827                     if (clients.getOrDefault(instance, Collections.emptyList()).size() > 0) {
6828                         changedInfoClients.put(currentInfo, clients.get(instance));
6829                     }
6830                 }
6831             }
6832 
6833             // Check if old info removed or not (client changed case)
6834             for (SoftApInfo info : mCurrentInfos.values()) {
6835                 String changedInstance = info.getApInstanceIdentifier();
6836                 List<WifiClient> changedClientList = clients.getOrDefault(
6837                         changedInstance, Collections.emptyList());
6838                 if (!changedInfoList.contains(info)) {
6839                     isInfoChanged = true;
6840                     if (mCurrentClients.getOrDefault(changedInstance,
6841                               Collections.emptyList()).size() > 0) {
6842                         SoftApInfo changedInfo = infos.get(changedInstance);
6843                         if (changedInfo == null || changedInfo.getFrequency() == 0) {
6844                             Log.d(TAG, "SoftApCallbackProxy on mode " + mIpMode
6845                                     + ", info changed on client connected instance(AP disabled)");
6846                             // Send old info with empty client list for shutdown case
6847                             changedInfoClients.put(info, Collections.emptyList());
6848                         } else {
6849                             Log.d(TAG, "SoftApCallbackProxy on mode " + mIpMode
6850                                     + ", info changed on client connected instance");
6851                             changedInfoClients.put(changedInfo, changedClientList);
6852                         }
6853                     }
6854                 } else {
6855                     // info doesn't change, check client list
6856                     if (changedClientList.size()
6857                             != mCurrentClients
6858                             .getOrDefault(changedInstance, Collections.emptyList()).size()) {
6859                         // Here should notify client changed on new info(same as old info)
6860                         changedInfoClients.put(info, changedClientList);
6861                     }
6862                 }
6863             }
6864 
6865             mCurrentClients = clients;
6866             mCurrentInfos = infos;
6867             if (!isInfoChanged && changedInfoClients.isEmpty()
6868                     && !isRegistration && !areClientsChangedWithoutInfosChanged) {
6869                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6870                         + ", No changed & Not Registration don't need to notify the client");
6871                 return;
6872             }
6873             Binder.clearCallingIdentity();
6874             // Notify the clients changed first for old info shutdown case
6875             for (SoftApInfo changedInfo : changedInfoClients.keySet()) {
6876                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6877                         + ", send onConnectedClientsChanged, changedInfo is "
6878                         + changedInfo + " and clients are " + changedInfoClients.get(changedInfo));
6879                 mExecutor.execute(() -> {
6880                     mCallback.onConnectedClientsChanged(
6881                             changedInfo, changedInfoClients.get(changedInfo));
6882                 });
6883             }
6884 
6885             if (isInfoChanged || isRegistration) {
6886                 if (!isBridged) {
6887                     SoftApInfo newInfo = changedInfoList.isEmpty()
6888                             ? new SoftApInfo() : changedInfoList.get(0);
6889                     Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6890                             + ", send InfoChanged, newInfo: " + newInfo);
6891                     mExecutor.execute(() -> {
6892                         mCallback.onInfoChanged(newInfo);
6893                     });
6894                 }
6895                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6896                         + ", send InfoChanged, changedInfoList: " + changedInfoList);
6897                 mExecutor.execute(() -> {
6898                     mCallback.onInfoChanged(changedInfoList);
6899                 });
6900             }
6901 
6902             if (isRegistration || !changedInfoClients.isEmpty()
6903                     || areClientsChangedWithoutInfosChanged) {
6904                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6905                         + ", send onConnectedClientsChanged(clients): "
6906                         + getConnectedClientList(clients));
6907                 mExecutor.execute(() -> {
6908                     mCallback.onConnectedClientsChanged(getConnectedClientList(clients));
6909                 });
6910             }
6911         }
6912 
6913         @Override
onCapabilityChanged(SoftApCapability capability)6914         public void onCapabilityChanged(SoftApCapability capability) {
6915             if (mVerboseLoggingEnabled) {
6916                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6917                         + ",  onCapabilityChanged: SoftApCapability = " + capability);
6918             }
6919 
6920             Binder.clearCallingIdentity();
6921             mExecutor.execute(() -> {
6922                 mCallback.onCapabilityChanged(capability);
6923             });
6924         }
6925 
6926         @Override
onBlockedClientConnecting(@onNull WifiClient client, int blockedReason)6927         public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) {
6928             if (mVerboseLoggingEnabled) {
6929                 Log.v(TAG, "SoftApCallbackProxy on mode " + mIpMode
6930                         + ", onBlockedClientConnecting: client =" + client
6931                         + " with reason = " + blockedReason);
6932             }
6933 
6934             Binder.clearCallingIdentity();
6935             mExecutor.execute(() -> {
6936                 mCallback.onBlockedClientConnecting(client, blockedReason);
6937             });
6938         }
6939     }
6940 
6941     /**
6942      * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the
6943      * following callbacks on registration:
6944      * <ul>
6945      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
6946      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
6947      * <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
6948      * <li> {@link SoftApCallback#onInfoChanged(List<SoftApInfo>)}</li>
6949      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
6950      * </ul>
6951      *
6952      * Use {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} to know
6953      * if there are any clients connected to a specific bridged instance of this AP
6954      * (if bridged AP is enabled).
6955      *
6956      * Note: Caller will receive the callback
6957      * {@link SoftApCallback#onConnectedClientsChanged(SoftApInfo, List<WifiClient>)}
6958      * on registration when there are clients connected to AP.
6959      *
6960      * These will be dispatched on registration to provide the caller with the current state
6961      * (and are not an indication of any current change). Note that receiving an immediate
6962      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
6963      * soft AP has failed. Caller can unregister a previously registered callback using
6964      * {@link #unregisterSoftApCallback}
6965      * <p>
6966      * Applications should have the
6967      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
6968      * without the permission will trigger a {@link java.lang.SecurityException}.
6969      * <p>
6970      *
6971      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
6972      *                 object.
6973      * @param callback Callback for soft AP events
6974      * @hide
6975      */
6976     @SystemApi
6977     @RequiresPermission(anyOf = {
6978             android.Manifest.permission.NETWORK_SETTINGS,
6979             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
6980             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
6981     })
registerSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)6982     public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
6983             @NonNull SoftApCallback callback) {
6984         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
6985         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
6986         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
6987 
6988         try {
6989             synchronized (sSoftApCallbackMap) {
6990                 ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
6991                         IFACE_IP_MODE_TETHERED);
6992                 sSoftApCallbackMap.put(System.identityHashCode(callback), binderCallback);
6993                 mService.registerSoftApCallback(binderCallback);
6994             }
6995         } catch (RemoteException e) {
6996             throw e.rethrowFromSystemServer();
6997         }
6998     }
6999 
7000     /**
7001      * Allow callers to unregister a previously registered callback. After calling this method,
7002      * applications will no longer receive soft AP events.
7003      *
7004      * @param callback Callback to unregister for soft AP events
7005      *
7006      * @hide
7007      */
7008     @SystemApi
7009     @RequiresPermission(anyOf = {
7010             android.Manifest.permission.NETWORK_SETTINGS,
7011             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
7012             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
7013     })
unregisterSoftApCallback(@onNull SoftApCallback callback)7014     public void unregisterSoftApCallback(@NonNull SoftApCallback callback) {
7015         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
7016         Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
7017 
7018         try {
7019             synchronized (sSoftApCallbackMap) {
7020                 int callbackIdentifier = System.identityHashCode(callback);
7021                 if (!sSoftApCallbackMap.contains(callbackIdentifier)) {
7022                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
7023                     return;
7024                 }
7025                 mService.unregisterSoftApCallback(sSoftApCallbackMap.get(callbackIdentifier));
7026                 sSoftApCallbackMap.remove(callbackIdentifier);
7027             }
7028         } catch (RemoteException e) {
7029             throw e.rethrowFromSystemServer();
7030         }
7031     }
7032 
7033     /**
7034      * LocalOnlyHotspotReservation that contains the {@link SoftApConfiguration} for the active
7035      * LocalOnlyHotspot request.
7036      * <p>
7037      * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
7038      * LocalOnlyHotspotReservation in the
7039      * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call.  This
7040      * reservation contains the relevant {@link SoftApConfiguration}.
7041      * When an application is done with the LocalOnlyHotspot, they should call {@link
7042      * LocalOnlyHotspotReservation#close()}.  Once this happens, the application will not receive
7043      * any further callbacks. If the LocalOnlyHotspot is stopped due to a
7044      * user triggered mode change, applications will be notified via the {@link
7045      * LocalOnlyHotspotCallback#onStopped()} callback.
7046      */
7047     public class LocalOnlyHotspotReservation implements AutoCloseable {
7048 
7049         private final CloseGuard mCloseGuard = new CloseGuard();
7050         private final SoftApConfiguration mSoftApConfig;
7051         private final WifiConfiguration mWifiConfig;
7052         private boolean mClosed = false;
7053 
7054         /** @hide */
7055         @VisibleForTesting
LocalOnlyHotspotReservation(SoftApConfiguration config)7056         public LocalOnlyHotspotReservation(SoftApConfiguration config) {
7057             mSoftApConfig = config;
7058             mWifiConfig = config.toWifiConfiguration();
7059             mCloseGuard.open("close");
7060         }
7061 
7062         /**
7063          * Returns the {@link WifiConfiguration} of the current Local Only Hotspot (LOHS).
7064          * May be null if hotspot enabled and security type is not
7065          * {@code WifiConfiguration.KeyMgmt.None} or {@code WifiConfiguration.KeyMgmt.WPA2_PSK}.
7066          *
7067          * @deprecated Use {@code WifiManager#getSoftApConfiguration()} to get the
7068          * LOHS configuration.
7069          */
7070         @Deprecated
7071         @Nullable
getWifiConfiguration()7072         public WifiConfiguration getWifiConfiguration() {
7073             return mWifiConfig;
7074         }
7075 
7076         /**
7077          * Returns the {@link SoftApConfiguration} of the current Local Only Hotspot (LOHS).
7078          */
7079         @NonNull
getSoftApConfiguration()7080         public SoftApConfiguration getSoftApConfiguration() {
7081             return mSoftApConfig;
7082         }
7083 
7084         @Override
close()7085         public void close() {
7086             try {
7087                 synchronized (mLock) {
7088                     if (!mClosed) {
7089                         mClosed = true;
7090                         stopLocalOnlyHotspot();
7091                         mCloseGuard.close();
7092                     }
7093                 }
7094             } catch (Exception e) {
7095                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
7096             } finally {
7097                 Reference.reachabilityFence(this);
7098             }
7099         }
7100 
7101         @Override
finalize()7102         protected void finalize() throws Throwable {
7103             try {
7104                 if (mCloseGuard != null) {
7105                     mCloseGuard.warnIfOpen();
7106                 }
7107                 close();
7108             } finally {
7109                 super.finalize();
7110             }
7111         }
7112     }
7113 
7114     /**
7115      * Callback class for applications to receive updates about the LocalOnlyHotspot status.
7116      */
7117     public static class LocalOnlyHotspotCallback {
7118         /** @hide */
7119         public static final int REQUEST_REGISTERED = 0;
7120 
7121         public static final int ERROR_NO_CHANNEL = 1;
7122         public static final int ERROR_GENERIC = 2;
7123         public static final int ERROR_INCOMPATIBLE_MODE = 3;
7124         public static final int ERROR_TETHERING_DISALLOWED = 4;
7125 
7126         /** LocalOnlyHotspot start succeeded. */
onStarted(LocalOnlyHotspotReservation reservation)7127         public void onStarted(LocalOnlyHotspotReservation reservation) {};
7128 
7129         /**
7130          * LocalOnlyHotspot stopped.
7131          * <p>
7132          * The LocalOnlyHotspot can be disabled at any time by the user.  When this happens,
7133          * applications will be notified that it was stopped. This will not be invoked when an
7134          * application calls {@link LocalOnlyHotspotReservation#close()}.
7135          */
onStopped()7136         public void onStopped() {};
7137 
7138         /**
7139          * LocalOnlyHotspot failed to start.
7140          * <p>
7141          * Applications can attempt to call
7142          * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at
7143          * a later time.
7144          * <p>
7145          * @param reason The reason for failure could be one of: {@link
7146          * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE},
7147          * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}.
7148          */
onFailed(int reason)7149         public void onFailed(int reason) { };
7150     }
7151 
7152     /**
7153      * Callback proxy for LocalOnlyHotspotCallback objects.
7154      */
7155     private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub {
7156         private final WeakReference<WifiManager> mWifiManager;
7157         private final Executor mExecutor;
7158         private final LocalOnlyHotspotCallback mCallback;
7159 
7160         /**
7161          * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor.  All
7162          * callbacks will run using the given executor.
7163          *
7164          * @param manager WifiManager
7165          * @param executor Executor for delivering callbacks.
7166          * @param callback LocalOnlyHotspotCallback to notify the calling application, or null.
7167          */
LocalOnlyHotspotCallbackProxy( @onNull WifiManager manager, @NonNull @CallbackExecutor Executor executor, @Nullable LocalOnlyHotspotCallback callback)7168         LocalOnlyHotspotCallbackProxy(
7169                 @NonNull WifiManager manager,
7170                 @NonNull @CallbackExecutor Executor executor,
7171                 @Nullable LocalOnlyHotspotCallback callback) {
7172             mWifiManager = new WeakReference<>(manager);
7173             mExecutor = executor;
7174             mCallback = callback;
7175         }
7176 
7177         @Override
onHotspotStarted(SoftApConfiguration config)7178         public void onHotspotStarted(SoftApConfiguration config) {
7179             WifiManager manager = mWifiManager.get();
7180             if (manager == null) return;
7181 
7182             if (config == null) {
7183                 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
7184                 onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
7185                 return;
7186             }
7187             final LocalOnlyHotspotReservation reservation =
7188                     manager.new LocalOnlyHotspotReservation(config);
7189             if (mCallback == null) return;
7190             mExecutor.execute(() -> mCallback.onStarted(reservation));
7191         }
7192 
7193         @Override
onHotspotStopped()7194         public void onHotspotStopped() {
7195             WifiManager manager = mWifiManager.get();
7196             if (manager == null) return;
7197 
7198             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
7199             if (mCallback == null) return;
7200             mExecutor.execute(() -> mCallback.onStopped());
7201         }
7202 
7203         @Override
onHotspotFailed(int reason)7204         public void onHotspotFailed(int reason) {
7205             WifiManager manager = mWifiManager.get();
7206             if (manager == null) return;
7207 
7208             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
7209                     + reason);
7210             if (mCallback == null) return;
7211             mExecutor.execute(() -> mCallback.onFailed(reason));
7212         }
7213     }
7214 
7215     /**
7216      * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications
7217      * watching for LocalOnlyHotspot changes.
7218      *
7219      * @hide
7220      */
7221     public class LocalOnlyHotspotSubscription implements AutoCloseable {
7222         private final CloseGuard mCloseGuard = new CloseGuard();
7223 
7224         /** @hide */
7225         @VisibleForTesting
LocalOnlyHotspotSubscription()7226         public LocalOnlyHotspotSubscription() {
7227             mCloseGuard.open("close");
7228         }
7229 
7230         @Override
close()7231         public void close() {
7232             try {
7233                 unregisterLocalOnlyHotspotObserver();
7234                 mCloseGuard.close();
7235             } catch (Exception e) {
7236                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
7237             } finally {
7238                 Reference.reachabilityFence(this);
7239             }
7240         }
7241 
7242         @Override
finalize()7243         protected void finalize() throws Throwable {
7244             try {
7245                 if (mCloseGuard != null) {
7246                     mCloseGuard.warnIfOpen();
7247                 }
7248                 close();
7249             } finally {
7250                 super.finalize();
7251             }
7252         }
7253     }
7254 
7255     /**
7256      * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates.
7257      *
7258      * @hide
7259      */
7260     public static class LocalOnlyHotspotObserver {
7261         /**
7262          * Confirm registration for LocalOnlyHotspotChanges by returning a
7263          * LocalOnlyHotspotSubscription.
7264          */
onRegistered(LocalOnlyHotspotSubscription subscription)7265         public void onRegistered(LocalOnlyHotspotSubscription subscription) {};
7266 
7267         /**
7268          * LocalOnlyHotspot started with the supplied config.
7269          */
onStarted(SoftApConfiguration config)7270         public void onStarted(SoftApConfiguration config) {};
7271 
7272         /**
7273          * LocalOnlyHotspot stopped.
7274          */
onStopped()7275         public void onStopped() {};
7276     }
7277 
7278     /**
7279      * Callback proxy for LocalOnlyHotspotObserver objects.
7280      */
7281     private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub {
7282         private final WeakReference<WifiManager> mWifiManager;
7283         private final Executor mExecutor;
7284         private final LocalOnlyHotspotObserver mObserver;
7285 
7286         /**
7287          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
7288          * All callbacks will be delivered on the thread of the specified looper.
7289          *
7290          * @param manager WifiManager
7291          * @param executor Executor for delivering callbacks
7292          * @param observer LocalOnlyHotspotObserver to notify the calling application.
7293          */
LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor, final LocalOnlyHotspotObserver observer)7294         LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor,
7295                 final LocalOnlyHotspotObserver observer) {
7296             mWifiManager = new WeakReference<>(manager);
7297             mExecutor = executor;
7298             mObserver = observer;
7299         }
7300 
registered()7301         public void registered() throws RemoteException {
7302             WifiManager manager = mWifiManager.get();
7303             if (manager == null) return;
7304 
7305             mExecutor.execute(() ->
7306                     mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription()));
7307         }
7308 
7309         @Override
onHotspotStarted(SoftApConfiguration config)7310         public void onHotspotStarted(SoftApConfiguration config) {
7311             WifiManager manager = mWifiManager.get();
7312             if (manager == null) return;
7313 
7314             if (config == null) {
7315                 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
7316                 return;
7317             }
7318             mExecutor.execute(() -> mObserver.onStarted(config));
7319         }
7320 
7321         @Override
onHotspotStopped()7322         public void onHotspotStopped() {
7323             WifiManager manager = mWifiManager.get();
7324             if (manager == null) return;
7325 
7326             mExecutor.execute(() -> mObserver.onStopped());
7327         }
7328 
7329         @Override
onHotspotFailed(int reason)7330         public void onHotspotFailed(int reason) {
7331             // do nothing
7332         }
7333     }
7334 
7335     /**
7336      * Callback proxy for ActionListener objects.
7337      */
7338     private class ActionListenerProxy extends IActionListener.Stub {
7339         private final String mActionTag;
7340         private final Handler mHandler;
7341         private final ActionListener mCallback;
7342 
ActionListenerProxy(String actionTag, Looper looper, ActionListener callback)7343         ActionListenerProxy(String actionTag, Looper looper, ActionListener callback) {
7344             mActionTag = actionTag;
7345             mHandler = new Handler(looper);
7346             mCallback = callback;
7347         }
7348 
7349         @Override
onSuccess()7350         public void onSuccess() {
7351             if (mVerboseLoggingEnabled) {
7352                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onSuccess");
7353             }
7354             mHandler.post(() -> {
7355                 mCallback.onSuccess();
7356             });
7357         }
7358 
7359         @Override
onFailure(@ctionListenerFailureReason int reason)7360         public void onFailure(@ActionListenerFailureReason int reason) {
7361             if (mVerboseLoggingEnabled) {
7362                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onFailure=" + reason);
7363             }
7364             mHandler.post(() -> {
7365                 mCallback.onFailure(reason);
7366             });
7367         }
7368     }
7369 
connectInternal(@ullable WifiConfiguration config, int networkId, @Nullable ActionListener listener)7370     private void connectInternal(@Nullable WifiConfiguration config, int networkId,
7371             @Nullable ActionListener listener) {
7372         ActionListenerProxy listenerProxy = null;
7373         if (listener != null) {
7374             listenerProxy = new ActionListenerProxy("connect", mLooper, listener);
7375         }
7376         try {
7377             Bundle extras = new Bundle();
7378             if (SdkLevel.isAtLeastS()) {
7379                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
7380                         mContext.getAttributionSource());
7381             }
7382             mService.connect(config, networkId, listenerProxy, mContext.getOpPackageName(), extras);
7383         } catch (RemoteException e) {
7384             if (listenerProxy != null) {
7385                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7386             }
7387         } catch (SecurityException e) {
7388             if (listenerProxy != null) {
7389                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7390             }
7391         }
7392     }
7393 
7394     /**
7395      * Connect to a network with the given configuration. The network also
7396      * gets added to the list of configured networks for the foreground user.
7397      *
7398      * For a new network, this function is used instead of a
7399      * sequence of addNetwork(), enableNetwork(), and reconnect()
7400      *
7401      * @param config the set of variables that describe the configuration,
7402      *            contained in a {@link WifiConfiguration} object.
7403      * @param listener for callbacks on success or failure. Can be null.
7404      * @throws IllegalStateException if the WifiManager instance needs to be
7405      * initialized again
7406      *
7407      * @hide
7408      */
7409     @SystemApi
7410     @RequiresPermission(anyOf = {
7411             android.Manifest.permission.NETWORK_SETTINGS,
7412             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7413             android.Manifest.permission.NETWORK_STACK
7414     })
connect(@onNull WifiConfiguration config, @Nullable ActionListener listener)7415     public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
7416         if (config == null) throw new IllegalArgumentException("config cannot be null");
7417         connectInternal(config, WifiConfiguration.INVALID_NETWORK_ID, listener);
7418     }
7419 
7420     /**
7421      * Connect to a network with the given networkId.
7422      *
7423      * This function is used instead of a enableNetwork() and reconnect()
7424      *
7425      * <li> This API will cause reconnect if the credentials of the current active
7426      * connection has been changed.</li>
7427      * <li> This API will cause reconnect if the current active connection is marked metered.</li>
7428      *
7429      * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
7430      *        #getConfiguredNetworks()}.
7431      * @param listener for callbacks on success or failure. Can be null.
7432      * @throws IllegalStateException if the WifiManager instance needs to be
7433      * initialized again
7434      * @hide
7435      */
7436     @SystemApi
7437     @RequiresPermission(anyOf = {
7438             android.Manifest.permission.NETWORK_SETTINGS,
7439             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7440             android.Manifest.permission.NETWORK_STACK
7441     })
connect(int networkId, @Nullable ActionListener listener)7442     public void connect(int networkId, @Nullable ActionListener listener) {
7443         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7444         connectInternal(null, networkId, listener);
7445     }
7446 
7447     /**
7448      * Temporarily disable autojoin for all currently visible and provisioned (saved, suggested)
7449      * wifi networks except merged carrier networks from the provided subscription ID.
7450      *
7451      * Disabled networks will get automatically re-enabled when they are out of range for a period
7452      * of time, or after the maximum disable duration specified in the framework.
7453      *
7454      * Calling {@link #stopRestrictingAutoJoinToSubscriptionId()} will immediately re-enable
7455      * autojoin on all disabled networks.
7456      *
7457      * @param subscriptionId the subscription ID of the carrier whose merged wifi networks won't be
7458      *                       disabled {@link android.telephony.SubscriptionInfo#getSubscriptionId()}
7459      * @hide
7460      */
7461     @SystemApi
7462     @RequiresPermission(anyOf = {
7463             android.Manifest.permission.NETWORK_SETTINGS,
7464             android.Manifest.permission.NETWORK_SETUP_WIZARD})
7465     @RequiresApi(Build.VERSION_CODES.S)
startRestrictingAutoJoinToSubscriptionId(int subscriptionId)7466     public void startRestrictingAutoJoinToSubscriptionId(int subscriptionId) {
7467         try {
7468             mService.startRestrictingAutoJoinToSubscriptionId(subscriptionId);
7469         } catch (RemoteException e) {
7470             throw e.rethrowFromSystemServer();
7471         }
7472     }
7473 
7474     /**
7475      * Re-enable autojoin for all non carrier merged wifi networks temporarily disconnected by
7476      * {@link #startRestrictingAutoJoinToSubscriptionId(int)}.
7477      * @hide
7478      */
7479     @SystemApi
7480     @RequiresPermission(anyOf = {
7481             android.Manifest.permission.NETWORK_SETTINGS,
7482             android.Manifest.permission.NETWORK_SETUP_WIZARD})
7483     @RequiresApi(Build.VERSION_CODES.S)
stopRestrictingAutoJoinToSubscriptionId()7484     public void stopRestrictingAutoJoinToSubscriptionId() {
7485         try {
7486             mService.stopRestrictingAutoJoinToSubscriptionId();
7487         } catch (RemoteException e) {
7488             throw e.rethrowFromSystemServer();
7489         }
7490     }
7491 
7492     /**
7493      * Save the given network to the list of configured networks for the
7494      * foreground user. If the network already exists, the configuration
7495      * is updated. Any new network is enabled by default.
7496      *
7497      * For a new network, this function is used instead of a
7498      * sequence of addNetwork() and enableNetwork().
7499      *
7500      * For an existing network, it accomplishes the task of updateNetwork()
7501      *
7502      * <li> This API will cause reconnect if the credentials of the current active
7503      * connection has been changed.</li>
7504      * <li> This API will cause disconnect if the current active connection is marked metered.</li>
7505      *
7506      * @param config the set of variables that describe the configuration,
7507      *            contained in a {@link WifiConfiguration} object.
7508      * @param listener for callbacks on success or failure. Can be null.
7509      * @throws IllegalStateException if the WifiManager instance needs to be
7510      * initialized again
7511      * @hide
7512      */
7513     @SystemApi
7514     @RequiresPermission(anyOf = {
7515             android.Manifest.permission.NETWORK_SETTINGS,
7516             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7517             android.Manifest.permission.NETWORK_STACK
7518     })
save(@onNull WifiConfiguration config, @Nullable ActionListener listener)7519     public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
7520         if (config == null) throw new IllegalArgumentException("config cannot be null");
7521         ActionListenerProxy listenerProxy = null;
7522         if (listener != null) {
7523             listenerProxy = new ActionListenerProxy("save", mLooper, listener);
7524         }
7525         try {
7526             mService.save(config, listenerProxy, mContext.getOpPackageName());
7527         } catch (RemoteException e) {
7528             if (listenerProxy != null) {
7529                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7530             }
7531         } catch (SecurityException e) {
7532             if (listenerProxy != null) {
7533                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7534             }
7535         }
7536     }
7537 
7538     /**
7539      * Delete the network from the list of configured networks for the
7540      * foreground user.
7541      *
7542      * This function is used instead of a sequence of removeNetwork()
7543      *
7544      * @param config the set of variables that describe the configuration,
7545      *            contained in a {@link WifiConfiguration} object.
7546      * @param listener for callbacks on success or failure. Can be null.
7547      * @throws IllegalStateException if the WifiManager instance needs to be
7548      * initialized again
7549      * @hide
7550      */
7551     @SystemApi
7552     @RequiresPermission(anyOf = {
7553             android.Manifest.permission.NETWORK_SETTINGS,
7554             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7555             android.Manifest.permission.NETWORK_STACK
7556     })
forget(int netId, @Nullable ActionListener listener)7557     public void forget(int netId, @Nullable ActionListener listener) {
7558         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7559         ActionListenerProxy listenerProxy = null;
7560         if (listener != null) {
7561             listenerProxy = new ActionListenerProxy("forget", mLooper, listener);
7562         }
7563         try {
7564             mService.forget(netId, listenerProxy);
7565         } catch (RemoteException e) {
7566             if (listenerProxy != null) {
7567                 listenerProxy.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7568             }
7569         } catch (SecurityException e) {
7570             if (listenerProxy != null) {
7571                 listenerProxy.onFailure(ActionListener.FAILURE_NOT_AUTHORIZED);
7572             }
7573         }
7574     }
7575 
7576     /**
7577      * Disable network
7578      *
7579      * @param netId is the network Id
7580      * @param listener for callbacks on success or failure. Can be null.
7581      * @throws IllegalStateException if the WifiManager instance needs to be
7582      * initialized again
7583      * @deprecated This API is deprecated. Use {@link #disableNetwork(int)} instead.
7584      * @hide
7585      */
7586     @SystemApi
7587     @RequiresPermission(anyOf = {
7588             android.Manifest.permission.NETWORK_SETTINGS,
7589             android.Manifest.permission.NETWORK_SETUP_WIZARD,
7590             android.Manifest.permission.NETWORK_STACK
7591     })
7592     @Deprecated
disable(int netId, @Nullable ActionListener listener)7593     public void disable(int netId, @Nullable ActionListener listener) {
7594         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
7595         // Simple wrapper which forwards the call to disableNetwork. This is a temporary
7596         // implementation until we can remove this API completely.
7597         boolean status = disableNetwork(netId);
7598         if (listener != null) {
7599             if (status) {
7600                 listener.onSuccess();
7601             } else {
7602                 listener.onFailure(ActionListener.FAILURE_INTERNAL_ERROR);
7603             }
7604         }
7605     }
7606 
7607     /**
7608      * Control whether the device will automatically search for and connect to Wi-Fi networks -
7609      * auto-join Wi-Fi networks. Disabling this option will not impact manual connections - i.e.
7610      * the user will still be able to manually select and connect to a Wi-Fi network. Disabling
7611      * this option significantly impacts the device connectivity and is a restricted operation
7612      * (see below for permissions). Note that disabling this operation will also disable
7613      * connectivity initiated scanning operations.
7614      * <p>
7615      * Disabling the auto-join configuration is a temporary operation (with the exception of a
7616      * DO/PO caller): it will be reset (to enabled) when the device reboots or the user toggles
7617      * Wi-Fi off/on. When the caller is a DO/PO then toggling Wi-Fi will not reset the
7618      * configuration. Additionally, if a DO/PO disables auto-join then it cannot be (re)enabled by
7619      * a non-DO/PO caller.
7620      *
7621      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
7622      *
7623      * Available for DO/PO apps.
7624      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
7625      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
7626      */
allowAutojoinGlobal(boolean allowAutojoin)7627     public void allowAutojoinGlobal(boolean allowAutojoin) {
7628         try {
7629             Bundle extras = new Bundle();
7630             if (SdkLevel.isAtLeastS()) {
7631                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
7632                         mContext.getAttributionSource());
7633             }
7634             mService.allowAutojoinGlobal(allowAutojoin, mContext.getOpPackageName(), extras);
7635         } catch (RemoteException e) {
7636             throw e.rethrowFromSystemServer();
7637         }
7638     }
7639 
7640     /**
7641      * Query whether or not auto-join global is enabled/disabled
7642      * @see #allowAutojoinGlobal(boolean)
7643      *
7644      * Available for DO/PO apps.
7645      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
7646      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
7647      *
7648      * @param executor The executor on which callback will be invoked.
7649      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
7650      *                        whether auto-join global is enabled/disabled.
7651      *
7652      * @throws SecurityException if the caller does not have permission.
7653      * @throws NullPointerException if the caller provided invalid inputs.
7654      */
queryAutojoinGlobal(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)7655     public void queryAutojoinGlobal(@NonNull @CallbackExecutor Executor executor,
7656             @NonNull Consumer<Boolean> resultsCallback) {
7657         Objects.requireNonNull(executor, "executor cannot be null");
7658         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
7659         try {
7660             mService.queryAutojoinGlobal(
7661                     new IBooleanListener.Stub() {
7662                         @Override
7663                         public void onResult(boolean value) {
7664                             Binder.clearCallingIdentity();
7665                             executor.execute(() -> {
7666                                 resultsCallback.accept(value);
7667                             });
7668                         }
7669                     });
7670         } catch (RemoteException e) {
7671             throw e.rethrowFromSystemServer();
7672         }
7673     }
7674 
7675     /**
7676      * Sets the user choice for allowing auto-join to a network.
7677      * The updated choice will be made available through the updated config supplied by the
7678      * CONFIGURED_NETWORKS_CHANGED broadcast.
7679      *
7680      * @param netId the id of the network to allow/disallow auto-join for.
7681      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
7682      * @hide
7683      */
7684     @SystemApi
7685     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoin(int netId, boolean allowAutojoin)7686     public void allowAutojoin(int netId, boolean allowAutojoin) {
7687         try {
7688             mService.allowAutojoin(netId, allowAutojoin);
7689         } catch (RemoteException e) {
7690             throw e.rethrowFromSystemServer();
7691         }
7692     }
7693 
7694     /**
7695      * Configure auto-join settings for a Passpoint profile.
7696      *
7697      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7698      * @param allowAutojoin true to enable auto-join, false to disable auto-join.
7699      * @hide
7700      */
7701     @SystemApi
7702     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoinPasspoint(@onNull String fqdn, boolean allowAutojoin)7703     public void allowAutojoinPasspoint(@NonNull String fqdn, boolean allowAutojoin) {
7704         try {
7705             mService.allowAutojoinPasspoint(fqdn, allowAutojoin);
7706         } catch (RemoteException e) {
7707             throw e.rethrowFromSystemServer();
7708         }
7709     }
7710 
7711     /**
7712      * Configure MAC randomization setting for a Passpoint profile.
7713      * MAC randomization is enabled by default.
7714      *
7715      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7716      * @param enable true to enable MAC randomization, false to disable MAC randomization.
7717      * @hide
7718      */
7719     @SystemApi
7720     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setMacRandomizationSettingPasspointEnabled(@onNull String fqdn, boolean enable)7721     public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
7722         try {
7723             mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
7724         } catch (RemoteException e) {
7725             throw e.rethrowFromSystemServer();
7726         }
7727     }
7728 
7729     /**
7730      * Sets the user's choice of metered override for a Passpoint profile.
7731      *
7732      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
7733      * @param meteredOverride One of three values: {@link WifiConfiguration#METERED_OVERRIDE_NONE},
7734      *                        {@link WifiConfiguration#METERED_OVERRIDE_METERED},
7735      *                        {@link WifiConfiguration#METERED_OVERRIDE_NOT_METERED}
7736      * @hide
7737      */
7738     @SystemApi
7739     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setPasspointMeteredOverride(@onNull String fqdn, @WifiConfiguration.MeteredOverride int meteredOverride)7740     public void setPasspointMeteredOverride(@NonNull String fqdn,
7741             @WifiConfiguration.MeteredOverride int meteredOverride) {
7742         try {
7743             mService.setPasspointMeteredOverride(fqdn, meteredOverride);
7744         } catch (RemoteException e) {
7745             throw e.rethrowFromSystemServer();
7746         }
7747     }
7748 
7749     /**
7750      * Temporarily disable a network. Should always trigger with user disconnect network.
7751      *
7752      * @param network Input can be SSID or FQDN. And caller must ensure that the SSID passed thru
7753      *                this API matched the WifiConfiguration.SSID rules, and thus be surrounded by
7754      *                quotes.
7755      * @hide
7756      */
7757     @SystemApi
7758     @RequiresPermission(anyOf = {
7759             android.Manifest.permission.NETWORK_SETTINGS,
7760             android.Manifest.permission.NETWORK_STACK
7761     })
disableEphemeralNetwork(@onNull String network)7762     public void disableEphemeralNetwork(@NonNull String network) {
7763         if (TextUtils.isEmpty(network)) {
7764             throw new IllegalArgumentException("SSID cannot be null or empty!");
7765         }
7766         try {
7767             mService.disableEphemeralNetwork(network, mContext.getOpPackageName());
7768         } catch (RemoteException e) {
7769             throw e.rethrowFromSystemServer();
7770         }
7771     }
7772 
7773     /**
7774      * WPS suport has been deprecated from Client mode and this method will immediately trigger
7775      * {@link WpsCallback#onFailed(int)} with a generic error.
7776      *
7777      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
7778      * @param listener for callbacks on success or failure. Can be null.
7779      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
7780      * @deprecated This API is deprecated
7781      */
startWps(WpsInfo config, WpsCallback listener)7782     public void startWps(WpsInfo config, WpsCallback listener) {
7783         if (listener != null ) {
7784             listener.onFailed(ActionListener.FAILURE_INTERNAL_ERROR);
7785         }
7786     }
7787 
7788     /**
7789      * WPS support has been deprecated from Client mode and this method will immediately trigger
7790      * {@link WpsCallback#onFailed(int)} with a generic error.
7791      *
7792      * @param listener for callbacks on success or failure. Can be null.
7793      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
7794      * @deprecated This API is deprecated
7795      */
cancelWps(WpsCallback listener)7796     public void cancelWps(WpsCallback listener) {
7797         if (listener != null) {
7798             listener.onFailed(ActionListener.FAILURE_INTERNAL_ERROR);
7799         }
7800     }
7801 
7802     /**
7803      * Allows an application to keep the Wi-Fi radio awake.
7804      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
7805      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
7806      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
7807      * WifiLocks are held in any application.
7808      * <p>
7809      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
7810      * could function over a mobile network, if available.  A program that needs to download large
7811      * files should hold a WifiLock to ensure that the download will complete, but a program whose
7812      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
7813      * affecting battery life.
7814      * <p>
7815      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
7816      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
7817      * is idle.
7818      * <p>
7819      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
7820      * permission in an {@code <uses-permission>} element of the application's manifest.
7821      */
7822     public class WifiLock {
7823         private String mTag;
7824         private final IBinder mBinder;
7825         private int mRefCount;
7826         int mLockType;
7827         private boolean mRefCounted;
7828         private boolean mHeld;
7829         private WorkSource mWorkSource;
7830 
WifiLock(int lockType, String tag)7831         private WifiLock(int lockType, String tag) {
7832             mTag = tag;
7833             mLockType = lockType;
7834             mBinder = new Binder();
7835             mRefCount = 0;
7836             mRefCounted = true;
7837             mHeld = false;
7838         }
7839 
7840         /**
7841          * Locks the Wi-Fi radio on until {@link #release} is called.
7842          *
7843          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
7844          * reference count, and the radio will remain locked as long as the reference count is
7845          * above zero.
7846          *
7847          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
7848          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
7849          * will be required, regardless of the number of times that {@code acquire} is called.
7850          */
acquire()7851         public void acquire() {
7852             synchronized (mBinder) {
7853                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
7854                     try {
7855                         Bundle extras = new Bundle();
7856                         if (SdkLevel.isAtLeastS()) {
7857                             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
7858                                     mContext.getAttributionSource());
7859                         }
7860                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource,
7861                                 mContext.getOpPackageName(), extras);
7862                         synchronized (WifiManager.this) {
7863                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
7864                                 mService.releaseWifiLock(mBinder);
7865                                 throw new UnsupportedOperationException(
7866                                             "Exceeded maximum number of wifi locks");
7867                             }
7868                             mActiveLockCount++;
7869                         }
7870                     } catch (RemoteException e) {
7871                         throw e.rethrowFromSystemServer();
7872                     }
7873                     mHeld = true;
7874                 }
7875             }
7876         }
7877 
7878         /**
7879          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
7880          *
7881          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
7882          * reference count, and the radio will be unlocked only when the reference count reaches
7883          * zero.  If the reference count goes below zero (that is, if {@code release} is called
7884          * a greater number of times than {@link #acquire}), an exception is thrown.
7885          *
7886          * If this WifiLock is not reference-counted, the first call to {@code release} (after
7887          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
7888          * calls will be ignored.
7889          */
release()7890         public void release() {
7891             synchronized (mBinder) {
7892                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
7893                     try {
7894                         mService.releaseWifiLock(mBinder);
7895                         synchronized (WifiManager.this) {
7896                             mActiveLockCount--;
7897                         }
7898                     } catch (RemoteException e) {
7899                         throw e.rethrowFromSystemServer();
7900                     }
7901                     mHeld = false;
7902                 }
7903                 if (mRefCount < 0) {
7904                     throw new RuntimeException("WifiLock under-locked " + mTag);
7905                 }
7906             }
7907         }
7908 
7909         /**
7910          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
7911          *
7912          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
7913          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
7914          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
7915          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
7916          * radio whenever {@link #release} is called and it is locked.
7917          *
7918          * @param refCounted true if this WifiLock should keep a reference count
7919          */
setReferenceCounted(boolean refCounted)7920         public void setReferenceCounted(boolean refCounted) {
7921             mRefCounted = refCounted;
7922         }
7923 
7924         /**
7925          * Checks whether this WifiLock is currently held.
7926          *
7927          * @return true if this WifiLock is held, false otherwise
7928          */
isHeld()7929         public boolean isHeld() {
7930             synchronized (mBinder) {
7931                 return mHeld;
7932             }
7933         }
7934 
setWorkSource(WorkSource ws)7935         public void setWorkSource(WorkSource ws) {
7936             synchronized (mBinder) {
7937                 if (ws != null && ws.isEmpty()) {
7938                     ws = null;
7939                 }
7940                 boolean changed = true;
7941                 if (ws == null) {
7942                     mWorkSource = null;
7943                 } else {
7944                     ws = ws.withoutNames();
7945                     if (mWorkSource == null) {
7946                         changed = mWorkSource != null;
7947                         mWorkSource = new WorkSource(ws);
7948                     } else {
7949                         changed = !mWorkSource.equals(ws);
7950                         if (changed) {
7951                             mWorkSource.set(ws);
7952                         }
7953                     }
7954                 }
7955                 if (changed && mHeld) {
7956                     try {
7957                         Bundle extras = new Bundle();
7958                         if (SdkLevel.isAtLeastS()) {
7959                             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
7960                                     mContext.getAttributionSource());
7961                         }
7962                         mService.updateWifiLockWorkSource(mBinder, mWorkSource,
7963                                 mContext.getOpPackageName(), extras);
7964                     } catch (RemoteException e) {
7965                         throw e.rethrowFromSystemServer();
7966                     }
7967                 }
7968             }
7969         }
7970 
toString()7971         public String toString() {
7972             String s1, s2, s3;
7973             synchronized (mBinder) {
7974                 s1 = Integer.toHexString(System.identityHashCode(this));
7975                 s2 = mHeld ? "held; " : "";
7976                 if (mRefCounted) {
7977                     s3 = "refcounted: refcount = " + mRefCount;
7978                 } else {
7979                     s3 = "not refcounted";
7980                 }
7981                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
7982             }
7983         }
7984 
7985         @Override
finalize()7986         protected void finalize() throws Throwable {
7987             super.finalize();
7988             synchronized (mBinder) {
7989                 if (mHeld) {
7990                     try {
7991                         mService.releaseWifiLock(mBinder);
7992                         synchronized (WifiManager.this) {
7993                             mActiveLockCount--;
7994                         }
7995                     } catch (RemoteException e) {
7996                         throw e.rethrowFromSystemServer();
7997                     }
7998                 }
7999             }
8000         }
8001     }
8002 
8003     /**
8004      * Creates a new WifiLock.
8005      *
8006      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL_HIGH_PERF}
8007      * and {@link #WIFI_MODE_FULL_LOW_LATENCY} for descriptions of the types of Wi-Fi locks.
8008      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
8009      *            never shown to the user under normal conditions, but should be descriptive
8010      *            enough to identify your application and the specific WifiLock within it, if it
8011      *            holds multiple WifiLocks.
8012      *
8013      * @return a new, unacquired WifiLock with the given tag.
8014      *
8015      * @see WifiLock
8016      */
createWifiLock(int lockType, String tag)8017     public WifiLock createWifiLock(int lockType, String tag) {
8018         return new WifiLock(lockType, tag);
8019     }
8020 
8021     /**
8022      * Interface for low latency lock listener. Should be extended by application and set when
8023      * calling {@link WifiManager#addWifiLowLatencyLockListener(Executor,
8024      * WifiLowLatencyLockListener)}.
8025      *
8026      * @hide
8027      */
8028     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
8029     @SystemApi
8030     public interface WifiLowLatencyLockListener {
8031         /**
8032          * Provides low latency mode is activated or not. Triggered when Wi-Fi chip enters into low
8033          * latency mode.
8034          *
8035          * <p>Note: Always called with current state when a new listener gets registered.
8036          */
8037         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onActivatedStateChanged(boolean activated)8038         void onActivatedStateChanged(boolean activated);
8039 
8040         /**
8041          * Provides UIDs (lock owners) of the applications which currently acquired low latency
8042          * lock. Triggered when an application acquires or releases a lock.
8043          *
8044          * <p>Note: Always called with UIDs of the current acquired locks when a new listener gets
8045          * registered.
8046          *
8047          * @param ownerUids An array of UIDs.
8048          */
8049         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onOwnershipChanged(@onNull int[] ownerUids)8050         default void onOwnershipChanged(@NonNull int[] ownerUids) {}
8051 
8052         /**
8053          * Provides UIDs of the applications which acquired the low latency lock and is currently
8054          * active. See {@link WifiManager#WIFI_MODE_FULL_LOW_LATENCY} for the conditions to be met
8055          * for low latency lock to be active. Triggered when application acquiring the lock
8056          * satisfies or does not satisfy low latency conditions when the low latency mode is
8057          * activated. Also gets triggered when the lock becomes active, immediately after the {@link
8058          * WifiLowLatencyLockListener#onActivatedStateChanged(boolean)} callback is triggered.
8059          *
8060          * <p>Note: Always called with UIDs of the current active locks when a new listener gets
8061          * registered if the Wi-Fi chip is in low latency mode.
8062          *
8063          * @param activeUids An array of UIDs.
8064          */
8065         @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
onActiveUsersChanged(@onNull int[] activeUids)8066         default void onActiveUsersChanged(@NonNull int[] activeUids) {}
8067     }
8068 
8069     /**
8070      * Helper class to support wifi low latency lock listener.
8071      */
8072     private static class OnWifiLowLatencyLockProxy extends IWifiLowLatencyLockListener.Stub {
8073         @NonNull
8074         private Executor mExecutor;
8075         @NonNull
8076         private WifiLowLatencyLockListener mListener;
8077 
OnWifiLowLatencyLockProxy(@onNull Executor executor, @NonNull WifiLowLatencyLockListener listener)8078         OnWifiLowLatencyLockProxy(@NonNull Executor executor,
8079                 @NonNull WifiLowLatencyLockListener listener) {
8080             Objects.requireNonNull(executor);
8081             Objects.requireNonNull(listener);
8082             mExecutor = executor;
8083             mListener = listener;
8084         }
8085 
8086         @Override
onActivatedStateChanged(boolean activated)8087         public void onActivatedStateChanged(boolean activated) {
8088             Binder.clearCallingIdentity();
8089             mExecutor.execute(() -> mListener.onActivatedStateChanged(activated));
8090 
8091         }
8092 
8093         @Override
onOwnershipChanged(@onNull int[] ownerUids)8094         public void onOwnershipChanged(@NonNull int[] ownerUids) {
8095             Binder.clearCallingIdentity();
8096             mExecutor.execute(() -> mListener.onOwnershipChanged(ownerUids));
8097 
8098         }
8099 
8100         @Override
onActiveUsersChanged(@onNull int[] activeUids)8101         public void onActiveUsersChanged(@NonNull int[] activeUids) {
8102             Binder.clearCallingIdentity();
8103             mExecutor.execute(() -> mListener.onActiveUsersChanged(activeUids));
8104         }
8105     }
8106 
8107     /**
8108      * Add a listener for monitoring the low latency lock. The caller can unregister a previously
8109      * registered listener using {@link WifiManager#removeWifiLowLatencyLockListener(
8110      * WifiLowLatencyLockListener)}.
8111      *
8112      * <p>Applications should have the {@link android.Manifest.permission#NETWORK_SETTINGS} and
8113      * {@link android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission. Callers without
8114      * the permission will trigger a {@link java.lang.SecurityException}.
8115      *
8116      * @param executor The Executor on which to execute the callbacks.
8117      * @param listener The listener for the latency mode change.
8118      * @throws IllegalArgumentException if incorrect input arguments are provided.
8119      * @throws SecurityException if the caller is not allowed to call this API
8120      * @hide
8121      */
8122     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
8123     @SystemApi
8124     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
8125     @RequiresPermission(
8126             anyOf = {android.Manifest.permission.NETWORK_SETTINGS, MANAGE_WIFI_NETWORK_SELECTION})
addWifiLowLatencyLockListener( @onNull @allbackExecutor Executor executor, @NonNull WifiLowLatencyLockListener listener)8127     public void addWifiLowLatencyLockListener(
8128             @NonNull @CallbackExecutor Executor executor,
8129             @NonNull WifiLowLatencyLockListener listener) {
8130         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
8131         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
8132         if (mVerboseLoggingEnabled) {
8133             Log.d(TAG, "addWifiLowLatencyLockListener: listener=" + listener + ", executor="
8134                     + executor);
8135         }
8136         final int listenerIdentifier = System.identityHashCode(listener);
8137         try {
8138             synchronized (sWifiLowLatencyLockListenerMap) {
8139                 IWifiLowLatencyLockListener.Stub listenerProxy = new OnWifiLowLatencyLockProxy(
8140                         executor,
8141                         listener);
8142                 sWifiLowLatencyLockListenerMap.put(listenerIdentifier, listenerProxy);
8143                 mService.addWifiLowLatencyLockListener(listenerProxy);
8144             }
8145         } catch (RemoteException e) {
8146             sWifiLowLatencyLockListenerMap.remove(listenerIdentifier);
8147             throw e.rethrowFromSystemServer();
8148         }
8149     }
8150 
8151     /**
8152      * Removes a listener added using {@link WifiManager#addWifiLowLatencyLockListener(Executor,
8153      * WifiLowLatencyLockListener)}. After calling this method, applications will no longer receive
8154      * low latency mode notifications.
8155      *
8156      * @param listener the listener to be removed.
8157      * @throws IllegalArgumentException if incorrect input arguments are provided.
8158      * @hide
8159      */
8160     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
8161     @SystemApi
8162     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
removeWifiLowLatencyLockListener(@onNull WifiLowLatencyLockListener listener)8163     public void removeWifiLowLatencyLockListener(@NonNull WifiLowLatencyLockListener listener) {
8164         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
8165         if (mVerboseLoggingEnabled) {
8166             Log.d(TAG, "removeWifiLowLatencyLockListener: listener=" + listener);
8167         }
8168         final int listenerIdentifier = System.identityHashCode(listener);
8169         synchronized (sWifiLowLatencyLockListenerMap) {
8170             try {
8171                 if (!sWifiLowLatencyLockListenerMap.contains(listenerIdentifier)) {
8172                     Log.w(TAG, "Unknown external listener " + listenerIdentifier);
8173                     return;
8174                 }
8175                 mService.removeWifiLowLatencyLockListener(
8176                         sWifiLowLatencyLockListenerMap.get(listenerIdentifier));
8177 
8178             } catch (RemoteException e) {
8179                 throw e.rethrowFromSystemServer();
8180             } finally {
8181                 sWifiLowLatencyLockListenerMap.remove(listenerIdentifier);
8182             }
8183         }
8184     }
8185 
8186     /**
8187      * Creates a new WifiLock.
8188      *
8189      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
8190      *            never shown to the user under normal conditions, but should be descriptive
8191      *            enough to identify your application and the specific WifiLock within it, if it
8192      *            holds multiple WifiLocks.
8193      *
8194      * @return a new, unacquired WifiLock with the given tag.
8195      *
8196      * @see WifiLock
8197      *
8198      * @deprecated This API is non-functional.
8199      */
8200     @Deprecated
createWifiLock(String tag)8201     public WifiLock createWifiLock(String tag) {
8202         return new WifiLock(WIFI_MODE_FULL, tag);
8203     }
8204 
8205     /**
8206      * Create a new MulticastLock
8207      *
8208      * @param tag a tag for the MulticastLock to identify it in debugging
8209      *            messages.  This string is never shown to the user under
8210      *            normal conditions, but should be descriptive enough to
8211      *            identify your application and the specific MulticastLock
8212      *            within it, if it holds multiple MulticastLocks.
8213      *
8214      * @return a new, unacquired MulticastLock with the given tag.
8215      *
8216      * @see MulticastLock
8217      */
createMulticastLock(String tag)8218     public MulticastLock createMulticastLock(String tag) {
8219         return new MulticastLock(tag);
8220     }
8221 
8222     /**
8223      * Allows an application to receive Wifi Multicast packets.
8224      * Normally the Wifi stack filters out packets not explicitly
8225      * addressed to this device.  Acquring a MulticastLock will
8226      * cause the stack to receive packets addressed to multicast
8227      * addresses.  Processing these extra packets can cause a noticeable
8228      * battery drain and should be disabled when not needed.
8229      */
8230     public class MulticastLock {
8231         private String mTag;
8232         private final IBinder mBinder;
8233         private int mRefCount;
8234         private boolean mRefCounted;
8235         private boolean mHeld;
8236 
MulticastLock(String tag)8237         private MulticastLock(String tag) {
8238             mTag = tag;
8239             mBinder = new Binder();
8240             mRefCount = 0;
8241             mRefCounted = true;
8242             mHeld = false;
8243         }
8244 
8245         /**
8246          * Locks Wifi Multicast on until {@link #release} is called.
8247          *
8248          * If this MulticastLock is reference-counted each call to
8249          * {@code acquire} will increment the reference count, and the
8250          * wifi interface will receive multicast packets as long as the
8251          * reference count is above zero.
8252          *
8253          * If this MulticastLock is not reference-counted, the first call to
8254          * {@code acquire} will turn on the multicast packets, but subsequent
8255          * calls will be ignored.  Only one call to {@link #release} will
8256          * be required, regardless of the number of times that {@code acquire}
8257          * is called.
8258          *
8259          * Note that other applications may also lock Wifi Multicast on.
8260          * Only they can relinquish their lock.
8261          *
8262          * Also note that applications cannot leave Multicast locked on.
8263          * When an app exits or crashes, any Multicast locks will be released.
8264          */
acquire()8265         public void acquire() {
8266             synchronized (mBinder) {
8267                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
8268                     try {
8269                         mService.acquireMulticastLock(mBinder, mTag);
8270                         synchronized (WifiManager.this) {
8271                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
8272                                 mService.releaseMulticastLock(mTag);
8273                                 throw new UnsupportedOperationException(
8274                                         "Exceeded maximum number of wifi locks");
8275                             }
8276                             mActiveLockCount++;
8277                         }
8278                     } catch (RemoteException e) {
8279                         throw e.rethrowFromSystemServer();
8280                     }
8281                     mHeld = true;
8282                 }
8283             }
8284         }
8285 
8286         /**
8287          * Unlocks Wifi Multicast, restoring the filter of packets
8288          * not addressed specifically to this device and saving power.
8289          *
8290          * If this MulticastLock is reference-counted, each call to
8291          * {@code release} will decrement the reference count, and the
8292          * multicast packets will only stop being received when the reference
8293          * count reaches zero.  If the reference count goes below zero (that
8294          * is, if {@code release} is called a greater number of times than
8295          * {@link #acquire}), an exception is thrown.
8296          *
8297          * If this MulticastLock is not reference-counted, the first call to
8298          * {@code release} (after the radio was multicast locked using
8299          * {@link #acquire}) will unlock the multicast, and subsequent calls
8300          * will be ignored.
8301          *
8302          * Note that if any other Wifi Multicast Locks are still outstanding
8303          * this {@code release} call will not have an immediate effect.  Only
8304          * when all applications have released all their Multicast Locks will
8305          * the Multicast filter be turned back on.
8306          *
8307          * Also note that when an app exits or crashes all of its Multicast
8308          * Locks will be automatically released.
8309          */
release()8310         public void release() {
8311             synchronized (mBinder) {
8312                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
8313                     try {
8314                         mService.releaseMulticastLock(mTag);
8315                         synchronized (WifiManager.this) {
8316                             mActiveLockCount--;
8317                         }
8318                     } catch (RemoteException e) {
8319                         throw e.rethrowFromSystemServer();
8320                     }
8321                     mHeld = false;
8322                 }
8323                 if (mRefCount < 0) {
8324                     throw new RuntimeException("MulticastLock under-locked "
8325                             + mTag);
8326                 }
8327             }
8328         }
8329 
8330         /**
8331          * Controls whether this is a reference-counted or non-reference-
8332          * counted MulticastLock.
8333          *
8334          * Reference-counted MulticastLocks keep track of the number of calls
8335          * to {@link #acquire} and {@link #release}, and only stop the
8336          * reception of multicast packets when every call to {@link #acquire}
8337          * has been balanced with a call to {@link #release}.  Non-reference-
8338          * counted MulticastLocks allow the reception of multicast packets
8339          * whenever {@link #acquire} is called and stop accepting multicast
8340          * packets whenever {@link #release} is called.
8341          *
8342          * @param refCounted true if this MulticastLock should keep a reference
8343          * count
8344          */
setReferenceCounted(boolean refCounted)8345         public void setReferenceCounted(boolean refCounted) {
8346             mRefCounted = refCounted;
8347         }
8348 
8349         /**
8350          * Checks whether this MulticastLock is currently held.
8351          *
8352          * @return true if this MulticastLock is held, false otherwise
8353          */
isHeld()8354         public boolean isHeld() {
8355             synchronized (mBinder) {
8356                 return mHeld;
8357             }
8358         }
8359 
toString()8360         public String toString() {
8361             String s1, s2, s3;
8362             synchronized (mBinder) {
8363                 s1 = Integer.toHexString(System.identityHashCode(this));
8364                 s2 = mHeld ? "held; " : "";
8365                 if (mRefCounted) {
8366                     s3 = "refcounted: refcount = " + mRefCount;
8367                 } else {
8368                     s3 = "not refcounted";
8369                 }
8370                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
8371             }
8372         }
8373 
8374         @Override
finalize()8375         protected void finalize() throws Throwable {
8376             super.finalize();
8377             setReferenceCounted(false);
8378             release();
8379         }
8380     }
8381 
8382     /**
8383      * Check multicast filter status.
8384      *
8385      * @return true if multicast packets are allowed.
8386      *
8387      * @hide pending API council approval
8388      */
isMulticastEnabled()8389     public boolean isMulticastEnabled() {
8390         try {
8391             return mService.isMulticastEnabled();
8392         } catch (RemoteException e) {
8393             throw e.rethrowFromSystemServer();
8394         }
8395     }
8396 
8397     /**
8398      * Initialize the multicast filtering to 'on'
8399      * @hide no intent to publish
8400      */
8401     @UnsupportedAppUsage
initializeMulticastFiltering()8402     public boolean initializeMulticastFiltering() {
8403         try {
8404             mService.initializeMulticastFiltering();
8405             return true;
8406         } catch (RemoteException e) {
8407             throw e.rethrowFromSystemServer();
8408         }
8409     }
8410 
8411     /**
8412      * Set Wi-Fi verbose logging level from developer settings.
8413      *
8414      * @param enable true to enable verbose logging, false to disable.
8415      *
8416      * @hide
8417      */
8418     @SystemApi
8419     @RequiresPermission(anyOf = {
8420             android.Manifest.permission.NETWORK_SETTINGS,
8421             android.Manifest.permission.DUMP
8422     })
setVerboseLoggingEnabled(boolean enable)8423     public void setVerboseLoggingEnabled(boolean enable) {
8424         enableVerboseLogging(enable ? VERBOSE_LOGGING_LEVEL_ENABLED
8425                 : VERBOSE_LOGGING_LEVEL_DISABLED);
8426     }
8427 
8428     /**
8429      * Set Wi-Fi verbose logging level from developer settings.
8430      *
8431      * @param verbose the verbose logging mode which could be
8432      * {@link #VERBOSE_LOGGING_LEVEL_DISABLED}, {@link #VERBOSE_LOGGING_LEVEL_ENABLED}, or
8433      * {@link #VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY}.
8434      *
8435      * @hide
8436      */
8437     @SystemApi
8438     @RequiresPermission(anyOf = {
8439             android.Manifest.permission.NETWORK_SETTINGS,
8440             android.Manifest.permission.DUMP
8441     })
setVerboseLoggingLevel(@erboseLoggingLevel int verbose)8442     public void setVerboseLoggingLevel(@VerboseLoggingLevel int verbose) {
8443         enableVerboseLogging(verbose);
8444     }
8445 
8446     /** @hide */
8447     @UnsupportedAppUsage(
8448             maxTargetSdk = Build.VERSION_CODES.Q,
8449             publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead."
8450     )
8451     @RequiresPermission(anyOf = {
8452             android.Manifest.permission.NETWORK_SETTINGS,
8453             android.Manifest.permission.DUMP
8454     })
enableVerboseLogging(@erboseLoggingLevel int verbose)8455     public void enableVerboseLogging(@VerboseLoggingLevel int verbose) {
8456         try {
8457             mService.enableVerboseLogging(verbose);
8458             mVerboseLoggingEnabled =
8459                     verbose == VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY
8460                             || verbose == VERBOSE_LOGGING_LEVEL_ENABLED;
8461         } catch (RemoteException e) {
8462             throw e.rethrowFromSystemServer();
8463         }
8464     }
8465 
8466     /**
8467      * Get the persisted Wi-Fi verbose logging level, set by
8468      * {@link #setVerboseLoggingEnabled(boolean)} or {@link #setVerboseLoggingLevel(int)}.
8469      * No permissions are required to call this method.
8470      *
8471      * @return true to indicate that verbose logging is enabled, false to indicate that verbose
8472      * logging is disabled.
8473      *
8474      * @hide
8475      */
8476     @SystemApi
isVerboseLoggingEnabled()8477     public boolean isVerboseLoggingEnabled() {
8478         int verboseLoggingLevel = getVerboseLoggingLevel();
8479         return verboseLoggingLevel == VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY
8480                 || verboseLoggingLevel == VERBOSE_LOGGING_LEVEL_ENABLED;
8481     }
8482 
8483     /**
8484      * Get the persisted Wi-Fi verbose logging level, set by
8485      * {@link #setVerboseLoggingEnabled(boolean)} or {@link #setVerboseLoggingLevel(int)}.
8486      * No permissions are required to call this method.
8487      *
8488      * @return one of {@link #VERBOSE_LOGGING_LEVEL_DISABLED},
8489      *         {@link #VERBOSE_LOGGING_LEVEL_ENABLED},
8490      *         or {@link #VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY}.
8491      *
8492      * @hide
8493      */
8494     @SystemApi
getVerboseLoggingLevel()8495     public @VerboseLoggingLevel int getVerboseLoggingLevel() {
8496         try {
8497             return mService.getVerboseLoggingLevel();
8498         } catch (RemoteException e) {
8499             throw e.rethrowFromSystemServer();
8500         }
8501     }
8502 
8503     /**
8504      * Removes all saved Wi-Fi networks, Passpoint configurations, ephemeral networks, Network
8505      * Requests, and Network Suggestions.
8506      *
8507      * @hide
8508      */
8509     @SystemApi
8510     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
factoryReset()8511     public void factoryReset() {
8512         try {
8513             mService.factoryReset(mContext.getOpPackageName());
8514         } catch (RemoteException e) {
8515             throw e.rethrowFromSystemServer();
8516         }
8517     }
8518 
8519     /**
8520      * Get {@link Network} object of current wifi network, or null if not connected.
8521      * @hide
8522      */
8523     @Nullable
8524     @SystemApi
8525     @RequiresPermission(anyOf = {
8526             android.Manifest.permission.NETWORK_SETTINGS,
8527             android.Manifest.permission.NETWORK_SETUP_WIZARD
8528     })
getCurrentNetwork()8529     public Network getCurrentNetwork() {
8530         try {
8531             return mService.getCurrentNetwork();
8532         } catch (RemoteException e) {
8533             throw e.rethrowFromSystemServer();
8534         }
8535     }
8536 
8537     /**
8538      * Deprecated
8539      * returns false
8540      * @hide
8541      * @deprecated
8542      */
setEnableAutoJoinWhenAssociated(boolean enabled)8543     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
8544         return false;
8545     }
8546 
8547     /**
8548      * Deprecated
8549      * returns false
8550      * @hide
8551      * @deprecated
8552      */
getEnableAutoJoinWhenAssociated()8553     public boolean getEnableAutoJoinWhenAssociated() {
8554         return false;
8555     }
8556 
8557     /**
8558      * Returns a byte stream representing the data that needs to be backed up to save the
8559      * current Wifi state.
8560      * This Wifi state can be restored by calling {@link #restoreWifiBackupData(byte[])}.
8561      * @hide
8562      */
8563     @SystemApi
8564     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
8565     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
8566     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
retrieveWifiBackupData(@onNull @allbackExecutor Executor executor, @NonNull Consumer<byte[]> resultsCallback)8567     public void retrieveWifiBackupData(@NonNull @CallbackExecutor Executor executor,
8568             @NonNull Consumer<byte[]> resultsCallback) {
8569         if (!SdkLevel.isAtLeastV()) {
8570             throw new UnsupportedOperationException();
8571         }
8572 
8573         Objects.requireNonNull(executor, "executor cannot be null");
8574         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
8575         try {
8576             mService.retrieveWifiBackupData(
8577                     new IByteArrayListener.Stub() {
8578                         @Override
8579                         public void onResult(byte[] value) {
8580                             Binder.clearCallingIdentity();
8581                             executor.execute(() -> {
8582                                 resultsCallback.accept(value);
8583                             });
8584                         }
8585                     });
8586         } catch (RemoteException e) {
8587             throw e.rethrowFromSystemServer();
8588         }
8589     }
8590 
8591     /**
8592      * Restore state from the backed up data.
8593      * @param data byte stream in the same format produced by {@link #retrieveWifiBackupData()}
8594      * @hide
8595      */
8596     @SystemApi
8597     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
8598     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
8599     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
restoreWifiBackupData(@onNull byte[] data)8600     public void restoreWifiBackupData(@NonNull byte[] data) {
8601         if (!SdkLevel.isAtLeastV()) {
8602             throw new UnsupportedOperationException();
8603         }
8604         try {
8605             mService.restoreWifiBackupData(data);
8606         } catch (RemoteException e) {
8607             throw e.rethrowFromSystemServer();
8608         }
8609     }
8610 
8611     /**
8612      * Returns a byte stream representing the data that needs to be backed up to save the
8613      * current Wifi state.
8614      * This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}.
8615      * @hide
8616      */
8617     @NonNull
8618     @SystemApi
8619     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveBackupData()8620     public byte[] retrieveBackupData() {
8621         try {
8622             return mService.retrieveBackupData();
8623         } catch (RemoteException e) {
8624             throw e.rethrowFromSystemServer();
8625         }
8626     }
8627 
8628     /**
8629      * Restore state from the backed up data.
8630      * @param data byte stream in the same format produced by {@link #retrieveBackupData()}
8631      * @hide
8632      */
8633     @SystemApi
8634     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreBackupData(@onNull byte[] data)8635     public void restoreBackupData(@NonNull byte[] data) {
8636         try {
8637             mService.restoreBackupData(data);
8638         } catch (RemoteException e) {
8639             throw e.rethrowFromSystemServer();
8640         }
8641     }
8642 
8643     /**
8644      * Returns a byte stream representing the data that needs to be backed up to save the
8645      * current soft ap config data.
8646      *
8647      * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
8648      * @hide
8649      */
8650     @NonNull
8651     @SystemApi
8652     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveSoftApBackupData()8653     public byte[] retrieveSoftApBackupData() {
8654         try {
8655             return mService.retrieveSoftApBackupData();
8656         } catch (RemoteException e) {
8657             throw e.rethrowFromSystemServer();
8658         }
8659     }
8660 
8661     /**
8662      * Returns soft ap config from the backed up data or null if data is invalid.
8663      * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
8664      *
8665      * @hide
8666      */
8667     @Nullable
8668     @SystemApi
8669     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSoftApBackupData(@onNull byte[] data)8670     public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
8671         try {
8672             return mService.restoreSoftApBackupData(data);
8673         } catch (RemoteException e) {
8674             throw e.rethrowFromSystemServer();
8675         }
8676     }
8677 
8678     /**
8679      * Restore state from the older version of back up data.
8680      * The old backup data was essentially a backup of wpa_supplicant.conf
8681      * and ipconfig.txt file.
8682      * @param supplicantData bytes representing wpa_supplicant.conf
8683      * @param ipConfigData bytes representing ipconfig.txt
8684      * @hide
8685      */
8686     @SystemApi
8687     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSupplicantBackupData( @onNull byte[] supplicantData, @NonNull byte[] ipConfigData)8688     public void restoreSupplicantBackupData(
8689             @NonNull byte[] supplicantData, @NonNull byte[] ipConfigData) {
8690         try {
8691             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
8692         } catch (RemoteException e) {
8693             throw e.rethrowFromSystemServer();
8694         }
8695     }
8696 
8697     /**
8698      * Start subscription provisioning flow
8699      *
8700      * @param provider {@link OsuProvider} to provision with
8701      * @param executor the Executor on which to run the callback.
8702      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
8703      * @hide
8704      */
8705     @SystemApi
8706     @RequiresPermission(anyOf = {
8707             android.Manifest.permission.NETWORK_SETTINGS,
8708             android.Manifest.permission.NETWORK_SETUP_WIZARD
8709     })
startSubscriptionProvisioning(@onNull OsuProvider provider, @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback)8710     public void startSubscriptionProvisioning(@NonNull OsuProvider provider,
8711             @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback) {
8712         // Verify arguments
8713         if (executor == null) {
8714             throw new IllegalArgumentException("executor must not be null");
8715         }
8716         if (callback == null) {
8717             throw new IllegalArgumentException("callback must not be null");
8718         }
8719         try {
8720             mService.startSubscriptionProvisioning(provider,
8721                     new ProvisioningCallbackProxy(executor, callback));
8722         } catch (RemoteException e) {
8723             throw e.rethrowFromSystemServer();
8724         }
8725     }
8726 
8727     /**
8728      * Helper class to support OSU Provisioning callbacks
8729      */
8730     private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
8731         private final Executor mExecutor;
8732         private final ProvisioningCallback mCallback;
8733 
ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback)8734         ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback) {
8735             mExecutor = executor;
8736             mCallback = callback;
8737         }
8738 
8739         @Override
onProvisioningStatus(int status)8740         public void onProvisioningStatus(int status) {
8741             mExecutor.execute(() -> mCallback.onProvisioningStatus(status));
8742         }
8743 
8744         @Override
onProvisioningFailure(int status)8745         public void onProvisioningFailure(int status) {
8746             mExecutor.execute(() -> mCallback.onProvisioningFailure(status));
8747         }
8748 
8749         @Override
onProvisioningComplete()8750         public void onProvisioningComplete() {
8751             mExecutor.execute(() -> mCallback.onProvisioningComplete());
8752         }
8753     }
8754 
8755     /**
8756      * Interface for Traffic state callback. Should be extended by applications and set when
8757      * calling {@link #registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}.
8758      * @hide
8759      */
8760     @SystemApi
8761     public interface TrafficStateCallback {
8762         /** @hide */
8763         @Retention(RetentionPolicy.SOURCE)
8764         @IntDef(prefix = {"DATA_ACTIVITY_"}, value = {
8765                 DATA_ACTIVITY_NONE,
8766                 DATA_ACTIVITY_IN,
8767                 DATA_ACTIVITY_OUT,
8768                 DATA_ACTIVITY_INOUT})
8769         @interface DataActivity {}
8770 
8771         // Lowest bit indicates data reception and the second lowest bit indicates data transmitted
8772         /** No data in or out */
8773         int DATA_ACTIVITY_NONE         = 0x00;
8774         /** Data in, no data out */
8775         int DATA_ACTIVITY_IN           = 0x01;
8776         /** Data out, no data in */
8777         int DATA_ACTIVITY_OUT          = 0x02;
8778         /** Data in and out */
8779         int DATA_ACTIVITY_INOUT        = 0x03;
8780 
8781         /**
8782          * Callback invoked to inform clients about the current traffic state.
8783          *
8784          * @param state One of the values: {@link #DATA_ACTIVITY_NONE}, {@link #DATA_ACTIVITY_IN},
8785          * {@link #DATA_ACTIVITY_OUT} & {@link #DATA_ACTIVITY_INOUT}.
8786          */
onStateChanged(@ataActivity int state)8787         void onStateChanged(@DataActivity int state);
8788     }
8789 
8790     /**
8791      * Callback proxy for TrafficStateCallback objects.
8792      *
8793      * @hide
8794      */
8795     private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub {
8796         private final Executor mExecutor;
8797         private final TrafficStateCallback mCallback;
8798 
TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback)8799         TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback) {
8800             mExecutor = executor;
8801             mCallback = callback;
8802         }
8803 
8804         @Override
onStateChanged(int state)8805         public void onStateChanged(int state) {
8806             if (mVerboseLoggingEnabled) {
8807                 Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state);
8808             }
8809             Binder.clearCallingIdentity();
8810             mExecutor.execute(() -> {
8811                 mCallback.onStateChanged(state);
8812             });
8813         }
8814     }
8815 
8816     /**
8817      * Registers a callback for monitoring traffic state. See {@link TrafficStateCallback}. These
8818      * callbacks will be invoked periodically by platform to inform clients about the current
8819      * traffic state. Caller can unregister a previously registered callback using
8820      * {@link #unregisterTrafficStateCallback(TrafficStateCallback)}
8821      * <p>
8822      * Applications should have the
8823      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
8824      * without the permission will trigger a {@link java.lang.SecurityException}.
8825      * <p>
8826      *
8827      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
8828      *                 object.
8829      * @param callback Callback for traffic state events
8830      * @hide
8831      */
8832     @SystemApi
8833     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerTrafficStateCallback(@onNull @allbackExecutor Executor executor, @NonNull TrafficStateCallback callback)8834     public void registerTrafficStateCallback(@NonNull @CallbackExecutor Executor executor,
8835                                              @NonNull TrafficStateCallback callback) {
8836         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
8837         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
8838         Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", executor=" + executor);
8839 
8840         try {
8841             synchronized (sTrafficStateCallbackMap) {
8842                 ITrafficStateCallback.Stub binderCallback = new TrafficStateCallbackProxy(executor,
8843                         callback);
8844                 sTrafficStateCallbackMap.put(System.identityHashCode(callback), binderCallback);
8845                 mService.registerTrafficStateCallback(binderCallback);
8846             }
8847         } catch (RemoteException e) {
8848             throw e.rethrowFromSystemServer();
8849         }
8850     }
8851 
8852     /**
8853      * Allow callers to unregister a previously registered callback. After calling this method,
8854      * applications will no longer receive traffic state notifications.
8855      *
8856      * @param callback Callback to unregister for traffic state events
8857      * @hide
8858      */
8859     @SystemApi
8860     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterTrafficStateCallback(@onNull TrafficStateCallback callback)8861     public void unregisterTrafficStateCallback(@NonNull TrafficStateCallback callback) {
8862         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
8863         Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
8864 
8865         try {
8866             synchronized (sTrafficStateCallbackMap) {
8867                 int callbackIdentifier = System.identityHashCode(callback);
8868                 if (!sTrafficStateCallbackMap.contains(callbackIdentifier)) {
8869                     Log.w(TAG, "Unknown external callback " + callbackIdentifier);
8870                     return;
8871                 }
8872                 mService.unregisterTrafficStateCallback(
8873                         sTrafficStateCallbackMap.get(callbackIdentifier));
8874                 sTrafficStateCallbackMap.remove(callbackIdentifier);
8875             }
8876         } catch (RemoteException e) {
8877             throw e.rethrowFromSystemServer();
8878         }
8879     }
8880 
8881     /**
8882      * Helper method to update the local verbose logging flag based on the verbose logging
8883      * level from wifi service.
8884      */
updateVerboseLoggingEnabledFromService()8885     private void updateVerboseLoggingEnabledFromService() {
8886         mVerboseLoggingEnabled = isVerboseLoggingEnabled();
8887     }
8888 
8889     /**
8890      * @return true if this device supports WPA3-Personal SAE
8891      */
isWpa3SaeSupported()8892     public boolean isWpa3SaeSupported() {
8893         return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
8894     }
8895 
8896     /**
8897      * @return true if this device supports WPA3-Enterprise Suite-B-192
8898      */
isWpa3SuiteBSupported()8899     public boolean isWpa3SuiteBSupported() {
8900         return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
8901     }
8902 
8903     /**
8904      * @return true if this device supports Wi-Fi Enhanced Open (OWE)
8905      */
isEnhancedOpenSupported()8906     public boolean isEnhancedOpenSupported() {
8907         return isFeatureSupported(WIFI_FEATURE_OWE);
8908     }
8909 
8910     /**
8911      * Wi-Fi Easy Connect (DPP) introduces standardized mechanisms to simplify the provisioning and
8912      * configuration of Wi-Fi devices.
8913      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
8914      * search for "Easy Connect" or "Device Provisioning Protocol specification".
8915      *
8916      * @return true if this device supports Wi-Fi Easy-connect (Device Provisioning Protocol)
8917      */
isEasyConnectSupported()8918     public boolean isEasyConnectSupported() {
8919         return isFeatureSupported(WIFI_FEATURE_DPP);
8920     }
8921 
8922     /**
8923      * @return true if this device supports Wi-Fi Easy Connect (DPP) Enrollee Responder mode.
8924      */
isEasyConnectEnrolleeResponderModeSupported()8925     public boolean isEasyConnectEnrolleeResponderModeSupported() {
8926         return isFeatureSupported(WIFI_FEATURE_DPP_ENROLLEE_RESPONDER);
8927     }
8928 
8929     /**
8930      * @return true if this device supports WAPI.
8931      */
isWapiSupported()8932     public boolean isWapiSupported() {
8933         return isFeatureSupported(WIFI_FEATURE_WAPI);
8934     }
8935 
8936     /**
8937      * @return true if this device supports WPA3 SAE Public Key.
8938      */
isWpa3SaePublicKeySupported()8939     public boolean isWpa3SaePublicKeySupported() {
8940         // This feature is not fully implemented in the framework yet.
8941         // After the feature complete, it returns whether WIFI_FEATURE_SAE_PK
8942         // is supported or not directly.
8943         return false;
8944     }
8945 
8946     /**
8947      * @return true if this device supports Wi-Fi Passpoint Terms and Conditions feature.
8948      */
isPasspointTermsAndConditionsSupported()8949     public boolean isPasspointTermsAndConditionsSupported() {
8950         return isFeatureSupported(WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS);
8951     }
8952 
8953     /**
8954      * @return true if this device supports WPA3 SAE Hash-to-Element.
8955      */
isWpa3SaeH2eSupported()8956     public boolean isWpa3SaeH2eSupported() {
8957         return isFeatureSupported(WIFI_FEATURE_SAE_H2E);
8958     }
8959 
8960     /**
8961      * @return true if this device supports Wi-Fi Display R2.
8962      */
isWifiDisplayR2Supported()8963     public boolean isWifiDisplayR2Supported() {
8964         return isFeatureSupported(WIFI_FEATURE_WFD_R2);
8965     }
8966 
8967     /**
8968      * @return true if this device supports RFC 7542 decorated identity.
8969      */
isDecoratedIdentitySupported()8970     public boolean isDecoratedIdentitySupported() {
8971         return isFeatureSupported(WIFI_FEATURE_DECORATED_IDENTITY);
8972     }
8973 
8974     /**
8975      * @return true if this device supports Trust On First Use (TOFU).
8976      */
isTrustOnFirstUseSupported()8977     public boolean isTrustOnFirstUseSupported() {
8978         return isFeatureSupported(WIFI_FEATURE_TRUST_ON_FIRST_USE);
8979     }
8980 
8981     /**
8982      * Wi-Fi Easy Connect DPP AKM enables provisioning and configuration of Wi-Fi devices without
8983      * the need of using the device PSK passphrase.
8984      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
8985      * search for "Easy Connect" or "Device Provisioning Protocol specification".
8986      *
8987      * @return true if this device supports Wi-Fi Easy-connect DPP (Device Provisioning Protocol)
8988      * AKM, false otherwise.
8989      */
isEasyConnectDppAkmSupported()8990     public boolean isEasyConnectDppAkmSupported() {
8991         return isFeatureSupported(WIFI_FEATURE_DPP_AKM);
8992     }
8993 
8994     /**
8995      * Indicate that whether or not settings required TLS minimum version is supported.
8996      *
8997      * If the device doesn't support this capability, the minimum accepted TLS version is 1.0.
8998      *
8999      * @return true if this device supports setting TLS minimum version.
9000      */
isTlsMinimumVersionSupported()9001     public boolean isTlsMinimumVersionSupported() {
9002         return isFeatureSupported(WIFI_FEATURE_SET_TLS_MINIMUM_VERSION);
9003     }
9004 
9005     /**
9006      * Indicate that whether or not TLS v1.3 is supported.
9007      *
9008      * If requested minimum is not supported, it will default to the maximum supported version.
9009      *
9010      * @return true if this device supports TLS v1.3.
9011      */
isTlsV13Supported()9012     public boolean isTlsV13Supported() {
9013         return isFeatureSupported(WIFI_FEATURE_TLS_V1_3);
9014     }
9015 
9016     /**
9017      * @return true if this device supports Dual Band Simultaneous (DBS) operation.
9018      */
isDualBandSimultaneousSupported()9019     public boolean isDualBandSimultaneousSupported() {
9020         return isFeatureSupported(WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS);
9021     }
9022 
9023     /**
9024      * @return true if this device supports TID-To-Link Mapping Negotiation.
9025      */
isTidToLinkMappingNegotiationSupported()9026     public boolean isTidToLinkMappingNegotiationSupported() {
9027         return isFeatureSupported(WIFI_FEATURE_T2LM_NEGOTIATION);
9028     }
9029 
9030 
9031     /**
9032     * @return true if this device supports connections to Wi-Fi WEP networks.
9033     */
9034     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isWepSupported()9035     public boolean isWepSupported() {
9036         return isFeatureSupported(WIFI_FEATURE_WEP);
9037     }
9038 
9039     /**
9040     * @return true if this device supports connections to Wi-Fi WPA-Personal networks.
9041     *
9042     * Note that this is the older and less secure WPA-Personal protocol, not WPA2-Personal
9043     * or later protocols.
9044     */
9045     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isWpaPersonalSupported()9046     public boolean isWpaPersonalSupported() {
9047         return isFeatureSupported(WIFI_FEATURE_WPA_PERSONAL);
9048     }
9049 
9050     /**
9051      * Gets the factory Wi-Fi MAC addresses.
9052      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
9053      * if failed.
9054      * @hide
9055      */
9056     @NonNull
9057     @SystemApi
9058     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getFactoryMacAddresses()9059     public String[] getFactoryMacAddresses() {
9060         try {
9061             return mService.getFactoryMacAddresses();
9062         } catch (RemoteException e) {
9063             throw e.rethrowFromSystemServer();
9064         }
9065     }
9066 
9067     /** @hide */
9068     @Retention(RetentionPolicy.SOURCE)
9069     @IntDef(prefix = {"DEVICE_MOBILITY_STATE_"}, value = {
9070             DEVICE_MOBILITY_STATE_UNKNOWN,
9071             DEVICE_MOBILITY_STATE_HIGH_MVMT,
9072             DEVICE_MOBILITY_STATE_LOW_MVMT,
9073             DEVICE_MOBILITY_STATE_STATIONARY})
9074     public @interface DeviceMobilityState {}
9075 
9076     /**
9077      * Unknown device mobility state
9078      *
9079      * @see #setDeviceMobilityState(int)
9080      *
9081      * @hide
9082      */
9083     @SystemApi
9084     public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0;
9085 
9086     /**
9087      * High movement device mobility state.
9088      * e.g. on a bike, in a motor vehicle
9089      *
9090      * @see #setDeviceMobilityState(int)
9091      *
9092      * @hide
9093      */
9094     @SystemApi
9095     public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1;
9096 
9097     /**
9098      * Low movement device mobility state.
9099      * e.g. walking, running
9100      *
9101      * @see #setDeviceMobilityState(int)
9102      *
9103      * @hide
9104      */
9105     @SystemApi
9106     public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2;
9107 
9108     /**
9109      * Stationary device mobility state
9110      *
9111      * @see #setDeviceMobilityState(int)
9112      *
9113      * @hide
9114      */
9115     @SystemApi
9116     public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3;
9117 
9118     /**
9119      * Updates the device mobility state. Wifi uses this information to adjust the interval between
9120      * Wifi scans in order to balance power consumption with scan accuracy.
9121      * The default mobility state when the device boots is {@link #DEVICE_MOBILITY_STATE_UNKNOWN}.
9122      * This API should be called whenever there is a change in the mobility state.
9123      * @param state the updated device mobility state
9124      * @hide
9125      */
9126     @SystemApi
9127     @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
setDeviceMobilityState(@eviceMobilityState int state)9128     public void setDeviceMobilityState(@DeviceMobilityState int state) {
9129         try {
9130             mService.setDeviceMobilityState(state);
9131         } catch (RemoteException e) {
9132             throw e.rethrowFromSystemServer();
9133         }
9134     }
9135 
9136     /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
9137 
9138     /**
9139      * Easy Connect Network role: Station.
9140      *
9141      * @hide
9142      */
9143     @SystemApi
9144     public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
9145 
9146     /**
9147      * Easy Connect Network role: Access Point.
9148      *
9149      * @hide
9150      */
9151     @SystemApi
9152     public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
9153 
9154     /** @hide */
9155     @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
9156             EASY_CONNECT_NETWORK_ROLE_STA,
9157             EASY_CONNECT_NETWORK_ROLE_AP,
9158     })
9159     @Retention(RetentionPolicy.SOURCE)
9160     public @interface EasyConnectNetworkRole {
9161     }
9162 
9163     /** Easy Connect Device information maximum allowed length */
9164     private static final int EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH = 40;
9165 
9166     /**
9167      * Easy Connect Cryptography Curve name: prime256v1
9168      *
9169      * @hide
9170      */
9171     @SystemApi
9172     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1 = 0;
9173 
9174     /**
9175      * Easy Connect Cryptography Curve name: secp384r1
9176      *
9177      * @hide
9178      */
9179     @SystemApi
9180     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1 = 1;
9181 
9182     /**
9183      * Easy Connect Cryptography Curve name: secp521r1
9184      *
9185      * @hide
9186      */
9187     @SystemApi
9188     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1 = 2;
9189 
9190 
9191     /**
9192      * Easy Connect Cryptography Curve name: brainpoolP256r1
9193      *
9194      * @hide
9195      */
9196     @SystemApi
9197     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1 = 3;
9198 
9199 
9200     /**
9201      * Easy Connect Cryptography Curve name: brainpoolP384r1
9202      *
9203      * @hide
9204      */
9205     @SystemApi
9206     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1 = 4;
9207 
9208 
9209     /**
9210      * Easy Connect Cryptography Curve name: brainpoolP512r1
9211      *
9212      * @hide
9213      */
9214     @SystemApi
9215     public static final int EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1 = 5;
9216 
9217     /** @hide */
9218     @IntDef(prefix = {"EASY_CONNECT_CRYPTOGRAPHY_CURVE_"}, value = {
9219             EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1,
9220             EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP384R1,
9221             EASY_CONNECT_CRYPTOGRAPHY_CURVE_SECP521R1,
9222             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP256R1,
9223             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP384R1,
9224             EASY_CONNECT_CRYPTOGRAPHY_CURVE_BRAINPOOLP512R1,
9225     })
9226     @Retention(RetentionPolicy.SOURCE)
9227     public @interface EasyConnectCryptographyCurve {
9228     }
9229 
9230     /**
9231      * Verbose logging mode: DISABLED.
9232      * @hide
9233      */
9234     @SystemApi
9235     public static final int VERBOSE_LOGGING_LEVEL_DISABLED = 0;
9236 
9237     /**
9238      * Verbose logging mode: ENABLED.
9239      * @hide
9240      */
9241     @SystemApi
9242     public static final int VERBOSE_LOGGING_LEVEL_ENABLED = 1;
9243 
9244     /**
9245      * Verbose logging mode: ENABLED_SHOW_KEY. This mode causes the Wi-Fi password and encryption
9246      * keys to be output to the logcat. This is security sensitive information useful for debugging.
9247      * This configuration is enabled for 30 seconds and then falls back to the regular verbose mode
9248      * (i.e. to {@link VERBOSE_LOGGING_LEVEL_ENABLED}). Show key mode is not persistent, i.e.
9249      * rebooting the device would fallback to the regular verbose mode.
9250      *
9251      * @hide
9252      */
9253     @SystemApi public static final int VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY = 2;
9254 
9255     /**
9256      * Verbose logging mode: only enable for Wi-Fi Aware feature.
9257      *
9258      * @hide
9259      */
9260     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
9261     @SystemApi
9262     public static final int VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY = 3;
9263 
9264     /** @hide */
9265     @IntDef(prefix = {"VERBOSE_LOGGING_LEVEL_"}, value = {
9266             VERBOSE_LOGGING_LEVEL_DISABLED,
9267             VERBOSE_LOGGING_LEVEL_ENABLED,
9268             VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY,
9269             VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY,
9270     })
9271     @Retention(RetentionPolicy.SOURCE)
9272     public @interface VerboseLoggingLevel {
9273     }
9274 
9275     /**
9276      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
9277      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
9278      * the specified network using the Easy Connect protocol on an encrypted link.
9279      *
9280      * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
9281      * @param selectedNetworkId   Selected network ID to be sent to the peer
9282      * @param enrolleeNetworkRole The network role of the enrollee
9283      * @param callback            Callback for status updates
9284      * @param executor            The Executor on which to run the callback.
9285      * @hide
9286      */
9287     @SystemApi
9288     @RequiresPermission(anyOf = {
9289             android.Manifest.permission.NETWORK_SETTINGS,
9290             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsConfiguratorInitiator(@onNull String enrolleeUri, int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)9291     public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
9292             int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
9293             @NonNull @CallbackExecutor Executor executor,
9294             @NonNull EasyConnectStatusCallback callback) {
9295         Binder binder = new Binder();
9296         try {
9297             mService.startDppAsConfiguratorInitiator(binder, mContext.getOpPackageName(),
9298                     enrolleeUri, selectedNetworkId, enrolleeNetworkRole,
9299                     new EasyConnectCallbackProxy(executor, callback));
9300         } catch (RemoteException e) {
9301             throw e.rethrowFromSystemServer();
9302         }
9303     }
9304 
9305     /**
9306      * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
9307      * Connect bootstrapping with a peer, and receive the SSID and password from the peer
9308      * configurator.
9309      *
9310      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
9311      * @param callback        Callback for status updates
9312      * @param executor        The Executor on which to run the callback.
9313      * @hide
9314      */
9315     @SystemApi
9316     @RequiresPermission(anyOf = {
9317             android.Manifest.permission.NETWORK_SETTINGS,
9318             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsEnrolleeInitiator(@onNull String configuratorUri, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)9319     public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
9320             @NonNull @CallbackExecutor Executor executor,
9321             @NonNull EasyConnectStatusCallback callback) {
9322         Binder binder = new Binder();
9323         try {
9324             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
9325                     new EasyConnectCallbackProxy(executor, callback));
9326         } catch (RemoteException e) {
9327             throw e.rethrowFromSystemServer();
9328         }
9329     }
9330 
9331     /**
9332      * Start Easy Connect (DPP) in Enrollee-Responder role.
9333      * The device will:
9334      * 1. Generate a DPP bootstrap URI and return it using the
9335      * {@link EasyConnectStatusCallback#onBootstrapUriGenerated(Uri)} method.
9336      * 2. Start DPP as a Responder, waiting for an Initiator device to start the DPP
9337      * authentication process.
9338      * The caller should use the URI provided in step #1, for instance display it as a QR code
9339      * or communicate it in some other way to the initiator device.
9340      *
9341      * @param deviceInfo      Device specific information to add to the DPP URI. This field allows
9342      *                        the users of the configurators to identify the device.
9343      *                        Optional - if not provided or in case of an empty string,
9344      *                        Info field (I:) will be skipped in the generated DPP URI.
9345      *                        Allowed Range of ASCII characters in deviceInfo - %x20-7E.
9346      *                        semicolon and space are not allowed. Due to the limitation of maximum
9347      *                        allowed characters in QR code, framework adds a limit to maximum
9348      *                        characters in deviceInfo. Users must call
9349      *                        {@link WifiManager#getEasyConnectMaxAllowedResponderDeviceInfoLength()
9350      *                        } method to know max allowed length. Violation of these rules will
9351      *                        result in an exception.
9352      * @param curve           Elliptic curve cryptography used to generate DPP
9353      *                        public/private key pair. If application is not interested in a
9354      *                        specific curve, use specification mandated NIST P-256 elliptic curve,
9355      *                        {@link WifiManager#EASY_CONNECT_CRYPTOGRAPHY_CURVE_PRIME256V1}.
9356      * @param callback        Callback for status updates
9357      * @param executor        The Executor on which to run the callback.
9358      * @hide
9359      */
9360     @SystemApi
9361     @RequiresPermission(anyOf = {
9362             android.Manifest.permission.NETWORK_SETTINGS,
9363             android.Manifest.permission.NETWORK_SETUP_WIZARD})
9364     @RequiresApi(Build.VERSION_CODES.S)
startEasyConnectAsEnrolleeResponder(@ullable String deviceInfo, @EasyConnectCryptographyCurve int curve, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)9365     public void startEasyConnectAsEnrolleeResponder(@Nullable String deviceInfo,
9366             @EasyConnectCryptographyCurve int curve,
9367             @NonNull @CallbackExecutor Executor executor,
9368             @NonNull EasyConnectStatusCallback callback) {
9369         Binder binder = new Binder();
9370         try {
9371             mService.startDppAsEnrolleeResponder(binder, deviceInfo, curve,
9372                     new EasyConnectCallbackProxy(executor, callback));
9373         } catch (RemoteException e) {
9374             throw e.rethrowFromSystemServer();
9375         }
9376     }
9377 
9378     /**
9379      * Maximum allowed length of Device specific information that can be added to the URI of
9380      * Easy Connect responder device.
9381      * @see #startEasyConnectAsEnrolleeResponder(String, int, Executor, EasyConnectStatusCallback)}
9382      *
9383      * @hide
9384      */
9385     @SystemApi
getEasyConnectMaxAllowedResponderDeviceInfoLength()9386     public static int getEasyConnectMaxAllowedResponderDeviceInfoLength() {
9387         return EASY_CONNECT_DEVICE_INFO_MAXIMUM_LENGTH;
9388     }
9389 
9390     /**
9391      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
9392      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
9393      * expect any callbacks once this call is made. However, due to the asynchronous nature of
9394      * this call, a callback may be fired if it was already pending in the queue.
9395      *
9396      * @hide
9397      */
9398     @SystemApi
9399     @RequiresPermission(anyOf = {
9400             android.Manifest.permission.NETWORK_SETTINGS,
9401             android.Manifest.permission.NETWORK_SETUP_WIZARD})
stopEasyConnectSession()9402     public void stopEasyConnectSession() {
9403         try {
9404             /* Request lower layers to stop/abort and clear resources */
9405             mService.stopDppSession();
9406         } catch (RemoteException e) {
9407             throw e.rethrowFromSystemServer();
9408         }
9409     }
9410 
9411     /**
9412      * Helper class to support Easy Connect (DPP) callbacks
9413      *
9414      * @hide
9415      */
9416     private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
9417         private final Executor mExecutor;
9418         private final EasyConnectStatusCallback mEasyConnectStatusCallback;
9419 
EasyConnectCallbackProxy(Executor executor, EasyConnectStatusCallback easyConnectStatusCallback)9420         EasyConnectCallbackProxy(Executor executor,
9421                 EasyConnectStatusCallback easyConnectStatusCallback) {
9422             mExecutor = executor;
9423             mEasyConnectStatusCallback = easyConnectStatusCallback;
9424         }
9425 
9426         @Override
onSuccessConfigReceived(int newNetworkId)9427         public void onSuccessConfigReceived(int newNetworkId) {
9428             Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
9429             Binder.clearCallingIdentity();
9430             mExecutor.execute(() -> {
9431                 mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
9432             });
9433         }
9434 
9435         @Override
onSuccess(int status)9436         public void onSuccess(int status) {
9437             Log.d(TAG, "Easy Connect onSuccess callback");
9438             Binder.clearCallingIdentity();
9439             mExecutor.execute(() -> {
9440                 mEasyConnectStatusCallback.onConfiguratorSuccess(status);
9441             });
9442         }
9443 
9444         @Override
onFailure(int status, String ssid, String channelList, int[] operatingClassArray)9445         public void onFailure(int status, String ssid, String channelList,
9446                 int[] operatingClassArray) {
9447             Log.d(TAG, "Easy Connect onFailure callback");
9448             Binder.clearCallingIdentity();
9449             mExecutor.execute(() -> {
9450                 SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
9451                 mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
9452                         operatingClassArray);
9453             });
9454         }
9455 
9456         @Override
onProgress(int status)9457         public void onProgress(int status) {
9458             Log.d(TAG, "Easy Connect onProgress callback");
9459             Binder.clearCallingIdentity();
9460             mExecutor.execute(() -> {
9461                 mEasyConnectStatusCallback.onProgress(status);
9462             });
9463         }
9464 
9465         @Override
onBootstrapUriGenerated(@onNull String uri)9466         public void onBootstrapUriGenerated(@NonNull String uri) {
9467             Log.d(TAG, "Easy Connect onBootstrapUriGenerated callback");
9468             if (!SdkLevel.isAtLeastS()) {
9469                 Log.e(TAG, "Easy Connect bootstrap URI callback supported only on S+");
9470                 return;
9471             }
9472             Binder.clearCallingIdentity();
9473             mExecutor.execute(() -> {
9474                 mEasyConnectStatusCallback.onBootstrapUriGenerated(Uri.parse(uri));
9475             });
9476         }
9477     }
9478 
9479     /**
9480      * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
9481      * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor,
9482      * OnWifiUsabilityStatsListener)}.
9483      *
9484      * @hide
9485      */
9486     @SystemApi
9487     public interface OnWifiUsabilityStatsListener {
9488         /**
9489          * Called when Wi-Fi usability statistics is updated.
9490          *
9491          * @param seqNum The sequence number of statistics, used to derive the timing of updated
9492          *               Wi-Fi usability statistics, set by framework and incremented by one after
9493          *               each update.
9494          * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
9495          *                           network stays the same or not relative to the last update of
9496          *                           Wi-Fi usability stats.
9497          * @param stats The updated Wi-Fi usability statistics.
9498          */
onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, @NonNull WifiUsabilityStatsEntry stats)9499         void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
9500                 @NonNull WifiUsabilityStatsEntry stats);
9501     }
9502 
9503     /**
9504      * Interface for Wi-Fi verbose logging status listener. Should be implemented by applications
9505      * and set when calling {@link WifiManager#addWifiVerboseLoggingStatusListener(Executor,
9506      * WifiVerboseLoggingStatusListener)}.
9507      *
9508      * @hide
9509      */
9510     @SystemApi
9511     public interface WifiVerboseLoggingStatusChangedListener {
9512         /**
9513          * Called when Wi-Fi verbose logging setting is updated.
9514          *
9515          * @param enabled true if verbose logging is enabled, false if verbose logging is disabled.
9516          */
onWifiVerboseLoggingStatusChanged(boolean enabled)9517         void onWifiVerboseLoggingStatusChanged(boolean enabled);
9518     }
9519 
9520     /**
9521      * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}.
9522      * Multiple listeners can be added. Callers will be invoked periodically by framework to
9523      * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
9524      * added listener using
9525      * {@link #removeOnWifiUsabilityStatsListener(OnWifiUsabilityStatsListener)}.
9526      *
9527      * @param executor The executor on which callback will be invoked.
9528      * @param listener Listener for Wifi usability statistics.
9529      *
9530      * @hide
9531      */
9532     @SystemApi
9533     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
addOnWifiUsabilityStatsListener(@onNull @allbackExecutor Executor executor, @NonNull OnWifiUsabilityStatsListener listener)9534     public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
9535             @NonNull OnWifiUsabilityStatsListener listener) {
9536         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
9537         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
9538         if (mVerboseLoggingEnabled) {
9539             Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
9540         }
9541         try {
9542             synchronized (sOnWifiUsabilityStatsListenerMap) {
9543                 IOnWifiUsabilityStatsListener.Stub binderCallback =
9544                         new IOnWifiUsabilityStatsListener.Stub() {
9545                             @Override
9546                             public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
9547                                     WifiUsabilityStatsEntry stats) {
9548                                 if (mVerboseLoggingEnabled) {
9549                                     Log.v(TAG, "OnWifiUsabilityStatsListener: "
9550                                             + "onWifiUsabilityStats: seqNum=" + seqNum);
9551                                 }
9552                                 Binder.clearCallingIdentity();
9553                                 executor.execute(() -> listener.onWifiUsabilityStats(
9554                                         seqNum, isSameBssidAndFreq, stats));
9555                             }
9556                         };
9557                 sOnWifiUsabilityStatsListenerMap.put(System.identityHashCode(listener),
9558                         binderCallback);
9559                 mService.addOnWifiUsabilityStatsListener(binderCallback);
9560             }
9561         } catch (RemoteException e) {
9562             throw e.rethrowFromSystemServer();
9563         }
9564     }
9565 
9566     /**
9567      * Allow callers to remove a previously registered listener. After calling this method,
9568      * applications will no longer receive Wi-Fi usability statistics.
9569      *
9570      * @param listener Listener to remove the Wi-Fi usability statistics.
9571      *
9572      * @hide
9573      */
9574     @SystemApi
9575     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
removeOnWifiUsabilityStatsListener(@onNull OnWifiUsabilityStatsListener listener)9576     public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) {
9577         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
9578         if (mVerboseLoggingEnabled) {
9579             Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
9580         }
9581         try {
9582             synchronized (sOnWifiUsabilityStatsListenerMap) {
9583                 int listenerIdentifier = System.identityHashCode(listener);
9584                 if (!sOnWifiUsabilityStatsListenerMap.contains(listenerIdentifier)) {
9585                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9586                     return;
9587                 }
9588                 mService.removeOnWifiUsabilityStatsListener(
9589                         sOnWifiUsabilityStatsListenerMap.get(listenerIdentifier));
9590                 sOnWifiUsabilityStatsListenerMap.remove(listenerIdentifier);
9591             }
9592         } catch (RemoteException e) {
9593             throw e.rethrowFromSystemServer();
9594         }
9595     }
9596 
9597     /**
9598      * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
9599      * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
9600      * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
9601      * is used to quantify whether Wi-Fi is usable in a future time.
9602      *
9603      * @param seqNum Sequence number of the Wi-Fi usability score.
9604      * @param score The Wi-Fi usability score, expected range: [0, 100].
9605      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
9606      *                             expected range: [0, 30].
9607      *
9608      * @hide
9609      */
9610     @SystemApi
9611     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)9612     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
9613         try {
9614             mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
9615         } catch (RemoteException e) {
9616             throw e.rethrowFromSystemServer();
9617         }
9618     }
9619 
9620     /**
9621      * Gets the list of BSSIDs which are currently disabled for Wi-Fi auto-join connections.
9622      *
9623      * @param ssids If empty, then get all currently disabled BSSIDs.
9624      *              If non-empty, then only get currently disabled BSSIDs with matching SSIDs.
9625      * @param executor The executor to execute the callback of the {@code resultListener} object.
9626      * @param resultListener callback to retrieve the blocked BSSIDs
9627      *
9628      * @hide
9629      */
9630     @SystemApi
9631     @FlaggedApi(Flags.FLAG_GET_BSSID_BLOCKLIST_API)
9632     @RequiresPermission(anyOf = {
9633             android.Manifest.permission.NETWORK_SETTINGS,
9634             android.Manifest.permission.NETWORK_SETUP_WIZARD})
getBssidBlocklist(@onNull List<WifiSsid> ssids, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<List<MacAddress>> resultListener)9635     public void getBssidBlocklist(@NonNull List<WifiSsid> ssids,
9636             @NonNull @CallbackExecutor Executor executor,
9637             @NonNull Consumer<List<MacAddress>> resultListener) {
9638         Objects.requireNonNull(ssids, "ssids cannot be null");
9639         Objects.requireNonNull(executor, "executor cannot be null");
9640         Objects.requireNonNull(resultListener, "resultsCallback cannot be null");
9641         try {
9642             mService.getBssidBlocklist(
9643                     new ParceledListSlice<>(ssids),
9644                     new IMacAddressListListener.Stub() {
9645                         @Override
9646                         public void onResult(ParceledListSlice<MacAddress> value) {
9647                             Binder.clearCallingIdentity();
9648                             executor.execute(() -> {
9649                                 resultListener.accept(value.getList());
9650                             });
9651                         }
9652                     });
9653         } catch (RemoteException e) {
9654             throw e.rethrowFromSystemServer();
9655         }
9656     }
9657 
9658     /**
9659      * Abstract class for scan results callback. Should be extended by applications and set when
9660      * calling {@link WifiManager#registerScanResultsCallback(Executor, ScanResultsCallback)}.
9661      */
9662     public abstract static class ScanResultsCallback {
9663         private final ScanResultsCallbackProxy mScanResultsCallbackProxy;
9664 
ScanResultsCallback()9665         public ScanResultsCallback() {
9666             mScanResultsCallbackProxy = new ScanResultsCallbackProxy();
9667         }
9668 
9669         /**
9670          * Called when new scan results are available.
9671          * Clients should use {@link WifiManager#getScanResults()} to get the scan results.
9672          */
onScanResultsAvailable()9673         public abstract void onScanResultsAvailable();
9674 
getProxy()9675         /*package*/ @NonNull ScanResultsCallbackProxy getProxy() {
9676             return mScanResultsCallbackProxy;
9677         }
9678 
9679         private static class ScanResultsCallbackProxy extends IScanResultsCallback.Stub {
9680             private final Object mLock = new Object();
9681             @Nullable @GuardedBy("mLock") private Executor mExecutor;
9682             @Nullable @GuardedBy("mLock") private ScanResultsCallback mCallback;
9683 
ScanResultsCallbackProxy()9684             ScanResultsCallbackProxy() {
9685                 mCallback = null;
9686                 mExecutor = null;
9687             }
9688 
initProxy(@onNull Executor executor, @NonNull ScanResultsCallback callback)9689             /*package*/ void initProxy(@NonNull Executor executor,
9690                     @NonNull ScanResultsCallback callback) {
9691                 synchronized (mLock) {
9692                     mExecutor = executor;
9693                     mCallback = callback;
9694                 }
9695             }
9696 
cleanUpProxy()9697             /*package*/ void cleanUpProxy() {
9698                 synchronized (mLock) {
9699                     mExecutor = null;
9700                     mCallback = null;
9701                 }
9702             }
9703 
9704             @Override
onScanResultsAvailable()9705             public void onScanResultsAvailable() {
9706                 ScanResultsCallback callback;
9707                 Executor executor;
9708                 synchronized (mLock) {
9709                     executor = mExecutor;
9710                     callback = mCallback;
9711                 }
9712                 if (callback == null || executor == null) {
9713                     return;
9714                 }
9715                 Binder.clearCallingIdentity();
9716                 executor.execute(callback::onScanResultsAvailable);
9717             }
9718         }
9719     }
9720 
9721     /**
9722      * Register a callback for Scan Results. See {@link ScanResultsCallback}.
9723      * Caller will receive the event when scan results are available.
9724      * Caller should use {@link WifiManager#getScanResults()} requires
9725      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results.
9726      * Caller can remove a previously registered callback using
9727      * {@link WifiManager#unregisterScanResultsCallback(ScanResultsCallback)}
9728      * Same caller can add multiple listeners.
9729      * <p>
9730      * Applications should have the
9731      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers
9732      * without the permission will trigger a {@link java.lang.SecurityException}.
9733      * <p>
9734      *
9735      * @param executor The executor to execute the callback of the {@code callback} object.
9736      * @param callback callback for Scan Results events
9737      */
9738 
9739     @RequiresPermission(ACCESS_WIFI_STATE)
registerScanResultsCallback(@onNull @allbackExecutor Executor executor, @NonNull ScanResultsCallback callback)9740     public void registerScanResultsCallback(@NonNull @CallbackExecutor Executor executor,
9741             @NonNull ScanResultsCallback callback) {
9742         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
9743         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9744 
9745         Log.v(TAG, "registerScanResultsCallback: callback=" + callback
9746                 + ", executor=" + executor);
9747         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
9748         proxy.initProxy(executor, callback);
9749         try {
9750             mService.registerScanResultsCallback(proxy);
9751         } catch (RemoteException e) {
9752             throw e.rethrowFromSystemServer();
9753         }
9754     }
9755 
9756     /**
9757      * Allow callers to unregister a previously registered callback. After calling this method,
9758      * applications will no longer receive Scan Results events.
9759      *
9760      * @param callback callback to unregister for Scan Results events
9761      */
9762     @RequiresPermission(ACCESS_WIFI_STATE)
unregisterScanResultsCallback(@onNull ScanResultsCallback callback)9763     public void unregisterScanResultsCallback(@NonNull ScanResultsCallback callback) {
9764         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
9765         Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback);
9766         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
9767         try {
9768             mService.unregisterScanResultsCallback(proxy);
9769         } catch (RemoteException e) {
9770             throw e.rethrowFromSystemServer();
9771         } finally {
9772             proxy.cleanUpProxy();
9773         }
9774     }
9775 
9776     /**
9777      * Interface for suggestion connection status listener.
9778      * Should be implemented by applications and set when calling
9779      * {@link WifiManager#addSuggestionConnectionStatusListener(
9780      * Executor, SuggestionConnectionStatusListener)}.
9781      */
9782     public interface SuggestionConnectionStatusListener {
9783 
9784         /**
9785          * Called when the framework attempted to connect to a suggestion provided by the
9786          * registering app, but the connection to the suggestion failed.
9787          * @param wifiNetworkSuggestion The suggestion which failed to connect.
9788          * @param failureReason the connection failure reason code.
9789          */
onConnectionStatus( @onNull WifiNetworkSuggestion wifiNetworkSuggestion, @SuggestionConnectionStatusCode int failureReason)9790         void onConnectionStatus(
9791                 @NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
9792                 @SuggestionConnectionStatusCode int failureReason);
9793     }
9794 
9795     private class SuggestionConnectionStatusListenerProxy extends
9796             ISuggestionConnectionStatusListener.Stub {
9797         private final Executor mExecutor;
9798         private final SuggestionConnectionStatusListener mListener;
9799 
SuggestionConnectionStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionConnectionStatusListener listener)9800         SuggestionConnectionStatusListenerProxy(@NonNull Executor executor,
9801                 @NonNull SuggestionConnectionStatusListener listener) {
9802             mExecutor = executor;
9803             mListener = listener;
9804         }
9805 
9806         @Override
onConnectionStatus(@onNull WifiNetworkSuggestion wifiNetworkSuggestion, int failureReason)9807         public void onConnectionStatus(@NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
9808                 int failureReason) {
9809             Binder.clearCallingIdentity();
9810             mExecutor.execute(() ->
9811                     mListener.onConnectionStatus(wifiNetworkSuggestion, failureReason));
9812         }
9813 
9814     }
9815 
9816     /**
9817      * Interface for local-only connection failure listener.
9818      * Should be implemented by applications and set when calling
9819      * {@link WifiManager#addLocalOnlyConnectionFailureListener(Executor, LocalOnlyConnectionFailureListener)}
9820      */
9821     public interface LocalOnlyConnectionFailureListener {
9822 
9823         /**
9824          * Called when the framework attempted to connect to a local-only network requested by the
9825          * registering app, but the connection to the network failed.
9826          * @param wifiNetworkSpecifier The {@link WifiNetworkSpecifier} which failed to connect.
9827          * @param failureReason the connection failure reason code.
9828          */
onConnectionFailed( @onNull WifiNetworkSpecifier wifiNetworkSpecifier, @LocalOnlyConnectionStatusCode int failureReason)9829         void onConnectionFailed(
9830                 @NonNull WifiNetworkSpecifier wifiNetworkSpecifier,
9831                 @LocalOnlyConnectionStatusCode int failureReason);
9832     }
9833 
9834     private static class LocalOnlyConnectionStatusListenerProxy extends
9835             ILocalOnlyConnectionStatusListener.Stub {
9836         private final Executor mExecutor;
9837         private final LocalOnlyConnectionFailureListener mListener;
9838 
LocalOnlyConnectionStatusListenerProxy(@onNull Executor executor, @NonNull LocalOnlyConnectionFailureListener listener)9839         LocalOnlyConnectionStatusListenerProxy(@NonNull Executor executor,
9840                 @NonNull LocalOnlyConnectionFailureListener listener) {
9841             mExecutor = executor;
9842             mListener = listener;
9843         }
9844 
9845         @Override
onConnectionStatus(@onNull WifiNetworkSpecifier networkSpecifier, int failureReason)9846         public void onConnectionStatus(@NonNull WifiNetworkSpecifier networkSpecifier,
9847                 int failureReason) {
9848             Binder.clearCallingIdentity();
9849             mExecutor.execute(() ->
9850                     mListener.onConnectionFailed(networkSpecifier, failureReason));
9851         }
9852 
9853     }
9854 
9855     /**
9856      * Add a listener listening to wifi verbose logging changes.
9857      * See {@link WifiVerboseLoggingStatusChangedListener}.
9858      * Caller can remove a previously registered listener using
9859      * {@link WifiManager#removeWifiVerboseLoggingStatusChangedListener(
9860      * WifiVerboseLoggingStatusChangedListener)}
9861      * Same caller can add multiple listeners to monitor the event.
9862      * <p>
9863      * Applications should have the
9864      * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
9865      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
9866      * <p>
9867      * @param executor The executor to execute the listener of the {@code listener} object.
9868      * @param listener listener for changes in wifi verbose logging.
9869      *
9870      * @hide
9871      */
9872     @SystemApi
9873     @RequiresPermission(ACCESS_WIFI_STATE)
addWifiVerboseLoggingStatusChangedListener( @onNull @allbackExecutor Executor executor, @NonNull WifiVerboseLoggingStatusChangedListener listener)9874     public void addWifiVerboseLoggingStatusChangedListener(
9875             @NonNull @CallbackExecutor Executor executor,
9876             @NonNull WifiVerboseLoggingStatusChangedListener listener) {
9877         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9878         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
9879         if (mVerboseLoggingEnabled) {
9880             Log.v(TAG, "addWifiVerboseLoggingStatusChangedListener listener=" + listener
9881                     + ", executor=" + executor);
9882         }
9883         try {
9884             synchronized (sWifiVerboseLoggingStatusChangedListenerMap) {
9885                 IWifiVerboseLoggingStatusChangedListener.Stub binderCallback =
9886                         new IWifiVerboseLoggingStatusChangedListener.Stub() {
9887                             @Override
9888                             public void onStatusChanged(boolean enabled) {
9889                                 if (mVerboseLoggingEnabled) {
9890                                     Log.v(TAG, "WifiVerboseLoggingStatusListener: "
9891                                             + "onVerboseLoggingStatusChanged: enabled=" + enabled);
9892                                 }
9893                                 Binder.clearCallingIdentity();
9894                                 executor.execute(() -> listener.onWifiVerboseLoggingStatusChanged(
9895                                         enabled));
9896                             }
9897                         };
9898                 sWifiVerboseLoggingStatusChangedListenerMap.put(System.identityHashCode(listener),
9899                         binderCallback);
9900                 mService.addWifiVerboseLoggingStatusChangedListener(binderCallback);
9901             }
9902         } catch (RemoteException e) {
9903             throw e.rethrowFromSystemServer();
9904         }
9905     }
9906 
9907     /**
9908      * Allow callers to remove a previously registered listener.
9909      * <p>
9910      * Applications should have the
9911      * {@link android.Manifest.permission#ACCESS_WIFI_STATE}.
9912      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
9913      * <p>
9914      * @param listener listener to remove.
9915      *
9916      * @hide
9917      */
9918     @SystemApi
9919     @RequiresPermission(ACCESS_WIFI_STATE)
removeWifiVerboseLoggingStatusChangedListener( @onNull WifiVerboseLoggingStatusChangedListener listener)9920     public void removeWifiVerboseLoggingStatusChangedListener(
9921             @NonNull WifiVerboseLoggingStatusChangedListener listener) {
9922         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9923         Log.v(TAG, "removeWifiVerboseLoggingStatusChangedListener: listener=" + listener);
9924         try {
9925             synchronized (sWifiVerboseLoggingStatusChangedListenerMap) {
9926                 int listenerIdentifier = System.identityHashCode(listener);
9927                 if (!sWifiVerboseLoggingStatusChangedListenerMap.contains(listenerIdentifier)) {
9928                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9929                     return;
9930                 }
9931                 mService.removeWifiVerboseLoggingStatusChangedListener(
9932                         sWifiVerboseLoggingStatusChangedListenerMap.get(listenerIdentifier));
9933                 sWifiVerboseLoggingStatusChangedListenerMap.remove(listenerIdentifier);
9934             }
9935         } catch (RemoteException e) {
9936             throw e.rethrowFromSystemServer();
9937         }
9938     }
9939 
9940     /**
9941      * Add a listener for suggestion networks. See {@link SuggestionConnectionStatusListener}.
9942      * Caller will receive the event when suggested network have connection failure.
9943      * Caller can remove a previously registered listener using
9944      * {@link WifiManager#removeSuggestionConnectionStatusListener(
9945      * SuggestionConnectionStatusListener)}
9946      * Same caller can add multiple listeners to monitor the event.
9947      * <p>
9948      * Applications should have the
9949      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
9950      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permissions.
9951      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
9952      * <p>
9953      *
9954      * @param executor The executor to execute the listener of the {@code listener} object.
9955      * @param listener listener for suggestion network connection failure.
9956      */
9957     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
addSuggestionConnectionStatusListener(@onNull @allbackExecutor Executor executor, @NonNull SuggestionConnectionStatusListener listener)9958     public void addSuggestionConnectionStatusListener(@NonNull @CallbackExecutor Executor executor,
9959             @NonNull SuggestionConnectionStatusListener listener) {
9960         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9961         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
9962         Log.v(TAG, "addSuggestionConnectionStatusListener listener=" + listener
9963                 + ", executor=" + executor);
9964         try {
9965             synchronized (sSuggestionConnectionStatusListenerMap) {
9966                 ISuggestionConnectionStatusListener.Stub binderCallback =
9967                         new SuggestionConnectionStatusListenerProxy(executor, listener);
9968                 sSuggestionConnectionStatusListenerMap.put(System.identityHashCode(listener),
9969                         binderCallback);
9970                 mService.registerSuggestionConnectionStatusListener(binderCallback,
9971                         mContext.getOpPackageName(), mContext.getAttributionTag());
9972             }
9973         } catch (RemoteException e) {
9974             throw e.rethrowFromSystemServer();
9975         }
9976 
9977     }
9978 
9979     /**
9980      * Allow callers to remove a previously registered listener. After calling this method,
9981      * applications will no longer receive suggestion connection events through that listener.
9982      *
9983      * @param listener listener to remove.
9984      */
9985     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionConnectionStatusListener( @onNull SuggestionConnectionStatusListener listener)9986     public void removeSuggestionConnectionStatusListener(
9987             @NonNull SuggestionConnectionStatusListener listener) {
9988         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
9989         Log.v(TAG, "removeSuggestionConnectionStatusListener: listener=" + listener);
9990         try {
9991             synchronized (sSuggestionConnectionStatusListenerMap) {
9992                 int listenerIdentifier = System.identityHashCode(listener);
9993                 if (!sSuggestionConnectionStatusListenerMap.contains(listenerIdentifier)) {
9994                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
9995                     return;
9996                 }
9997                 mService.unregisterSuggestionConnectionStatusListener(
9998                         sSuggestionConnectionStatusListenerMap.get(listenerIdentifier),
9999                         mContext.getOpPackageName());
10000                 sSuggestionConnectionStatusListenerMap.remove(listenerIdentifier);
10001             }
10002         } catch (RemoteException e) {
10003             throw e.rethrowFromSystemServer();
10004         }
10005     }
10006 
10007     /**
10008      * Add a listener for local-only networks. See {@link WifiNetworkSpecifier}.
10009      * Specify the caller will only get connection failures for networks they requested.
10010      * Caller can remove a previously registered listener using
10011      * {@link WifiManager#removeLocalOnlyConnectionFailureListener(LocalOnlyConnectionFailureListener)}
10012      * Same caller can add multiple listeners to monitor the event.
10013      * <p>
10014      * Applications should have the {@link android.Manifest.permission#ACCESS_WIFI_STATE}
10015      * permissions.
10016      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
10017      * <p>
10018      *
10019      * @param executor The executor to execute the listener of the {@code listener} object.
10020      * @param listener listener for local-only network connection failure.
10021      */
10022     @RequiresPermission(ACCESS_WIFI_STATE)
addLocalOnlyConnectionFailureListener(@onNull @allbackExecutor Executor executor, @NonNull LocalOnlyConnectionFailureListener listener)10023     public void addLocalOnlyConnectionFailureListener(@NonNull @CallbackExecutor Executor executor,
10024             @NonNull LocalOnlyConnectionFailureListener listener) {
10025         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10026         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
10027         try {
10028             synchronized (sLocalOnlyConnectionStatusListenerMap) {
10029                 if (sLocalOnlyConnectionStatusListenerMap
10030                         .contains(System.identityHashCode(listener))) {
10031                     Log.w(TAG, "Same listener already registered");
10032                     return;
10033                 }
10034                 ILocalOnlyConnectionStatusListener.Stub binderCallback =
10035                         new LocalOnlyConnectionStatusListenerProxy(executor, listener);
10036                 sLocalOnlyConnectionStatusListenerMap.put(System.identityHashCode(listener),
10037                         binderCallback);
10038                 mService.addLocalOnlyConnectionStatusListener(binderCallback,
10039                         mContext.getOpPackageName(), mContext.getAttributionTag());
10040             }
10041         } catch (RemoteException e) {
10042             throw e.rethrowFromSystemServer();
10043         }
10044     }
10045 
10046     /**
10047      * Allow callers to remove a previously registered listener. After calling this method,
10048      * applications will no longer receive local-only connection events through that listener.
10049      *
10050      * @param listener listener to remove.
10051      */
10052     @RequiresPermission(ACCESS_WIFI_STATE)
removeLocalOnlyConnectionFailureListener( @onNull LocalOnlyConnectionFailureListener listener)10053     public void removeLocalOnlyConnectionFailureListener(
10054             @NonNull LocalOnlyConnectionFailureListener listener) {
10055         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
10056         try {
10057             synchronized (sLocalOnlyConnectionStatusListenerMap) {
10058                 int listenerIdentifier = System.identityHashCode(listener);
10059                 if (!sLocalOnlyConnectionStatusListenerMap.contains(listenerIdentifier)) {
10060                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
10061                     return;
10062                 }
10063                 mService.removeLocalOnlyConnectionStatusListener(
10064                         sLocalOnlyConnectionStatusListenerMap.get(listenerIdentifier),
10065                         mContext.getOpPackageName());
10066                 sLocalOnlyConnectionStatusListenerMap.remove(listenerIdentifier);
10067             }
10068         } catch (RemoteException e) {
10069             throw e.rethrowFromSystemServer();
10070         }
10071     }
10072 
10073     /**
10074      * Parse the list of channels the DPP enrollee reports when it fails to find an AP.
10075      *
10076      * @param channelList List of channels in the format defined in the DPP specification.
10077      * @return A parsed sparse array, where the operating class is the key.
10078      * @hide
10079      */
10080     @VisibleForTesting
parseDppChannelList(String channelList)10081     public static SparseArray<int[]> parseDppChannelList(String channelList) {
10082         SparseArray<int[]> channelListArray = new SparseArray<>();
10083 
10084         if (TextUtils.isEmpty(channelList)) {
10085             return channelListArray;
10086         }
10087         StringTokenizer str = new StringTokenizer(channelList, ",");
10088         String classStr = null;
10089         List<Integer> channelsInClass = new ArrayList<>();
10090 
10091         try {
10092             while (str.hasMoreElements()) {
10093                 String cur = str.nextToken();
10094 
10095                 /**
10096                  * Example for a channel list:
10097                  *
10098                  * 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,
10099                  * 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
10100                  *
10101                  * Detect operating class by the delimiter of '/' and use a string tokenizer with
10102                  * ',' as a delimiter.
10103                  */
10104                 int classDelim = cur.indexOf('/');
10105                 if (classDelim != -1) {
10106                     if (classStr != null) {
10107                         // Store the last channel array in the sparse array, where the operating
10108                         // class is the key (as an integer).
10109                         int[] channelsArray = new int[channelsInClass.size()];
10110                         for (int i = 0; i < channelsInClass.size(); i++) {
10111                             channelsArray[i] = channelsInClass.get(i);
10112                         }
10113                         channelListArray.append(Integer.parseInt(classStr), channelsArray);
10114                         channelsInClass = new ArrayList<>();
10115                     }
10116 
10117                     // Init a new operating class and store the first channel
10118                     classStr = cur.substring(0, classDelim);
10119                     String channelStr = cur.substring(classDelim + 1);
10120                     channelsInClass.add(Integer.parseInt(channelStr));
10121                 } else {
10122                     if (classStr == null) {
10123                         // Invalid format
10124                         Log.e(TAG, "Cannot parse DPP channel list");
10125                         return new SparseArray<>();
10126                     }
10127                     channelsInClass.add(Integer.parseInt(cur));
10128                 }
10129             }
10130 
10131             // Store the last array
10132             if (classStr != null) {
10133                 int[] channelsArray = new int[channelsInClass.size()];
10134                 for (int i = 0; i < channelsInClass.size(); i++) {
10135                     channelsArray[i] = channelsInClass.get(i);
10136                 }
10137                 channelListArray.append(Integer.parseInt(classStr), channelsArray);
10138             }
10139             return channelListArray;
10140         } catch (NumberFormatException e) {
10141             Log.e(TAG, "Cannot parse DPP channel list");
10142             return new SparseArray<>();
10143         }
10144     }
10145 
10146     /**
10147      * Callback interface for framework to receive network status updates and trigger of updating
10148      * {@link WifiUsabilityStatsEntry}.
10149      *
10150      * @hide
10151      */
10152     @SystemApi
10153     public interface ScoreUpdateObserver {
10154         /**
10155          * Called by applications to indicate network status. For applications targeting
10156          * {@link android.os.Build.VERSION_CODES#S} or above: The score is not used to take action
10157          * on network selection but for the purpose of Wifi metric collection only; Network
10158          * selection is influenced by inputs from
10159          * {@link ScoreUpdateObserver#notifyStatusUpdate(int, boolean)},
10160          * {@link ScoreUpdateObserver#requestNudOperation(int, boolean)}, and
10161          * {@link ScoreUpdateObserver#blocklistCurrentBssid(int)}.
10162          *
10163          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10164          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10165          * @param score The score representing link quality of current Wi-Fi network connection.
10166          *              Populated by connected network scorer in applications..
10167          */
notifyScoreUpdate(int sessionId, int score)10168         void notifyScoreUpdate(int sessionId, int score);
10169 
10170         /**
10171          * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
10172          * To receive update applications need to add WifiUsabilityStatsEntry listener. See
10173          * {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
10174          *
10175          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10176          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10177          */
triggerUpdateOfWifiUsabilityStats(int sessionId)10178         void triggerUpdateOfWifiUsabilityStats(int sessionId);
10179 
10180         /**
10181          * Called by applications to indicate whether current Wi-Fi network is usable or not.
10182          *
10183          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10184          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10185          * @param isUsable The boolean representing whether current Wi-Fi network is usable, and it
10186          *                 may be sent to ConnectivityService and used for setting default network.
10187          *                 Populated by connected network scorer in applications.
10188          */
10189         @RequiresApi(Build.VERSION_CODES.S)
notifyStatusUpdate(int sessionId, boolean isUsable)10190         default void notifyStatusUpdate(int sessionId, boolean isUsable) {}
10191 
10192         /**
10193          * Called by applications to start a NUD (Neighbor Unreachability Detection) operation. The
10194          * framework throttles NUD operations to no more frequently than every five seconds
10195          * (see {@link WifiScoreReport#NUD_THROTTLE_MILLIS}). The framework keeps track of requests
10196          * and executes them as soon as possible based on the throttling criteria.
10197          *
10198          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10199          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10200          */
10201         @RequiresApi(Build.VERSION_CODES.S)
requestNudOperation(int sessionId)10202         default void requestNudOperation(int sessionId) {}
10203 
10204         /**
10205          * Called by applications to blocklist currently connected BSSID. No blocklisting operation
10206          * if called after disconnection.
10207          *
10208          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10209          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10210          */
10211         @RequiresApi(Build.VERSION_CODES.S)
blocklistCurrentBssid(int sessionId)10212         default void blocklistCurrentBssid(int sessionId) {}
10213     }
10214 
10215     /**
10216      * Callback proxy for {@link ScoreUpdateObserver} objects.
10217      *
10218      * @hide
10219      */
10220     private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
10221         private final IScoreUpdateObserver mScoreUpdateObserver;
10222 
ScoreUpdateObserverProxy(IScoreUpdateObserver observer)10223         private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
10224             mScoreUpdateObserver = observer;
10225         }
10226 
10227         @Override
notifyScoreUpdate(int sessionId, int score)10228         public void notifyScoreUpdate(int sessionId, int score) {
10229             try {
10230                 mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
10231             } catch (RemoteException e) {
10232                 throw e.rethrowFromSystemServer();
10233             }
10234         }
10235 
10236         @Override
triggerUpdateOfWifiUsabilityStats(int sessionId)10237         public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
10238             try {
10239                 mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
10240             } catch (RemoteException e) {
10241                 throw e.rethrowFromSystemServer();
10242             }
10243         }
10244 
10245         @Override
notifyStatusUpdate(int sessionId, boolean isUsable)10246         public void notifyStatusUpdate(int sessionId, boolean isUsable) {
10247             if (!SdkLevel.isAtLeastS()) {
10248                 throw new UnsupportedOperationException();
10249             }
10250             try {
10251                 mScoreUpdateObserver.notifyStatusUpdate(sessionId, isUsable);
10252             } catch (RemoteException e) {
10253                 throw e.rethrowFromSystemServer();
10254             }
10255         }
10256 
10257         @Override
requestNudOperation(int sessionId)10258         public void requestNudOperation(int sessionId) {
10259             if (!SdkLevel.isAtLeastS()) {
10260                 throw new UnsupportedOperationException();
10261             }
10262             try {
10263                 mScoreUpdateObserver.requestNudOperation(sessionId);
10264             } catch (RemoteException e) {
10265                 throw e.rethrowFromSystemServer();
10266             }
10267         }
10268 
10269         @Override
blocklistCurrentBssid(int sessionId)10270         public void blocklistCurrentBssid(int sessionId) {
10271             if (!SdkLevel.isAtLeastS()) {
10272                 throw new UnsupportedOperationException();
10273             }
10274             try {
10275                 mScoreUpdateObserver.blocklistCurrentBssid(sessionId);
10276             } catch (RemoteException e) {
10277                 throw e.rethrowFromSystemServer();
10278             }
10279         }
10280     }
10281 
10282     /**
10283      * Interface for Wi-Fi connected network scorer. Should be implemented by applications and set
10284      * when calling
10285      * {@link WifiManager#setWifiConnectedNetworkScorer(Executor, WifiConnectedNetworkScorer)}.
10286      *
10287      * @hide
10288      */
10289     @SystemApi
10290     public interface WifiConnectedNetworkScorer {
10291         /**
10292          * Called by framework to indicate the start of a network connection.
10293          * @param sessionId The ID to indicate current Wi-Fi network connection.
10294          * @deprecated This API is deprecated.  Please use
10295          *             {@link WifiConnectedNetworkScorer#onStart(WifiConnectedSessionInfo)}.
10296          */
10297         @Deprecated
onStart(int sessionId)10298         default void onStart(int sessionId) {}
10299 
10300         /**
10301          * Called by framework to indicate the start of a network connection.
10302          * @param sessionInfo The session information to indicate current Wi-Fi network connection.
10303          *                    See {@link WifiConnectedSessionInfo}.
10304          */
onStart(@onNull WifiConnectedSessionInfo sessionInfo)10305         default void onStart(@NonNull WifiConnectedSessionInfo sessionInfo) {
10306             onStart(sessionInfo.getSessionId());
10307         }
10308 
10309         /**
10310          * Called by framework to indicate the end of a network connection.
10311          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10312          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10313          */
onStop(int sessionId)10314         void onStop(int sessionId);
10315 
10316         /**
10317          * Framework sets callback for score change events after application sets its scorer.
10318          * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
10319          * implemented and instantiated by framework.
10320          */
onSetScoreUpdateObserver(@onNull ScoreUpdateObserver observerImpl)10321         void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
10322 
10323         /**
10324          * Called by framework to indicate the user accepted a dialog to switch to a new network.
10325          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10326          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10327          * @param targetNetworkId Network ID of the target network.
10328          * @param targetBssid BSSID of the target network.
10329          */
onNetworkSwitchAccepted( int sessionId, int targetNetworkId, @NonNull String targetBssid)10330         default void onNetworkSwitchAccepted(
10331                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10332             // No-op.
10333         }
10334 
10335         /**
10336          * Called by framework to indicate the user rejected a dialog to switch to new network.
10337          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
10338          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
10339          * @param targetNetworkId Network ID of the target network.
10340          * @param targetBssid BSSID of the target network.
10341          */
onNetworkSwitchRejected( int sessionId, int targetNetworkId, @NonNull String targetBssid)10342         default void onNetworkSwitchRejected(
10343                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10344             // No-op.
10345         }
10346     }
10347 
10348 
10349     /**
10350      * Callback registered with {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
10351      * PnoScanResultsCallback)}. Returns status and result information on offloaded external PNO
10352      * requests.
10353      * @hide
10354      */
10355     @SystemApi
10356     public interface PnoScanResultsCallback {
10357         /**
10358          * A status code returned by {@link #onRegisterFailed(int)}.
10359          * Unknown failure.
10360          */
10361         int REGISTER_PNO_CALLBACK_UNKNOWN = 0;
10362 
10363         /**
10364          * A status code returned by {@link #onRegisterFailed(int)}.
10365          * A callback has already been registered by the caller.
10366          */
10367         int REGISTER_PNO_CALLBACK_ALREADY_REGISTERED = 1;
10368 
10369         /**
10370          * A status code returned by {@link #onRegisterFailed(int)}.
10371          * The platform is unable to serve this request because another app has a PNO scan request
10372          * active.
10373          */
10374         int REGISTER_PNO_CALLBACK_RESOURCE_BUSY = 2;
10375 
10376         /**
10377          * A status code returned by {@link #onRegisterFailed(int)}.
10378          * PNO scans are not supported on this device.
10379          */
10380         int REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED = 3;
10381 
10382         /** @hide */
10383         @IntDef(prefix = { "REGISTER_PNO_CALLBACK_" }, value = {
10384                 REGISTER_PNO_CALLBACK_UNKNOWN,
10385                 REGISTER_PNO_CALLBACK_ALREADY_REGISTERED,
10386                 REGISTER_PNO_CALLBACK_RESOURCE_BUSY,
10387                 REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED
10388         })
10389         @Retention(RetentionPolicy.SOURCE)
10390         public @interface RegisterFailureReason {}
10391 
10392         /**
10393          * A status code returned by {@link #onRemoved(int)}.
10394          * Unknown reason.
10395          */
10396         int REMOVE_PNO_CALLBACK_UNKNOWN = 0;
10397 
10398         /**
10399          * A status code returned by {@link #onRemoved(int)}.
10400          * This Callback is automatically removed after results ScanResults are delivered.
10401          */
10402         int REMOVE_PNO_CALLBACK_RESULTS_DELIVERED = 1;
10403 
10404         /**
10405          * A status code returned by {@link #onRemoved(int)}.
10406          * This callback has been unregistered via {@link WifiManager#clearExternalPnoScanRequest()}
10407          */
10408         int REMOVE_PNO_CALLBACK_UNREGISTERED = 2;
10409 
10410         /** @hide */
10411         @IntDef(prefix = { "REMOVE_PNO_CALLBACK_" }, value = {
10412                 REMOVE_PNO_CALLBACK_UNKNOWN,
10413                 REMOVE_PNO_CALLBACK_RESULTS_DELIVERED,
10414                 REMOVE_PNO_CALLBACK_UNREGISTERED
10415         })
10416         @Retention(RetentionPolicy.SOURCE)
10417         public @interface RemovalReason {}
10418 
10419         /**
10420          * Called when PNO scan finds one of the requested SSIDs. This is a one time callback.
10421          * After results are reported the callback will be automatically unregistered.
10422          */
onScanResultsAvailable(@onNull List<ScanResult> scanResults)10423         void onScanResultsAvailable(@NonNull List<ScanResult> scanResults);
10424 
10425         /**
10426          * Called when this callback has been successfully registered.
10427          */
onRegisterSuccess()10428         void onRegisterSuccess();
10429 
10430         /**
10431          * Called when this callback failed to register with the failure reason.
10432          * See {@link RegisterFailureReason} for details.
10433          */
onRegisterFailed(@egisterFailureReason int reason)10434         void onRegisterFailed(@RegisterFailureReason int reason);
10435 
10436         /**
10437          * Called when this callback has been unregistered from the Wi-Fi subsystem.
10438          * See {@link RemovalReason} for details.
10439          */
onRemoved(@emovalReason int reason)10440         void onRemoved(@RemovalReason int reason);
10441     }
10442 
10443 
10444     private class PnoScanResultsCallbackProxy extends IPnoScanResultsCallback.Stub {
10445         private Executor mExecutor;
10446         private PnoScanResultsCallback mCallback;
10447 
PnoScanResultsCallbackProxy(@onNull Executor executor, @NonNull PnoScanResultsCallback callback)10448         PnoScanResultsCallbackProxy(@NonNull Executor executor,
10449                 @NonNull PnoScanResultsCallback callback) {
10450             mExecutor = executor;
10451             mCallback = callback;
10452         }
10453 
10454         @Override
onScanResultsAvailable(List<ScanResult> scanResults)10455         public void onScanResultsAvailable(List<ScanResult> scanResults) {
10456             if (mVerboseLoggingEnabled) {
10457                 Log.v(TAG, "PnoScanResultsCallback: " + "onScanResultsAvailable");
10458             }
10459             Binder.clearCallingIdentity();
10460             mExecutor.execute(() -> mCallback.onScanResultsAvailable(scanResults));
10461         }
10462 
10463         @Override
onRegisterSuccess()10464         public void onRegisterSuccess() {
10465             if (mVerboseLoggingEnabled) {
10466                 Log.v(TAG, "PnoScanResultsCallback: " + "onRegisterSuccess");
10467             }
10468             Binder.clearCallingIdentity();
10469             mExecutor.execute(() -> mCallback.onRegisterSuccess());
10470         }
10471 
10472         @Override
onRegisterFailed(int reason)10473         public void onRegisterFailed(int reason) {
10474             if (mVerboseLoggingEnabled) {
10475                 Log.v(TAG, "PnoScanResultsCallback: " + "onRegisterFailed " + reason);
10476             }
10477             Binder.clearCallingIdentity();
10478             mExecutor.execute(() -> mCallback.onRegisterFailed(reason));
10479         }
10480 
10481         @Override
onRemoved(int reason)10482         public void onRemoved(int reason) {
10483             if (mVerboseLoggingEnabled) {
10484                 Log.v(TAG, "PnoScanResultsCallback: " + "onRemoved");
10485             }
10486             Binder.clearCallingIdentity();
10487             mExecutor.execute(() -> mCallback.onRemoved(reason));
10488         }
10489     }
10490 
10491     /**
10492      * Callback proxy for {@link WifiConnectedNetworkScorer} objects.
10493      *
10494      * @hide
10495      */
10496     private class WifiConnectedNetworkScorerProxy extends IWifiConnectedNetworkScorer.Stub {
10497         private Executor mExecutor;
10498         private WifiConnectedNetworkScorer mScorer;
10499 
WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer)10500         WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer) {
10501             mExecutor = executor;
10502             mScorer = scorer;
10503         }
10504 
10505         @Override
onStart(@onNull WifiConnectedSessionInfo sessionInfo)10506         public void onStart(@NonNull WifiConnectedSessionInfo sessionInfo) {
10507             if (mVerboseLoggingEnabled) {
10508                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionInfo=" + sessionInfo);
10509             }
10510             Binder.clearCallingIdentity();
10511             mExecutor.execute(() -> mScorer.onStart(sessionInfo));
10512         }
10513 
10514         @Override
onStop(int sessionId)10515         public void onStop(int sessionId) {
10516             if (mVerboseLoggingEnabled) {
10517                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
10518             }
10519             Binder.clearCallingIdentity();
10520             mExecutor.execute(() -> mScorer.onStop(sessionId));
10521         }
10522 
10523         @Override
onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl)10524         public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
10525             if (mVerboseLoggingEnabled) {
10526                 Log.v(TAG, "WifiConnectedNetworkScorer: "
10527                         + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
10528             }
10529             Binder.clearCallingIdentity();
10530             mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
10531                     new ScoreUpdateObserverProxy(observerImpl)));
10532         }
10533 
10534         @Override
onNetworkSwitchAccepted( int sessionId, int targetNetworkId, @NonNull String targetBssid)10535         public void onNetworkSwitchAccepted(
10536                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10537             if (mVerboseLoggingEnabled) {
10538                 Log.v(TAG, "WifiConnectedNetworkScorer: onNetworkSwitchAccepted:"
10539                         + " sessionId=" + sessionId
10540                         + " targetNetworkId=" + targetNetworkId
10541                         + " targetBssid=" + targetBssid);
10542             }
10543             Binder.clearCallingIdentity();
10544             mExecutor.execute(() -> mScorer.onNetworkSwitchAccepted(
10545                     sessionId, targetNetworkId, targetBssid));
10546         }
10547         @Override
onNetworkSwitchRejected( int sessionId, int targetNetworkId, @NonNull String targetBssid)10548         public void onNetworkSwitchRejected(
10549                 int sessionId, int targetNetworkId, @NonNull String targetBssid) {
10550             if (mVerboseLoggingEnabled) {
10551                 Log.v(TAG, "WifiConnectedNetworkScorer: onNetworkSwitchRejected:"
10552                                 + " sessionId=" + sessionId
10553                                 + " targetNetworkId=" + targetNetworkId
10554                                 + " targetBssid=" + targetBssid);
10555             }
10556             Binder.clearCallingIdentity();
10557             mExecutor.execute(() -> mScorer.onNetworkSwitchRejected(
10558                     sessionId, targetNetworkId, targetBssid));
10559         }
10560     }
10561 
10562     /**
10563      * This API allows the caller to program up to 2 SSIDs for PNO scans. PNO scans are offloaded
10564      * to the Wi-Fi chip when the device is inactive (typically screen-off).
10565      * If the screen is currently off when this API is called, then a PNO scan including the
10566      * requested SSIDs will immediately get started. If the screen is on when this API is called,
10567      * the requested SSIDs will get included for PNO scans the next time the screen turns off.
10568      * <p>
10569      * Note, due to PNO being a limited resource, only one external PNO request is supported, and
10570      * calling this API will fail if an external PNO scan request is already registered by another
10571      * caller. If the caller that has already registered a callback calls this API again, the new
10572      * callback will override the previous one.
10573      * <p>
10574      * After this API is called, {@link PnoScanResultsCallback#onRegisterSuccess()} will be invoked
10575      * if the operation is successful, or {@link PnoScanResultsCallback#onRegisterFailed(int)} will
10576      * be invoked if the operation failed.
10577      * <p>
10578      * {@link PnoScanResultsCallback#onRemoved(int)} will be invoked to notify the caller when the
10579      * external PNO scan request is removed, which will happen when one of the following events
10580      * happen:
10581      * </p>
10582      * <ul>
10583      * <li>Upon finding any of the requested SSIDs through either a connectivity scan or PNO scan,
10584      * the matching ScanResults will be returned
10585      * via {@link PnoScanResultsCallback#onScanResultsAvailable(List)}, and the registered PNO
10586      * scan request will get automatically removed.</li>
10587      * <li>The external PNO scan request is removed by a call to
10588      * {@link #clearExternalPnoScanRequest()}</li>
10589      * </ul>
10590      *
10591      * @param ssids The list of SSIDs to request for PNO scan.
10592      * @param frequencies Provide as hint a list of up to 10 frequencies to be used for PNO scan.
10593      *                    Each frequency should be in MHz. For example 2412 and 5180 are valid
10594      *                    frequencies. {@link WifiInfo#getFrequency()} is a location where this
10595      *                    information could be obtained. If a null or empty array is provided, the
10596      *                    Wi-Fi framework will automatically decide the list of frequencies to scan.
10597      * @param executor The executor on which callback will be invoked.
10598      * @param callback For the calling application to receive results and status updates.
10599      *
10600      * @throws SecurityException if the caller does not have permission.
10601      * @throws IllegalArgumentException if the caller provided invalid inputs.
10602      * @throws UnsupportedOperationException if this API is not supported on this SDK version.
10603      * @hide
10604      */
10605     @SystemApi
10606     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION,
10607             REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION})
10608     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setExternalPnoScanRequest(@onNull List<WifiSsid> ssids, @Nullable int[] frequencies, @NonNull @CallbackExecutor Executor executor, @NonNull PnoScanResultsCallback callback)10609     public void setExternalPnoScanRequest(@NonNull List<WifiSsid> ssids,
10610             @Nullable int[] frequencies, @NonNull @CallbackExecutor Executor executor,
10611             @NonNull PnoScanResultsCallback callback) {
10612         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
10613         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
10614         try {
10615             mService.setExternalPnoScanRequest(new Binder(),
10616                     new PnoScanResultsCallbackProxy(executor, callback),
10617                     ssids, frequencies == null ? new int[0] : frequencies,
10618                     mContext.getOpPackageName(), mContext.getAttributionTag());
10619         } catch (RemoteException e) {
10620             throw e.rethrowFromSystemServer();
10621         }
10622     }
10623 
10624     /**
10625      * Wi-Fi Preferred Network Offload (PNO) scanning offloads scanning to the chip to save power
10626      * when Wi-Fi is disconnected and the screen is off. See
10627      * {@link https://source.android.com/docs/core/connect/wifi-scan} for more details.
10628      * <p>
10629      * This API can be used to enable or disable PNO scanning. After boot, PNO scanning is enabled
10630      * by default. When PNO scanning is disabled, the Wi-Fi framework will not trigger scans at all
10631      * when the screen is off. This can be used to save power on devices with small batteries.
10632      *
10633      * @param enabled True - enable PNO scanning
10634      *                False - disable PNO scanning
10635      * @param enablePnoScanAfterWifiToggle True - Wifi being enabled by
10636      *                                     {@link #setWifiEnabled(boolean)} will re-enable PNO
10637      *                                     scanning.
10638      *                                     False - Wifi being enabled by
10639      *                                     {@link #setWifiEnabled(boolean)} will not re-enable PNO
10640      *                                     scanning.
10641      *
10642      * @throws SecurityException if the caller does not have permission.
10643      * @hide
10644      */
10645     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
10646     @SystemApi
10647     @RequiresPermission(
10648             anyOf = {MANAGE_WIFI_NETWORK_SELECTION, NETWORK_SETTINGS, NETWORK_SETUP_WIZARD})
setPnoScanState(@noScanState int pnoScanState)10649     public void setPnoScanState(@PnoScanState int pnoScanState) {
10650         try {
10651             boolean enabled = false;
10652             boolean enablePnoScanAfterWifiToggle = false;
10653             switch (pnoScanState) {
10654                 case PNO_SCAN_STATE_DISABLED_UNTIL_REBOOT:
10655                     break;
10656                 case PNO_SCAN_STATE_DISABLED_UNTIL_WIFI_TOGGLE:
10657                     enablePnoScanAfterWifiToggle = true;
10658                     break;
10659                 case PNO_SCAN_STATE_ENABLED:
10660                     enabled = true;
10661                     break;
10662                 default:
10663                     throw new IllegalArgumentException("Invalid PnoScanState");
10664             }
10665             mService.setPnoScanEnabled(enabled, enablePnoScanAfterWifiToggle,
10666                     mContext.getOpPackageName());
10667         } catch (RemoteException e) {
10668             throw e.rethrowFromSystemServer();
10669         }
10670     }
10671 
10672     /**
10673      * Wi-Fi Preferred Network Offload (PNO) scanning offloads scanning to the chip to save power
10674      * when Wi-Fi is disconnected and the screen is off. See
10675      * {@link https://source.android.com/docs/core/connect/wifi-scan} for more details.
10676      * <p>
10677      * This API can be used to enable or disable PNO scanning. After boot, PNO scanning is enabled
10678      * by default. When PNO scanning is disabled, the Wi-Fi framework will not trigger scans at all
10679      * when the screen is off. This can be used to save power on devices with small batteries.
10680      *
10681      * @param enabled True - enable PNO scanning
10682      *                False - disable PNO scanning
10683      * @param enablePnoScanAfterWifiToggle True - Wifi being enabled by
10684      *                                     {@link #setWifiEnabled(boolean)} will re-enable PNO
10685      *                                     scanning.
10686      *                                     False - Wifi being enabled by
10687      *                                     {@link #setWifiEnabled(boolean)} will not re-enable PNO
10688      *                                     scanning.
10689      *
10690      * @throws SecurityException if the caller does not have permission.
10691      * @hide
10692      */
10693     @RequiresPermission(
10694             anyOf = {MANAGE_WIFI_NETWORK_SELECTION, NETWORK_SETTINGS, NETWORK_SETUP_WIZARD})
setPnoScanEnabled(boolean enabled, boolean enablePnoScanAfterWifiToggle)10695     public void setPnoScanEnabled(boolean enabled, boolean enablePnoScanAfterWifiToggle) {
10696         try {
10697             mService.setPnoScanEnabled(enabled, enablePnoScanAfterWifiToggle,
10698                     mContext.getOpPackageName());
10699         } catch (RemoteException e) {
10700             throw e.rethrowFromSystemServer();
10701         }
10702     }
10703 
10704     /**
10705      * Clear the current PNO scan request that's been set by the calling UID. Note, the call will
10706      * be no-op if the current PNO scan request is set by a different UID.
10707      *
10708      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
10709      * @hide
10710      */
10711     @SystemApi
10712     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
clearExternalPnoScanRequest()10713     public void clearExternalPnoScanRequest() {
10714         try {
10715             mService.clearExternalPnoScanRequest();
10716         } catch (RemoteException e) {
10717             throw e.rethrowFromSystemServer();
10718         }
10719     }
10720 
10721     /**
10722      * Returns information about the last caller of an API.
10723      *
10724      * @param apiType The type of API to request information for the last caller.
10725      * @param executor The executor on which callback will be invoked.
10726      * @param resultsCallback An asynchronous callback that will return 2 arguments.
10727      *                        {@code String} the name of the package that performed the last API
10728      *                        call. {@code Boolean} the value associated with the last API call.
10729      *
10730      * @throws SecurityException if the caller does not have permission.
10731      * @throws IllegalArgumentException if the caller provided invalid inputs.
10732      * @hide
10733      */
10734     @SystemApi
10735     @RequiresPermission(anyOf = {
10736             android.Manifest.permission.NETWORK_SETTINGS,
10737             android.Manifest.permission.NETWORK_STACK,
10738             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
getLastCallerInfoForApi(@piType int apiType, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<String, Boolean> resultsCallback)10739     public void getLastCallerInfoForApi(@ApiType int apiType,
10740             @NonNull @CallbackExecutor Executor executor,
10741             @NonNull BiConsumer<String, Boolean> resultsCallback) {
10742         if (executor == null) {
10743             throw new IllegalArgumentException("executor can't be null");
10744         }
10745         if (resultsCallback == null) {
10746             throw new IllegalArgumentException("resultsCallback can't be null");
10747         }
10748         try {
10749             mService.getLastCallerInfoForApi(apiType,
10750                     new ILastCallerListener.Stub() {
10751                         @Override
10752                         public void onResult(String packageName, boolean enabled) {
10753                             Binder.clearCallingIdentity();
10754                             executor.execute(() -> {
10755                                 resultsCallback.accept(packageName, enabled);
10756                             });
10757                         }
10758                     });
10759         } catch (RemoteException e) {
10760             throw e.rethrowFromSystemServer();
10761         }
10762     }
10763 
10764     /**
10765      * Set a callback for Wi-Fi connected network scorer.  See {@link WifiConnectedNetworkScorer}.
10766      * Only a single scorer can be set. Caller will be invoked periodically by framework to inform
10767      * client about start and stop of Wi-Fi connection. Caller can clear a previously set scorer
10768      * using {@link clearWifiConnectedNetworkScorer()}.
10769      *
10770      * @param executor The executor on which callback will be invoked.
10771      * @param scorer Scorer for Wi-Fi network implemented by application.
10772      * @return true Scorer is set successfully.
10773      *
10774      * @hide
10775      */
10776     @SystemApi
10777     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
setWifiConnectedNetworkScorer(@onNull @allbackExecutor Executor executor, @NonNull WifiConnectedNetworkScorer scorer)10778     public boolean setWifiConnectedNetworkScorer(@NonNull @CallbackExecutor Executor executor,
10779             @NonNull WifiConnectedNetworkScorer scorer) {
10780         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
10781         if (scorer == null) throw new IllegalArgumentException("scorer cannot be null");
10782         if (mVerboseLoggingEnabled) {
10783             Log.v(TAG, "setWifiConnectedNetworkScorer: scorer=" + scorer);
10784         }
10785         try {
10786             return mService.setWifiConnectedNetworkScorer(new Binder(),
10787                     new WifiConnectedNetworkScorerProxy(executor, scorer));
10788         } catch (RemoteException e) {
10789             throw e.rethrowFromSystemServer();
10790         }
10791     }
10792 
10793     /**
10794      * Allow caller to clear a previously set scorer. After calling this method,
10795      * client will no longer receive information about start and stop of Wi-Fi connection.
10796      *
10797      * @hide
10798      */
10799     @SystemApi
10800     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
clearWifiConnectedNetworkScorer()10801     public void clearWifiConnectedNetworkScorer() {
10802         if (mVerboseLoggingEnabled) {
10803             Log.v(TAG, "clearWifiConnectedNetworkScorer");
10804         }
10805         try {
10806             mService.clearWifiConnectedNetworkScorer();
10807         } catch (RemoteException e) {
10808             throw e.rethrowFromSystemServer();
10809         }
10810     }
10811 
10812     /**
10813      * Enable/disable wifi scan throttling from 3rd party apps.
10814      *
10815      * <p>
10816      * The throttling limits for apps are described in
10817      * <a href="Wi-Fi Scan Throttling">
10818      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
10819      * </p>
10820      *
10821      * @param enable true to allow scan throttling, false to disallow scan throttling.
10822      * @hide
10823      */
10824     @SystemApi
10825     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanThrottleEnabled(boolean enable)10826     public void setScanThrottleEnabled(boolean enable) {
10827         try {
10828             mService.setScanThrottleEnabled(enable);
10829         } catch (RemoteException e) {
10830             throw e.rethrowFromSystemServer();
10831         }
10832     }
10833 
10834     /**
10835      * Get the persisted Wi-Fi scan throttle state. Defaults to true, unless changed by the user via
10836      * Developer options.
10837      *
10838      * <p>
10839      * The throttling limits for apps are described in
10840      * <a href="Wi-Fi Scan Throttling">
10841      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
10842      * </p>
10843      *
10844      * @return true to indicate that scan throttling is enabled, false to indicate that scan
10845      * throttling is disabled.
10846      */
10847     @RequiresPermission(ACCESS_WIFI_STATE)
isScanThrottleEnabled()10848     public boolean isScanThrottleEnabled() {
10849         try {
10850             return mService.isScanThrottleEnabled();
10851         } catch (RemoteException e) {
10852             throw e.rethrowFromSystemServer();
10853         }
10854     }
10855 
10856     /**
10857      * Enable/disable wifi auto wakeup feature.
10858      *
10859      * <p>
10860      * The feature is described in
10861      * <a href="Wi-Fi Turn on automatically">
10862      * https://source.android.com/devices/tech/connect/wifi-infrastructure
10863      * #turn_on_wi-fi_automatically
10864      * </a>
10865      *
10866      * @param enable true to enable, false to disable.
10867      * @hide
10868      */
10869     @SystemApi
10870     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setAutoWakeupEnabled(boolean enable)10871     public void setAutoWakeupEnabled(boolean enable) {
10872         try {
10873             mService.setAutoWakeupEnabled(enable);
10874         } catch (RemoteException e) {
10875             throw e.rethrowFromSystemServer();
10876         }
10877     }
10878 
10879     /**
10880      * Get the persisted Wi-Fi auto wakeup feature state. Defaults to false, unless changed by the
10881      * user via Settings.
10882      *
10883      * <p>
10884      * The feature is described in
10885      * <a href="Wi-Fi Turn on automatically">
10886      * https://source.android.com/devices/tech/connect/wifi-infrastructure
10887      * #turn_on_wi-fi_automatically
10888      * </a>
10889      *
10890      * @return true to indicate that wakeup feature is enabled, false to indicate that wakeup
10891      * feature is disabled.
10892      */
10893     @RequiresPermission(ACCESS_WIFI_STATE)
isAutoWakeupEnabled()10894     public boolean isAutoWakeupEnabled() {
10895         try {
10896             return mService.isAutoWakeupEnabled();
10897         } catch (RemoteException e) {
10898             throw e.rethrowFromSystemServer();
10899         }
10900     }
10901 
10902     /**
10903      * Sets the state of carrier offload on merged or unmerged networks for specified subscription.
10904      *
10905      * <p>
10906      * When a subscription's carrier network offload is disabled, all network suggestions related to
10907      * this subscription will not be considered for auto join.
10908      * <p>
10909      * If calling app want disable all carrier network offload from a specified subscription, should
10910      * call this API twice to disable both merged and unmerged carrier network suggestions.
10911      *
10912      * @param subscriptionId See {@link SubscriptionInfo#getSubscriptionId()}.
10913      * @param merged True for carrier merged network, false otherwise.
10914      *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
10915      * @param enabled True for enable carrier network offload, false otherwise.
10916      * @see #isCarrierNetworkOffloadEnabled(int, boolean)
10917      * @hide
10918      */
10919     @SystemApi
10920     @RequiresPermission(anyOf = {
10921             android.Manifest.permission.NETWORK_SETTINGS,
10922             android.Manifest.permission.NETWORK_SETUP_WIZARD})
setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged, boolean enabled)10923     public void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged,
10924             boolean enabled) {
10925         try {
10926             mService.setCarrierNetworkOffloadEnabled(subscriptionId, merged, enabled);
10927         } catch (RemoteException e) {
10928             throw e.rethrowFromSystemServer();
10929         }
10930     }
10931 
10932     /**
10933      * Get the carrier network offload state for merged or unmerged networks for specified
10934      * subscription.
10935      * @param subscriptionId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
10936      * @param merged True for carrier merged network, false otherwise.
10937      *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
10938      * @return True to indicate that carrier network offload is enabled, false otherwise.
10939      */
10940     @RequiresPermission(ACCESS_WIFI_STATE)
isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged)10941     public boolean isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged) {
10942         try {
10943             return mService.isCarrierNetworkOffloadEnabled(subscriptionId, merged);
10944         } catch (RemoteException e) {
10945             throw e.rethrowFromSystemServer();
10946         }
10947     }
10948 
10949     /**
10950      * Interface for network suggestion user approval status change listener.
10951      * Should be implemented by applications and registered using
10952      * {@link #addSuggestionUserApprovalStatusListener(Executor,
10953      * SuggestionUserApprovalStatusListener)} (
10954      */
10955     public interface SuggestionUserApprovalStatusListener {
10956 
10957         /**
10958          * Called when the user approval status of the App has changed.
10959          * @param status The current status code for the user approval. One of the
10960          *               {@code STATUS_SUGGESTION_APPROVAL_} values.
10961          */
onUserApprovalStatusChange(@uggestionUserApprovalStatus int status)10962         void onUserApprovalStatusChange(@SuggestionUserApprovalStatus int status);
10963     }
10964 
10965     private class SuggestionUserApprovalStatusListenerProxy extends
10966             ISuggestionUserApprovalStatusListener.Stub {
10967         private final Executor mExecutor;
10968         private final SuggestionUserApprovalStatusListener mListener;
10969 
SuggestionUserApprovalStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionUserApprovalStatusListener listener)10970         SuggestionUserApprovalStatusListenerProxy(@NonNull Executor executor,
10971                 @NonNull SuggestionUserApprovalStatusListener listener) {
10972             mExecutor = executor;
10973             mListener = listener;
10974         }
10975 
10976         @Override
onUserApprovalStatusChange(int status)10977         public void onUserApprovalStatusChange(int status) {
10978             mExecutor.execute(() -> mListener.onUserApprovalStatusChange(status));
10979         }
10980 
10981     }
10982 
10983     /**
10984      * Add a listener for Wi-Fi network suggestion user approval status.
10985      * See {@link SuggestionUserApprovalStatusListener}.
10986      * Caller will receive a callback immediately after adding a listener and when the user approval
10987      * status of the caller has changed.
10988      * Caller can remove a previously registered listener using
10989      * {@link WifiManager#removeSuggestionUserApprovalStatusListener(
10990      * SuggestionUserApprovalStatusListener)}
10991      * A caller can add multiple listeners to monitor the event.
10992      * @param executor The executor to execute the listener of the {@code listener} object.
10993      * @param listener listener for suggestion user approval status changes.
10994      */
10995     @RequiresPermission(ACCESS_WIFI_STATE)
addSuggestionUserApprovalStatusListener( @onNull @allbackExecutor Executor executor, @NonNull SuggestionUserApprovalStatusListener listener)10996     public void addSuggestionUserApprovalStatusListener(
10997             @NonNull @CallbackExecutor Executor executor,
10998             @NonNull SuggestionUserApprovalStatusListener listener) {
10999         if (listener == null) throw new NullPointerException("Listener cannot be null");
11000         if (executor == null) throw new NullPointerException("Executor cannot be null");
11001         Log.v(TAG, "addSuggestionUserApprovalStatusListener listener=" + listener
11002                 + ", executor=" + executor);
11003         try {
11004             synchronized (sSuggestionUserApprovalStatusListenerMap) {
11005                 ISuggestionUserApprovalStatusListener.Stub binderCallback =
11006                         new SuggestionUserApprovalStatusListenerProxy(executor, listener);
11007                 sSuggestionUserApprovalStatusListenerMap.put(System.identityHashCode(listener),
11008                         binderCallback);
11009                 mService.addSuggestionUserApprovalStatusListener(binderCallback,
11010                         mContext.getOpPackageName());
11011             }
11012         } catch (RemoteException e) {
11013             throw e.rethrowFromSystemServer();
11014         }
11015 
11016     }
11017 
11018     /**
11019      * Allow callers to remove a previously registered listener using
11020      * {@link #addSuggestionUserApprovalStatusListener(Executor,
11021      * SuggestionUserApprovalStatusListener)}. After calling this method,
11022      * applications will no longer receive network suggestion user approval status change through
11023      * that listener.
11024      */
11025     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionUserApprovalStatusListener( @onNull SuggestionUserApprovalStatusListener listener)11026     public void removeSuggestionUserApprovalStatusListener(
11027             @NonNull SuggestionUserApprovalStatusListener listener) {
11028         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
11029         Log.v(TAG, "removeSuggestionUserApprovalStatusListener: listener=" + listener);
11030         try {
11031             synchronized (sSuggestionUserApprovalStatusListenerMap) {
11032                 int listenerIdentifier = System.identityHashCode(listener);
11033                 if (!sSuggestionUserApprovalStatusListenerMap.contains(listenerIdentifier)) {
11034                     Log.w(TAG, "Unknown external callback " + listenerIdentifier);
11035                     return;
11036                 }
11037                 mService.removeSuggestionUserApprovalStatusListener(
11038                         sSuggestionUserApprovalStatusListenerMap.get(listenerIdentifier),
11039                         mContext.getOpPackageName());
11040                 sSuggestionUserApprovalStatusListenerMap.remove(listenerIdentifier);
11041             }
11042         } catch (RemoteException e) {
11043             throw e.rethrowFromSystemServer();
11044         }
11045     }
11046 
11047     /**
11048      * Indicates the start/end of an emergency scan request being processed by {@link WifiScanner}.
11049      * The wifi stack should ensure that the wifi chip remains on for the duration of the scan.
11050      * WifiScanner detects emergency scan requests via
11051      * {@link WifiScanner.ScanSettings#ignoreLocationSettings} flag.
11052      *
11053      * If the wifi stack is off (because location & wifi toggles are off) when this indication is
11054      * received, the wifi stack will temporarily move to a scan only mode. Since location toggle
11055      * is off, only scan with
11056      * {@link WifiScanner.ScanSettings#ignoreLocationSettings} flag set will be
11057      * allowed to be processed for this duration.
11058      *
11059      * @hide
11060      */
11061     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
setEmergencyScanRequestInProgress(boolean inProgress)11062     public void setEmergencyScanRequestInProgress(boolean inProgress) {
11063         try {
11064             mService.setEmergencyScanRequestInProgress(inProgress);
11065         } catch (RemoteException e) {
11066             throw e.rethrowFromSystemServer();
11067         }
11068     }
11069 
11070     /**
11071      * Enable or disable Wi-Fi scoring.  Wi-Fi network status is evaluated by Wi-Fi scoring
11072      * {@link WifiScoreReport}. This API enables/disables Wi-Fi scoring to take action on network
11073      * selection.
11074      *
11075      * @param enabled {@code true} to enable, {@code false} to disable.
11076      * @return true The status of Wifi scoring is set successfully.
11077      * @hide
11078      */
11079     @SystemApi
11080     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setWifiScoringEnabled(boolean enabled)11081     public boolean setWifiScoringEnabled(boolean enabled) {
11082         if (mVerboseLoggingEnabled) {
11083             Log.v(TAG, "setWifiScoringEnabled: " + enabled);
11084         }
11085         try {
11086             return mService.setWifiScoringEnabled(enabled);
11087         } catch (RemoteException e) {
11088             throw e.rethrowFromSystemServer();
11089         }
11090     }
11091 
11092     /**
11093      * Flush Passpoint ANQP cache, and clear pending ANQP requests. Allows the caller to reset the
11094      * Passpoint ANQP state, if required.
11095      *
11096      * Notes:
11097      * 1. Flushing the ANQP cache may cause delays in discovering and connecting to Passpoint
11098      * networks.
11099      * 2. Intended to be used by Device Owner (DO), Profile Owner (PO), Settings and provisioning
11100      * apps.
11101      */
11102     @RequiresPermission(anyOf = {
11103             android.Manifest.permission.NETWORK_SETTINGS,
11104             android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
11105             android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
11106             }, conditional = true)
flushPasspointAnqpCache()11107     public void flushPasspointAnqpCache() {
11108         try {
11109             mService.flushPasspointAnqpCache(mContext.getOpPackageName());
11110         } catch (RemoteException e) {
11111             throw e.rethrowFromSystemServer();
11112         }
11113     }
11114 
11115     /**
11116      * Returns a list of {@link WifiAvailableChannel} for the specified band and operational
11117      * mode(s), that is allowed for the current regulatory domain. An empty list implies that there
11118      * are no available channels for use.
11119      *
11120      * Note: the {@code band} parameter which is specified as a {@code WifiScanner#WIFI_BAND_*}
11121      * constant is limited to one of the band values specified below. Specifically, if the 5GHz
11122      * band is included then it must include the DFS channels - an exception will be thrown
11123      * otherwise. The caller should not make any assumptions about whether DFS channels are allowed.
11124      * This API will indicate whether DFS channels are allowed for the specified operation mode(s)
11125      * per device policy.
11126      *
11127      * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
11128      *             constants.
11129      *             1. {@code WifiScanner#WIFI_BAND_UNSPECIFIED}=0 - no band specified; Looks for the
11130      *                channels in all the available bands - 2.4 GHz, 5 GHz, 6 GHz and 60 GHz
11131      *             2. {@code WifiScanner#WIFI_BAND_24_GHZ}=1
11132      *             3. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}=6
11133      *             4. {@code WifiScanner#WIFI_BAND_BOTH_WITH_DFS}=7
11134      *             5. {@code WifiScanner#WIFI_BAND_6_GHZ}=8
11135      *             6. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_GHZ}=15
11136      *             7. {@code WifiScanner#WIFI_BAND_60_GHZ}=16
11137      *             8. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_60_GHZ}=31
11138      * @param mode Bitwise OR of {@code WifiAvailableChannel#OP_MODE_*} constants
11139      *        e.g. {@link WifiAvailableChannel#OP_MODE_WIFI_AWARE}
11140      * @return a list of {@link WifiAvailableChannel}
11141      *
11142      * @throws UnsupportedOperationException - if this API is not supported on this device
11143      *         or IllegalArgumentException - if the band specified is not one among the list
11144      *         of bands mentioned above.
11145      */
11146     @RequiresApi(Build.VERSION_CODES.S)
11147     @NonNull
11148     @RequiresPermission(NEARBY_WIFI_DEVICES)
getAllowedChannels( int band, @WifiAvailableChannel.OpMode int mode)11149     public List<WifiAvailableChannel> getAllowedChannels(
11150             int band,
11151             @WifiAvailableChannel.OpMode int mode) {
11152         if (!SdkLevel.isAtLeastS()) {
11153             throw new UnsupportedOperationException();
11154         }
11155         try {
11156             Bundle extras = new Bundle();
11157             if (SdkLevel.isAtLeastS()) {
11158                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
11159                         mContext.getAttributionSource());
11160             }
11161             return mService.getUsableChannels(band, mode,
11162                     WifiAvailableChannel.FILTER_REGULATORY, mContext.getOpPackageName(), extras);
11163         } catch (RemoteException e) {
11164             throw e.rethrowFromSystemServer();
11165         }
11166     }
11167 
11168     /**
11169      * Returns a list of {@link WifiAvailableChannel} for the specified band and operational
11170      * mode(s) per the current regulatory domain and device-specific constraints such as concurrency
11171      * state and interference due to other radios. An empty list implies that there are no available
11172      * channels for use.
11173      *
11174      * Note: the {@code band} parameter which is specified as a {@code WifiScanner#WIFI_BAND_*}
11175      * constant is limited to one of the band values specified below. Specifically, if the 5GHz
11176      * band is included then it must include the DFS channels - an exception will be thrown
11177      * otherwise. The caller should not make any assumptions about whether DFS channels are allowed.
11178      * This API will indicate whether DFS channels are allowed for the specified operation mode(s)
11179      * per device policy.
11180      *
11181      * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*}
11182      *             constants.
11183      *             1. {@code WifiScanner#WIFI_BAND_UNSPECIFIED}=0 - no band specified; Looks for the
11184      *                channels in all the available bands - 2.4 GHz, 5 GHz, 6 GHz and 60 GHz
11185      *             2. {@code WifiScanner#WIFI_BAND_24_GHZ}=1
11186      *             3. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS}=6
11187      *             4. {@code WifiScanner#WIFI_BAND_BOTH_WITH_DFS}=7
11188      *             5. {@code WifiScanner#WIFI_BAND_6_GHZ}=8
11189      *             6. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_GHZ}=15
11190      *             7. {@code WifiScanner#WIFI_BAND_60_GHZ}=16
11191      *             8. {@code WifiScanner#WIFI_BAND_24_5_WITH_DFS_6_60_GHZ}=31
11192      * @param mode Bitwise OR of {@code WifiAvailableChannel#OP_MODE_*} constants
11193      *        e.g. {@link WifiAvailableChannel#OP_MODE_WIFI_AWARE}
11194      * @return a list of {@link WifiAvailableChannel}
11195      *
11196      * @throws UnsupportedOperationException - if this API is not supported on this device
11197      *         or IllegalArgumentException - if the band specified is not one among the list
11198      *         of bands mentioned above.
11199      */
11200     @RequiresApi(Build.VERSION_CODES.S)
11201     @NonNull
11202     @RequiresPermission(NEARBY_WIFI_DEVICES)
getUsableChannels( int band, @WifiAvailableChannel.OpMode int mode)11203     public List<WifiAvailableChannel> getUsableChannels(
11204             int band,
11205             @WifiAvailableChannel.OpMode int mode) {
11206         if (!SdkLevel.isAtLeastS()) {
11207             throw new UnsupportedOperationException();
11208         }
11209         try {
11210             Bundle extras = new Bundle();
11211             if (SdkLevel.isAtLeastS()) {
11212                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
11213                         mContext.getAttributionSource());
11214             }
11215             return mService.getUsableChannels(band, mode,
11216                     WifiAvailableChannel.getUsableFilter(), mContext.getOpPackageName(), extras);
11217         } catch (RemoteException e) {
11218             throw e.rethrowFromSystemServer();
11219         }
11220     }
11221 
11222     /**
11223      * If the device supports Wi-Fi Passpoint, the user can explicitly enable or disable it.
11224      * That status can be queried using this method.
11225      * @return {@code true} if Wi-Fi Passpoint is enabled
11226      *
11227      */
11228     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiPasspointEnabled()11229     public boolean isWifiPasspointEnabled() {
11230         try {
11231             return mService.isWifiPasspointEnabled();
11232         } catch (RemoteException e) {
11233             throw e.rethrowFromSystemServer();
11234         }
11235     }
11236 
11237     /**
11238      * Explicitly enable or disable Wi-Fi Passpoint as a global switch.
11239      * The global Passpoint enabling/disabling overrides individual configuration
11240      * enabling/disabling.
11241      * Passpoint global status can be queried by {@link WifiManager#isWifiPasspointEnabled }.
11242      *
11243      * @param enabled {@code true} to enable, {@code false} to disable.
11244      * @hide
11245      */
11246     @SystemApi
11247     @RequiresPermission(anyOf = {
11248             android.Manifest.permission.NETWORK_SETTINGS,
11249             android.Manifest.permission.NETWORK_SETUP_WIZARD
11250     })
setWifiPasspointEnabled(boolean enabled)11251     public void setWifiPasspointEnabled(boolean enabled) {
11252         if (mVerboseLoggingEnabled) {
11253             Log.v(TAG, "setWifiPasspointEnabled: " + enabled);
11254         }
11255         try {
11256             mService.setWifiPasspointEnabled(enabled);
11257         } catch (RemoteException e) {
11258             throw e.rethrowFromSystemServer();
11259         }
11260     }
11261 
11262     /**
11263      * The device may support concurrent connections to multiple internet-providing Wi-Fi
11264      * networks (APs) - that is indicated by
11265      * {@link WifiManager#isStaConcurrencyForMultiInternetSupported()}.
11266      * This method indicates whether or not the feature is currently enabled.
11267      * A value of {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DISABLED} indicates that the feature
11268      * is disabled, a value of {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DBS_AP} or
11269      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_MULTI_AP} indicates that the feature is enabled.
11270      *
11271      * The app can register to receive the corresponding Wi-Fi networks using the
11272      * {@link ConnectivityManager#registerNetworkCallback(NetworkRequest, NetworkCallback)} API with
11273      * a {@link WifiNetworkSpecifier} configured using the
11274      * {@link WifiNetworkSpecifier.Builder#setBand(int)} method.
11275      */
11276     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11277     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getStaConcurrencyForMultiInternetMode()11278     public @WifiMultiInternetMode int getStaConcurrencyForMultiInternetMode() {
11279         try {
11280             return mService.getStaConcurrencyForMultiInternetMode();
11281         } catch (RemoteException e) {
11282             throw e.rethrowFromSystemServer();
11283         }
11284     }
11285 
11286     /**
11287      * Check if the currently connected network meets the minimum required Wi-Fi security level set.
11288      * If not, the current network will be disconnected.
11289      *
11290      * @throws SecurityException if the caller does not have permission.
11291      * @hide
11292      */
11293     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11294     @SystemApi
11295     @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
notifyMinimumRequiredWifiSecurityLevelChanged(int level)11296     public void notifyMinimumRequiredWifiSecurityLevelChanged(int level) {
11297         if (mVerboseLoggingEnabled) {
11298             Log.v(TAG, "notifyMinimumRequiredWifiSecurityLevelChanged");
11299         }
11300         try {
11301             mService.notifyMinimumRequiredWifiSecurityLevelChanged(level);
11302         } catch (RemoteException e) {
11303             throw e.rethrowFromSystemServer();
11304         }
11305     }
11306 
11307     /**
11308      * Check if the currently connected network meets the Wi-Fi SSID policy set.
11309      * If not, the current network will be disconnected.
11310      *
11311      * @throws SecurityException if the caller does not have permission.
11312      * @hide
11313      */
11314     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11315     @SystemApi
11316     @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
notifyWifiSsidPolicyChanged(@onNull WifiSsidPolicy policy)11317     public void notifyWifiSsidPolicyChanged(@NonNull WifiSsidPolicy policy) {
11318         if (mVerboseLoggingEnabled) {
11319             Log.v(TAG, "notifyWifiSsidPolicyChanged");
11320         }
11321         try {
11322             if (policy != null) {
11323                 mService.notifyWifiSsidPolicyChanged(
11324                         policy.getPolicyType(), new ArrayList<>(policy.getSsids()));
11325             }
11326         } catch (RemoteException e) {
11327             throw e.rethrowFromSystemServer();
11328         }
11329     }
11330 
11331     /**
11332      * Configure whether or not concurrent multiple connections to internet-providing Wi-Fi
11333      * networks (AP) is enabled.
11334      * Use {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DISABLED} to disable, and either
11335      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_DBS_AP} or
11336      * {@link WifiManager#WIFI_MULTI_INTERNET_MODE_MULTI_AP} to enable in different modes.
11337      * The {@link WifiManager#getStaConcurrencyForMultiInternetMode() } can be used to retrieve
11338      * the current mode.
11339      *
11340      * @param mode Multi internet mode.
11341      * @return true when the mode is set successfully, false when failed.
11342      * @hide
11343      */
11344     @SystemApi
11345     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11346     @RequiresPermission(anyOf = {
11347             android.Manifest.permission.NETWORK_SETTINGS,
11348             android.Manifest.permission.NETWORK_SETUP_WIZARD
11349     })
setStaConcurrencyForMultiInternetMode(@ifiMultiInternetMode int mode)11350     public boolean setStaConcurrencyForMultiInternetMode(@WifiMultiInternetMode int mode) {
11351         if (mVerboseLoggingEnabled) {
11352             Log.v(TAG, "setStaConcurrencyForMultiInternetMode: " + mode);
11353         }
11354         try {
11355             return mService.setStaConcurrencyForMultiInternetMode(mode);
11356         } catch (RemoteException e) {
11357             throw e.rethrowFromSystemServer();
11358         }
11359     }
11360 
11361     /**
11362      * Intent action to launch a dialog from the WifiDialog app.
11363      * Must include EXTRA_DIALOG_ID, EXTRA_DIALOG_TYPE, and appropriate extras for the dialog type.
11364      * @hide
11365      */
11366     public static final String ACTION_LAUNCH_DIALOG =
11367             "android.net.wifi.action.LAUNCH_DIALOG";
11368 
11369     /**
11370      * Intent action to dismiss an existing dialog from the WifiDialog app.
11371      * Must include EXTRA_DIALOG_ID.
11372      * @hide
11373      */
11374     public static final String ACTION_DISMISS_DIALOG =
11375             "android.net.wifi.action.DISMISS_DIALOG";
11376 
11377     /**
11378      * Unknown DialogType.
11379      * @hide
11380      */
11381     public static final int DIALOG_TYPE_UNKNOWN = 0;
11382 
11383     /**
11384      * DialogType for a simple dialog.
11385      * @see {@link com.android.server.wifi.WifiDialogManager#createSimpleDialog}
11386      * @hide
11387      */
11388     public static final int DIALOG_TYPE_SIMPLE = 1;
11389 
11390     /**
11391      * DialogType for a P2P Invitation Sent dialog.
11392      * @see {@link com.android.server.wifi.WifiDialogManager#createP2pInvitationSentDialog}
11393      * @hide
11394      */
11395     public static final int DIALOG_TYPE_P2P_INVITATION_SENT = 2;
11396 
11397     /**
11398      * DialogType for a P2P Invitation Received dialog.
11399      * @see {@link com.android.server.wifi.WifiDialogManager#createP2pInvitationReceivedDialog}
11400      * @hide
11401      */
11402     public static final int DIALOG_TYPE_P2P_INVITATION_RECEIVED = 3;
11403 
11404     /** @hide */
11405     @IntDef(prefix = { "DIALOG_TYPE_" }, value = {
11406             DIALOG_TYPE_UNKNOWN,
11407             DIALOG_TYPE_SIMPLE,
11408             DIALOG_TYPE_P2P_INVITATION_SENT,
11409             DIALOG_TYPE_P2P_INVITATION_RECEIVED,
11410     })
11411     @Retention(RetentionPolicy.SOURCE)
11412     public @interface DialogType {}
11413 
11414     /**
11415      * Dialog positive button was clicked.
11416      * @hide
11417      */
11418     public static final int DIALOG_REPLY_POSITIVE = 0;
11419 
11420     /**
11421      * Dialog negative button was clicked.
11422      * @hide
11423      */
11424     public static final int DIALOG_REPLY_NEGATIVE = 1;
11425 
11426     /**
11427      * Dialog neutral button was clicked.
11428      * @hide
11429      */
11430     public static final int DIALOG_REPLY_NEUTRAL = 2;
11431 
11432     /**
11433      * Dialog was cancelled.
11434      * @hide
11435      */
11436     public static final int DIALOG_REPLY_CANCELLED = 3;
11437 
11438     /**
11439      * Indication of a reply to a dialog.
11440      * See {@link WifiManager#replyToSimpleDialog(int, int)}
11441      * @hide
11442      */
11443     @IntDef(prefix = { "DIALOG_TYPE_" }, value = {
11444             DIALOG_REPLY_POSITIVE,
11445             DIALOG_REPLY_NEGATIVE,
11446             DIALOG_REPLY_NEUTRAL,
11447             DIALOG_REPLY_CANCELLED,
11448     })
11449     @Retention(RetentionPolicy.SOURCE)
11450     public @interface DialogReply {}
11451 
11452     /**
11453      * Invalid dialog id for dialogs that are not currently active.
11454      * @hide
11455      */
11456     public static final int INVALID_DIALOG_ID = -1;
11457 
11458     /**
11459      * Extra int indicating the type of dialog to display.
11460      * @hide
11461      */
11462     public static final String EXTRA_DIALOG_TYPE = "android.net.wifi.extra.DIALOG_TYPE";
11463 
11464     /**
11465      * Extra int indicating the ID of a dialog. The value must not be {@link #INVALID_DIALOG_ID}.
11466      * @hide
11467      */
11468     public static final String EXTRA_DIALOG_ID = "android.net.wifi.extra.DIALOG_ID";
11469 
11470     /**
11471      * Extra String indicating the title of a simple dialog.
11472      * @hide
11473      */
11474     public static final String EXTRA_DIALOG_TITLE = "android.net.wifi.extra.DIALOG_TITLE";
11475 
11476     /**
11477      * Extra String indicating the message of a simple dialog.
11478      * @hide
11479      */
11480     public static final String EXTRA_DIALOG_MESSAGE = "android.net.wifi.extra.DIALOG_MESSAGE";
11481 
11482     /**
11483      * Extra String indicating the message URL of a simple dialog.
11484      * @hide
11485      */
11486     public static final String EXTRA_DIALOG_MESSAGE_URL =
11487             "android.net.wifi.extra.DIALOG_MESSAGE_URL";
11488 
11489     /**
11490      * Extra String indicating the start index of a message URL span of a simple dialog.
11491      * @hide
11492      */
11493     public static final String EXTRA_DIALOG_MESSAGE_URL_START =
11494             "android.net.wifi.extra.DIALOG_MESSAGE_URL_START";
11495 
11496     /**
11497      * Extra String indicating the end index of a message URL span of a simple dialog.
11498      * @hide
11499      */
11500     public static final String EXTRA_DIALOG_MESSAGE_URL_END =
11501             "android.net.wifi.extra.DIALOG_MESSAGE_URL_END";
11502 
11503     /**
11504      * Extra String indicating the positive button text of a simple dialog.
11505      * @hide
11506      */
11507     public static final String EXTRA_DIALOG_POSITIVE_BUTTON_TEXT =
11508             "android.net.wifi.extra.DIALOG_POSITIVE_BUTTON_TEXT";
11509 
11510     /**
11511      * Extra String indicating the negative button text of a simple dialog.
11512      * @hide
11513      */
11514     public static final String EXTRA_DIALOG_NEGATIVE_BUTTON_TEXT =
11515             "android.net.wifi.extra.DIALOG_NEGATIVE_BUTTON_TEXT";
11516 
11517     /**
11518      * Extra String indicating the neutral button text of a simple dialog.
11519      * @hide
11520      */
11521     public static final String EXTRA_DIALOG_NEUTRAL_BUTTON_TEXT =
11522             "android.net.wifi.extra.DIALOG_NEUTRAL_BUTTON_TEXT";
11523 
11524     /**
11525      * Extra long indicating the timeout in milliseconds of a dialog.
11526      * @hide
11527      */
11528     public static final String EXTRA_DIALOG_TIMEOUT_MS = "android.net.wifi.extra.DIALOG_TIMEOUT_MS";
11529 
11530     /**
11531      * Extra String indicating a P2P device name for a P2P Invitation Sent/Received dialog.
11532      * @hide
11533      */
11534     public static final String EXTRA_P2P_DEVICE_NAME = "android.net.wifi.extra.P2P_DEVICE_NAME";
11535 
11536     /**
11537      * Extra boolean indicating that a PIN is requested for a P2P Invitation Received dialog.
11538      * @hide
11539      */
11540     public static final String EXTRA_P2P_PIN_REQUESTED = "android.net.wifi.extra.P2P_PIN_REQUESTED";
11541 
11542     /**
11543      * Extra String indicating the PIN to be displayed for a P2P Invitation Sent/Received dialog.
11544      * @hide
11545      */
11546     public static final String EXTRA_P2P_DISPLAY_PIN = "android.net.wifi.extra.P2P_DISPLAY_PIN";
11547 
11548     /**
11549      * Extra boolean indicating ACTION_CLOSE_SYSTEM_DIALOGS should not close the Wi-Fi dialogs.
11550      * @hide
11551      */
11552     public static final String EXTRA_CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI =
11553             "android.net.wifi.extra.CLOSE_SYSTEM_DIALOGS_EXCEPT_WIFI";
11554 
11555     /**
11556      * Returns a set of packages that aren't DO or PO but should be able to manage WiFi networks.
11557      * @hide
11558      */
11559     @SystemApi
11560     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
11561     @NonNull
getOemPrivilegedWifiAdminPackages()11562     public Set<String> getOemPrivilegedWifiAdminPackages() {
11563         try {
11564             return new ArraySet<>(mService.getOemPrivilegedWifiAdminPackages());
11565         } catch (RemoteException e) {
11566             throw e.rethrowFromSystemServer();
11567         }
11568     }
11569 
11570     /**
11571      * Method for WifiDialog to notify the framework of a reply to a simple dialog.
11572      * @param dialogId id of the replying dialog.
11573      * @param reply reply of the dialog.
11574      * @hide
11575      */
replyToSimpleDialog(int dialogId, @DialogReply int reply)11576     public void replyToSimpleDialog(int dialogId, @DialogReply int reply) {
11577         if (mVerboseLoggingEnabled) {
11578             Log.v(TAG, "replyToWifiEnableRequestDialog: dialogId=" + dialogId
11579                     + " reply=" + reply);
11580         }
11581         try {
11582             mService.replyToSimpleDialog(dialogId, reply);
11583         } catch (RemoteException e) {
11584             throw e.rethrowFromSystemServer();
11585         }
11586     }
11587 
11588     /**
11589      * Method for WifiDialog to notify the framework of a reply to a P2P Invitation Received dialog.
11590      * @param dialogId id of the replying dialog.
11591      * @param accepted Whether the invitation was accepted.
11592      * @param optionalPin PIN of the reply, or {@code null} if none was supplied.
11593      * @hide
11594      */
replyToP2pInvitationReceivedDialog( int dialogId, boolean accepted, @Nullable String optionalPin)11595     public void replyToP2pInvitationReceivedDialog(
11596             int dialogId, boolean accepted, @Nullable String optionalPin) {
11597         if (mVerboseLoggingEnabled) {
11598             Log.v(TAG, "replyToP2pInvitationReceivedDialog: "
11599                     + "dialogId=" + dialogId
11600                     + ", accepted=" + accepted
11601                     + ", pin=" + optionalPin);
11602         }
11603         try {
11604             mService.replyToP2pInvitationReceivedDialog(dialogId, accepted, optionalPin);
11605         } catch (RemoteException e) {
11606             throw e.rethrowFromSystemServer();
11607         }
11608     }
11609 
11610     /**
11611      * Specify a list of DHCP options to use for any network whose SSID is specified and which
11612      * transmits vendor-specific information elements (VSIEs) using the specified Organizationally
11613      * Unique Identifier (OUI). If the AP transmits VSIEs for multiple specified OUIs then all
11614      * matching DHCP options will be used. The allowlist for DHCP options in
11615      * {@link android.net.ip.IpClient} gates whether the DHCP options will actually be used.
11616      * When DHCP options are used: if the option value {@link android.net.DhcpOption#getValue()}
11617      * is null, the option type {@link android.net.DhcpOption#getType()} will be put in the
11618      * Parameter Request List in the DHCP packets; otherwise, the option will be included in the
11619      * options section in the DHCP packets. Use {@link #removeCustomDhcpOptions(Object, Object)}
11620      * to remove the specified DHCP options.
11621      *
11622      * @param ssid the network SSID.
11623      * @param oui the 3-byte OUI.
11624      * @param options the list of {@link android.net.DhcpOption}.
11625      *
11626      * @hide
11627      */
11628     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
11629     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11630     @RequiresPermission(anyOf = {
11631             android.Manifest.permission.NETWORK_SETTINGS,
11632             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
11633     })
addCustomDhcpOptions(@onNull WifiSsid ssid, @NonNull byte[] oui, @NonNull List<DhcpOption> options)11634     public void addCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui,
11635             @NonNull List<DhcpOption> options) {
11636         try {
11637             mService.addCustomDhcpOptions(ssid, oui, options);
11638         } catch (RemoteException e) {
11639             throw e.rethrowFromSystemServer();
11640         }
11641     }
11642 
11643     /**
11644      * Remove custom DHCP options specified by {@link #addCustomDhcpOptions(Object, Object, List)}.
11645      *
11646      * @param ssid the network SSID.
11647      * @param oui the 3-byte OUI.
11648      *
11649      * @hide
11650      */
11651     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
11652     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11653     @RequiresPermission(anyOf = {
11654             android.Manifest.permission.NETWORK_SETTINGS,
11655             android.Manifest.permission.OVERRIDE_WIFI_CONFIG
11656     })
removeCustomDhcpOptions(@onNull WifiSsid ssid, @NonNull byte[] oui)11657     public void removeCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui) {
11658         try {
11659             mService.removeCustomDhcpOptions(ssid, oui);
11660         } catch (RemoteException e) {
11661             throw e.rethrowFromSystemServer();
11662         }
11663     }
11664 
11665     /**
11666      * Wi-Fi interface of type STA (station/client Wi-Fi infrastructure device).
11667      */
11668     public static final int WIFI_INTERFACE_TYPE_STA = 0;
11669 
11670     /**
11671      * Wi-Fi interface of type AP (access point Wi-Fi infrastructure device).
11672      */
11673     public static final int WIFI_INTERFACE_TYPE_AP = 1;
11674 
11675     /**
11676      * Wi-Fi interface of type Wi-Fi Aware (aka NAN).
11677      */
11678     public static final int WIFI_INTERFACE_TYPE_AWARE = 2;
11679 
11680     /**
11681      * Wi-Fi interface of type Wi-Fi Direct (aka P2P).
11682      */
11683     public static final int WIFI_INTERFACE_TYPE_DIRECT = 3;
11684 
11685     /** @hide */
11686     @IntDef(prefix = { "WIFI_INTERFACE_TYPE_" }, value = {
11687             WIFI_INTERFACE_TYPE_STA,
11688             WIFI_INTERFACE_TYPE_AP,
11689             WIFI_INTERFACE_TYPE_AWARE,
11690             WIFI_INTERFACE_TYPE_DIRECT,
11691     })
11692     @Retention(RetentionPolicy.SOURCE)
11693     public @interface WifiInterfaceType {}
11694 
11695     /**
11696      * Class describing an impact of interface creation - returned by
11697      * {@link #reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)}. Due to Wi-Fi
11698      * concurrency limitations certain interfaces may have to be torn down. Each of these
11699      * interfaces was requested by a set of applications who could potentially be impacted.
11700      *
11701      * This class contain the information for a single interface: the interface type with
11702      * {@link InterfaceCreationImpact#getInterfaceType()} and the set of impacted packages
11703      * with {@link InterfaceCreationImpact#getPackages()}.
11704      */
11705     public static class InterfaceCreationImpact {
11706         private final int mInterfaceType;
11707         private final Set<String> mPackages;
11708 
InterfaceCreationImpact(@ifiInterfaceType int interfaceType, @NonNull Set<String> packages)11709         public InterfaceCreationImpact(@WifiInterfaceType int interfaceType,
11710                 @NonNull Set<String> packages) {
11711             mInterfaceType = interfaceType;
11712             mPackages = packages;
11713         }
11714 
11715         /**
11716          * @return The interface type which will be torn down to make room for the interface
11717          * requested in {@link #reportCreateInterfaceImpact(int, boolean, Executor, BiConsumer)}.
11718          */
getInterfaceType()11719         public @WifiInterfaceType int getInterfaceType() {
11720             return mInterfaceType;
11721         }
11722 
11723         /**
11724          * @return The list of potentially impacted packages due to tearing down the interface
11725          * specified in {@link #getInterfaceType()}.
11726          */
getPackages()11727         public @NonNull Set<String> getPackages() {
11728             return mPackages;
11729         }
11730 
11731         @Override
hashCode()11732         public int hashCode() {
11733             return Objects.hash(mInterfaceType, mPackages);
11734         }
11735 
11736         @Override
equals(Object that)11737         public boolean equals(Object that) {
11738             if (this == that) return true;
11739             if (!(that instanceof InterfaceCreationImpact)) return false;
11740             InterfaceCreationImpact thatInterfaceCreationImpact = (InterfaceCreationImpact) that;
11741 
11742             return this.mInterfaceType == thatInterfaceCreationImpact.mInterfaceType
11743                     && Objects.equals(this.mPackages, thatInterfaceCreationImpact.mPackages);
11744         }
11745     }
11746 
11747     /**
11748      * Queries the framework to determine whether the specified interface can be created, and if
11749      * so - what other interfaces would be torn down by the framework to allow this creation if
11750      * it were requested. The result is returned via the specified {@link BiConsumer} callback
11751      * which returns two arguments:
11752      * <li>First argument: a {@code boolean} - indicating whether or not the interface can be
11753      * created.</li>
11754      * <li>Second argument: a {@code Set<InterfaceCreationImpact>} - if the interface can be
11755      * created (first argument is {@code true} then this is the set of interface types which
11756      * will be removed and the packages which requested them. Possibly an empty set. If the
11757      * first argument is {@code false}, then an empty set will be returned here.</li>
11758      * <p>
11759      * Interfaces, input and output, are specified using the {@code WIFI_INTERFACE_*} constants:
11760      * {@link #WIFI_INTERFACE_TYPE_STA}, {@link #WIFI_INTERFACE_TYPE_AP},
11761      * {@link #WIFI_INTERFACE_TYPE_AWARE}, or {@link #WIFI_INTERFACE_TYPE_DIRECT}.
11762      * <p>
11763      * This method does not actually create the interface. That operation is handled by the
11764      * framework when a particular service method is called. E.g. a Wi-Fi Direct interface may be
11765      * created when various methods of {@link android.net.wifi.p2p.WifiP2pManager} are called,
11766      * similarly for Wi-Fi Aware and {@link android.net.wifi.aware.WifiAwareManager}.
11767      * <p>
11768      * Note: the information returned via this method is the current snapshot of the system. It may
11769      * change due to actions of the framework or other apps.
11770      *
11771      * @param interfaceType The interface type whose possible creation is being queried.
11772      * @param requireNewInterface Indicates that the query is for a new interface of the specified
11773      *                             type - an existing interface won't meet the query. Some
11774      *                             operations (such as Wi-Fi Direct and Wi-Fi Aware are a shared
11775      *                             resource and so may not need a new interface).
11776      * @param executor An {@link Executor} on which to return the result.
11777      * @param resultCallback The asynchronous callback which will return two argument: a
11778      * {@code boolean} (whether the interface can be created), and a
11779      * {@code Set<InterfaceCreationImpact>} (a set of {@link InterfaceCreationImpact}:
11780      *                       interfaces which will be destroyed when the interface is created
11781      *                       and the packages which requested them and thus may be impacted).
11782      */
11783     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11784     @RequiresPermission(allOf = {android.Manifest.permission.MANAGE_WIFI_INTERFACES,
11785             ACCESS_WIFI_STATE})
reportCreateInterfaceImpact(@ifiInterfaceType int interfaceType, boolean requireNewInterface, @NonNull @CallbackExecutor Executor executor, @NonNull BiConsumer<Boolean, Set<InterfaceCreationImpact>> resultCallback)11786     public void reportCreateInterfaceImpact(@WifiInterfaceType int interfaceType,
11787             boolean requireNewInterface,
11788             @NonNull @CallbackExecutor Executor executor,
11789             @NonNull BiConsumer<Boolean, Set<InterfaceCreationImpact>> resultCallback) {
11790         Objects.requireNonNull(executor, "Non-null executor required");
11791         Objects.requireNonNull(resultCallback, "Non-null resultCallback required");
11792         try {
11793             mService.reportCreateInterfaceImpact(mContext.getOpPackageName(), interfaceType,
11794                     requireNewInterface, new IInterfaceCreationInfoCallback.Stub() {
11795                         @Override
11796                         public void onResults(boolean canCreate, int[] interfacesToDelete,
11797                                 String[] packagesForInterfaces) {
11798                             Binder.clearCallingIdentity();
11799                             if ((interfacesToDelete == null && packagesForInterfaces != null)
11800                                     || (interfacesToDelete != null
11801                                     && packagesForInterfaces == null) || (canCreate && (
11802                                     interfacesToDelete == null || interfacesToDelete.length
11803                                             != packagesForInterfaces.length))) {
11804                                 Log.e(TAG,
11805                                         "reportImpactToCreateIfaceRequest: Invalid callback "
11806                                                 + "parameters - canCreate="
11807                                                 + canCreate + ", interfacesToDelete="
11808                                                 + Arrays.toString(interfacesToDelete)
11809                                                 + ", worksourcesForInterfaces="
11810                                                 + Arrays.toString(packagesForInterfaces));
11811                                 return;
11812                             }
11813 
11814                             final Set<InterfaceCreationImpact> finalSet =
11815                                     (canCreate && interfacesToDelete.length > 0) ? new ArraySet<>()
11816                                             : Collections.emptySet();
11817                             if (canCreate) {
11818                                 for (int i = 0; i < interfacesToDelete.length; ++i) {
11819                                     finalSet.add(
11820                                             new InterfaceCreationImpact(interfacesToDelete[i],
11821                                                     packagesForInterfaces[i] == null
11822                                                             ? Collections.emptySet()
11823                                                             : new ArraySet<>(
11824                                                                     packagesForInterfaces[i]
11825                                                                             .split(","))));
11826                                 }
11827                             }
11828                             executor.execute(() -> resultCallback.accept(canCreate, finalSet));
11829                         }
11830                     });
11831         } catch (RemoteException e) {
11832             throw e.rethrowFromSystemServer();
11833         }
11834     }
11835 
11836     /**
11837      * Returns the max number of channels that is allowed to be set on a
11838      * {@link WifiNetworkSpecifier}.
11839      * @see WifiNetworkSpecifier.Builder#setPreferredChannelsFrequenciesMhz(int[])
11840      *
11841      * @return The max number of channels can be set on a request.
11842      */
11843 
getMaxNumberOfChannelsPerNetworkSpecifierRequest()11844     public int getMaxNumberOfChannelsPerNetworkSpecifierRequest() {
11845         try {
11846             return mService.getMaxNumberOfChannelsPerRequest();
11847         } catch (RemoteException e) {
11848             throw e.rethrowFromSystemServer();
11849         }
11850     }
11851 
11852     /**
11853      * Add a list of new application-initiated QoS policies.
11854      *
11855      * Note: Policies are managed using a policy ID, which can be retrieved using
11856      *       {@link QosPolicyParams#getPolicyId()}. This ID can be used when removing a policy via
11857      *       {@link #removeQosPolicies(int[])}. The caller is in charge of assigning and managing
11858      *       the policy IDs for any requested policies.
11859      *
11860      * Note: Policies with duplicate IDs are not allowed. To update an existing policy, first
11861      *       remove it using {@link #removeQosPolicies(int[])}, and then re-add it using this API.
11862      *
11863      * Note: All policies in a single request must have the same {@link QosPolicyParams.Direction}.
11864      *
11865      * Note: Support for the {@link QosPolicyParams#DIRECTION_UPLINK} direction is added in
11866      *       {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM}. For earlier releases,
11867      *       only the {@link QosPolicyParams#DIRECTION_DOWNLINK} direction is supported.
11868      *
11869      * @param policyParamsList List of {@link QosPolicyParams} objects describing the requested
11870      *                         policies. Must have a maximum length of
11871      *                         {@link #getMaxNumberOfPoliciesPerQosRequest()}.
11872      * @param executor The executor on which callback will be invoked.
11873      * @param resultsCallback An asynchronous callback that will return a list of integer status
11874      *                        codes from {@link QosRequestStatus}. Result list will be the same
11875      *                        length as the input list, and each status code will correspond to
11876      *                        the policy at that index in the input list.
11877      *
11878      * @throws SecurityException if caller does not have the required permissions.
11879      * @throws NullPointerException if the caller provided a null input.
11880      * @throws UnsupportedOperationException if the feature is not enabled.
11881      * @throws IllegalArgumentException if the input list is invalid.
11882      * @hide
11883      */
11884     @SystemApi
11885     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11886     @RequiresPermission(anyOf = {
11887             android.Manifest.permission.NETWORK_SETTINGS,
11888             MANAGE_WIFI_NETWORK_SELECTION
11889     })
addQosPolicies(@onNull List<QosPolicyParams> policyParamsList, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<List<Integer>> resultsCallback)11890     public void addQosPolicies(@NonNull List<QosPolicyParams> policyParamsList,
11891             @NonNull @CallbackExecutor Executor executor,
11892             @NonNull Consumer<List<Integer>> resultsCallback) {
11893         Objects.requireNonNull(policyParamsList, "policyParamsList cannot be null");
11894         Objects.requireNonNull(executor, "executor cannot be null");
11895         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
11896         try {
11897             mService.addQosPolicies(policyParamsList, new Binder(), mContext.getOpPackageName(),
11898                     new IListListener.Stub() {
11899                         @Override
11900                         public void onResult(List value) {
11901                             Binder.clearCallingIdentity();
11902                             executor.execute(() -> {
11903                                 resultsCallback.accept(value);
11904                             });
11905                         }
11906                     });
11907         } catch (RemoteException e) {
11908             throw e.rethrowFromSystemServer();
11909         }
11910     }
11911 
11912     /**
11913      * Remove a list of existing application-initiated QoS policies, previously added via
11914      * {@link #addQosPolicies(List, Executor, Consumer)}.
11915      *
11916      * Note: Policies are identified by their policy IDs, which are assigned by the caller. The ID
11917      *       for a given policy can be retrieved using {@link QosPolicyParams#getPolicyId()}.
11918      *
11919      * @param policyIdList List of policy IDs corresponding to the policies to remove. Must have
11920      *                     a maximum length of {@link #getMaxNumberOfPoliciesPerQosRequest()}.
11921      * @throws SecurityException if caller does not have the required permissions.
11922      * @throws NullPointerException if the caller provided a null input.
11923      * @throws IllegalArgumentException if the input list is invalid.
11924      * @hide
11925      */
11926     @SystemApi
11927     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11928     @RequiresPermission(anyOf = {
11929             android.Manifest.permission.NETWORK_SETTINGS,
11930             MANAGE_WIFI_NETWORK_SELECTION
11931     })
removeQosPolicies(@onNull int[] policyIdList)11932     public void removeQosPolicies(@NonNull int[] policyIdList) {
11933         Objects.requireNonNull(policyIdList, "policyIdList cannot be null");
11934         try {
11935             mService.removeQosPolicies(policyIdList, mContext.getOpPackageName());
11936         } catch (RemoteException e) {
11937             throw e.rethrowFromSystemServer();
11938         }
11939     }
11940 
11941     /**
11942      * Remove all application-initiated QoS policies requested by this caller,
11943      * previously added via {@link #addQosPolicies(List, Executor, Consumer)}.
11944      *
11945      * @throws SecurityException if caller does not have the required permissions.
11946      * @hide
11947      */
11948     @SystemApi
11949     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
11950     @RequiresPermission(anyOf = {
11951             android.Manifest.permission.NETWORK_SETTINGS,
11952             MANAGE_WIFI_NETWORK_SELECTION
11953     })
removeAllQosPolicies()11954     public void removeAllQosPolicies() {
11955         try {
11956             mService.removeAllQosPolicies(mContext.getOpPackageName());
11957         } catch (RemoteException e) {
11958             throw e.rethrowFromSystemServer();
11959         }
11960     }
11961 
11962     /**
11963      * Set the link layer stats polling interval, in milliseconds.
11964      *
11965      * @param intervalMs a non-negative integer, for the link layer stats polling interval
11966      *                   in milliseconds.
11967      *                   To set a fixed interval, use a positive value.
11968      *                   For automatic handling of the interval, use value 0
11969      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
11970      * @throws SecurityException if the caller does not have permission.
11971      * @throws IllegalArgumentException if input is invalid.
11972      * @hide
11973      */
11974     @SystemApi
11975     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11976     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
setLinkLayerStatsPollingInterval(@ntRange from = 0) int intervalMs)11977     public void setLinkLayerStatsPollingInterval(@IntRange (from = 0) int intervalMs) {
11978         try {
11979             mService.setLinkLayerStatsPollingInterval(intervalMs);
11980         } catch (RemoteException e) {
11981             throw e.rethrowFromSystemServer();
11982         }
11983     }
11984 
11985     /**
11986      * Get the link layer stats polling interval, in milliseconds.
11987      *
11988      * @param executor The executor on which callback will be invoked.
11989      * @param resultsCallback An asynchronous callback that will return current
11990      *                        link layer stats polling interval in milliseconds.
11991      *
11992      * @throws UnsupportedOperationException if the API is not supported on this SDK version.
11993      * @throws SecurityException if the caller does not have permission.
11994      * @throws NullPointerException if the caller provided invalid inputs.
11995      * @hide
11996      */
11997     @SystemApi
11998     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
11999     @RequiresPermission(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION)
getLinkLayerStatsPollingInterval(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12000     public void getLinkLayerStatsPollingInterval(@NonNull @CallbackExecutor Executor executor,
12001             @NonNull Consumer<Integer> resultsCallback) {
12002         Objects.requireNonNull(executor, "executor cannot be null");
12003         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12004         try {
12005             mService.getLinkLayerStatsPollingInterval(
12006                     new IIntegerListener.Stub() {
12007                         @Override
12008                         public void onResult(int value) {
12009                             Binder.clearCallingIdentity();
12010                             executor.execute(() -> {
12011                                 resultsCallback.accept(value);
12012                             });
12013                         }
12014                     });
12015         } catch (RemoteException e) {
12016             throw e.rethrowFromSystemServer();
12017         }
12018     }
12019 
12020     /**
12021      * This API allows a privileged application to set Multi-Link Operation mode.
12022      *
12023      * Multi-link operation (MLO) will allow Wi-Fi devices to operate on multiple links at the same
12024      * time through a single connection, aiming to support applications that require lower latency,
12025      * and higher capacity. Chip vendors have algorithms that run on the chip to use available links
12026      * based on incoming traffic and various inputs. This API allows system application to give a
12027      * suggestion to such algorithms on its preference using {@link MloMode}.
12028      *
12029      *
12030      * @param mode Refer {@link MloMode} for supported modes.
12031      * @param executor The executor on which callback will be invoked.
12032      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
12033      *                        whether the MLO mode is successfully set or not.
12034      * @throws IllegalArgumentException if mode value is not in {@link MloMode}.
12035      * @throws NullPointerException if the caller provided a null input.
12036      * @throws SecurityException if caller does not have the required permissions.
12037      * @throws UnsupportedOperationException if the set operation is not supported on this SDK.
12038      * @hide
12039      */
12040     @SystemApi
12041     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12042     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
setMloMode(@loMode int mode, @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)12043     public void setMloMode(@MloMode int mode, @NonNull @CallbackExecutor Executor executor,
12044             @NonNull Consumer<Boolean> resultsCallback) {
12045 
12046         if (mode < MLO_MODE_DEFAULT || mode > MLO_MODE_LOW_POWER) {
12047             throw new IllegalArgumentException("invalid mode: " + mode);
12048         }
12049         Objects.requireNonNull(executor, "executor cannot be null");
12050         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12051         try {
12052             mService.setMloMode(mode, new IBooleanListener.Stub() {
12053                 @Override
12054                 public void onResult(boolean value) {
12055                     Binder.clearCallingIdentity();
12056                     executor.execute(() -> {
12057                         resultsCallback.accept(value);
12058                     });
12059                 }
12060             });
12061         } catch (RemoteException e) {
12062             throw e.rethrowFromSystemServer();
12063         }
12064     }
12065 
12066     /**
12067      * This API allows a privileged application to get Multi-Link Operation mode. Refer
12068      * {@link WifiManager#setMloMode(int, Executor, Consumer)}  for more details.
12069      *
12070      * @param executor The executor on which callback will be invoked.
12071      * @param resultsCallback An asynchronous callback that will return current MLO mode. Returns
12072      *                        {@link MloMode#MLO_MODE_DEFAULT} if information is not available,
12073      *                        e.g. if the driver/firmware doesn't provide this information.
12074      * @throws NullPointerException if the caller provided a null input.
12075      * @throws SecurityException if caller does not have the required permissions.
12076      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
12077      * @hide
12078      */
12079     @SystemApi
12080     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12081     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMloMode(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12082     public void getMloMode(@NonNull @CallbackExecutor Executor executor,
12083             @NonNull Consumer<Integer> resultsCallback) {
12084         Objects.requireNonNull(executor, "executor cannot be null");
12085         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12086         try {
12087             mService.getMloMode(new IIntegerListener.Stub() {
12088                 @Override
12089                 public void onResult(int value) {
12090                     Binder.clearCallingIdentity();
12091                     executor.execute(() -> {
12092                         resultsCallback.accept(value);
12093                     });
12094                 }
12095             });
12096         } catch (RemoteException e) {
12097             throw e.rethrowFromSystemServer();
12098         }
12099     }
12100 
12101     /**
12102      * Get the maximum number of links supported by the chip for MLO association. e.g. if the Wi-Fi
12103      * chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous Transmit and
12104      * Receive) with following capabilities,
12105      * - Max MLO assoc link count = 3.
12106      * - Max MLO STR link count   = 2. See
12107      * {@link WifiManager#getMaxMloStrLinkCount(Executor, Consumer)}
12108      * One of the possible configuration is - STR (2.4 GHz , eMLSR(5 GHz, 6 GHz)), provided the
12109      * radio combination of the chip supports it.
12110      *
12111      * @param executor        The executor on which callback will be invoked.
12112      * @param resultsCallback An asynchronous callback that will return maximum MLO association link
12113      *                        count supported by the chip or -1 if error or not available.
12114      * @throws NullPointerException          if the caller provided a null input.
12115      * @throws SecurityException             if caller does not have the required permissions.
12116      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
12117      * @hide
12118      */
12119     @SystemApi
12120     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12121     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12122     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMaxMloAssociationLinkCount(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12123     public void getMaxMloAssociationLinkCount(@NonNull @CallbackExecutor Executor executor,
12124             @NonNull Consumer<Integer> resultsCallback) {
12125         Objects.requireNonNull(executor, "executor cannot be null");
12126         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12127         try {
12128             Bundle extras = new Bundle();
12129             if (SdkLevel.isAtLeastS()) {
12130                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12131                         mContext.getAttributionSource());
12132             }
12133             mService.getMaxMloAssociationLinkCount(new IIntegerListener.Stub() {
12134                 @Override
12135                 public void onResult(int value) {
12136                     Binder.clearCallingIdentity();
12137                     executor.execute(() -> {
12138                         resultsCallback.accept(value);
12139                     });
12140                 }
12141             }, extras);
12142         } catch (RemoteException e) {
12143             throw e.rethrowFromSystemServer();
12144         }
12145     }
12146 
12147     /**
12148      * Get the maximum number of STR links used in Multi-Link Operation. The maximum number of STR
12149      * links used for MLO can be different from the number of radios supported by the chip. e.g. if
12150      * the Wi-Fi chip supports eMLSR (Enhanced Multi-Link Single Radio) and STR (Simultaneous
12151      * Transmit and Receive) with following capabilities,
12152      * - Max MLO assoc link count = 3. See
12153      *   {@link WifiManager#getMaxMloAssociationLinkCount(Executor, Consumer)}.
12154      * - Max MLO STR link count   = 2.
12155      * One of the possible configuration is - STR (2.4 GHz, eMLSR(5 GHz, 6 GHz)), provided the radio
12156      * combination of the chip supports it.
12157      *
12158      * @param executor The executor on which callback will be invoked.
12159      * @param resultsCallback An asynchronous callback that will return maximum STR link count
12160      *                       supported by the chip in MLO mode or -1 if error or not available.
12161      * @throws NullPointerException if the caller provided a null input.
12162      * @throws SecurityException if caller does not have the required permissions.
12163      * @throws UnsupportedOperationException if the get operation is not supported on this SDK
12164      * @hide
12165      */
12166     @SystemApi
12167     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12168     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12169     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getMaxMloStrLinkCount(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Integer> resultsCallback)12170     public void getMaxMloStrLinkCount(@NonNull @CallbackExecutor Executor executor,
12171             @NonNull Consumer<Integer> resultsCallback) {
12172         Objects.requireNonNull(executor, "executor cannot be null");
12173         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12174         try {
12175             Bundle extras = new Bundle();
12176             if (SdkLevel.isAtLeastS()) {
12177                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12178                         mContext.getAttributionSource());
12179             }
12180             mService.getMaxMloStrLinkCount(new IIntegerListener.Stub() {
12181                 @Override
12182                 public void onResult(int value) {
12183                     Binder.clearCallingIdentity();
12184                     executor.execute(() -> {
12185                         resultsCallback.accept(value);
12186                     });
12187                 }
12188             }, extras);
12189         } catch (RemoteException e) {
12190             throw e.rethrowFromSystemServer();
12191         }
12192     }
12193 
12194     /**
12195      * Get the set of band combinations supported simultaneously by the Wi-Fi Chip.
12196      *
12197      * Note: This method returns simultaneous band operation combination and not multichannel
12198      * concurrent operation (MCC) combination.
12199      *
12200      * @param executor The executor on which callback will be invoked.
12201      * @param resultsCallback An asynchronous callback that will return a list of possible
12202      *                        simultaneous band combinations supported by the chip or empty list if
12203      *                        not available. Band value is defined in {@link WifiScanner.WifiBand}.
12204      * @throws NullPointerException if the caller provided a null input.
12205      * @throws SecurityException if caller does not have the required permissions.
12206      * @throws UnsupportedOperationException if the get operation is not supported on this SDK.
12207      * @hide
12208      */
12209     @SystemApi
12210     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12211     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
12212     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
getSupportedSimultaneousBandCombinations( @onNull @allbackExecutor Executor executor, @NonNull Consumer<List<int[]>> resultsCallback)12213     public void getSupportedSimultaneousBandCombinations(
12214             @NonNull @CallbackExecutor Executor executor,
12215             @NonNull Consumer<List<int[]>> resultsCallback) {
12216         Objects.requireNonNull(executor, "executor cannot be null");
12217         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12218         try {
12219             Bundle extras = new Bundle();
12220             if (SdkLevel.isAtLeastS()) {
12221                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12222                         mContext.getAttributionSource());
12223             }
12224             mService.getSupportedSimultaneousBandCombinations(new IWifiBandsListener.Stub() {
12225                 @Override
12226                 public void onResult(WifiBands[] supportedBands) {
12227                     Binder.clearCallingIdentity();
12228                     List<int[]> bandCombinations = new ArrayList<>();
12229                     for (WifiBands wifiBands : supportedBands) {
12230                         bandCombinations.add(wifiBands.bands);
12231                     }
12232                     executor.execute(() -> {
12233                         resultsCallback.accept(bandCombinations);
12234                     });
12235                 }
12236             }, extras);
12237         } catch (RemoteException e) {
12238             throw e.rethrowFromSystemServer();
12239         }
12240     }
12241 
12242     /**
12243      * This API allows a privileged application to set whether or not this device allows
12244      * connections to Wi-Fi WEP networks.
12245      *
12246      * Note: The WEP connections may not work even if caller invokes this method with {@code true}
12247      * because device may NOT support connections to Wi-Fi WEP networks.
12248      * See: {@link #isWepSupported()}.
12249      *
12250      * @param isAllowed whether or not the user allow connections to Wi-Fi WEP networks.
12251      * @throws SecurityException if the caller does not have permission.
12252      * @hide
12253      */
12254     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12255     @SystemApi
12256     @RequiresPermission(anyOf = {
12257             android.Manifest.permission.NETWORK_SETTINGS,
12258             android.Manifest.permission.NETWORK_SETUP_WIZARD
12259     })
setWepAllowed(boolean isAllowed)12260     public void setWepAllowed(boolean isAllowed) {
12261         try {
12262             mService.setWepAllowed(isAllowed);
12263         } catch (RemoteException e) {
12264             throw e.rethrowFromSystemServer();
12265         }
12266     }
12267 
12268     /**
12269      * Query whether or not this device is configured to allow connections to Wi-Fi WEP networks.
12270      * @see #setWepAllowed(boolean)
12271      *
12272      * Note: The WEP connections may not work even if this method returns {@code true} in the
12273      * result callback because device may NOT support connections to Wi-Fi WEP networks.
12274      * See: {@link #isWepSupported()}.
12275      *
12276      * @param executor The executor on which callback will be invoked.
12277      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
12278      *                        whether wep network support is enabled/disabled.
12279      *
12280      * @throws SecurityException if the caller does not have permission.
12281      * @hide
12282      */
12283     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12284     @SystemApi
12285     @RequiresPermission(anyOf = {
12286             android.Manifest.permission.NETWORK_SETTINGS,
12287             android.Manifest.permission.NETWORK_SETUP_WIZARD
12288     })
queryWepAllowed(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)12289     public void queryWepAllowed(@NonNull @CallbackExecutor Executor executor,
12290             @NonNull Consumer<Boolean> resultsCallback) {
12291         Objects.requireNonNull(executor, "executor cannot be null");
12292         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12293         try {
12294             mService.queryWepAllowed(
12295                     new IBooleanListener.Stub() {
12296                         @Override
12297                         public void onResult(boolean value) {
12298                             Binder.clearCallingIdentity();
12299                             executor.execute(() -> {
12300                                 resultsCallback.accept(value);
12301                             });
12302                         }
12303                     });
12304         } catch (RemoteException e) {
12305             throw e.rethrowFromSystemServer();
12306         }
12307     }
12308 
12309     /**
12310      * Enable Mirrored Stream Classification Service (MSCS) and configure using
12311      * the provided configuration values.
12312      *
12313      * If MSCS has already been enabled/configured, this will override the
12314      * existing configuration.
12315      *
12316      * Refer to Section 11.25.3 of the IEEE 802.11-2020 standard for more information.
12317      *
12318      * @param mscsParams {@link MscsParams} object containing the configuration parameters.
12319      * @hide
12320      */
12321     @SystemApi
12322     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12323     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12324     @RequiresPermission(anyOf = {MANAGE_WIFI_NETWORK_SELECTION})
enableMscs(@onNull MscsParams mscsParams)12325     public void enableMscs(@NonNull MscsParams mscsParams) {
12326         Objects.requireNonNull(mscsParams);
12327         try {
12328             mService.enableMscs(mscsParams);
12329         } catch (RemoteException e) {
12330             throw e.rethrowFromSystemServer();
12331         }
12332     }
12333 
12334     /**
12335      * Disable Mirrored Stream Classification Service (MSCS).
12336      *
12337      * If MSCS is enabled/configured, this will send a remove request to the AP.
12338      *
12339      * Refer to Section 11.25.3 of the IEEE 802.11-2020 standard for more information.
12340      * @hide
12341      */
12342     @SystemApi
12343     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12344     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12345     @RequiresPermission(anyOf = {MANAGE_WIFI_NETWORK_SELECTION})
disableMscs()12346     public void disableMscs() {
12347         try {
12348             mService.disableMscs();
12349         } catch (RemoteException e) {
12350             throw e.rethrowFromSystemServer();
12351         }
12352     }
12353 
12354     /**
12355      * Do not send the DHCP hostname to open networks.
12356      */
12357     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12358     public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN = 1 << 0;
12359 
12360     /**
12361      * Do not send the DHCP hostname to secure network.
12362      */
12363     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12364     public static final int FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE = 1 << 1;
12365 
12366     /** @hide */
12367     @IntDef(flag = true, prefix = { "FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_" }, value = {
12368             FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN,
12369             FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE,
12370     })
12371     @Retention(RetentionPolicy.SOURCE)
12372     public @interface SendDhcpHostnameRestriction {}
12373 
12374     /**
12375      * Sets the global restrictions on which networks to send the device hostname to during DHCP.
12376      *
12377      * @param restriction Bitmask of {@link SendDhcpHostnameRestriction}, or none to indicate no
12378      *                    restriction.
12379      * @throws IllegalArgumentException if input is invalid
12380      * @throws SecurityException if the calling app is not a Device Owner (DO), or a privileged app
12381      *                           that has one of the permissions required by this API.
12382      */
12383     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12384     @RequiresPermission(anyOf = {
12385             android.Manifest.permission.NETWORK_SETTINGS,
12386             android.Manifest.permission.NETWORK_SETUP_WIZARD
12387     })
setSendDhcpHostnameRestriction(@endDhcpHostnameRestriction int restriction)12388     public void setSendDhcpHostnameRestriction(@SendDhcpHostnameRestriction int restriction) {
12389         try {
12390             mService.setSendDhcpHostnameRestriction(mContext.getOpPackageName(), restriction);
12391         } catch (RemoteException e) {
12392             throw e.rethrowFromSystemServer();
12393         }
12394     }
12395 
12396     /**
12397      * Query the global restriction on which networks to send the device hostname to during DHCP.
12398      * @see #setSendDhcpHostnameRestriction(int)
12399      *
12400      * @param executor The executor on which callback will be invoked.
12401      * @param resultsCallback An asynchronous callback that will return a bitmask of
12402      *                        {@link SendDhcpHostnameRestriction}.
12403      *
12404      * @throws SecurityException if the calling app is not a Device Owner (DO), or a privileged app
12405      *                           that has one of the permissions required by this API.
12406      */
12407     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12408     @RequiresPermission(anyOf = {
12409             android.Manifest.permission.NETWORK_SETTINGS,
12410             android.Manifest.permission.NETWORK_SETUP_WIZARD
12411     })
querySendDhcpHostnameRestriction(@onNull @allbackExecutor Executor executor, @NonNull IntConsumer resultsCallback)12412     public void querySendDhcpHostnameRestriction(@NonNull @CallbackExecutor Executor executor,
12413             @NonNull IntConsumer resultsCallback) {
12414         Objects.requireNonNull(executor, "executor cannot be null");
12415         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12416         try {
12417             mService.querySendDhcpHostnameRestriction(mContext.getOpPackageName(),
12418                     new IIntegerListener.Stub() {
12419                         @Override
12420                         public void onResult(int value) {
12421                             Binder.clearCallingIdentity();
12422                             executor.execute(() -> {
12423                                 resultsCallback.accept(value);
12424                             });
12425                         }
12426                     });
12427         } catch (RemoteException e) {
12428             throw e.rethrowFromSystemServer();
12429         }
12430     }
12431 
12432     /**
12433      * @return true if this device supports Aggressive roaming mode
12434      * {@link #setPerSsidRoamingMode(WifiSsid, int)}
12435      */
12436     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
isAggressiveRoamingModeSupported()12437     public boolean isAggressiveRoamingModeSupported() {
12438         return isFeatureSupported(WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT);
12439     }
12440 
12441     /**
12442      * This API allows a privileged application to set roaming mode per SSID.
12443      *
12444      * Available for DO/COPE apps.
12445      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
12446      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
12447      *
12448      * @param ssid SSID to be mapped to apply roaming policy
12449      * @param roamingMode refer {@link RoamingMode} for supported modes.
12450      * @throws IllegalArgumentException if mode value is not in {@link RoamingMode}.
12451      * @throws NullPointerException if the caller provided a null input.
12452      * @throws SecurityException if caller does not have the required permission.
12453      * @throws UnsupportedOperationException if the set operation is not supported on this SDK or
12454      *                                       if the feature is not available
12455      *                                       {@link #isAggressiveRoamingModeSupported()}.
12456      */
12457     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12458     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12459     @SuppressLint("RequiresPermission")
setPerSsidRoamingMode(@onNull WifiSsid ssid, @RoamingMode int roamingMode)12460     public void setPerSsidRoamingMode(@NonNull WifiSsid ssid, @RoamingMode int roamingMode) {
12461         if (roamingMode < ROAMING_MODE_NONE || roamingMode > ROAMING_MODE_AGGRESSIVE) {
12462             throw new IllegalArgumentException("invalid roaming mode: " + roamingMode);
12463         }
12464         Objects.requireNonNull(ssid, "ssid cannot be null");
12465         try {
12466             mService.setPerSsidRoamingMode(ssid, roamingMode, mContext.getOpPackageName());
12467         } catch (RemoteException e) {
12468             throw e.rethrowFromSystemServer();
12469         }
12470     }
12471 
12472     /**
12473      * This API allows a privileged application to remove roaming mode policy
12474      * configured using the {@link #setPerSsidRoamingMode(WifiSsid, int)}.
12475      *
12476      * Available for DO/COPE apps.
12477      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
12478      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
12479      *
12480      * @param ssid SSID to be removed from the roaming mode policy.
12481      * @throws NullPointerException if the caller provided a null input.
12482      * @throws SecurityException if caller does not have the required permission.
12483      * @throws UnsupportedOperationException if the set operation is not supported on this SDK or
12484      *                                       if the feature is not available
12485      *                                       {@link #isAggressiveRoamingModeSupported()}.
12486      */
12487     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12488     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12489     @SuppressLint("RequiresPermission")
removePerSsidRoamingMode(@onNull WifiSsid ssid)12490     public void removePerSsidRoamingMode(@NonNull WifiSsid ssid) {
12491         Objects.requireNonNull(ssid, "ssid cannot be null");
12492         try {
12493             mService.removePerSsidRoamingMode(ssid, mContext.getOpPackageName());
12494         } catch (RemoteException e) {
12495             throw e.rethrowFromSystemServer();
12496         }
12497     }
12498 
12499     /**
12500      * This API allows a privileged application to get roaming mode policies
12501      * configured using the {@link #setPerSsidRoamingMode(WifiSsid, int)}.
12502      *
12503      * Available for DO/COPE apps.
12504      * Other apps require {@code android.Manifest.permission#NETWORK_SETTINGS} or
12505      * {@code android.Manifest.permission#MANAGE_WIFI_NETWORK_SELECTION} permission.
12506      *
12507      * @param executor The executor on which callback will be invoked.
12508      * @param resultsCallback An asynchronous callback that will return the corresponding
12509      *                        roaming policies for the API caller.
12510      * @throws SecurityException if caller does not have the required permission.
12511      * @throws UnsupportedOperationException if the get operation is not supported on this SDK or
12512      *                                       if the feature is not available
12513      *                                       {@link #isAggressiveRoamingModeSupported()}.
12514      */
12515     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12516     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12517     @SuppressLint("RequiresPermission")
getPerSsidRoamingModes(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Map<String, Integer>> resultsCallback)12518     public void getPerSsidRoamingModes(@NonNull @CallbackExecutor Executor executor,
12519             @NonNull Consumer<Map<String, Integer>> resultsCallback) {
12520         Objects.requireNonNull(executor, "executor cannot be null");
12521         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12522         try {
12523             mService.getPerSsidRoamingModes(mContext.getOpPackageName(), new IMapListener.Stub() {
12524                 @Override
12525                 public void onResult(Map roamingPolicies) {
12526                     Binder.clearCallingIdentity();
12527                     executor.execute(() -> {
12528                         resultsCallback.accept(roamingPolicies);
12529                     });
12530                 }
12531             });
12532         } catch (RemoteException e) {
12533             throw e.rethrowFromSystemServer();
12534         }
12535     }
12536 
12537     /**
12538      * Bundle key to check target wake time requester mode supported or not
12539      * @hide
12540      */
12541     @SystemApi
12542     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12543     public static final String TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER =
12544             "key_requester";
12545 
12546     /**
12547      * Bundle key to get minimum wake duration supported in microseconds
12548      * @hide
12549      */
12550     @SystemApi
12551     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12552     public static final String TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS =
12553             "key_min_wake_duration";
12554     /**
12555      * Bundle key to get maximum wake duration supported in microseconds
12556      * @hide
12557      */
12558     @SystemApi
12559     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12560     public static final String TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS =
12561             "key_max_wake_duration";
12562     /**
12563      * Bundle key to get minimum wake interval supported in microseconds
12564      * @hide
12565      */
12566     @SystemApi
12567     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12568     public static final String TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS =
12569             "key_min_wake_interval";
12570     /**
12571      * Bundle key to get maximum wake interval supported in microseconds
12572      * @hide
12573      */
12574     @SystemApi
12575     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12576     public static final String TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS =
12577             "key_max_wake_interval";
12578 
12579     /** @hide */
12580     @StringDef(prefix = { "TWT_CAPABILITIES_KEY_"}, value = {
12581             TWT_CAPABILITIES_KEY_BOOLEAN_TWT_REQUESTER,
12582             TWT_CAPABILITIES_KEY_INT_MIN_WAKE_DURATION_MICROS,
12583             TWT_CAPABILITIES_KEY_INT_MAX_WAKE_DURATION_MICROS,
12584             TWT_CAPABILITIES_KEY_LONG_MIN_WAKE_INTERVAL_MICROS,
12585             TWT_CAPABILITIES_KEY_LONG_MAX_WAKE_INTERVAL_MICROS,
12586     })
12587     @Retention(RetentionPolicy.SOURCE)
12588     public @interface TwtCapabilities {}
12589 
12590     /**
12591      * Get target wake time (TWT) capabilities of the primary station interface.
12592      *
12593      * Note: Target wake time feature is only supported for primary station. If Wi-Fi is off or the
12594      * capability is not available the asynchronous callback will be called with the bundle
12595      * with values { false, -1, -1, -1, -1 }.
12596      *
12597      * @param executor Executor to execute listener callback
12598      * @param resultCallback An asynchronous callback that will return a bundle for target wake time
12599      *                       capabilities. See {@link TwtCapabilities} for the string keys for
12600      *                       the bundle.
12601      * @throws SecurityException if the caller does not have permission.
12602      * @throws NullPointerException if the caller provided null inputs.
12603      * @throws UnsupportedOperationException if the API is not supported.
12604      * @hide
12605      */
12606     @SystemApi
12607     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12608     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
12609     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
getTwtCapabilities(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Bundle> resultCallback)12610     public void getTwtCapabilities(@NonNull @CallbackExecutor Executor executor,
12611             @NonNull Consumer<Bundle> resultCallback) {
12612         Objects.requireNonNull(executor, "executor cannot be null");
12613         Objects.requireNonNull(resultCallback, "resultCallback cannot be null");
12614         if (!SdkLevel.isAtLeastV()) {
12615             throw new UnsupportedOperationException();
12616         }
12617         try {
12618             Bundle extras = new Bundle();
12619             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12620                     mContext.getAttributionSource());
12621             mService.getTwtCapabilities(
12622                     new ITwtCapabilitiesListener.Stub() {
12623                         @Override
12624                         public void onResult(Bundle value) {
12625                             Binder.clearCallingIdentity();
12626                             executor.execute(() -> {
12627                                 resultCallback.accept(value);
12628                             });
12629                         }
12630                     }, extras);
12631         } catch (RemoteException e) {
12632             throw e.rethrowFromSystemServer();
12633         }
12634     }
12635 
12636     private class TwtCallbackProxy extends ITwtCallback.Stub {
12637         private final Executor mExecutor;
12638         private final TwtSessionCallback mCallback;
12639 
TwtCallbackProxy(Executor executor, TwtSessionCallback callback)12640         private TwtCallbackProxy(Executor executor, TwtSessionCallback callback) {
12641             mExecutor = executor;
12642             mCallback = callback;
12643         }
12644 
12645         @Override
onFailure(@wtSessionCallback.TwtErrorCode int errorCode)12646         public void onFailure(@TwtSessionCallback.TwtErrorCode int errorCode)
12647                 throws RemoteException {
12648             if (mVerboseLoggingEnabled) {
12649                 Log.v(TAG, "TwtCallbackProxy: onFailure(errorCode = " + errorCode + " )");
12650             }
12651             Binder.clearCallingIdentity();
12652             mExecutor.execute(() -> mCallback.onFailure(errorCode));
12653         }
12654 
12655         @Override
onTeardown(@wtSessionCallback.TwtReasonCode int reasonCode)12656         public void onTeardown(@TwtSessionCallback.TwtReasonCode int reasonCode)
12657                 throws RemoteException {
12658             if (mVerboseLoggingEnabled) {
12659                 Log.v(TAG, "TwtCallbackProxy: onTeardown(errorCode = " + reasonCode + " )");
12660             }
12661             Binder.clearCallingIdentity();
12662             mExecutor.execute(() -> mCallback.onTeardown(reasonCode));
12663         }
12664 
12665         @Override
onCreate(int wakeDuration, long wakeInterval, int mloLinkId, int owner, int sessionId)12666         public void onCreate(int wakeDuration, long wakeInterval, int mloLinkId, int owner,
12667                 int sessionId) throws RemoteException {
12668             if (mVerboseLoggingEnabled) {
12669                 Log.v(TAG, "TwtCallbackProxy: onCreate " + sessionId);
12670             }
12671 
12672             WifiTwtSession wifiTwtSession = new WifiTwtSession(WifiManager.this, wakeDuration,
12673                     wakeInterval, mloLinkId, owner, sessionId);
12674             Binder.clearCallingIdentity();
12675             mExecutor.execute(() -> mCallback.onCreate(wifiTwtSession));
12676         }
12677     }
12678 
12679     /**
12680      * Set up a TWT session with a TWT responder capable AP. Only supported for primary connected
12681      * station which is a TWT requester. See {@link #getTwtCapabilities(Executor, Consumer)} and
12682      * {@link ScanResult#isTwtResponder()} to check station and AP support.
12683      *
12684      * Following callbacks are invoked,
12685      *  - {@link TwtSessionCallback#onFailure(int)} upon error with error code.
12686      *  - {@link TwtSessionCallback#onCreate(TwtSession)} upon TWT session creation.
12687      *  - {@link TwtSessionCallback#onTeardown(int)} upon TWT session teardown.
12688      *
12689      * Note: {@link #getTwtCapabilities(Executor, Consumer)} gives {@link TwtCapabilities} which can
12690      * be used to fill in the valid TWT wake interval and duration ranges for {@link TwtRequest}.
12691      *
12692      * @param twtRequest TWT request
12693      * @param executor Executor to execute listener callback on
12694      * @param callback Callback to register
12695      * @throws SecurityException if the caller does not have permission.
12696      * @throws NullPointerException if the caller provided null inputs.
12697      * @throws UnsupportedOperationException if the API is not supported.
12698      * @hide
12699      */
12700     @SystemApi
12701     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
12702     @RequiresPermission(MANAGE_WIFI_NETWORK_SELECTION)
12703     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
setupTwtSession(@onNull TwtRequest twtRequest, @NonNull @CallbackExecutor Executor executor, @NonNull TwtSessionCallback callback)12704     public void setupTwtSession(@NonNull TwtRequest twtRequest,
12705             @NonNull @CallbackExecutor Executor executor, @NonNull TwtSessionCallback callback) {
12706         Objects.requireNonNull(executor, "executor cannot be null");
12707         Objects.requireNonNull(callback, "callback cannot be null");
12708         Objects.requireNonNull(twtRequest, "twtRequest cannot be null");
12709         if (!SdkLevel.isAtLeastV()) {
12710             throw new UnsupportedOperationException();
12711         }
12712         try {
12713             ITwtCallback.Stub binderCallback = new TwtCallbackProxy(executor, callback);
12714             Bundle extras = new Bundle();
12715             extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12716                     mContext.getAttributionSource());
12717             mService.setupTwtSession(twtRequest, binderCallback, extras);
12718         } catch (RemoteException e) {
12719             throw e.rethrowFromSystemServer();
12720         }
12721     }
12722 
12723     /**
12724      * Get stats of the target wake time session.
12725      *
12726      * Note: For Internal use only. Expected to be called through
12727      * {@link TwtSession#getStats(Executor, Consumer)}. If the command fails, -1 will be returned
12728      * for all stats values.
12729      *
12730      * @param sessionId TWT session id
12731      * @param executor The executor on which callback will be invoked.
12732      * @param resultCallback The asynchronous callback that will return bundle with key string
12733      *                       {@link TwtSession.TwtStats}.
12734      *
12735      * @throws SecurityException if the caller does not have permission.
12736      * @throws NullPointerException if the caller provided null inputs.
12737      * @throws UnsupportedOperationException if the API is not supported or primary station is
12738      * not connected.
12739      * @hide
12740      */
getStatsTwtSession(@onNull int sessionId, @NonNull Executor executor, @NonNull Consumer<Bundle> resultCallback)12741     public void getStatsTwtSession(@NonNull int sessionId, @NonNull Executor executor,
12742             @NonNull Consumer<Bundle> resultCallback) {
12743         Objects.requireNonNull(executor, "executor cannot be null");
12744         Objects.requireNonNull(resultCallback, "resultsCallback cannot be null");
12745         if (!SdkLevel.isAtLeastV()) {
12746             throw new UnsupportedOperationException();
12747         }
12748         try {
12749             Bundle extras = new Bundle();
12750             if (SdkLevel.isAtLeastS()) {
12751                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12752                         mContext.getAttributionSource());
12753             }
12754             mService.getStatsTwtSession(sessionId,
12755                     new ITwtStatsListener.Stub() {
12756                         @Override
12757                         public void onResult(Bundle value) {
12758                             Binder.clearCallingIdentity();
12759                             executor.execute(() -> {
12760                                 resultCallback.accept(value);
12761                             });
12762                         }
12763                     }, extras);
12764         } catch (RemoteException e) {
12765             throw e.rethrowFromSystemServer();
12766         }
12767     }
12768 
12769     /**
12770      * Teardown the target wake time session. Only owner can teardown the session.
12771      *
12772      * Note: For internal use only. Expected to be called through
12773      * {@link TwtSessionCallback#onTeardown(int)}.
12774      *
12775      * @param sessionId TWT session id
12776      * @throws SecurityException if the caller does not have permission.
12777      * @throws UnsupportedOperationException if the API is not supported or primary station is not
12778      * connected.
12779      * @hide
12780      */
teardownTwtSession(int sessionId)12781     public void teardownTwtSession(int sessionId) {
12782         if (!SdkLevel.isAtLeastV()) {
12783             throw new UnsupportedOperationException();
12784         }
12785         try {
12786             Bundle extras = new Bundle();
12787             if (SdkLevel.isAtLeastS()) {
12788                 extras.putParcelable(EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
12789                         mContext.getAttributionSource());
12790             }
12791             mService.teardownTwtSession(sessionId, extras);
12792         } catch (RemoteException e) {
12793             throw e.rethrowFromSystemServer();
12794         }
12795     }
12796 
12797     /**
12798      * Allows a privileged application to set whether or not this device allows
12799      * device-to-device connections when infra STA is disabled. Callers can use
12800      * {@link #queryD2dAllowedWhenInfraStaDisabled(Executor, Consumer)} to check the currently
12801      * set value.
12802      *
12803      * Note: This functionality is supported only when the device support device-to-device
12804      * when infra STA is disabled. Use {@link #isD2dSupportedWhenInfraStaDisabled()} to
12805      * know if device supported device-to-device when infra STA is disabled.
12806      *
12807      * @param isAllowed whether or not the device allows to device-to-device connectivity when
12808      *                  infra STA is disabled.
12809      * @throws SecurityException if the caller does not have permission.
12810      * @hide
12811      */
12812     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12813     @SystemApi
12814     @RequiresPermission(anyOf = {
12815             android.Manifest.permission.NETWORK_SETTINGS,
12816             android.Manifest.permission.NETWORK_SETUP_WIZARD
12817     })
12818     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setD2dAllowedWhenInfraStaDisabled(boolean isAllowed)12819     public void setD2dAllowedWhenInfraStaDisabled(boolean isAllowed) {
12820         try {
12821             mService.setD2dAllowedWhenInfraStaDisabled(isAllowed);
12822         } catch (RemoteException e) {
12823             throw e.rethrowFromSystemServer();
12824         }
12825     }
12826 
12827     /**
12828      * Query whether or not this device is configured to allow D2d connection when
12829      * infra STA is disabled.
12830      * see: {@link #setD2dAllowedWhenInfraStaDisabled(boolean)}.
12831      *
12832      *
12833      * @param executor The executor on which callback will be invoked.
12834      * @param resultsCallback An asynchronous callback that will return {@code Boolean} indicating
12835      *                        whether device-to-device connection is allowed or disallowed
12836      *                        when infra STA is disabled.
12837      * @hide
12838      */
12839     @FlaggedApi(Flags.FLAG_ANDROID_V_WIFI_API)
12840     @SystemApi
queryD2dAllowedWhenInfraStaDisabled(@onNull @allbackExecutor Executor executor, @NonNull Consumer<Boolean> resultsCallback)12841     public void queryD2dAllowedWhenInfraStaDisabled(@NonNull @CallbackExecutor Executor executor,
12842             @NonNull Consumer<Boolean> resultsCallback) {
12843         Objects.requireNonNull(executor, "executor cannot be null");
12844         Objects.requireNonNull(resultsCallback, "resultsCallback cannot be null");
12845         try {
12846             mService.queryD2dAllowedWhenInfraStaDisabled(
12847                     new IBooleanListener.Stub() {
12848                         @Override
12849                         public void onResult(boolean value) {
12850                             Binder.clearCallingIdentity();
12851                             executor.execute(() -> {
12852                                 resultsCallback.accept(value);
12853                             });
12854                         }
12855                     });
12856         } catch (RemoteException e) {
12857             throw e.rethrowFromSystemServer();
12858         }
12859     }
12860 }
12861