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