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