• 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.content.pm.ParceledListSlice;
38 import android.net.ConnectivityManager;
39 import android.net.DhcpInfo;
40 import android.net.MacAddress;
41 import android.net.Network;
42 import android.net.NetworkStack;
43 import android.net.wifi.hotspot2.IProvisioningCallback;
44 import android.net.wifi.hotspot2.OsuProvider;
45 import android.net.wifi.hotspot2.PasspointConfiguration;
46 import android.net.wifi.hotspot2.ProvisioningCallback;
47 import android.os.Binder;
48 import android.os.Build;
49 import android.os.Handler;
50 import android.os.HandlerExecutor;
51 import android.os.IBinder;
52 import android.os.Looper;
53 import android.os.RemoteException;
54 import android.os.WorkSource;
55 import android.os.connectivity.WifiActivityEnergyInfo;
56 import android.text.TextUtils;
57 import android.util.CloseGuard;
58 import android.util.Log;
59 import android.util.Pair;
60 import android.util.SparseArray;
61 
62 import com.android.internal.annotations.GuardedBy;
63 import com.android.internal.annotations.VisibleForTesting;
64 
65 import java.lang.annotation.Retention;
66 import java.lang.annotation.RetentionPolicy;
67 import java.lang.ref.Reference;
68 import java.lang.ref.WeakReference;
69 import java.net.InetAddress;
70 import java.util.ArrayList;
71 import java.util.Collections;
72 import java.util.HashMap;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Objects;
76 import java.util.Set;
77 import java.util.StringTokenizer;
78 import java.util.concurrent.Executor;
79 
80 /**
81  * This class provides the primary API for managing all aspects of Wi-Fi
82  * connectivity.
83  * <p>
84  * On releases before {@link android.os.Build.VERSION_CODES#N}, this object
85  * should only be obtained from an {@linkplain Context#getApplicationContext()
86  * application context}, and not from any other derived context to avoid memory
87  * leaks within the calling process.
88  * <p>
89  * It deals with several categories of items:
90  * </p>
91  * <ul>
92  * <li>The list of configured networks. The list can be viewed and updated, and
93  * attributes of individual entries can be modified.</li>
94  * <li>The currently active Wi-Fi network, if any. Connectivity can be
95  * established or torn down, and dynamic information about the state of the
96  * network can be queried.</li>
97  * <li>Results of access point scans, containing enough information to make
98  * decisions about what access point to connect to.</li>
99  * <li>It defines the names of various Intent actions that are broadcast upon
100  * any sort of change in Wi-Fi state.
101  * </ul>
102  * <p>
103  * This is the API to use when performing Wi-Fi specific operations. To perform
104  * operations that pertain to network connectivity at an abstract level, use
105  * {@link android.net.ConnectivityManager}.
106  * </p>
107  */
108 @SystemService(Context.WIFI_SERVICE)
109 public class WifiManager {
110 
111     private static final String TAG = "WifiManager";
112     // Supplicant error codes:
113     /**
114      * The error code if there was a problem authenticating.
115      * @deprecated This is no longer supported.
116      */
117     @Deprecated
118     public static final int ERROR_AUTHENTICATING = 1;
119 
120     /**
121      * The reason code if there is no error during authentication.
122      * It could also imply that there no authentication in progress,
123      * this reason code also serves as a reset value.
124      * @deprecated This is no longer supported.
125      * @hide
126      */
127     @Deprecated
128     public static final int ERROR_AUTH_FAILURE_NONE = 0;
129 
130     /**
131      * The reason code if there was a timeout authenticating.
132      * @deprecated This is no longer supported.
133      * @hide
134      */
135     @Deprecated
136     public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
137 
138     /**
139      * The reason code if there was a wrong password while
140      * authenticating.
141      * @deprecated This is no longer supported.
142      * @hide
143      */
144     @Deprecated
145     public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
146 
147     /**
148      * The reason code if there was EAP failure while
149      * authenticating.
150      * @deprecated This is no longer supported.
151      * @hide
152      */
153     @Deprecated
154     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
155 
156     /** @hide */
157     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM = 256;
158 
159     /** @hide */
160     public static final int NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM = 1024;
161 
162     /**
163      * Reason code if all of the network suggestions were successfully added or removed.
164      */
165     public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0;
166 
167     /**
168      * Reason code if there was an internal error in the platform while processing the addition or
169      * removal of suggestions.
170      */
171     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1;
172 
173     /**
174      * Reason code if the user has disallowed "android:change_wifi_state" app-ops from the app.
175      * @see android.app.AppOpsManager#unsafeCheckOp(String, int, String).
176      */
177     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED = 2;
178 
179     /**
180      * Reason code if one or more of the network suggestions added already exists in platform's
181      * database.
182      * Note: this code will not be returned with Android 11 as in-place modification is allowed,
183      * please check {@link #addNetworkSuggestions(List)}.
184      * @see WifiNetworkSuggestion#equals(Object)
185      */
186     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE = 3;
187 
188     /**
189      * Reason code if the number of network suggestions provided by the app crosses the max
190      * threshold set per app.
191      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)} if
192      * the total size exceeds the limit.
193      * @see #getMaxNumberOfNetworkSuggestionsPerApp()
194      */
195     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP = 4;
196 
197     /**
198      * Reason code if one or more of the network suggestions removed does not exist in platform's
199      * database.
200      * The framework won't remove any suggestions if one or more of suggestions provided
201      * by {@link #removeNetworkSuggestions(List)} does not exist in database.
202      * @see WifiNetworkSuggestion#equals(Object)
203      */
204     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5;
205 
206     /**
207      * Reason code if one or more of the network suggestions added is not allowed.
208      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
209      * if one or more of them is not allowed.
210      * This error may be caused by suggestion is using SIM-based encryption method, but calling app
211      * is not carrier privileged.
212      */
213     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED = 6;
214 
215     /**
216      * Reason code if one or more of the network suggestions added is invalid. Framework will reject
217      * all the suggestions in the list.
218      * The framework will reject all suggestions provided by {@link #addNetworkSuggestions(List)}
219      * if one or more of them is invalid.
220      * Please use {@link WifiNetworkSuggestion.Builder} to create network suggestions.
221      */
222     public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID = 7;
223 
224     /** @hide */
225     @IntDef(prefix = { "STATUS_NETWORK_SUGGESTIONS_" }, value = {
226             STATUS_NETWORK_SUGGESTIONS_SUCCESS,
227             STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
228             STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED,
229             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE,
230             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_EXCEEDS_MAX_PER_APP,
231             STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID,
232             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_NOT_ALLOWED,
233             STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_INVALID,
234     })
235     @Retention(RetentionPolicy.SOURCE)
236     public @interface NetworkSuggestionsStatusCode {}
237 
238     /**
239      * Reason code if suggested network connection attempt failed with an unknown failure.
240      */
241     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN = 0;
242     /**
243      * Reason code if suggested network connection attempt failed with association failure.
244      */
245     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1;
246     /**
247      * Reason code if suggested network connection attempt failed with an authentication failure.
248      */
249     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2;
250     /**
251      * Reason code if suggested network connection attempt failed with an IP provision failure.
252      */
253     public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3;
254 
255     /** @hide */
256     @IntDef(prefix = {"STATUS_SUGGESTION_CONNECTION_FAILURE_"},
257             value = {STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN,
258                     STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION,
259                     STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION,
260                     STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING
261     })
262     @Retention(RetentionPolicy.SOURCE)
263     public @interface SuggestionConnectionStatusCode {}
264 
265     /**
266      * Broadcast intent action indicating whether Wi-Fi scanning is currently available.
267      * Available extras:
268      * - {@link #EXTRA_SCAN_AVAILABLE}
269      */
270     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
271     public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED =
272             "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
273 
274     /**
275      * A boolean extra indicating whether scanning is currently available.
276      * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABILITY_CHANGED}.
277      * Its value is true if scanning is currently available, false otherwise.
278      */
279     public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
280 
281     /**
282      * Broadcast intent action indicating that the credential of a Wi-Fi network
283      * has been changed. One extra provides the ssid of the network. Another
284      * extra provides the event type, whether the credential is saved or forgot.
285      * @hide
286      */
287     @SystemApi
288     public static final String WIFI_CREDENTIAL_CHANGED_ACTION =
289             "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
290     /** @hide */
291     @SystemApi
292     public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
293     /** @hide */
294     @SystemApi
295     public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
296     /** @hide */
297     @SystemApi
298     public static final int WIFI_CREDENTIAL_SAVED = 0;
299     /** @hide */
300     @SystemApi
301     public static final int WIFI_CREDENTIAL_FORGOT = 1;
302 
303     /** @hide */
304     @SystemApi
305     public static final int PASSPOINT_HOME_NETWORK = 0;
306 
307     /** @hide */
308     @SystemApi
309     public static final int PASSPOINT_ROAMING_NETWORK = 1;
310 
311     /**
312      * Broadcast intent action indicating that a Passpoint provider icon has been received.
313      *
314      * Included extras:
315      * {@link #EXTRA_BSSID_LONG}
316      * {@link #EXTRA_FILENAME}
317      * {@link #EXTRA_ICON}
318      *
319      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
320      *
321      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
322      * components will be launched.
323      *
324      * @hide
325      */
326     public static final String ACTION_PASSPOINT_ICON = "android.net.wifi.action.PASSPOINT_ICON";
327     /**
328      * BSSID of an AP in long representation.  The {@link #EXTRA_BSSID} contains BSSID in
329      * String representation.
330      *
331      * Retrieve with {@link android.content.Intent#getLongExtra(String, long)}.
332      *
333      * @hide
334      */
335     public static final String EXTRA_BSSID_LONG = "android.net.wifi.extra.BSSID_LONG";
336     /**
337      * Icon data.
338      *
339      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)} and cast into
340      * {@link android.graphics.drawable.Icon}.
341      *
342      * @hide
343      */
344     public static final String EXTRA_ICON = "android.net.wifi.extra.ICON";
345     /**
346      * Name of a file.
347      *
348      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
349      *
350      * @hide
351      */
352     public static final String EXTRA_FILENAME = "android.net.wifi.extra.FILENAME";
353 
354     /**
355      * Broadcast intent action indicating a Passpoint OSU Providers List element has been received.
356      *
357      * Included extras:
358      * {@link #EXTRA_BSSID_LONG}
359      * {@link #EXTRA_ANQP_ELEMENT_DATA}
360      *
361      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
362      *
363      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
364      * components will be launched.
365      *
366      * @hide
367      */
368     public static final String ACTION_PASSPOINT_OSU_PROVIDERS_LIST =
369             "android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST";
370     /**
371      * Raw binary data of an ANQP (Access Network Query Protocol) element.
372      *
373      * Retrieve with {@link android.content.Intent#getByteArrayExtra(String)}.
374      *
375      * @hide
376      */
377     public static final String EXTRA_ANQP_ELEMENT_DATA =
378             "android.net.wifi.extra.ANQP_ELEMENT_DATA";
379 
380     /**
381      * Broadcast intent action indicating that a Passpoint Deauth Imminent frame has been received.
382      *
383      * Included extras:
384      * {@link #EXTRA_BSSID_LONG}
385      * {@link #EXTRA_ESS}
386      * {@link #EXTRA_DELAY}
387      * {@link #EXTRA_URL}
388      *
389      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
390      *
391      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
392      * components will be launched.
393      *
394      * @hide
395      */
396     public static final String ACTION_PASSPOINT_DEAUTH_IMMINENT =
397             "android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT";
398     /**
399      * Flag indicating BSS (Basic Service Set) or ESS (Extended Service Set). This will be set to
400      * {@code true} for ESS.
401      *
402      * Retrieve with {@link android.content.Intent#getBooleanExtra(String, boolean)}.
403      *
404      * @hide
405      */
406     public static final String EXTRA_ESS = "android.net.wifi.extra.ESS";
407     /**
408      * Delay in seconds.
409      *
410      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
411      *
412      * @hide
413      */
414     public static final String EXTRA_DELAY = "android.net.wifi.extra.DELAY";
415 
416     /**
417      * Broadcast intent action indicating a Passpoint subscription remediation frame has been
418      * received.
419      *
420      * Included extras:
421      * {@link #EXTRA_BSSID_LONG}
422      * {@link #EXTRA_SUBSCRIPTION_REMEDIATION_METHOD}
423      * {@link #EXTRA_URL}
424      *
425      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
426      *
427      * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
428      * components will be launched.
429      *
430      * @hide
431      */
432     public static final String ACTION_PASSPOINT_SUBSCRIPTION_REMEDIATION =
433             "android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION";
434     /**
435      * The protocol supported by the subscription remediation server. The possible values are:
436      * 0 - OMA DM
437      * 1 - SOAP XML SPP
438      *
439      * Retrieve with {@link android.content.Intent#getIntExtra(String, int)}.
440      *
441      * @hide
442      */
443     public static final String EXTRA_SUBSCRIPTION_REMEDIATION_METHOD =
444             "android.net.wifi.extra.SUBSCRIPTION_REMEDIATION_METHOD";
445 
446     /**
447      * Activity Action: Receiver should launch Passpoint OSU (Online Sign Up) view.
448      * Included extras:
449      *
450      * {@link #EXTRA_OSU_NETWORK}: {@link Network} instance associated with OSU AP.
451      * {@link #EXTRA_URL}: String representation of a server URL used for OSU process.
452      *
453      * @hide
454      */
455     @SystemApi
456     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
457     public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW =
458             "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
459 
460     /**
461      * The lookup key for a {@link android.net.Network} associated with a Passpoint OSU server.
462      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
463      *
464      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
465      *
466      * @hide
467      */
468     @SystemApi
469     public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
470 
471     /**
472      * String representation of an URL for Passpoint OSU.
473      * Included in the {@link #ACTION_PASSPOINT_LAUNCH_OSU_VIEW} broadcast.
474      *
475      * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
476      *
477      * @hide
478      */
479     @SystemApi
480     public static final String EXTRA_URL = "android.net.wifi.extra.URL";
481 
482     /**
483      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
484      * enabling, disabling, or unknown. One extra provides this state as an int.
485      * Another extra provides the previous state, if available.  No network-related
486      * permissions are required to subscribe to this broadcast.
487      *
488      * <p class="note">This broadcast is not delivered to manifest receivers in
489      * applications that target API version 26 or later.
490      *
491      * @see #EXTRA_WIFI_STATE
492      * @see #EXTRA_PREVIOUS_WIFI_STATE
493      */
494     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
495     public static final String WIFI_STATE_CHANGED_ACTION =
496         "android.net.wifi.WIFI_STATE_CHANGED";
497     /**
498      * The lookup key for an int that indicates whether Wi-Fi is enabled,
499      * disabled, enabling, disabling, or unknown.  Retrieve it with
500      * {@link android.content.Intent#getIntExtra(String,int)}.
501      *
502      * @see #WIFI_STATE_DISABLED
503      * @see #WIFI_STATE_DISABLING
504      * @see #WIFI_STATE_ENABLED
505      * @see #WIFI_STATE_ENABLING
506      * @see #WIFI_STATE_UNKNOWN
507      */
508     public static final String EXTRA_WIFI_STATE = "wifi_state";
509     /**
510      * The previous Wi-Fi state.
511      *
512      * @see #EXTRA_WIFI_STATE
513      */
514     public static final String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
515 
516     /**
517      * Wi-Fi is currently being disabled. The state will change to {@link #WIFI_STATE_DISABLED} if
518      * it finishes successfully.
519      *
520      * @see #WIFI_STATE_CHANGED_ACTION
521      * @see #getWifiState()
522      */
523     public static final int WIFI_STATE_DISABLING = 0;
524     /**
525      * Wi-Fi is disabled.
526      *
527      * @see #WIFI_STATE_CHANGED_ACTION
528      * @see #getWifiState()
529      */
530     public static final int WIFI_STATE_DISABLED = 1;
531     /**
532      * Wi-Fi is currently being enabled. The state will change to {@link #WIFI_STATE_ENABLED} if
533      * it finishes successfully.
534      *
535      * @see #WIFI_STATE_CHANGED_ACTION
536      * @see #getWifiState()
537      */
538     public static final int WIFI_STATE_ENABLING = 2;
539     /**
540      * Wi-Fi is enabled.
541      *
542      * @see #WIFI_STATE_CHANGED_ACTION
543      * @see #getWifiState()
544      */
545     public static final int WIFI_STATE_ENABLED = 3;
546     /**
547      * Wi-Fi is in an unknown state. This state will occur when an error happens while enabling
548      * or disabling.
549      *
550      * @see #WIFI_STATE_CHANGED_ACTION
551      * @see #getWifiState()
552      */
553     public static final int WIFI_STATE_UNKNOWN = 4;
554 
555     /**
556      * Broadcast intent action indicating that Wi-Fi AP has been enabled, disabled,
557      * enabling, disabling, or failed.
558      *
559      * @hide
560      */
561     @SystemApi
562     public static final String WIFI_AP_STATE_CHANGED_ACTION =
563         "android.net.wifi.WIFI_AP_STATE_CHANGED";
564 
565     /**
566      * The lookup key for an int that indicates whether Wi-Fi AP is enabled,
567      * disabled, enabling, disabling, or failed.  Retrieve it with
568      * {@link android.content.Intent#getIntExtra(String,int)}.
569      *
570      * @see #WIFI_AP_STATE_DISABLED
571      * @see #WIFI_AP_STATE_DISABLING
572      * @see #WIFI_AP_STATE_ENABLED
573      * @see #WIFI_AP_STATE_ENABLING
574      * @see #WIFI_AP_STATE_FAILED
575      *
576      * @hide
577      */
578     @SystemApi
579     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
580 
581     /**
582      * An extra containing the int error code for Soft AP start failure.
583      * Can be obtained from the {@link #WIFI_AP_STATE_CHANGED_ACTION} using
584      * {@link android.content.Intent#getIntExtra}.
585      * This extra will only be attached if {@link #EXTRA_WIFI_AP_STATE} is
586      * attached and is equal to {@link #WIFI_AP_STATE_FAILED}.
587      *
588      * The error code will be one of:
589      * {@link #SAP_START_FAILURE_GENERAL},
590      * {@link #SAP_START_FAILURE_NO_CHANNEL},
591      * {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
592      *
593      * @hide
594      */
595     @SystemApi
596     public static final String EXTRA_WIFI_AP_FAILURE_REASON =
597             "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
598     /**
599      * The previous Wi-Fi state.
600      *
601      * @see #EXTRA_WIFI_AP_STATE
602      *
603      * @hide
604      */
605     @SystemApi
606     public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
607     /**
608      * The lookup key for a String extra that stores the interface name used for the Soft AP.
609      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
610      * Retrieve its value with {@link android.content.Intent#getStringExtra(String)}.
611      *
612      * @hide
613      */
614     @SystemApi
615     public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
616             "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
617     /**
618      * The lookup key for an int extra that stores the intended IP mode for this Soft AP.
619      * One of {@link #IFACE_IP_MODE_TETHERED} or {@link #IFACE_IP_MODE_LOCAL_ONLY}.
620      * This extra is included in the broadcast {@link #WIFI_AP_STATE_CHANGED_ACTION}.
621      * Retrieve its value with {@link android.content.Intent#getIntExtra(String, int)}.
622      *
623      * @hide
624      */
625     @SystemApi
626     public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
627 
628     /** @hide */
629     @IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
630         WIFI_AP_STATE_DISABLING,
631         WIFI_AP_STATE_DISABLED,
632         WIFI_AP_STATE_ENABLING,
633         WIFI_AP_STATE_ENABLED,
634         WIFI_AP_STATE_FAILED,
635     })
636     @Retention(RetentionPolicy.SOURCE)
637     public @interface WifiApState {}
638 
639     /**
640      * Wi-Fi AP is currently being disabled. The state will change to
641      * {@link #WIFI_AP_STATE_DISABLED} if it finishes successfully.
642      *
643      * @see #WIFI_AP_STATE_CHANGED_ACTION
644      * @see #getWifiApState()
645      *
646      * @hide
647      */
648     @SystemApi
649     public static final int WIFI_AP_STATE_DISABLING = 10;
650     /**
651      * Wi-Fi AP is disabled.
652      *
653      * @see #WIFI_AP_STATE_CHANGED_ACTION
654      * @see #getWifiState()
655      *
656      * @hide
657      */
658     @SystemApi
659     public static final int WIFI_AP_STATE_DISABLED = 11;
660     /**
661      * Wi-Fi AP is currently being enabled. The state will change to
662      * {@link #WIFI_AP_STATE_ENABLED} if it finishes successfully.
663      *
664      * @see #WIFI_AP_STATE_CHANGED_ACTION
665      * @see #getWifiApState()
666      *
667      * @hide
668      */
669     @SystemApi
670     public static final int WIFI_AP_STATE_ENABLING = 12;
671     /**
672      * Wi-Fi AP is enabled.
673      *
674      * @see #WIFI_AP_STATE_CHANGED_ACTION
675      * @see #getWifiApState()
676      *
677      * @hide
678      */
679     @SystemApi
680     public static final int WIFI_AP_STATE_ENABLED = 13;
681     /**
682      * Wi-Fi AP is in a failed state. This state will occur when an error occurs during
683      * enabling or disabling
684      *
685      * @see #WIFI_AP_STATE_CHANGED_ACTION
686      * @see #getWifiApState()
687      *
688      * @hide
689      */
690     @SystemApi
691     public static final int WIFI_AP_STATE_FAILED = 14;
692 
693     /** @hide */
694     @IntDef(flag = false, prefix = { "SAP_START_FAILURE_" }, value = {
695         SAP_START_FAILURE_GENERAL,
696         SAP_START_FAILURE_NO_CHANNEL,
697         SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION,
698     })
699     @Retention(RetentionPolicy.SOURCE)
700     public @interface SapStartFailure {}
701 
702     /**
703      *  All other reasons for AP start failure besides {@link #SAP_START_FAILURE_NO_CHANNEL} and
704      *  {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}.
705      *
706      *  @hide
707      */
708     @SystemApi
709     public static final int SAP_START_FAILURE_GENERAL= 0;
710 
711     /**
712      *  If Wi-Fi AP start failed, this reason code means that no legal channel exists on user
713      *  selected band due to regulatory constraints.
714      *
715      *  @hide
716      */
717     @SystemApi
718     public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
719 
720     /**
721      *  If Wi-Fi AP start failed, this reason code means that the specified configuration
722      *  is not supported by the current HAL version.
723      *
724      *  @hide
725      */
726     @SystemApi
727     public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2;
728 
729 
730     /** @hide */
731     @IntDef(flag = false, prefix = { "SAP_CLIENT_BLOCKED_REASON_" }, value = {
732         SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER,
733         SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS,
734     })
735     @Retention(RetentionPolicy.SOURCE)
736     public @interface SapClientBlockedReason {}
737 
738     /**
739      *  If Soft Ap client is blocked, this reason code means that client doesn't exist in the
740      *  specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
741      *  and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
742      *  and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
743      *  is configured as well.
744      *  @hide
745      */
746     @SystemApi
747     public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0;
748 
749     /**
750      *  If Soft Ap client is blocked, this reason code means that no more clients can be
751      *  associated to this AP since it reached maximum capacity. The maximum capacity is
752      *  the minimum of {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)} and
753      *  {@link SoftApCapability#getMaxSupportedClients} which get from
754      *  {@link WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}.
755      *
756      *  @hide
757      */
758     @SystemApi
759     public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1;
760 
761     /**
762      * Client disconnected for unspecified reason. This could for example be because the AP is being
763      * shut down.
764      * @hide
765      */
766     public static final int SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED = 2;
767 
768     /** @hide */
769     @Retention(RetentionPolicy.SOURCE)
770     @IntDef(prefix = {"IFACE_IP_MODE_"}, value = {
771             IFACE_IP_MODE_UNSPECIFIED,
772             IFACE_IP_MODE_CONFIGURATION_ERROR,
773             IFACE_IP_MODE_TETHERED,
774             IFACE_IP_MODE_LOCAL_ONLY})
775     public @interface IfaceIpMode {}
776 
777     /**
778      * Interface IP mode unspecified.
779      *
780      * @see #updateInterfaceIpState(String, int)
781      *
782      * @hide
783      */
784     @SystemApi
785     public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
786 
787     /**
788      * Interface IP mode for configuration error.
789      *
790      * @see #updateInterfaceIpState(String, int)
791      *
792      * @hide
793      */
794     @SystemApi
795     public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
796 
797     /**
798      * Interface IP mode for tethering.
799      *
800      * @see #updateInterfaceIpState(String, int)
801      *
802      * @hide
803      */
804     @SystemApi
805     public static final int IFACE_IP_MODE_TETHERED = 1;
806 
807     /**
808      * Interface IP mode for Local Only Hotspot.
809      *
810      * @see #updateInterfaceIpState(String, int)
811      *
812      * @hide
813      */
814     @SystemApi
815     public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
816 
817     /**
818      * Broadcast intent action indicating that the wifi network settings
819      * had been reset.
820      *
821      * Note: This intent is sent as a directed broadcast to each manifest registered receiver.
822      * Intent will not be received by dynamically registered receivers.
823      * @hide
824      */
825     @SystemApi
826     @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
827     public static final String ACTION_NETWORK_SETTINGS_RESET =
828             "android.net.wifi.action.NETWORK_SETTINGS_RESET";
829 
830     /**
831      * Broadcast intent action indicating that a connection to the supplicant has
832      * been established (and it is now possible
833      * to perform Wi-Fi operations) or the connection to the supplicant has been
834      * lost. One extra provides the connection state as a boolean, where {@code true}
835      * means CONNECTED.
836      * @deprecated This is no longer supported.
837      * @see #EXTRA_SUPPLICANT_CONNECTED
838      */
839     @Deprecated
840     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
841     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
842         "android.net.wifi.supplicant.CONNECTION_CHANGE";
843     /**
844      * The lookup key for a boolean that indicates whether a connection to
845      * the supplicant daemon has been gained or lost. {@code true} means
846      * a connection now exists.
847      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
848      * @deprecated This is no longer supported.
849      */
850     @Deprecated
851     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
852     /**
853      * Broadcast intent action indicating that the state of Wi-Fi connectivity
854      * has changed. An extra provides the new state
855      * in the form of a {@link android.net.NetworkInfo} object.  No network-related
856      * permissions are required to subscribe to this broadcast.
857      *
858      * <p class="note">This broadcast is not delivered to manifest receivers in
859      * applications that target API version 26 or later.
860      * @see #EXTRA_NETWORK_INFO
861      */
862     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
863     public static final String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
864     /**
865      * The lookup key for a {@link android.net.NetworkInfo} object associated with the
866      * Wi-Fi network. Retrieve with
867      * {@link android.content.Intent#getParcelableExtra(String)}.
868      */
869     public static final String EXTRA_NETWORK_INFO = "networkInfo";
870     /**
871      * The lookup key for a String giving the BSSID of the access point to which
872      * we are connected. No longer used.
873      */
874     @Deprecated
875     public static final String EXTRA_BSSID = "bssid";
876     /**
877      * The lookup key for a {@link android.net.wifi.WifiInfo} object giving the
878      * information about the access point to which we are connected.
879      * No longer used.
880      */
881     @Deprecated
882     public static final String EXTRA_WIFI_INFO = "wifiInfo";
883     /**
884      * Broadcast intent action indicating that the state of establishing a connection to
885      * an access point has changed.One extra provides the new
886      * {@link SupplicantState}. Note that the supplicant state is Wi-Fi specific, and
887      * is not generally the most useful thing to look at if you are just interested in
888      * the overall state of connectivity.
889      * @see #EXTRA_NEW_STATE
890      * @see #EXTRA_SUPPLICANT_ERROR
891      * @deprecated This is no longer supported.
892      */
893     @Deprecated
894     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
895     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
896         "android.net.wifi.supplicant.STATE_CHANGE";
897     /**
898      * The lookup key for a {@link SupplicantState} describing the new state
899      * Retrieve with
900      * {@link android.content.Intent#getParcelableExtra(String)}.
901      * @deprecated This is no longer supported.
902      */
903     @Deprecated
904     public static final String EXTRA_NEW_STATE = "newState";
905 
906     /**
907      * The lookup key for a {@link SupplicantState} describing the supplicant
908      * error code if any
909      * Retrieve with
910      * {@link android.content.Intent#getIntExtra(String, int)}.
911      * @see #ERROR_AUTHENTICATING
912      * @deprecated This is no longer supported.
913      */
914     @Deprecated
915     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
916 
917     /**
918      * The lookup key for a {@link SupplicantState} describing the supplicant
919      * error reason if any
920      * Retrieve with
921      * {@link android.content.Intent#getIntExtra(String, int)}.
922      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
923      * @deprecated This is no longer supported.
924      * @hide
925      */
926     @Deprecated
927     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
928 
929     /**
930      * Broadcast intent action indicating that the configured networks changed.
931      * This can be as a result of adding/updating/deleting a network.
932      * <br />
933      * {@link #EXTRA_CHANGE_REASON} contains whether the configuration was added/changed/removed.
934      * {@link #EXTRA_WIFI_CONFIGURATION} is never set starting in Android 11.
935      * {@link #EXTRA_MULTIPLE_NETWORKS_CHANGED} is set for backwards compatibility reasons, but
936      * its value is always true, even if only a single network changed.
937      * <br />
938      * The {@link android.Manifest.permission#ACCESS_WIFI_STATE ACCESS_WIFI_STATE} permission is
939      * required to receive this broadcast.
940      *
941      * @hide
942      */
943     @SystemApi
944     public static final String CONFIGURED_NETWORKS_CHANGED_ACTION =
945         "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
946     /**
947      * The lookup key for a {@link android.net.wifi.WifiConfiguration} object representing
948      * the changed Wi-Fi configuration when the {@link #CONFIGURED_NETWORKS_CHANGED_ACTION}
949      * broadcast is sent.
950      * Note: this extra is never set starting in Android 11.
951      * @hide
952      */
953     @SystemApi
954     public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
955     /**
956      * Multiple network configurations have changed.
957      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
958      * Note: this extra is always true starting in Android 11.
959      * @hide
960      */
961     @SystemApi
962     public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
963     /**
964      * The lookup key for an integer indicating the reason a Wi-Fi network configuration
965      * has changed. One of {@link #CHANGE_REASON_ADDED}, {@link #CHANGE_REASON_REMOVED},
966      * {@link #CHANGE_REASON_CONFIG_CHANGE}.
967      *
968      * @see #CONFIGURED_NETWORKS_CHANGED_ACTION
969      * @hide
970      */
971     @SystemApi
972     public static final String EXTRA_CHANGE_REASON = "changeReason";
973     /**
974      * The configuration is new and was added.
975      * @hide
976      */
977     @SystemApi
978     public static final int CHANGE_REASON_ADDED = 0;
979     /**
980      * The configuration was removed and is no longer present in the system's list of
981      * configured networks.
982      * @hide
983      */
984     @SystemApi
985     public static final int CHANGE_REASON_REMOVED = 1;
986     /**
987      * The configuration has changed as a result of explicit action or because the system
988      * took an automated action such as disabling a malfunctioning configuration.
989      * @hide
990      */
991     @SystemApi
992     public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
993     /**
994      * An access point scan has completed, and results are available.
995      * Call {@link #getScanResults()} to obtain the results.
996      * The broadcast intent may contain an extra field with the key {@link #EXTRA_RESULTS_UPDATED}
997      * and a {@code boolean} value indicating if the scan was successful.
998      */
999     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1000     public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
1001 
1002     /**
1003      * Lookup key for a {@code boolean} extra in intent {@link #SCAN_RESULTS_AVAILABLE_ACTION}
1004      * representing if the scan was successful or not.
1005      * Scans may fail for multiple reasons, these may include:
1006      * <ol>
1007      * <li>An app requested too many scans in a certain period of time.
1008      * This may lead to additional scan request rejections via "scan throttling" for both
1009      * foreground and background apps.
1010      * Note: Apps holding android.Manifest.permission.NETWORK_SETTINGS permission are
1011      * exempted from scan throttling.
1012      * </li>
1013      * <li>The device is idle and scanning is disabled.</li>
1014      * <li>Wifi hardware reported a scan failure.</li>
1015      * </ol>
1016      * @return true scan was successful, results are updated
1017      * @return false scan was not successful, results haven't been updated since previous scan
1018      */
1019     public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";
1020 
1021     /**
1022      * A batch of access point scans has been completed and the results areavailable.
1023      * Call {@link #getBatchedScanResults()} to obtain the results.
1024      * @deprecated This API is nolonger supported.
1025      * Use {@link android.net.wifi.WifiScanner} API
1026      * @hide
1027      */
1028     @Deprecated
1029     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1030     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
1031             "android.net.wifi.BATCHED_RESULTS";
1032 
1033     /**
1034      * The RSSI (signal strength) has changed.
1035      *
1036      * Receiver Required Permission: android.Manifest.permission.ACCESS_WIFI_STATE
1037      * @see #EXTRA_NEW_RSSI
1038      */
1039     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1040     public static final String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
1041     /**
1042      * The lookup key for an {@code int} giving the new RSSI in dBm.
1043      */
1044     public static final String EXTRA_NEW_RSSI = "newRssi";
1045 
1046     /**
1047      * @see #ACTION_LINK_CONFIGURATION_CHANGED
1048      * @hide
1049      */
1050     @UnsupportedAppUsage
1051     public static final String LINK_CONFIGURATION_CHANGED_ACTION =
1052             "android.net.wifi.LINK_CONFIGURATION_CHANGED";
1053 
1054     /**
1055      * Broadcast intent action indicating that the link configuration changed on wifi.
1056      * <br />Included Extras:
1057      * <br />{@link #EXTRA_LINK_PROPERTIES}: may not be set starting in Android 11. Check for
1058      * <br /> null before reading its value.
1059      * <br /> No permissions are required to listen to this broadcast.
1060      * @hide
1061      */
1062     @SystemApi
1063     public static final String ACTION_LINK_CONFIGURATION_CHANGED =
1064             // should be android.net.wifi.action.LINK_CONFIGURATION_CHANGED, but due to
1065             // @UnsupportedAppUsage leaving it as android.net.wifi.LINK_CONFIGURATION_CHANGED.
1066             LINK_CONFIGURATION_CHANGED_ACTION;
1067 
1068     /**
1069      * The lookup key for a {@link android.net.LinkProperties} object associated with the
1070      * Wi-Fi network.
1071      * Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
1072      *
1073      * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
1074      *
1075      * Note: this extra may not be set starting in Android 11. Check for null before reading its
1076      * value.
1077      *
1078      * @hide
1079      */
1080     @SystemApi
1081     public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
1082 
1083     /**
1084      * The lookup key for a {@link android.net.NetworkCapabilities} object associated with the
1085      * Wi-Fi network. Retrieve with
1086      * {@link android.content.Intent#getParcelableExtra(String)}.
1087      * @hide
1088      */
1089     public static final String EXTRA_NETWORK_CAPABILITIES = "networkCapabilities";
1090 
1091     /**
1092      * The network IDs of the configured networks could have changed.
1093      */
1094     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1095     public static final String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
1096 
1097     /**
1098      * Activity Action: Show a system activity that allows the user to enable
1099      * scans to be available even with Wi-Fi turned off.
1100      *
1101      * <p>Notification of the result of this activity is posted using the
1102      * {@link android.app.Activity#onActivityResult} callback. The
1103      * <code>resultCode</code>
1104      * will be {@link android.app.Activity#RESULT_OK} if scan always mode has
1105      * been turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
1106      * has rejected the request or an error has occurred.
1107      */
1108     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1109     public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE =
1110             "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
1111 
1112     /**
1113      * Activity Action: Pick a Wi-Fi network to connect to.
1114      * <p>Input: Nothing.
1115      * <p>Output: Nothing.
1116      */
1117     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1118     public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
1119 
1120     /**
1121      * Activity Action: Receiver should show UI to get user approval to enable WiFi.
1122      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1123      *           the name of the app requesting the action.
1124      * <p>Output: Nothing.
1125      * <p>No permissions are required to send this action.
1126      * @hide
1127      */
1128     @SystemApi
1129     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1130     public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
1131 
1132     /**
1133      * Activity Action: Receiver should show UI to get user approval to disable WiFi.
1134      * <p>Input: {@link android.content.Intent#EXTRA_PACKAGE_NAME} string extra with
1135      *           the name of the app requesting the action.
1136      * <p>Output: Nothing.
1137      * <p>No permissions are required to send this action.
1138      * @hide
1139      */
1140     @SystemApi
1141     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1142     public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
1143 
1144     /**
1145      * Directed broadcast intent action indicating that the device has connected to one of the
1146      * network suggestions provided by the app. This will be sent post connection to a network
1147      * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
1148      * boolean)}
1149      * flag set.
1150      * <p>
1151      * Note: The broadcast is sent to the app only if it holds
1152      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
1153      *
1154      * @see #EXTRA_NETWORK_SUGGESTION
1155      */
1156     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1157     public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION =
1158             "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
1159     /**
1160      * Sent as as a part of {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} that holds
1161      * an instance of {@link WifiNetworkSuggestion} corresponding to the connected network.
1162      */
1163     public static final String EXTRA_NETWORK_SUGGESTION =
1164             "android.net.wifi.extra.NETWORK_SUGGESTION";
1165 
1166     /**
1167      * Internally used Wi-Fi lock mode representing the case were no locks are held.
1168      * @hide
1169      */
1170     public static final int WIFI_MODE_NO_LOCKS_HELD = 0;
1171 
1172     /**
1173      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1174      * and will behave normally, i.e., it will attempt to automatically
1175      * establish a connection to a remembered access point that is
1176      * within range, and will do periodic scans if there are remembered
1177      * access points but none are in range.
1178      *
1179      * @deprecated This API is non-functional and will have no impact.
1180      */
1181     @Deprecated
1182     public static final int WIFI_MODE_FULL = 1;
1183 
1184     /**
1185      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
1186      * but the only operation that will be supported is initiation of
1187      * scans, and the subsequent reporting of scan results. No attempts
1188      * will be made to automatically connect to remembered access points,
1189      * nor will periodic scans be automatically performed looking for
1190      * remembered access points. Scans must be explicitly requested by
1191      * an application in this mode.
1192      *
1193      * @deprecated This API is non-functional and will have no impact.
1194      */
1195     @Deprecated
1196     public static final int WIFI_MODE_SCAN_ONLY = 2;
1197 
1198     /**
1199      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
1200      * This results in operating with low packet latency.
1201      * The lock is only active when the device is connected to an access point.
1202      * The lock is active even when the device screen is off or the acquiring application is
1203      * running in the background.
1204      * This mode will consume more power and hence should be used only
1205      * when there is a need for this tradeoff.
1206      * <p>
1207      * An example use case is when a voice connection needs to be
1208      * kept active even after the device screen goes off.
1209      * Holding a {@link #WIFI_MODE_FULL_HIGH_PERF} lock for the
1210      * duration of the voice call may improve the call quality.
1211      * <p>
1212      * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
1213      * lock will have no impact.
1214      */
1215     public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
1216 
1217     /**
1218      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
1219      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock has the following limitations:
1220      * <ol>
1221      * <li>The lock is only active when the device is connected to an access point.</li>
1222      * <li>The lock is only active when the screen is on.</li>
1223      * <li>The lock is only active when the acquiring app is running in the foreground.</li>
1224      * </ol>
1225      * Low latency mode optimizes for reduced packet latency,
1226      * and as a result other performance measures may suffer when there are trade-offs to make:
1227      * <ol>
1228      * <li>Battery life may be reduced.</li>
1229      * <li>Throughput may be reduced.</li>
1230      * <li>Frequency of Wi-Fi scanning may be reduced. This may result in: </li>
1231      * <ul>
1232      * <li>The device may not roam or switch to the AP with highest signal quality.</li>
1233      * <li>Location accuracy may be reduced.</li>
1234      * </ul>
1235      * </ol>
1236      * <p>
1237      * Example use cases are real time gaming or virtual reality applications where
1238      * low latency is a key factor for user experience.
1239      * <p>
1240      * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and
1241      * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY}
1242      * lock will be effective when app is running in foreground and screen is on,
1243      * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
1244      */
1245     public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
1246 
1247 
1248     /** Anything worse than or equal to this will show 0 bars. */
1249     @UnsupportedAppUsage
1250     private static final int MIN_RSSI = -100;
1251 
1252     /** Anything better than or equal to this will show the max bars. */
1253     @UnsupportedAppUsage
1254     private static final int MAX_RSSI = -55;
1255 
1256     /**
1257      * Number of RSSI levels used in the framework to initiate {@link #RSSI_CHANGED_ACTION}
1258      * broadcast, where each level corresponds to a range of RSSI values.
1259      * The {@link #RSSI_CHANGED_ACTION} broadcast will only fire if the RSSI
1260      * change is significant enough to change the RSSI signal level.
1261      * @hide
1262      */
1263     @UnsupportedAppUsage
1264     public static final int RSSI_LEVELS = 5;
1265 
1266     //TODO (b/146346676): This needs to be removed, not used in the code.
1267     /**
1268      * Auto settings in the driver. The driver could choose to operate on both
1269      * 2.4 GHz and 5 GHz or make a dynamic decision on selecting the band.
1270      * @hide
1271      */
1272     @UnsupportedAppUsage
1273     public static final int WIFI_FREQUENCY_BAND_AUTO = 0;
1274 
1275     /**
1276      * Operation on 5 GHz alone
1277      * @hide
1278      */
1279     @UnsupportedAppUsage
1280     public static final int WIFI_FREQUENCY_BAND_5GHZ = 1;
1281 
1282     /**
1283      * Operation on 2.4 GHz alone
1284      * @hide
1285      */
1286     @UnsupportedAppUsage
1287     public static final int WIFI_FREQUENCY_BAND_2GHZ = 2;
1288 
1289     /** @hide */
1290     public static final boolean DEFAULT_POOR_NETWORK_AVOIDANCE_ENABLED = false;
1291 
1292     /**
1293      * Maximum number of active locks we allow.
1294      * This limit was added to prevent apps from creating a ridiculous number
1295      * of locks and crashing the system by overflowing the global ref table.
1296      */
1297     private static final int MAX_ACTIVE_LOCKS = 50;
1298 
1299     /** Indicates an invalid SSID. */
1300     public static final String UNKNOWN_SSID = "<unknown ssid>";
1301 
1302     /** @hide */
1303     public static final MacAddress ALL_ZEROS_MAC_ADDRESS =
1304             MacAddress.fromString("00:00:00:00:00:00");
1305 
1306     /* Number of currently active WifiLocks and MulticastLocks */
1307     @UnsupportedAppUsage
1308     private int mActiveLockCount;
1309 
1310     private Context mContext;
1311     @UnsupportedAppUsage
1312     IWifiManager mService;
1313     private final int mTargetSdkVersion;
1314 
1315     private Looper mLooper;
1316     private boolean mVerboseLoggingEnabled = false;
1317 
1318     private final Object mLock = new Object(); // lock guarding access to the following vars
1319     @GuardedBy("mLock")
1320     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
1321     @GuardedBy("mLock")
1322     private LocalOnlyHotspotObserverProxy mLOHSObserverProxy;
1323 
1324     /**
1325      * Create a new WifiManager instance.
1326      * Applications will almost always want to use
1327      * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve
1328      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
1329      *
1330      * @param context the application context
1331      * @param service the Binder interface
1332      * @param looper the Looper used to deliver callbacks
1333      * @hide - hide this because it takes in a parameter of type IWifiManager, which
1334      * is a system private class.
1335      */
WifiManager(@onNull Context context, @NonNull IWifiManager service, @NonNull Looper looper)1336     public WifiManager(@NonNull Context context, @NonNull IWifiManager service,
1337         @NonNull Looper looper) {
1338         mContext = context;
1339         mService = service;
1340         mLooper = looper;
1341         mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
1342         updateVerboseLoggingEnabledFromService();
1343     }
1344 
1345     /**
1346      * Return a list of all the networks configured for the current foreground
1347      * user.
1348      *
1349      * Not all fields of WifiConfiguration are returned. Only the following
1350      * fields are filled in:
1351      * <ul>
1352      * <li>networkId</li>
1353      * <li>SSID</li>
1354      * <li>BSSID</li>
1355      * <li>priority</li>
1356      * <li>allowedProtocols</li>
1357      * <li>allowedKeyManagement</li>
1358      * <li>allowedAuthAlgorithms</li>
1359      * <li>allowedPairwiseCiphers</li>
1360      * <li>allowedGroupCiphers</li>
1361      * <li>status</li>
1362      * </ul>
1363      * @return a list of network configurations in the form of a list
1364      * of {@link WifiConfiguration} objects.
1365      *
1366      * @deprecated
1367      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1368      * mechanism to trigger connection to a Wi-Fi network.
1369      * b) See {@link #addNetworkSuggestions(List)},
1370      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1371      * when auto-connecting to wifi.
1372      * <b>Compatibility Note:</b> For applications targeting
1373      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return an
1374      * empty list.
1375      * <p>
1376      * Deprecation Exemptions:
1377      * <ul>
1378      * <li>Device Owner (DO), Profile Owner (PO) and system apps will have access to the full list.
1379      * <li>Callers with Carrier privilege will receive a restricted list only containing
1380      * configurations which they created.
1381      * </ul>
1382      */
1383     @Deprecated
1384     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
getConfiguredNetworks()1385     public List<WifiConfiguration> getConfiguredNetworks() {
1386         try {
1387             ParceledListSlice<WifiConfiguration> parceledList =
1388                     mService.getConfiguredNetworks(mContext.getOpPackageName(),
1389                             mContext.getAttributionTag());
1390             if (parceledList == null) {
1391                 return Collections.emptyList();
1392             }
1393             return parceledList.getList();
1394         } catch (RemoteException e) {
1395             throw e.rethrowFromSystemServer();
1396         }
1397     }
1398 
1399     /** @hide */
1400     @SystemApi
1401     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL})
getPrivilegedConfiguredNetworks()1402     public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
1403         try {
1404             ParceledListSlice<WifiConfiguration> parceledList =
1405                     mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
1406                             mContext.getAttributionTag());
1407             if (parceledList == null) {
1408                 return Collections.emptyList();
1409             }
1410             return parceledList.getList();
1411         } catch (RemoteException e) {
1412             throw e.rethrowFromSystemServer();
1413         }
1414     }
1415 
1416     /**
1417      * Returns a list of all matching WifiConfigurations for a given list of ScanResult.
1418      *
1419      * An empty list will be returned when no configurations are installed or if no configurations
1420      * match the ScanResult.
1421      *
1422      * @param scanResults a list of scanResult that represents the BSSID
1423      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
1424      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
1425      * @hide
1426      */
1427     @SystemApi
1428     @RequiresPermission(anyOf = {
1429             android.Manifest.permission.NETWORK_SETTINGS,
1430             android.Manifest.permission.NETWORK_SETUP_WIZARD
1431     })
1432     @NonNull
getAllMatchingWifiConfigs( @onNull List<ScanResult> scanResults)1433     public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
1434             @NonNull List<ScanResult> scanResults) {
1435         List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
1436         try {
1437             Map<String, Map<Integer, List<ScanResult>>> results =
1438                     mService.getAllMatchingPasspointProfilesForScanResults(scanResults);
1439             if (results.isEmpty()) {
1440                 return configs;
1441             }
1442             List<WifiConfiguration> wifiConfigurations =
1443                     mService.getWifiConfigsForPasspointProfiles(
1444                             new ArrayList<>(results.keySet()));
1445             for (WifiConfiguration configuration : wifiConfigurations) {
1446                 Map<Integer, List<ScanResult>> scanResultsPerNetworkType =
1447                         results.get(configuration.getKey());
1448                 if (scanResultsPerNetworkType != null) {
1449                     configs.add(Pair.create(configuration, scanResultsPerNetworkType));
1450                 }
1451             }
1452         } catch (RemoteException e) {
1453             throw e.rethrowFromSystemServer();
1454         }
1455 
1456         return configs;
1457     }
1458 
1459     /**
1460      * Retrieve a list of {@link WifiConfiguration} for available {@link WifiNetworkSuggestion}
1461      * matching the given list of {@link ScanResult}.
1462      *
1463      * An available {@link WifiNetworkSuggestion} must satisfy:
1464      * <ul>
1465      * <li> Matching one of the {@link ScanResult} from the given list.
1466      * <li> and {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} set
1467      * to true.
1468      * </ul>
1469      *
1470      * @param scanResults a list of scanResult.
1471      * @return a list of @link WifiConfiguration} for available {@link WifiNetworkSuggestion}
1472      * @hide
1473      */
1474     @SystemApi
1475     @RequiresPermission(anyOf = {
1476             android.Manifest.permission.NETWORK_SETTINGS,
1477             android.Manifest.permission.NETWORK_SETUP_WIZARD
1478     })
1479     @NonNull
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( @onNull List<ScanResult> scanResults)1480     public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
1481             @NonNull List<ScanResult> scanResults) {
1482         try {
1483             return mService.getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults);
1484         } catch (RemoteException e) {
1485             throw e.rethrowAsRuntimeException();
1486         }
1487     }
1488 
1489     /**
1490      * Returns a list of unique Hotspot 2.0 OSU (Online Sign-Up) providers associated with a given
1491      * list of ScanResult.
1492      *
1493      * An empty list will be returned if no match is found.
1494      *
1495      * @param scanResults a list of ScanResult
1496      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
1497      * @hide
1498      */
1499     @SystemApi
1500     @RequiresPermission(anyOf = {
1501             android.Manifest.permission.NETWORK_SETTINGS,
1502             android.Manifest.permission.NETWORK_SETUP_WIZARD
1503     })
1504     @NonNull
getMatchingOsuProviders( @ullable List<ScanResult> scanResults)1505     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
1506             @Nullable List<ScanResult> scanResults) {
1507         if (scanResults == null) {
1508             return new HashMap<>();
1509         }
1510         try {
1511             return mService.getMatchingOsuProviders(scanResults);
1512         } catch (RemoteException e) {
1513             throw e.rethrowFromSystemServer();
1514         }
1515     }
1516 
1517     /**
1518      * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers.
1519      *
1520      * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2
1521      * configurations in the device.
1522      * An empty map will be returned when there is no matching Passpoint R2 configuration for the
1523      * given OsuProviders.
1524      *
1525      * @param osuProviders a set of {@link OsuProvider}
1526      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
1527      * @hide
1528      */
1529     @SystemApi
1530     @RequiresPermission(anyOf = {
1531             android.Manifest.permission.NETWORK_SETTINGS,
1532             android.Manifest.permission.NETWORK_SETUP_WIZARD
1533     })
1534     @NonNull
getMatchingPasspointConfigsForOsuProviders( @onNull Set<OsuProvider> osuProviders)1535     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
1536             @NonNull Set<OsuProvider> osuProviders) {
1537         try {
1538             return mService.getMatchingPasspointConfigsForOsuProviders(
1539                     new ArrayList<>(osuProviders));
1540         } catch (RemoteException e) {
1541             throw e.rethrowFromSystemServer();
1542         }
1543     }
1544 
1545     /**
1546      * Add a new network description to the set of configured networks.
1547      * The {@code networkId} field of the supplied configuration object
1548      * is ignored.
1549      * <p/>
1550      * The new network will be marked DISABLED by default. To enable it,
1551      * called {@link #enableNetwork}.
1552      *
1553      * @param config the set of variables that describe the configuration,
1554      *            contained in a {@link WifiConfiguration} object.
1555      *            If the {@link WifiConfiguration} has an Http Proxy set
1556      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
1557      * @return the ID of the newly created network description. This is used in
1558      *         other operations to specified the network to be acted upon.
1559      *         Returns {@code -1} on failure.
1560      *
1561      * @deprecated
1562      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1563      * mechanism to trigger connection to a Wi-Fi network.
1564      * b) See {@link #addNetworkSuggestions(List)},
1565      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1566      * when auto-connecting to wifi.
1567      * <b>Compatibility Note:</b> For applications targeting
1568      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
1569      * {@code -1}.
1570      * <p>
1571      * Deprecation Exemptions:
1572      * <ul>
1573      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
1574      * </ul>
1575      */
1576     @Deprecated
addNetwork(WifiConfiguration config)1577     public int addNetwork(WifiConfiguration config) {
1578         if (config == null) {
1579             return -1;
1580         }
1581         config.networkId = -1;
1582         return addOrUpdateNetwork(config);
1583     }
1584 
1585     /**
1586      * Update the network description of an existing configured network.
1587      *
1588      * @param config the set of variables that describe the configuration,
1589      *            contained in a {@link WifiConfiguration} object. It may
1590      *            be sparse, so that only the items that are being changed
1591      *            are non-<code>null</code>. The {@code networkId} field
1592      *            must be set to the ID of the existing network being updated.
1593      *            If the {@link WifiConfiguration} has an Http Proxy set
1594      *            the calling app must be System, or be provisioned as the Profile or Device Owner.
1595      * @return Returns the {@code networkId} of the supplied
1596      *         {@code WifiConfiguration} on success.
1597      *         <br/>
1598      *         Returns {@code -1} on failure, including when the {@code networkId}
1599      *         field of the {@code WifiConfiguration} does not refer to an
1600      *         existing network.
1601      *
1602      * @deprecated
1603      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
1604      * mechanism to trigger connection to a Wi-Fi network.
1605      * b) See {@link #addNetworkSuggestions(List)},
1606      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
1607      * when auto-connecting to wifi.
1608      * <b>Compatibility Note:</b> For applications targeting
1609      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
1610      * {@code -1}.
1611      * <p>
1612      * Deprecation Exemptions:
1613      * <ul>
1614      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
1615      * </ul>
1616      */
1617     @Deprecated
updateNetwork(WifiConfiguration config)1618     public int updateNetwork(WifiConfiguration config) {
1619         if (config == null || config.networkId < 0) {
1620             return -1;
1621         }
1622         return addOrUpdateNetwork(config);
1623     }
1624 
1625     /**
1626      * Internal method for doing the RPC that creates a new network description
1627      * or updates an existing one.
1628      *
1629      * @param config The possibly sparse object containing the variables that
1630      *         are to set or updated in the network description.
1631      * @return the ID of the network on success, {@code -1} on failure.
1632      */
addOrUpdateNetwork(WifiConfiguration config)1633     private int addOrUpdateNetwork(WifiConfiguration config) {
1634         try {
1635             return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
1636         } catch (RemoteException e) {
1637             throw e.rethrowFromSystemServer();
1638         }
1639     }
1640 
1641     /**
1642      * Interface for indicating user selection from the list of networks presented in the
1643      * {@link NetworkRequestMatchCallback#onMatch(List)}.
1644      *
1645      * The platform will implement this callback and pass it along with the
1646      * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
1647      * NetworkRequestUserSelectionCallback)}. The UI component handling
1648      * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
1649      * {@link #reject()} to return the user's selection back to the platform via this callback.
1650      * @hide
1651      */
1652     @SystemApi
1653     public interface NetworkRequestUserSelectionCallback {
1654         /**
1655          * User selected this network to connect to.
1656          * @param wifiConfiguration WifiConfiguration object corresponding to the network
1657          *                          user selected.
1658          */
1659         @SuppressLint("CallbackMethodName")
select(@onNull WifiConfiguration wifiConfiguration)1660         default void select(@NonNull WifiConfiguration wifiConfiguration) {}
1661 
1662         /**
1663          * User rejected the app's request.
1664          */
1665         @SuppressLint("CallbackMethodName")
reject()1666         default void reject() {}
1667     }
1668 
1669     /**
1670      * Interface for network request callback. Should be implemented by applications and passed when
1671      * calling {@link #registerNetworkRequestMatchCallback(Executor,
1672      * WifiManager.NetworkRequestMatchCallback)}.
1673      *
1674      * This is meant to be implemented by a UI component to present the user with a list of networks
1675      * matching the app's request. The user is allowed to pick one of these networks to connect to
1676      * or reject the request by the app.
1677      * @hide
1678      */
1679     @SystemApi
1680     public interface NetworkRequestMatchCallback {
1681         /**
1682          * Invoked to register a callback to be invoked to convey user selection. The callback
1683          * object passed in this method is to be invoked by the UI component after the service sends
1684          * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
1685          * from that list.
1686          *
1687          * @param userSelectionCallback Callback object to send back the user selection.
1688          */
onUserSelectionCallbackRegistration( @onNull NetworkRequestUserSelectionCallback userSelectionCallback)1689         default void onUserSelectionCallbackRegistration(
1690                 @NonNull NetworkRequestUserSelectionCallback userSelectionCallback) {}
1691 
1692         /**
1693          * Invoked when the active network request is aborted, either because
1694          * <li> The app released the request, OR</li>
1695          * <li> Request was overridden by a new request</li>
1696          * This signals the end of processing for the current request and should stop the UI
1697          * component. No subsequent calls from the UI component will be handled by the platform.
1698          */
onAbort()1699         default void onAbort() {}
1700 
1701         /**
1702          * Invoked when a network request initiated by an app matches some networks in scan results.
1703          * This may be invoked multiple times for a single network request as the platform finds new
1704          * matching networks in scan results.
1705          *
1706          * @param scanResults List of {@link ScanResult} objects corresponding to the networks
1707          *                    matching the request.
1708          */
onMatch(@onNull List<ScanResult> scanResults)1709         default void onMatch(@NonNull List<ScanResult> scanResults) {}
1710 
1711         /**
1712          * Invoked on a successful connection with the network that the user selected
1713          * via {@link NetworkRequestUserSelectionCallback}.
1714          *
1715          * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
1716          *                          user selected.
1717          */
onUserSelectionConnectSuccess(@onNull WifiConfiguration wifiConfiguration)1718         default void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration) {}
1719 
1720         /**
1721          * Invoked on failure to establish connection with the network that the user selected
1722          * via {@link NetworkRequestUserSelectionCallback}.
1723          *
1724          * @param wifiConfiguration WifiConfiguration object corresponding to the network
1725          *                          user selected.
1726          */
onUserSelectionConnectFailure(@onNull WifiConfiguration wifiConfiguration)1727         default void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration) {}
1728     }
1729 
1730     /**
1731      * Callback proxy for NetworkRequestUserSelectionCallback objects.
1732      * @hide
1733      */
1734     private class NetworkRequestUserSelectionCallbackProxy implements
1735             NetworkRequestUserSelectionCallback {
1736         private final INetworkRequestUserSelectionCallback mCallback;
1737 
NetworkRequestUserSelectionCallbackProxy( INetworkRequestUserSelectionCallback callback)1738         NetworkRequestUserSelectionCallbackProxy(
1739                 INetworkRequestUserSelectionCallback callback) {
1740             mCallback = callback;
1741         }
1742 
1743         @Override
select(@onNull WifiConfiguration wifiConfiguration)1744         public void select(@NonNull WifiConfiguration wifiConfiguration) {
1745             if (mVerboseLoggingEnabled) {
1746                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
1747                         + "wificonfiguration: " + wifiConfiguration);
1748             }
1749             try {
1750                 mCallback.select(wifiConfiguration);
1751             } catch (RemoteException e) {
1752                 Log.e(TAG, "Failed to invoke onSelected", e);
1753                 throw e.rethrowFromSystemServer();
1754             }
1755         }
1756 
1757         @Override
reject()1758         public void reject() {
1759             if (mVerboseLoggingEnabled) {
1760                 Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
1761             }
1762             try {
1763                 mCallback.reject();
1764             } catch (RemoteException e) {
1765                 Log.e(TAG, "Failed to invoke onRejected", e);
1766                 throw e.rethrowFromSystemServer();
1767             }
1768         }
1769     }
1770 
1771     /**
1772      * Callback proxy for NetworkRequestMatchCallback objects.
1773      * @hide
1774      */
1775     private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
1776         private final Executor mExecutor;
1777         private final NetworkRequestMatchCallback mCallback;
1778 
NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback)1779         NetworkRequestMatchCallbackProxy(Executor executor, NetworkRequestMatchCallback callback) {
1780             mExecutor = executor;
1781             mCallback = callback;
1782         }
1783 
1784         @Override
onUserSelectionCallbackRegistration( INetworkRequestUserSelectionCallback userSelectionCallback)1785         public void onUserSelectionCallbackRegistration(
1786                 INetworkRequestUserSelectionCallback userSelectionCallback) {
1787             if (mVerboseLoggingEnabled) {
1788                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
1789                         + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
1790             }
1791             Binder.clearCallingIdentity();
1792             mExecutor.execute(() -> {
1793                 mCallback.onUserSelectionCallbackRegistration(
1794                         new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
1795             });
1796         }
1797 
1798         @Override
onAbort()1799         public void onAbort() {
1800             if (mVerboseLoggingEnabled) {
1801                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onAbort");
1802             }
1803             Binder.clearCallingIdentity();
1804             mExecutor.execute(() -> {
1805                 mCallback.onAbort();
1806             });
1807         }
1808 
1809         @Override
onMatch(List<ScanResult> scanResults)1810         public void onMatch(List<ScanResult> scanResults) {
1811             if (mVerboseLoggingEnabled) {
1812                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch scanResults: "
1813                         + scanResults);
1814             }
1815             Binder.clearCallingIdentity();
1816             mExecutor.execute(() -> {
1817                 mCallback.onMatch(scanResults);
1818             });
1819         }
1820 
1821         @Override
onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration)1822         public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
1823             if (mVerboseLoggingEnabled) {
1824                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
1825                         + " wificonfiguration: " + wifiConfiguration);
1826             }
1827             Binder.clearCallingIdentity();
1828             mExecutor.execute(() -> {
1829                 mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
1830             });
1831         }
1832 
1833         @Override
onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration)1834         public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
1835             if (mVerboseLoggingEnabled) {
1836                 Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
1837                         + " wificonfiguration: " + wifiConfiguration);
1838             }
1839             Binder.clearCallingIdentity();
1840             mExecutor.execute(() -> {
1841                 mCallback.onUserSelectionConnectFailure(wifiConfiguration);
1842             });
1843         }
1844     }
1845 
1846     /**
1847      * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
1848      * Caller can unregister a previously registered callback using
1849      * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
1850      * <p>
1851      * Applications should have the
1852      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
1853      * without the permission will trigger a {@link java.lang.SecurityException}.
1854      * <p>
1855      *
1856      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
1857      *                 object.
1858      * @param callback Callback for network match events to register.
1859      * @hide
1860      */
1861     @SystemApi
1862     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerNetworkRequestMatchCallback(@onNull @allbackExecutor Executor executor, @NonNull NetworkRequestMatchCallback callback)1863     public void registerNetworkRequestMatchCallback(@NonNull @CallbackExecutor Executor executor,
1864             @NonNull NetworkRequestMatchCallback callback) {
1865         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
1866         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
1867         Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
1868                 + ", executor=" + executor);
1869 
1870         Binder binder = new Binder();
1871         try {
1872             mService.registerNetworkRequestMatchCallback(
1873                     binder, new NetworkRequestMatchCallbackProxy(executor, callback),
1874                     callback.hashCode());
1875         } catch (RemoteException e) {
1876             throw e.rethrowFromSystemServer();
1877         }
1878     }
1879 
1880     /**
1881      * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
1882      * <p>
1883      * Applications should have the
1884      * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
1885      * without the permission will trigger a {@link java.lang.SecurityException}.
1886      * <p>
1887      *
1888      * @param callback Callback for network match events to unregister.
1889      * @hide
1890      */
1891     @SystemApi
1892     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterNetworkRequestMatchCallback( @onNull NetworkRequestMatchCallback callback)1893     public void unregisterNetworkRequestMatchCallback(
1894             @NonNull NetworkRequestMatchCallback callback) {
1895         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
1896         Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
1897 
1898         try {
1899             mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
1900         } catch (RemoteException e) {
1901             throw e.rethrowFromSystemServer();
1902         }
1903     }
1904 
1905     /**
1906      * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
1907      * for a detailed explanation of the parameters.
1908      * When the device decides to connect to one of the provided network suggestions, platform sends
1909      * a directed broadcast {@link #ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION} to the app if
1910      * the network was created with
1911      * {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(boolean)} flag set and the
1912      * app holds {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
1913      * permission.
1914      *<p>
1915      * NOTE:
1916      * <li> These networks are just a suggestion to the platform. The platform will ultimately
1917      * decide on which network the device connects to. </li>
1918      * <li> When an app is uninstalled or disabled, all its suggested networks are discarded.
1919      * If the device is currently connected to a suggested network which is being removed then the
1920      * device will disconnect from that network.</li>
1921      * <li> If user reset network settings, all added suggestions will be discarded. Apps can use
1922      * {@link #getNetworkSuggestions()} to check if their suggestions are in the device.</li>
1923      * <li> In-place modification of existing suggestions are allowed.
1924      * <li> If the provided suggestions include any previously provided suggestions by the app,
1925      * previous suggestions will be updated.</li>
1926      * <li>If one of the provided suggestions marks a previously unmetered suggestion as metered and
1927      * the device is currently connected to that suggested network, then the device will disconnect
1928      * from that network. The system will immediately re-evaluate all the network candidates
1929      * and possibly reconnect back to the same suggestion. This disconnect is to make sure that any
1930      * traffic flowing over unmetered networks isn't accidentally continued over a metered network.
1931      * </li>
1932      * </li>
1933      *
1934      * @param networkSuggestions List of network suggestions provided by the app.
1935      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
1936      * @throws {@link SecurityException} if the caller is missing required permissions.
1937      * @see WifiNetworkSuggestion#equals(Object)
1938      */
1939     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
addNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)1940     public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
1941             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
1942         try {
1943             return mService.addNetworkSuggestions(
1944                     networkSuggestions, mContext.getOpPackageName(), mContext.getAttributionTag());
1945         } catch (RemoteException e) {
1946             throw e.rethrowFromSystemServer();
1947         }
1948     }
1949 
1950     /**
1951      * Remove some or all of the network suggestions that were previously provided by the app.
1952      * If one of the suggestions being removed was used to establish connection to the current
1953      * network, then the device will immediately disconnect from that network.
1954      *
1955      * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
1956      * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
1957      *
1958      * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
1959      *                           to remove all the previous suggestions provided by the app.
1960      * @return Status code for the operation. One of the STATUS_NETWORK_SUGGESTIONS_ values.
1961      * Any matching suggestions are removed from the device and will not be considered for any
1962      * further connection attempts.
1963      */
1964     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
removeNetworkSuggestions( @onNull List<WifiNetworkSuggestion> networkSuggestions)1965     public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
1966             @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
1967         try {
1968             return mService.removeNetworkSuggestions(
1969                     networkSuggestions, mContext.getOpPackageName());
1970         } catch (RemoteException e) {
1971             throw e.rethrowFromSystemServer();
1972         }
1973     }
1974 
1975     /**
1976      * Get all network suggestions provided by the calling app.
1977      * See {@link #addNetworkSuggestions(List)}
1978      * See {@link #removeNetworkSuggestions(List)}
1979      * @return a list of {@link WifiNetworkSuggestion}
1980      */
1981     @RequiresPermission(ACCESS_WIFI_STATE)
getNetworkSuggestions()1982     public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
1983         try {
1984             return mService.getNetworkSuggestions(mContext.getOpPackageName());
1985         } catch (RemoteException e) {
1986             throw e.rethrowAsRuntimeException();
1987         }
1988     }
1989 
1990     /**
1991      * Returns the max number of network suggestions that are allowed per app on the device.
1992      * @see #addNetworkSuggestions(List)
1993      * @see #removeNetworkSuggestions(List)
1994      */
getMaxNumberOfNetworkSuggestionsPerApp()1995     public int getMaxNumberOfNetworkSuggestionsPerApp() {
1996         return getMaxNumberOfNetworkSuggestionsPerApp(
1997                 mContext.getSystemService(ActivityManager.class).isLowRamDevice());
1998     }
1999 
2000     /** @hide */
getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice)2001     public static int getMaxNumberOfNetworkSuggestionsPerApp(boolean isLowRamDevice) {
2002         return isLowRamDevice
2003                 ? NETWORK_SUGGESTIONS_MAX_PER_APP_LOW_RAM
2004                 : NETWORK_SUGGESTIONS_MAX_PER_APP_HIGH_RAM;
2005     }
2006 
2007     /**
2008      * Add or update a Passpoint configuration.  The configuration provides a credential
2009      * for connecting to Passpoint networks that are operated by the Passpoint
2010      * service provider specified in the configuration.
2011      *
2012      * Each configuration is uniquely identified by a unique key which depends on the contents of
2013      * the configuration. This allows the caller to install multiple profiles with the same FQDN
2014      * (Fully qualified domain name). Therefore, in order to update an existing profile, it is
2015      * first required to remove it using {@link WifiManager#removePasspointConfiguration(String)}.
2016      * Otherwise, a new profile will be added with both configuration.
2017      *
2018      * @param config The Passpoint configuration to be added
2019      * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
2020      *                                  the device.
2021      *
2022      * Deprecated for general app usage - except DO/PO apps.
2023      * See {@link WifiNetworkSuggestion.Builder#setPasspointConfig(PasspointConfiguration)} to
2024      * create a passpoint suggestion.
2025      * See {@link #addNetworkSuggestions(List)}, {@link #removeNetworkSuggestions(List)} for new
2026      * API to add Wi-Fi networks for consideration when auto-connecting to wifi.
2027      * <b>Compatibility Note:</b> For applications targeting
2028      * {@link android.os.Build.VERSION_CODES#R} or above, this API will always fail and throw
2029      * {@link IllegalArgumentException}.
2030      * <p>
2031      * Deprecation Exemptions:
2032      * <ul>
2033      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2034      * </ul>
2035      */
addOrUpdatePasspointConfiguration(PasspointConfiguration config)2036     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
2037         try {
2038             if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
2039                 throw new IllegalArgumentException();
2040             }
2041         } catch (RemoteException e) {
2042             throw e.rethrowFromSystemServer();
2043         }
2044     }
2045 
2046     /**
2047      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name) added
2048      * by the caller.
2049      *
2050      * @param fqdn The FQDN of the Passpoint configuration added by the caller to be removed
2051      * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
2052      *                                  Passpoint is not enabled on the device.
2053      * @deprecated This will be non-functional in a future release.
2054      */
2055     @Deprecated
2056     @RequiresPermission(anyOf = {
2057             android.Manifest.permission.NETWORK_SETTINGS,
2058             android.Manifest.permission.NETWORK_CARRIER_PROVISIONING
2059     })
removePasspointConfiguration(String fqdn)2060     public void removePasspointConfiguration(String fqdn) {
2061         try {
2062             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
2063                 throw new IllegalArgumentException();
2064             }
2065         } catch (RemoteException e) {
2066             throw e.rethrowFromSystemServer();
2067         }
2068     }
2069 
2070     /**
2071      * Return the list of installed Passpoint configurations added by the caller.
2072      *
2073      * An empty list will be returned when no configurations are installed.
2074      *
2075      * @return A list of {@link PasspointConfiguration} added by the caller
2076      * @deprecated This will be non-functional in a future release.
2077      */
2078     @Deprecated
2079     @RequiresPermission(anyOf = {
2080             android.Manifest.permission.NETWORK_SETTINGS,
2081             android.Manifest.permission.NETWORK_SETUP_WIZARD
2082     })
getPasspointConfigurations()2083     public List<PasspointConfiguration> getPasspointConfigurations() {
2084         try {
2085             return mService.getPasspointConfigurations(mContext.getOpPackageName());
2086         } catch (RemoteException e) {
2087             throw e.rethrowFromSystemServer();
2088         }
2089     }
2090 
2091     /**
2092      * Query for a Hotspot 2.0 release 2 OSU icon file. An {@link #ACTION_PASSPOINT_ICON} intent
2093      * will be broadcasted once the request is completed.  The presence of the intent extra
2094      * {@link #EXTRA_ICON} will indicate the result of the request.
2095      * A missing intent extra {@link #EXTRA_ICON} will indicate a failure.
2096      *
2097      * @param bssid The BSSID of the AP
2098      * @param fileName Name of the icon file (remote file) to query from the AP
2099      *
2100      * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
2101      * @hide
2102      */
queryPasspointIcon(long bssid, String fileName)2103     public void queryPasspointIcon(long bssid, String fileName) {
2104         try {
2105             mService.queryPasspointIcon(bssid, fileName);
2106         } catch (RemoteException e) {
2107             throw e.rethrowFromSystemServer();
2108         }
2109     }
2110 
2111     /**
2112      * Match the currently associated network against the SP matching the given FQDN
2113      * @param fqdn FQDN of the SP
2114      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
2115      * @hide
2116      */
matchProviderWithCurrentNetwork(String fqdn)2117     public int matchProviderWithCurrentNetwork(String fqdn) {
2118         try {
2119             return mService.matchProviderWithCurrentNetwork(fqdn);
2120         } catch (RemoteException e) {
2121             throw e.rethrowFromSystemServer();
2122         }
2123     }
2124 
2125     /**
2126      * Deauthenticate and set the re-authentication hold off time for the current network
2127      * @param holdoff hold off time in milliseconds
2128      * @param ess set if the hold off pertains to an ESS rather than a BSS
2129      * @hide
2130      *
2131      * TODO (140167680): This needs to be removed, the implementation is empty!
2132      */
deauthenticateNetwork(long holdoff, boolean ess)2133     public void deauthenticateNetwork(long holdoff, boolean ess) {
2134         try {
2135             mService.deauthenticateNetwork(holdoff, ess);
2136         } catch (RemoteException e) {
2137             throw e.rethrowFromSystemServer();
2138         }
2139     }
2140 
2141     /**
2142      * Remove the specified network from the list of configured networks.
2143      * This may result in the asynchronous delivery of state change
2144      * events.
2145      *
2146      * Applications are not allowed to remove networks created by other
2147      * applications.
2148      *
2149      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
2150      *        #getConfiguredNetworks}.
2151      * @return {@code true} if the operation succeeded
2152      *
2153      * @deprecated
2154      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2155      * mechanism to trigger connection to a Wi-Fi network.
2156      * b) See {@link #addNetworkSuggestions(List)},
2157      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2158      * when auto-connecting to wifi.
2159      * <b>Compatibility Note:</b> For applications targeting
2160      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2161      * {@code false}.
2162      * <p>
2163      * Deprecation Exemptions:
2164      * <ul>
2165      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2166      * </ul>
2167      */
2168     @Deprecated
removeNetwork(int netId)2169     public boolean removeNetwork(int netId) {
2170         try {
2171             return mService.removeNetwork(netId, mContext.getOpPackageName());
2172         } catch (RemoteException e) {
2173             throw e.rethrowFromSystemServer();
2174         }
2175     }
2176 
2177     /**
2178      * Allow a previously configured network to be associated with. If
2179      * <code>attemptConnect</code> is true, an attempt to connect to the selected
2180      * network is initiated. This may result in the asynchronous delivery
2181      * of state change events.
2182      * <p>
2183      * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
2184      * traffic may instead be sent through another network, such as cellular data,
2185      * Bluetooth tethering, or Ethernet. For example, traffic will never use a
2186      * Wi-Fi network that does not provide Internet access (e.g. a wireless
2187      * printer), if another network that does offer Internet access (e.g.
2188      * cellular data) is available. Applications that need to ensure that their
2189      * network traffic uses Wi-Fi should use APIs such as
2190      * {@link Network#bindSocket(java.net.Socket)},
2191      * {@link Network#openConnection(java.net.URL)}, or
2192      * {@link ConnectivityManager#bindProcessToNetwork} to do so.
2193      *
2194      * Applications are not allowed to enable networks created by other
2195      * applications.
2196      *
2197      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
2198      *        #getConfiguredNetworks}.
2199      * @param attemptConnect The way to select a particular network to connect to is specify
2200      *        {@code true} for this parameter.
2201      * @return {@code true} if the operation succeeded
2202      *
2203      * @deprecated
2204      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2205      * mechanism to trigger connection to a Wi-Fi network.
2206      * b) See {@link #addNetworkSuggestions(List)},
2207      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2208      * when auto-connecting to wifi.
2209      * <b>Compatibility Note:</b> For applications targeting
2210      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2211      * {@code false}.
2212      * Deprecation Exemptions:
2213      * <ul>
2214      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2215      * </ul>
2216      */
2217     @Deprecated
enableNetwork(int netId, boolean attemptConnect)2218     public boolean enableNetwork(int netId, boolean attemptConnect) {
2219         try {
2220             return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
2221         } catch (RemoteException e) {
2222             throw e.rethrowFromSystemServer();
2223         }
2224     }
2225 
2226     /**
2227      * Disable a configured network. The specified network will not be
2228      * a candidate for associating. This may result in the asynchronous
2229      * delivery of state change events.
2230      *
2231      * Applications are not allowed to disable networks created by other
2232      * applications.
2233      *
2234      * @param netId the ID of the network as returned by {@link #addNetwork} or {@link
2235      *        #getConfiguredNetworks}.
2236      * @return {@code true} if the operation succeeded
2237      *
2238      * @deprecated
2239      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2240      * mechanism to trigger connection to a Wi-Fi network.
2241      * b) See {@link #addNetworkSuggestions(List)},
2242      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2243      * when auto-connecting to wifi.
2244      * <b>Compatibility Note:</b> For applications targeting
2245      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2246      * {@code false}.
2247      * <p>
2248      * Deprecation Exemptions:
2249      * <ul>
2250      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2251      * </ul>
2252      */
2253     @Deprecated
disableNetwork(int netId)2254     public boolean disableNetwork(int netId) {
2255         try {
2256             return mService.disableNetwork(netId, mContext.getOpPackageName());
2257         } catch (RemoteException e) {
2258             throw e.rethrowFromSystemServer();
2259         }
2260     }
2261 
2262     /**
2263      * Disassociate from the currently active access point. This may result
2264      * in the asynchronous delivery of state change events.
2265      * @return {@code true} if the operation succeeded
2266      *
2267      * @deprecated
2268      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2269      * mechanism to trigger connection to a Wi-Fi network.
2270      * b) See {@link #addNetworkSuggestions(List)},
2271      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2272      * when auto-connecting to wifi.
2273      * <b>Compatibility Note:</b> For applications targeting
2274      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2275      * {@code false}.
2276      * <p>
2277      * Deprecation Exemptions:
2278      * <ul>
2279      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2280      * </ul>
2281      */
2282     @Deprecated
disconnect()2283     public boolean disconnect() {
2284         try {
2285             return mService.disconnect(mContext.getOpPackageName());
2286         } catch (RemoteException e) {
2287             throw e.rethrowFromSystemServer();
2288         }
2289     }
2290 
2291     /**
2292      * Reconnect to the currently active access point, if we are currently
2293      * disconnected. This may result in the asynchronous delivery of state
2294      * change events.
2295      * @return {@code true} if the operation succeeded
2296      *
2297      * @deprecated
2298      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2299      * mechanism to trigger connection to a Wi-Fi network.
2300      * b) See {@link #addNetworkSuggestions(List)},
2301      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2302      * when auto-connecting to wifi.
2303      * <b>Compatibility Note:</b> For applications targeting
2304      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2305      * {@code false}.
2306      * <p>
2307      * Deprecation Exemptions:
2308      * <ul>
2309      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2310      * </ul>
2311      */
2312     @Deprecated
reconnect()2313     public boolean reconnect() {
2314         try {
2315             return mService.reconnect(mContext.getOpPackageName());
2316         } catch (RemoteException e) {
2317             throw e.rethrowFromSystemServer();
2318         }
2319     }
2320 
2321     /**
2322      * Reconnect to the currently active access point, even if we are already
2323      * connected. This may result in the asynchronous delivery of state
2324      * change events.
2325      * @return {@code true} if the operation succeeded
2326      *
2327      * @deprecated
2328      * a) See {@link WifiNetworkSpecifier.Builder#build()} for new
2329      * mechanism to trigger connection to a Wi-Fi network.
2330      * b) See {@link #addNetworkSuggestions(List)},
2331      * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
2332      * when auto-connecting to wifi.
2333      * <b>Compatibility Note:</b> For applications targeting
2334      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
2335      */
2336     @Deprecated
reassociate()2337     public boolean reassociate() {
2338         try {
2339             return mService.reassociate(mContext.getOpPackageName());
2340         } catch (RemoteException e) {
2341             throw e.rethrowFromSystemServer();
2342         }
2343     }
2344 
2345     /**
2346      * Check that the supplicant daemon is responding to requests.
2347      * @return {@code true} if we were able to communicate with the supplicant and
2348      * it returned the expected response to the PING message.
2349      * @deprecated Will return the output of {@link #isWifiEnabled()} instead.
2350      */
2351     @Deprecated
pingSupplicant()2352     public boolean pingSupplicant() {
2353         return isWifiEnabled();
2354     }
2355 
2356     /** @hide */
2357     public static final long WIFI_FEATURE_INFRA            = 0x0001L;  // Basic infrastructure mode
2358     /** @hide */
2359     public static final long WIFI_FEATURE_PASSPOINT        = 0x0004L;  // Support for GAS/ANQP
2360     /** @hide */
2361     public static final long WIFI_FEATURE_P2P              = 0x0008L;  // Wifi-Direct
2362     /** @hide */
2363     public static final long WIFI_FEATURE_MOBILE_HOTSPOT   = 0x0010L;  // Soft AP
2364     /** @hide */
2365     public static final long WIFI_FEATURE_SCANNER          = 0x0020L;  // WifiScanner APIs
2366     /** @hide */
2367     public static final long WIFI_FEATURE_AWARE            = 0x0040L;  // Wi-Fi AWare networking
2368     /** @hide */
2369     public static final long WIFI_FEATURE_D2D_RTT          = 0x0080L;  // Device-to-device RTT
2370     /** @hide */
2371     public static final long WIFI_FEATURE_D2AP_RTT         = 0x0100L;  // Device-to-AP RTT
2372     /** @hide */
2373     public static final long WIFI_FEATURE_BATCH_SCAN       = 0x0200L;  // Batched Scan (deprecated)
2374     /** @hide */
2375     public static final long WIFI_FEATURE_PNO              = 0x0400L;  // Preferred network offload
2376     /** @hide */
2377     public static final long WIFI_FEATURE_ADDITIONAL_STA   = 0x0800L;  // Support for two STAs
2378     /** @hide */
2379     public static final long WIFI_FEATURE_TDLS             = 0x1000L;  // Tunnel directed link setup
2380     /** @hide */
2381     public static final long WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000L;  // TDLS off channel
2382     /** @hide */
2383     public static final long WIFI_FEATURE_EPR              = 0x4000L;  // Enhanced power reporting
2384     /** @hide */
2385     public static final long WIFI_FEATURE_AP_STA           = 0x8000L;  // AP STA Concurrency
2386     /** @hide */
2387     public static final long WIFI_FEATURE_LINK_LAYER_STATS = 0x10000L; // Link layer stats
2388     /** @hide */
2389     public static final long WIFI_FEATURE_LOGGER           = 0x20000L; // WiFi Logger
2390     /** @hide */
2391     public static final long WIFI_FEATURE_HAL_EPNO         = 0x40000L; // Enhanced PNO
2392     /** @hide */
2393     public static final long WIFI_FEATURE_RSSI_MONITOR     = 0x80000L; // RSSI Monitor
2394     /** @hide */
2395     public static final long WIFI_FEATURE_MKEEP_ALIVE      = 0x100000L; // mkeep_alive
2396     /** @hide */
2397     public static final long WIFI_FEATURE_CONFIG_NDO       = 0x200000L; // ND offload
2398     /** @hide */
2399     public static final long WIFI_FEATURE_TRANSMIT_POWER   = 0x400000L; // Capture transmit power
2400     /** @hide */
2401     public static final long WIFI_FEATURE_CONTROL_ROAMING  = 0x800000L; // Control firmware roaming
2402     /** @hide */
2403     public static final long WIFI_FEATURE_IE_WHITELIST     = 0x1000000L; // Probe IE white listing
2404     /** @hide */
2405     public static final long WIFI_FEATURE_SCAN_RAND        = 0x2000000L; // Random MAC & Probe seq
2406     /** @hide */
2407     public static final long WIFI_FEATURE_TX_POWER_LIMIT   = 0x4000000L; // Set Tx power limit
2408     /** @hide */
2409     public static final long WIFI_FEATURE_WPA3_SAE         = 0x8000000L; // WPA3-Personal SAE
2410     /** @hide */
2411     public static final long WIFI_FEATURE_WPA3_SUITE_B     = 0x10000000L; // WPA3-Enterprise Suite-B
2412     /** @hide */
2413     public static final long WIFI_FEATURE_OWE              = 0x20000000L; // Enhanced Open
2414     /** @hide */
2415     public static final long WIFI_FEATURE_LOW_LATENCY      = 0x40000000L; // Low Latency modes
2416     /** @hide */
2417     public static final long WIFI_FEATURE_DPP              = 0x80000000L; // DPP (Easy-Connect)
2418     /** @hide */
2419     public static final long WIFI_FEATURE_P2P_RAND_MAC     = 0x100000000L; // Random P2P MAC
2420     /** @hide */
2421     public static final long WIFI_FEATURE_CONNECTED_RAND_MAC    = 0x200000000L; // Random STA MAC
2422     /** @hide */
2423     public static final long WIFI_FEATURE_AP_RAND_MAC      = 0x400000000L; // Random AP MAC
2424     /** @hide */
2425     public static final long WIFI_FEATURE_MBO              = 0x800000000L; // MBO Support
2426     /** @hide */
2427     public static final long WIFI_FEATURE_OCE              = 0x1000000000L; // OCE Support
2428     /** @hide */
2429     public static final long WIFI_FEATURE_WAPI             = 0x2000000000L; // WAPI
2430 
2431     /** @hide */
2432     public static final long WIFI_FEATURE_FILS_SHA256     = 0x4000000000L; // FILS-SHA256
2433 
2434     /** @hide */
2435     public static final long WIFI_FEATURE_FILS_SHA384     = 0x8000000000L; // FILS-SHA384
2436 
getSupportedFeatures()2437     private long getSupportedFeatures() {
2438         try {
2439             return mService.getSupportedFeatures();
2440         } catch (RemoteException e) {
2441             throw e.rethrowFromSystemServer();
2442         }
2443     }
2444 
isFeatureSupported(long feature)2445     private boolean isFeatureSupported(long feature) {
2446         return (getSupportedFeatures() & feature) == feature;
2447     }
2448 
2449     /**
2450      * @return true if this adapter supports Passpoint
2451      * @hide
2452      */
isPasspointSupported()2453     public boolean isPasspointSupported() {
2454         return isFeatureSupported(WIFI_FEATURE_PASSPOINT);
2455     }
2456 
2457     /**
2458      * @return true if this adapter supports WifiP2pManager (Wi-Fi Direct)
2459      */
isP2pSupported()2460     public boolean isP2pSupported() {
2461         return isFeatureSupported(WIFI_FEATURE_P2P);
2462     }
2463 
2464     /**
2465      * @return true if this adapter supports portable Wi-Fi hotspot
2466      * @hide
2467      */
2468     @SystemApi
isPortableHotspotSupported()2469     public boolean isPortableHotspotSupported() {
2470         return isFeatureSupported(WIFI_FEATURE_MOBILE_HOTSPOT);
2471     }
2472 
2473     /**
2474      * @return true if this adapter supports WifiScanner APIs
2475      * @hide
2476      */
2477     @SystemApi
isWifiScannerSupported()2478     public boolean isWifiScannerSupported() {
2479         return isFeatureSupported(WIFI_FEATURE_SCANNER);
2480     }
2481 
2482     /**
2483      * @return true if this adapter supports Neighbour Awareness Network APIs
2484      * @hide
2485      */
isWifiAwareSupported()2486     public boolean isWifiAwareSupported() {
2487         return isFeatureSupported(WIFI_FEATURE_AWARE);
2488     }
2489 
2490     /**
2491      * Query whether the device supports Station (STA) + Access point (AP) concurrency or not.
2492      *
2493      * @return true if this device supports STA + AP concurrency, false otherwise.
2494      */
isStaApConcurrencySupported()2495     public boolean isStaApConcurrencySupported() {
2496         return isFeatureSupported(WIFI_FEATURE_AP_STA);
2497     }
2498 
2499     /**
2500      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
2501      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT} and
2502      * {@link android.content.pm.PackageManager#FEATURE_WIFI_AWARE}.
2503      *
2504      * @return true if this adapter supports Device-to-device RTT
2505      * @hide
2506      */
2507     @Deprecated
2508     @SystemApi
isDeviceToDeviceRttSupported()2509     public boolean isDeviceToDeviceRttSupported() {
2510         return isFeatureSupported(WIFI_FEATURE_D2D_RTT);
2511     }
2512 
2513     /**
2514      * @deprecated Please use {@link android.content.pm.PackageManager#hasSystemFeature(String)}
2515      * with {@link android.content.pm.PackageManager#FEATURE_WIFI_RTT}.
2516      *
2517      * @return true if this adapter supports Device-to-AP RTT
2518      */
2519     @Deprecated
isDeviceToApRttSupported()2520     public boolean isDeviceToApRttSupported() {
2521         return isFeatureSupported(WIFI_FEATURE_D2AP_RTT);
2522     }
2523 
2524     /**
2525      * @return true if this adapter supports offloaded connectivity scan
2526      */
isPreferredNetworkOffloadSupported()2527     public boolean isPreferredNetworkOffloadSupported() {
2528         return isFeatureSupported(WIFI_FEATURE_PNO);
2529     }
2530 
2531     /**
2532      * @return true if this adapter supports multiple simultaneous connections
2533      * @hide
2534      */
isAdditionalStaSupported()2535     public boolean isAdditionalStaSupported() {
2536         return isFeatureSupported(WIFI_FEATURE_ADDITIONAL_STA);
2537     }
2538 
2539     /**
2540      * @return true if this adapter supports Tunnel Directed Link Setup
2541      */
isTdlsSupported()2542     public boolean isTdlsSupported() {
2543         return isFeatureSupported(WIFI_FEATURE_TDLS);
2544     }
2545 
2546     /**
2547      * @return true if this adapter supports Off Channel Tunnel Directed Link Setup
2548      * @hide
2549      */
isOffChannelTdlsSupported()2550     public boolean isOffChannelTdlsSupported() {
2551         return isFeatureSupported(WIFI_FEATURE_TDLS_OFFCHANNEL);
2552     }
2553 
2554     /**
2555      * @return true if this adapter supports advanced power/performance counters
2556      */
isEnhancedPowerReportingSupported()2557     public boolean isEnhancedPowerReportingSupported() {
2558         return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
2559     }
2560 
2561     /**
2562      * @return true if this device supports connected MAC randomization.
2563      * @hide
2564      */
2565     @SystemApi
isConnectedMacRandomizationSupported()2566     public boolean isConnectedMacRandomizationSupported() {
2567         return isFeatureSupported(WIFI_FEATURE_CONNECTED_RAND_MAC);
2568     }
2569 
2570     /**
2571      * @return true if this device supports connected MAC randomization.
2572      * @hide
2573      */
2574     @SystemApi
isApMacRandomizationSupported()2575     public boolean isApMacRandomizationSupported() {
2576         return isFeatureSupported(WIFI_FEATURE_AP_RAND_MAC);
2577     }
2578 
2579     /**
2580      * Check if the chipset supports 5GHz band.
2581      * @return {@code true} if supported, {@code false} otherwise.
2582      */
is5GHzBandSupported()2583     public boolean is5GHzBandSupported() {
2584         try {
2585             return mService.is5GHzBandSupported();
2586         } catch (RemoteException e) {
2587             throw e.rethrowFromSystemServer();
2588         }
2589     }
2590 
2591     /**
2592      * Check if the chipset supports 6GHz band.
2593      * @return {@code true} if supported, {@code false} otherwise.
2594      */
is6GHzBandSupported()2595     public boolean is6GHzBandSupported() {
2596         try {
2597             return mService.is6GHzBandSupported();
2598         } catch (RemoteException e) {
2599             throw e.rethrowFromSystemServer();
2600         }
2601     }
2602 
2603     /**
2604      * Check if the chipset supports a certain Wi-Fi standard.
2605      * @param standard the IEEE 802.11 standard to check on.
2606      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
2607      * @return {@code true} if supported, {@code false} otherwise.
2608      */
isWifiStandardSupported(@ifiAnnotations.WifiStandard int standard)2609     public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
2610         try {
2611             return mService.isWifiStandardSupported(standard);
2612         } catch (RemoteException e) {
2613             throw e.rethrowFromSystemServer();
2614         }
2615     }
2616 
2617     /**
2618      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
2619      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
2620      *
2621      * @hide
2622      */
2623     @SystemApi
2624     public interface OnWifiActivityEnergyInfoListener {
2625         /**
2626          * Called when Wi-Fi activity energy info is available.
2627          * Note: this listener is triggered at most once for each call to
2628          * {@link #getWifiActivityEnergyInfoAsync}.
2629          *
2630          * @param info the latest {@link WifiActivityEnergyInfo}, or null if unavailable.
2631          */
onWifiActivityEnergyInfo(@ullable WifiActivityEnergyInfo info)2632         void onWifiActivityEnergyInfo(@Nullable WifiActivityEnergyInfo info);
2633     }
2634 
2635     private static class OnWifiActivityEnergyInfoProxy
2636             extends IOnWifiActivityEnergyInfoListener.Stub {
2637         private final Object mLock = new Object();
2638         @Nullable @GuardedBy("mLock") private Executor mExecutor;
2639         @Nullable @GuardedBy("mLock") private OnWifiActivityEnergyInfoListener mListener;
2640 
OnWifiActivityEnergyInfoProxy(Executor executor, OnWifiActivityEnergyInfoListener listener)2641         OnWifiActivityEnergyInfoProxy(Executor executor,
2642                 OnWifiActivityEnergyInfoListener listener) {
2643             mExecutor = executor;
2644             mListener = listener;
2645         }
2646 
2647         @Override
onWifiActivityEnergyInfo(WifiActivityEnergyInfo info)2648         public void onWifiActivityEnergyInfo(WifiActivityEnergyInfo info) {
2649             Executor executor;
2650             OnWifiActivityEnergyInfoListener listener;
2651             synchronized (mLock) {
2652                 if (mExecutor == null || mListener == null) {
2653                     return;
2654                 }
2655                 executor = mExecutor;
2656                 listener = mListener;
2657                 // null out to allow garbage collection, prevent triggering listener more than once
2658                 mExecutor = null;
2659                 mListener = null;
2660             }
2661             Binder.clearCallingIdentity();
2662             executor.execute(() -> listener.onWifiActivityEnergyInfo(info));
2663         }
2664     }
2665 
2666     /**
2667      * Request to get the current {@link WifiActivityEnergyInfo} asynchronously.
2668      * Note: This method will return null if {@link #isEnhancedPowerReportingSupported()} returns
2669      * false.
2670      *
2671      * @param executor the executor that the listener will be invoked on
2672      * @param listener the listener that will receive the {@link WifiActivityEnergyInfo} object
2673      *                 when it becomes available. The listener will be triggered at most once for
2674      *                 each call to this method.
2675      *
2676      * @hide
2677      */
2678     @SystemApi
2679     @RequiresPermission(ACCESS_WIFI_STATE)
getWifiActivityEnergyInfoAsync( @onNull @allbackExecutor Executor executor, @NonNull OnWifiActivityEnergyInfoListener listener)2680     public void getWifiActivityEnergyInfoAsync(
2681             @NonNull @CallbackExecutor Executor executor,
2682             @NonNull OnWifiActivityEnergyInfoListener listener) {
2683         Objects.requireNonNull(executor, "executor cannot be null");
2684         Objects.requireNonNull(listener, "listener cannot be null");
2685         try {
2686             mService.getWifiActivityEnergyInfoAsync(
2687                     new OnWifiActivityEnergyInfoProxy(executor, listener));
2688         } catch (RemoteException e) {
2689             throw e.rethrowFromSystemServer();
2690         }
2691     }
2692 
2693     /**
2694      * Request a scan for access points. Returns immediately. The availability
2695      * of the results is made known later by means of an asynchronous event sent
2696      * on completion of the scan.
2697      * <p>
2698      * To initiate a Wi-Fi scan, declare the
2699      * {@link android.Manifest.permission#CHANGE_WIFI_STATE}
2700      * permission in the manifest, and perform these steps:
2701      * </p>
2702      * <ol style="1">
2703      * <li>Invoke the following method:
2704      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).startScan()}</li>
2705      * <li>
2706      * Register a BroadcastReceiver to listen to
2707      * {@code SCAN_RESULTS_AVAILABLE_ACTION}.</li>
2708      * <li>When a broadcast is received, call:
2709      * {@code ((WifiManager) getSystemService(WIFI_SERVICE)).getScanResults()}</li>
2710      * </ol>
2711      * @return {@code true} if the operation succeeded, i.e., the scan was initiated.
2712      * @deprecated The ability for apps to trigger scan requests will be removed in a future
2713      * release.
2714      */
2715     @Deprecated
startScan()2716     public boolean startScan() {
2717         return startScan(null);
2718     }
2719 
2720     /** @hide */
2721     @SystemApi
2722     @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
startScan(WorkSource workSource)2723     public boolean startScan(WorkSource workSource) {
2724         try {
2725             String packageName = mContext.getOpPackageName();
2726             String attributionTag = mContext.getAttributionTag();
2727             return mService.startScan(packageName, attributionTag);
2728         } catch (RemoteException e) {
2729             throw e.rethrowFromSystemServer();
2730         }
2731     }
2732 
2733     /**
2734      * WPS has been deprecated from Client mode operation.
2735      *
2736      * @return null
2737      * @hide
2738      * @deprecated This API is deprecated
2739      */
getCurrentNetworkWpsNfcConfigurationToken()2740     public String getCurrentNetworkWpsNfcConfigurationToken() {
2741         return null;
2742     }
2743 
2744     /**
2745      * Return dynamic information about the current Wi-Fi connection, if any is active.
2746      * <p>
2747      * In the connected state, access to the SSID and BSSID requires
2748      * the same permissions as {@link #getScanResults}. If such access is not allowed,
2749      * {@link WifiInfo#getSSID} will return {@link #UNKNOWN_SSID} and
2750      * {@link WifiInfo#getBSSID} will return {@code "02:00:00:00:00:00"}.
2751      * {@link WifiInfo#getPasspointFqdn()} will return null.
2752      * {@link WifiInfo#getPasspointProviderFriendlyName()} will return null.
2753      *
2754      * @return the Wi-Fi information, contained in {@link WifiInfo}.
2755      */
getConnectionInfo()2756     public WifiInfo getConnectionInfo() {
2757         try {
2758             return mService.getConnectionInfo(mContext.getOpPackageName(),
2759                     mContext.getAttributionTag());
2760         } catch (RemoteException e) {
2761             throw e.rethrowFromSystemServer();
2762         }
2763     }
2764 
2765     /**
2766      * Return the results of the latest access point scan.
2767      * @return the list of access points found in the most recent scan. An app must hold
2768      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
2769      * in order to get valid results.
2770      */
getScanResults()2771     public List<ScanResult> getScanResults() {
2772         try {
2773             return mService.getScanResults(mContext.getOpPackageName(),
2774                     mContext.getAttributionTag());
2775         } catch (RemoteException e) {
2776             throw e.rethrowFromSystemServer();
2777         }
2778     }
2779 
2780     /**
2781      * Get the filtered ScanResults which match the network configurations specified by the
2782      * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
2783      * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
2784      * use the matching rules of Hotspot 2.0.
2785      * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
2786      * These may or may not be suggestions which are installed on the device.
2787      * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
2788      * the Wi-Fi service will use the most recent scan results which the system has.
2789      * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
2790      * corresponding to networks which match them.
2791      * @hide
2792      */
2793     @SystemApi
2794     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
2795     @NonNull
getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestionsToMatch, @Nullable List<ScanResult> scanResults)2796     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
2797             @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
2798             @Nullable List<ScanResult> scanResults) {
2799         if (networkSuggestionsToMatch == null) {
2800             throw new IllegalArgumentException("networkSuggestions must not be null.");
2801         }
2802         try {
2803             return mService.getMatchingScanResults(
2804                     networkSuggestionsToMatch, scanResults,
2805                     mContext.getOpPackageName(), mContext.getAttributionTag());
2806         } catch (RemoteException e) {
2807             throw e.rethrowFromSystemServer();
2808         }
2809     }
2810 
2811     /**
2812      * Set if scanning is always available.
2813      *
2814      * If set to {@code true}, apps can issue {@link #startScan} and fetch scan results
2815      * even when Wi-Fi is turned off.
2816      *
2817      * @param isAvailable true to enable, false to disable.
2818      * @hide
2819      * @see #isScanAlwaysAvailable()
2820      */
2821     @SystemApi
2822     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanAlwaysAvailable(boolean isAvailable)2823     public void setScanAlwaysAvailable(boolean isAvailable) {
2824         try {
2825             mService.setScanAlwaysAvailable(isAvailable);
2826         } catch (RemoteException e) {
2827             throw e.rethrowFromSystemServer();
2828         }
2829     }
2830 
2831     /**
2832      * Check if scanning is always available.
2833      *
2834      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results
2835      * even when Wi-Fi is turned off.
2836      *
2837      * To change this setting, see {@link #ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE}.
2838      * @deprecated The ability for apps to trigger scan requests will be removed in a future
2839      * release.
2840      */
2841     @Deprecated
isScanAlwaysAvailable()2842     public boolean isScanAlwaysAvailable() {
2843         try {
2844             return mService.isScanAlwaysAvailable();
2845         } catch (RemoteException e) {
2846             throw e.rethrowFromSystemServer();
2847         }
2848     }
2849 
2850     /**
2851      * Tell the device to persist the current list of configured networks.
2852      * <p>
2853      * Note: It is possible for this method to change the network IDs of
2854      * existing networks. You should assume the network IDs can be different
2855      * after calling this method.
2856      *
2857      * @return {@code false}.
2858      * @deprecated There is no need to call this method -
2859      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
2860      * and {@link #removeNetwork(int)} already persist the configurations automatically.
2861      */
2862     @Deprecated
saveConfiguration()2863     public boolean saveConfiguration() {
2864         return false;
2865     }
2866 
2867     /**
2868      * Get the country code.
2869      * @return the country code in ISO 3166 alpha-2 (2-letter) uppercase format, or null if
2870      * there is no country code configured.
2871      * @hide
2872      */
2873     @Nullable
2874     @SystemApi
2875     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getCountryCode()2876     public String getCountryCode() {
2877         try {
2878             return mService.getCountryCode();
2879         } catch (RemoteException e) {
2880             throw e.rethrowFromSystemServer();
2881         }
2882     }
2883 
2884     /**
2885      * Return the DHCP-assigned addresses from the last successful DHCP request,
2886      * if any.
2887      * @return the DHCP information
2888      */
getDhcpInfo()2889     public DhcpInfo getDhcpInfo() {
2890         try {
2891             return mService.getDhcpInfo();
2892         } catch (RemoteException e) {
2893             throw e.rethrowFromSystemServer();
2894         }
2895     }
2896 
2897     /**
2898      * Enable or disable Wi-Fi.
2899      * <p>
2900      * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
2901      * permission to toggle wifi.
2902      *
2903      * @param enabled {@code true} to enable, {@code false} to disable.
2904      * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
2905      *         either already in the requested state, or in progress toward the requested state.
2906      * @throws  {@link java.lang.SecurityException} if the caller is missing required permissions.
2907      *
2908      * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
2909      * enable/disable Wi-Fi.
2910      * <b>Compatibility Note:</b> For applications targeting
2911      * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
2912      * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
2913      * or below), they can continue to use this API.
2914      * <p>
2915      * Deprecation Exemptions:
2916      * <ul>
2917      * <li>Device Owner (DO), Profile Owner (PO) and system apps.
2918      * </ul>
2919      */
2920     @Deprecated
setWifiEnabled(boolean enabled)2921     public boolean setWifiEnabled(boolean enabled) {
2922         try {
2923             return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
2924         } catch (RemoteException e) {
2925             throw e.rethrowFromSystemServer();
2926         }
2927     }
2928 
2929     /**
2930      * Gets the Wi-Fi enabled state.
2931      * @return One of {@link #WIFI_STATE_DISABLED},
2932      *         {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
2933      *         {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
2934      * @see #isWifiEnabled()
2935      */
getWifiState()2936     public int getWifiState() {
2937         try {
2938             return mService.getWifiEnabledState();
2939         } catch (RemoteException e) {
2940             throw e.rethrowFromSystemServer();
2941         }
2942     }
2943 
2944     /**
2945      * Return whether Wi-Fi is enabled or disabled.
2946      * @return {@code true} if Wi-Fi is enabled
2947      * @see #getWifiState()
2948      */
isWifiEnabled()2949     public boolean isWifiEnabled() {
2950         return getWifiState() == WIFI_STATE_ENABLED;
2951     }
2952 
2953     /**
2954      * Calculates the level of the signal. This should be used any time a signal
2955      * is being shown.
2956      *
2957      * @param rssi The power of the signal measured in RSSI.
2958      * @param numLevels The number of levels to consider in the calculated level.
2959      * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive).
2960      * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the
2961      * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level
2962      * themselves using their own formula.
2963      */
2964     @Deprecated
calculateSignalLevel(int rssi, int numLevels)2965     public static int calculateSignalLevel(int rssi, int numLevels) {
2966         if (rssi <= MIN_RSSI) {
2967             return 0;
2968         } else if (rssi >= MAX_RSSI) {
2969             return numLevels - 1;
2970         } else {
2971             float inputRange = (MAX_RSSI - MIN_RSSI);
2972             float outputRange = (numLevels - 1);
2973             return (int)((float)(rssi - MIN_RSSI) * outputRange / inputRange);
2974         }
2975     }
2976 
2977     /**
2978      * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI
2979      * quality rating thresholds.
2980      * @param rssi a raw RSSI value, in dBm, usually between -55 and -90
2981      * @return the RSSI signal quality rating, in the range
2982      * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI
2983      * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating.
2984      */
2985     @IntRange(from = 0)
calculateSignalLevel(int rssi)2986     public int calculateSignalLevel(int rssi) {
2987         try {
2988             return mService.calculateSignalLevel(rssi);
2989         } catch (RemoteException e) {
2990             throw e.rethrowFromSystemServer();
2991         }
2992     }
2993 
2994     /**
2995      * Get the system default maximum signal level.
2996      * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}.
2997      */
2998     @IntRange(from = 0)
getMaxSignalLevel()2999     public int getMaxSignalLevel() {
3000         return calculateSignalLevel(Integer.MAX_VALUE);
3001     }
3002 
3003     /**
3004      * Compares two signal strengths.
3005      *
3006      * @param rssiA The power of the first signal measured in RSSI.
3007      * @param rssiB The power of the second signal measured in RSSI.
3008      * @return Returns <0 if the first signal is weaker than the second signal,
3009      *         0 if the two signals have the same strength, and >0 if the first
3010      *         signal is stronger than the second signal.
3011      */
compareSignalLevel(int rssiA, int rssiB)3012     public static int compareSignalLevel(int rssiA, int rssiB) {
3013         return rssiA - rssiB;
3014     }
3015 
3016     /**
3017      * Call allowing ConnectivityService to update WifiService with interface mode changes.
3018      *
3019      * @param ifaceName String name of the updated interface, or null to represent all interfaces
3020      * @param mode int representing the new mode, one of:
3021      *             {@link #IFACE_IP_MODE_TETHERED},
3022      *             {@link #IFACE_IP_MODE_LOCAL_ONLY},
3023      *             {@link #IFACE_IP_MODE_CONFIGURATION_ERROR},
3024      *             {@link #IFACE_IP_MODE_UNSPECIFIED}
3025      *
3026      * @hide
3027      */
3028     @SystemApi
3029     @RequiresPermission(anyOf = {
3030             android.Manifest.permission.NETWORK_STACK,
3031             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3032     })
updateInterfaceIpState(@ullable String ifaceName, @IfaceIpMode int mode)3033     public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
3034         try {
3035             mService.updateInterfaceIpState(ifaceName, mode);
3036         } catch (RemoteException e) {
3037             throw e.rethrowFromSystemServer();
3038         }
3039     }
3040 
3041     /**
3042      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
3043      * Note that starting Soft AP mode may disable station mode operation if the device does not
3044      * support concurrency.
3045      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration, or null to
3046      *                   use the persisted Soft AP configuration that was previously set using
3047      *                   {@link #setWifiApConfiguration(WifiConfiguration)}.
3048      * @return {@code true} if the operation succeeded, {@code false} otherwise
3049      *
3050      * @hide
3051      */
3052     @RequiresPermission(anyOf = {
3053             android.Manifest.permission.NETWORK_STACK,
3054             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3055     })
startSoftAp(@ullable WifiConfiguration wifiConfig)3056     public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
3057         try {
3058             return mService.startSoftAp(wifiConfig);
3059         } catch (RemoteException e) {
3060             throw e.rethrowFromSystemServer();
3061         }
3062     }
3063 
3064     /**
3065      * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
3066      * Note that starting Soft AP mode may disable station mode operation if the device does not
3067      * support concurrency.
3068      * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
3069      *                     or null to use the persisted Soft AP configuration that was previously
3070      *                     set using {@link #setSoftApConfiguration(softApConfiguration)}.
3071      * @return {@code true} if the operation succeeded, {@code false} otherwise
3072      *
3073      * @hide
3074      */
3075     @SystemApi
3076     @RequiresPermission(anyOf = {
3077             android.Manifest.permission.NETWORK_STACK,
3078             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3079     })
startTetheredHotspot(@ullable SoftApConfiguration softApConfig)3080     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
3081         try {
3082             return mService.startTetheredHotspot(softApConfig);
3083         } catch (RemoteException e) {
3084             throw e.rethrowFromSystemServer();
3085         }
3086     }
3087 
3088 
3089     /**
3090      * Stop SoftAp mode.
3091      * Note that stopping softap mode will restore the previous wifi mode.
3092      * @return {@code true} if the operation succeeds, {@code false} otherwise
3093      *
3094      * @hide
3095      */
3096     @SystemApi
3097     @RequiresPermission(anyOf = {
3098             android.Manifest.permission.NETWORK_STACK,
3099             NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
3100     })
stopSoftAp()3101     public boolean stopSoftAp() {
3102         try {
3103             return mService.stopSoftAp();
3104         } catch (RemoteException e) {
3105             throw e.rethrowFromSystemServer();
3106         }
3107     }
3108 
3109     /**
3110      * Request a local only hotspot that an application can use to communicate between co-located
3111      * devices connected to the created WiFi hotspot.  The network created by this method will not
3112      * have Internet access.  Each application can make a single request for the hotspot, but
3113      * multiple applications could be requesting the hotspot at the same time.  When multiple
3114      * applications have successfully registered concurrently, they will be sharing the underlying
3115      * hotspot. {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} is called
3116      * when the hotspot is ready for use by the application.
3117      * <p>
3118      * Each application can make a single active call to this method. The {@link
3119      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} callback supplies the
3120      * requestor with a {@link LocalOnlyHotspotReservation} that contains a
3121      * {@link SoftApConfiguration} with the SSID, security type and credentials needed to connect
3122      * to the hotspot.  Communicating this information is up to the application.
3123      * <p>
3124      * If the LocalOnlyHotspot cannot be created, the {@link LocalOnlyHotspotCallback#onFailed(int)}
3125      * method will be called. Example failures include errors bringing up the network or if
3126      * there is an incompatible operating mode.  For example, if the user is currently using Wifi
3127      * Tethering to provide an upstream to another device, LocalOnlyHotspot will not start due to
3128      * an incompatible mode. The possible error codes include:
3129      * {@link LocalOnlyHotspotCallback#ERROR_NO_CHANNEL},
3130      * {@link LocalOnlyHotspotCallback#ERROR_GENERIC},
3131      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE} and
3132      * {@link LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED}.
3133      * <p>
3134      * Internally, requests will be tracked to prevent the hotspot from being torn down while apps
3135      * are still using it.  The {@link LocalOnlyHotspotReservation} object passed in the  {@link
3136      * LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call should be closed when
3137      * the LocalOnlyHotspot is no longer needed using {@link LocalOnlyHotspotReservation#close()}.
3138      * Since the hotspot may be shared among multiple applications, removing the final registered
3139      * application request will trigger the hotspot teardown.  This means that applications should
3140      * not listen to broadcasts containing wifi state to determine if the hotspot was stopped after
3141      * they are done using it. Additionally, once {@link LocalOnlyHotspotReservation#close()} is
3142      * called, applications will not receive callbacks of any kind.
3143      * <p>
3144      * Applications should be aware that the user may also stop the LocalOnlyHotspot through the
3145      * Settings UI; it is not guaranteed to stay up as long as there is a requesting application.
3146      * The requestors will be notified of this case via
3147      * {@link LocalOnlyHotspotCallback#onStopped()}.  Other cases may arise where the hotspot is
3148      * torn down (Emergency mode, etc).  Application developers should be aware that it can stop
3149      * unexpectedly, but they will receive a notification if they have properly registered.
3150      * <p>
3151      * Applications should also be aware that this network will be shared with other applications.
3152      * Applications are responsible for protecting their data on this network (e.g., TLS).
3153      * <p>
3154      * Applications need to have the following permissions to start LocalOnlyHotspot: {@link
3155      * android.Manifest.permission#CHANGE_WIFI_STATE} and {@link
3156      * android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}.  Callers without
3157      * the permissions will trigger a {@link java.lang.SecurityException}.
3158      * <p>
3159      * @param callback LocalOnlyHotspotCallback for the application to receive updates about
3160      * operating status.
3161      * @param handler Handler to be used for callbacks.  If the caller passes a null Handler, the
3162      * main thread will be used.
3163      */
3164     @RequiresPermission(allOf = {
3165             android.Manifest.permission.CHANGE_WIFI_STATE,
3166             android.Manifest.permission.ACCESS_FINE_LOCATION})
startLocalOnlyHotspot(LocalOnlyHotspotCallback callback, @Nullable Handler handler)3167     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
3168             @Nullable Handler handler) {
3169         Executor executor = handler == null ? null : new HandlerExecutor(handler);
3170         startLocalOnlyHotspotInternal(null, executor, callback);
3171     }
3172 
3173     /**
3174      * Starts a local-only hotspot with a specific configuration applied. See
3175      * {@link #startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)}.
3176      *
3177      * Applications need either {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} or
3178      * {@link android.Manifest.permission#NETWORK_SETTINGS} to call this method.
3179      *
3180      * Since custom configuration settings may be incompatible with each other, the hotspot started
3181      * through this method cannot coexist with another hotspot created through
3182      * startLocalOnlyHotspot. If this is attempted, the first hotspot request wins and others
3183      * receive {@link LocalOnlyHotspotCallback#ERROR_GENERIC} through
3184      * {@link LocalOnlyHotspotCallback#onFailed}.
3185      *
3186      * @param config Custom configuration for the hotspot. See {@link SoftApConfiguration}.
3187      * @param executor Executor to run callback methods on, or null to use the main thread.
3188      * @param callback Callback object for updates about hotspot status, or null for no updates.
3189      * @hide
3190      */
3191     @SystemApi
3192     @RequiresPermission(anyOf = {
3193             android.Manifest.permission.NETWORK_SETTINGS,
3194             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startLocalOnlyHotspot(@onNull SoftApConfiguration config, @Nullable Executor executor, @Nullable LocalOnlyHotspotCallback callback)3195     public void startLocalOnlyHotspot(@NonNull SoftApConfiguration config,
3196             @Nullable Executor executor,
3197             @Nullable LocalOnlyHotspotCallback callback) {
3198         Objects.requireNonNull(config);
3199         startLocalOnlyHotspotInternal(config, executor, callback);
3200     }
3201 
3202     /**
3203      * Common implementation of both configurable and non-configurable LOHS.
3204      *
3205      * @param config App-specified configuration, or null. When present, additional privileges are
3206      *               required, and the hotspot cannot be shared with other clients.
3207      * @param executor Executor to run callback methods on, or null to use the main thread.
3208      * @param callback Callback object for updates about hotspot status, or null for no updates.
3209      */
startLocalOnlyHotspotInternal( @ullable SoftApConfiguration config, @Nullable Executor executor, @Nullable LocalOnlyHotspotCallback callback)3210     private void startLocalOnlyHotspotInternal(
3211             @Nullable SoftApConfiguration config,
3212             @Nullable Executor executor,
3213             @Nullable LocalOnlyHotspotCallback callback) {
3214         if (executor == null) {
3215             executor = mContext.getMainExecutor();
3216         }
3217         synchronized (mLock) {
3218             LocalOnlyHotspotCallbackProxy proxy =
3219                     new LocalOnlyHotspotCallbackProxy(this, executor, callback);
3220             try {
3221                 String packageName = mContext.getOpPackageName();
3222                 String featureId = mContext.getAttributionTag();
3223                 int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
3224                         config);
3225                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
3226                     // Send message to the proxy to make sure we call back on the correct thread
3227                     proxy.onHotspotFailed(returnCode);
3228                     return;
3229                 }
3230                 mLOHSCallbackProxy = proxy;
3231             } catch (RemoteException e) {
3232                 throw e.rethrowFromSystemServer();
3233             }
3234         }
3235     }
3236 
3237     /**
3238      * Cancels a pending local only hotspot request.  This can be used by the calling application to
3239      * cancel the existing request if the provided callback has not been triggered.  Calling this
3240      * method will be equivalent to closing the returned LocalOnlyHotspotReservation, but it is not
3241      * explicitly required.
3242      * <p>
3243      * When cancelling this request, application developers should be aware that there may still be
3244      * outstanding local only hotspot requests and the hotspot may still start, or continue running.
3245      * Additionally, if a callback was registered, it will no longer be triggered after calling
3246      * cancel.
3247      *
3248      * @hide
3249      */
3250     @UnsupportedAppUsage
cancelLocalOnlyHotspotRequest()3251     public void cancelLocalOnlyHotspotRequest() {
3252         synchronized (mLock) {
3253             stopLocalOnlyHotspot();
3254         }
3255     }
3256 
3257     /**
3258      *  Method used to inform WifiService that the LocalOnlyHotspot is no longer needed.  This
3259      *  method is used by WifiManager to release LocalOnlyHotspotReservations held by calling
3260      *  applications and removes the internal tracking for the hotspot request.  When all requesting
3261      *  applications are finished using the hotspot, it will be stopped and WiFi will return to the
3262      *  previous operational mode.
3263      *
3264      *  This method should not be called by applications.  Instead, they should call the close()
3265      *  method on their LocalOnlyHotspotReservation.
3266      */
stopLocalOnlyHotspot()3267     private void stopLocalOnlyHotspot() {
3268         synchronized (mLock) {
3269             if (mLOHSCallbackProxy == null) {
3270                 // nothing to do, the callback was already cleaned up.
3271                 return;
3272             }
3273             mLOHSCallbackProxy = null;
3274             try {
3275                 mService.stopLocalOnlyHotspot();
3276             } catch (RemoteException e) {
3277                 throw e.rethrowFromSystemServer();
3278             }
3279         }
3280     }
3281 
3282     /**
3283      * Allow callers (Settings UI) to watch LocalOnlyHotspot state changes.  Callers will
3284      * receive a {@link LocalOnlyHotspotSubscription} object as a parameter of the
3285      * {@link LocalOnlyHotspotObserver#onRegistered(LocalOnlyHotspotSubscription)}. The registered
3286      * callers will receive the {@link LocalOnlyHotspotObserver#onStarted(SoftApConfiguration)} and
3287      * {@link LocalOnlyHotspotObserver#onStopped()} callbacks.
3288      * <p>
3289      * Applications should have the
3290      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}
3291      * permission.  Callers without the permission will trigger a
3292      * {@link java.lang.SecurityException}.
3293      * <p>
3294      * @param observer LocalOnlyHotspotObserver callback.
3295      * @param handler Handler to use for callbacks
3296      *
3297      * @hide
3298      */
watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer, @Nullable Handler handler)3299     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
3300             @Nullable Handler handler) {
3301         Executor executor = handler == null ? mContext.getMainExecutor()
3302                 : new HandlerExecutor(handler);
3303         synchronized (mLock) {
3304             mLOHSObserverProxy =
3305                     new LocalOnlyHotspotObserverProxy(this, executor, observer);
3306             try {
3307                 mService.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
3308                 mLOHSObserverProxy.registered();
3309             } catch (RemoteException e) {
3310                 mLOHSObserverProxy = null;
3311                 throw e.rethrowFromSystemServer();
3312             }
3313         }
3314     }
3315 
3316     /**
3317      * Allow callers to stop watching LocalOnlyHotspot state changes.  After calling this method,
3318      * applications will no longer receive callbacks.
3319      *
3320      * @hide
3321      */
unregisterLocalOnlyHotspotObserver()3322     public void unregisterLocalOnlyHotspotObserver() {
3323         synchronized (mLock) {
3324             if (mLOHSObserverProxy == null) {
3325                 // nothing to do, the callback was already cleaned up
3326                 return;
3327             }
3328             mLOHSObserverProxy = null;
3329             try {
3330                 mService.stopWatchLocalOnlyHotspot();
3331             } catch (RemoteException e) {
3332                 throw e.rethrowFromSystemServer();
3333             }
3334         }
3335     }
3336 
3337     /**
3338      * Gets the tethered Wi-Fi hotspot enabled state.
3339      * @return One of {@link #WIFI_AP_STATE_DISABLED},
3340      *         {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
3341      *         {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
3342      * @see #isWifiApEnabled()
3343      *
3344      * @hide
3345      */
3346     @SystemApi
3347     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
getWifiApState()3348     public int getWifiApState() {
3349         try {
3350             return mService.getWifiApEnabledState();
3351         } catch (RemoteException e) {
3352             throw e.rethrowFromSystemServer();
3353         }
3354     }
3355 
3356     /**
3357      * Return whether tethered Wi-Fi AP is enabled or disabled.
3358      * @return {@code true} if tethered  Wi-Fi AP is enabled
3359      * @see #getWifiApState()
3360      *
3361      * @hide
3362      */
3363     @SystemApi
3364     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
isWifiApEnabled()3365     public boolean isWifiApEnabled() {
3366         return getWifiApState() == WIFI_AP_STATE_ENABLED;
3367     }
3368 
3369     /**
3370      * Gets the tethered Wi-Fi AP Configuration.
3371      * @return AP details in WifiConfiguration
3372      *
3373      * Note that AP detail may contain configuration which is cannot be represented
3374      * by the legacy WifiConfiguration, in such cases a null will be returned.
3375      *
3376      * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
3377      * @hide
3378      */
3379     @Nullable
3380     @SystemApi
3381     @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
3382     @Deprecated
getWifiApConfiguration()3383     public WifiConfiguration getWifiApConfiguration() {
3384         try {
3385             return mService.getWifiApConfiguration();
3386         } catch (RemoteException e) {
3387             throw e.rethrowFromSystemServer();
3388         }
3389     }
3390 
3391     /**
3392      * Gets the Wi-Fi tethered AP Configuration.
3393      * @return AP details in {@link SoftApConfiguration}
3394      *
3395      * @hide
3396      */
3397     @NonNull
3398     @SystemApi
3399     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getSoftApConfiguration()3400     public SoftApConfiguration getSoftApConfiguration() {
3401         try {
3402             return mService.getSoftApConfiguration();
3403         } catch (RemoteException e) {
3404             throw e.rethrowFromSystemServer();
3405         }
3406     }
3407 
3408     /**
3409      * Sets the tethered Wi-Fi AP Configuration.
3410      * @return {@code true} if the operation succeeded, {@code false} otherwise
3411      *
3412      * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
3413      * instead.
3414      * @hide
3415      */
3416     @SystemApi
3417     @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
3418     @Deprecated
setWifiApConfiguration(WifiConfiguration wifiConfig)3419     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
3420         try {
3421             return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
3422         } catch (RemoteException e) {
3423             throw e.rethrowFromSystemServer();
3424         }
3425     }
3426 
3427     /**
3428      * Sets the tethered Wi-Fi AP Configuration.
3429      *
3430      * If the API is called while the tethered soft AP is enabled, the configuration will apply to
3431      * the current soft AP if the new configuration only includes
3432      * {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
3433      * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
3434      * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
3435      * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
3436      * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
3437      *
3438      * Otherwise, the configuration changes will be applied when the Soft AP is next started
3439      * (the framework will not stop/start the AP).
3440      *
3441      * @param softApConfig  A valid SoftApConfiguration specifying the configuration of the SAP.
3442      * @return {@code true} if the operation succeeded, {@code false} otherwise
3443      *
3444      * @hide
3445      */
3446     @SystemApi
3447     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setSoftApConfiguration(@onNull SoftApConfiguration softApConfig)3448     public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
3449         try {
3450             return mService.setSoftApConfiguration(
3451                     softApConfig, mContext.getOpPackageName());
3452         } catch (RemoteException e) {
3453             throw e.rethrowFromSystemServer();
3454         }
3455     }
3456 
3457     /**
3458      * Enable/Disable TDLS on a specific local route.
3459      *
3460      * <p>
3461      * TDLS enables two wireless endpoints to talk to each other directly
3462      * without going through the access point that is managing the local
3463      * network. It saves bandwidth and improves quality of the link.
3464      * </p>
3465      * <p>
3466      * This API enables/disables the option of using TDLS. If enabled, the
3467      * underlying hardware is free to use TDLS or a hop through the access
3468      * point. If disabled, existing TDLS session is torn down and
3469      * hardware is restricted to use access point for transferring wireless
3470      * packets. Default value for all routes is 'disabled', meaning restricted
3471      * to use access point for transferring packets.
3472      * </p>
3473      *
3474      * @param remoteIPAddress IP address of the endpoint to setup TDLS with
3475      * @param enable true = setup and false = tear down TDLS
3476      */
setTdlsEnabled(InetAddress remoteIPAddress, boolean enable)3477     public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
3478         try {
3479             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
3480         } catch (RemoteException e) {
3481             throw e.rethrowFromSystemServer();
3482         }
3483     }
3484 
3485     /**
3486      * Similar to {@link #setTdlsEnabled(InetAddress, boolean) }, except
3487      * this version allows you to specify remote endpoint with a MAC address.
3488      * @param remoteMacAddress MAC address of the remote endpoint such as 00:00:0c:9f:f2:ab
3489      * @param enable true = setup and false = tear down TDLS
3490      */
setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable)3491     public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
3492         try {
3493             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
3494         } catch (RemoteException e) {
3495             throw e.rethrowFromSystemServer();
3496         }
3497     }
3498 
3499     /**
3500      * Passed with {@link ActionListener#onFailure}.
3501      * Indicates that the operation failed due to an internal error.
3502      * @hide
3503      */
3504     public static final int ERROR                       = 0;
3505 
3506     /**
3507      * Passed with {@link ActionListener#onFailure}.
3508      * Indicates that the operation is already in progress
3509      * @hide
3510      */
3511     public static final int IN_PROGRESS                 = 1;
3512 
3513     /**
3514      * Passed with {@link ActionListener#onFailure}.
3515      * Indicates that the operation failed because the framework is busy and
3516      * unable to service the request
3517      * @hide
3518      */
3519     public static final int BUSY                        = 2;
3520 
3521     /** @hide */
3522     @Retention(RetentionPolicy.SOURCE)
3523     @IntDef({ERROR, IN_PROGRESS, BUSY})
3524     public @interface ActionListenerFailureReason {}
3525 
3526     /* WPS specific errors */
3527     /** WPS overlap detected
3528      * @deprecated This is deprecated
3529      */
3530     public static final int WPS_OVERLAP_ERROR           = 3;
3531     /** WEP on WPS is prohibited
3532      * @deprecated This is deprecated
3533      */
3534     public static final int WPS_WEP_PROHIBITED          = 4;
3535     /** TKIP only prohibited
3536      * @deprecated This is deprecated
3537      */
3538     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
3539     /** Authentication failure on WPS
3540      * @deprecated This is deprecated
3541      */
3542     public static final int WPS_AUTH_FAILURE            = 6;
3543     /** WPS timed out
3544      * @deprecated This is deprecated
3545      */
3546     public static final int WPS_TIMED_OUT               = 7;
3547 
3548     /**
3549      * Passed with {@link ActionListener#onFailure}.
3550      * Indicates that the operation failed due to invalid inputs
3551      * @hide
3552      */
3553     public static final int INVALID_ARGS                = 8;
3554 
3555     /**
3556      * Passed with {@link ActionListener#onFailure}.
3557      * Indicates that the operation failed due to user permissions.
3558      * @hide
3559      */
3560     public static final int NOT_AUTHORIZED              = 9;
3561 
3562     /**
3563      * Interface for callback invocation on an application action
3564      * @hide
3565      */
3566     @SystemApi
3567     public interface ActionListener {
3568         /**
3569          * The operation succeeded.
3570          */
onSuccess()3571         void onSuccess();
3572         /**
3573          * The operation failed.
3574          * @param reason The reason for failure depends on the operation.
3575          */
onFailure(@ctionListenerFailureReason int reason)3576         void onFailure(@ActionListenerFailureReason int reason);
3577     }
3578 
3579     /** Interface for callback invocation on a start WPS action
3580      * @deprecated This is deprecated
3581      */
3582     public static abstract class WpsCallback {
3583 
3584         /** WPS start succeeded
3585          * @deprecated This API is deprecated
3586          */
onStarted(String pin)3587         public abstract void onStarted(String pin);
3588 
3589         /** WPS operation completed successfully
3590          * @deprecated This API is deprecated
3591          */
onSucceeded()3592         public abstract void onSucceeded();
3593 
3594         /**
3595          * WPS operation failed
3596          * @param reason The reason for failure could be one of
3597          * {@link #WPS_TKIP_ONLY_PROHIBITED}, {@link #WPS_OVERLAP_ERROR},
3598          * {@link #WPS_WEP_PROHIBITED}, {@link #WPS_TIMED_OUT} or {@link #WPS_AUTH_FAILURE}
3599          * and some generic errors.
3600          * @deprecated This API is deprecated
3601          */
onFailed(int reason)3602         public abstract void onFailed(int reason);
3603     }
3604 
3605     /**
3606      * Base class for soft AP callback. Should be extended by applications and set when calling
3607      * {@link WifiManager#registerSoftApCallback(Executor, SoftApCallback)}.
3608      *
3609      * @hide
3610      */
3611     @SystemApi
3612     public interface SoftApCallback {
3613         /**
3614          * Called when soft AP state changes.
3615          *
3616          * @param state         the new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
3617          *                      {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
3618          *                      {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
3619          * @param failureReason reason when in failed state. One of
3620          *                      {@link #SAP_START_FAILURE_GENERAL},
3621          *                      {@link #SAP_START_FAILURE_NO_CHANNEL},
3622          *                      {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
3623          */
onStateChanged(@ifiApState int state, @SapStartFailure int failureReason)3624         default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
3625 
3626         /**
3627          * Called when the connected clients to soft AP changes.
3628          *
3629          * @param clients the currently connected clients
3630          */
onConnectedClientsChanged(@onNull List<WifiClient> clients)3631         default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
3632 
3633         /**
3634          * Called when information of softap changes.
3635          *
3636          * @param softApInfo is the softap information. {@link SoftApInfo}
3637          */
onInfoChanged(@onNull SoftApInfo softApInfo)3638         default void onInfoChanged(@NonNull SoftApInfo softApInfo) {
3639             // Do nothing: can be updated to add SoftApInfo details (e.g. channel) to the UI.
3640         }
3641 
3642         /**
3643          * Called when capability of softap changes.
3644          *
3645          * @param softApCapability is the softap capability. {@link SoftApCapability}
3646          */
onCapabilityChanged(@onNull SoftApCapability softApCapability)3647         default void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {
3648             // Do nothing: can be updated to add SoftApCapability details (e.g. meximum supported
3649             // client number) to the UI.
3650         }
3651 
3652         /**
3653          * Called when client trying to connect but device blocked the client with specific reason.
3654          *
3655          * Can be used to ask user to update client to allowed list or blocked list
3656          * when reason is {@link SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER}, or
3657          * indicate the block due to maximum supported client number limitation when reason is
3658          * {@link SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS}.
3659          *
3660          * @param client the currently blocked client.
3661          * @param blockedReason one of blocked reason from {@link SapClientBlockedReason}
3662          */
onBlockedClientConnecting(@onNull WifiClient client, @SapClientBlockedReason int blockedReason)3663         default void onBlockedClientConnecting(@NonNull WifiClient client,
3664                 @SapClientBlockedReason int blockedReason) {
3665             // Do nothing: can be used to ask user to update client to allowed list or blocked list.
3666         }
3667     }
3668 
3669     /**
3670      * Callback proxy for SoftApCallback objects.
3671      *
3672      * @hide
3673      */
3674     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
3675         private final Executor mExecutor;
3676         private final SoftApCallback mCallback;
3677 
SoftApCallbackProxy(Executor executor, SoftApCallback callback)3678         SoftApCallbackProxy(Executor executor, SoftApCallback callback) {
3679             mExecutor = executor;
3680             mCallback = callback;
3681         }
3682 
3683         @Override
onStateChanged(int state, int failureReason)3684         public void onStateChanged(int state, int failureReason) {
3685             if (mVerboseLoggingEnabled) {
3686                 Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state
3687                         + ", failureReason=" + failureReason);
3688             }
3689 
3690             Binder.clearCallingIdentity();
3691             mExecutor.execute(() -> {
3692                 mCallback.onStateChanged(state, failureReason);
3693             });
3694         }
3695 
3696         @Override
onConnectedClientsChanged(List<WifiClient> clients)3697         public void onConnectedClientsChanged(List<WifiClient> clients) {
3698             if (mVerboseLoggingEnabled) {
3699                 Log.v(TAG, "SoftApCallbackProxy: onConnectedClientsChanged: clients="
3700                         + clients.size() + " clients");
3701             }
3702 
3703             Binder.clearCallingIdentity();
3704             mExecutor.execute(() -> {
3705                 mCallback.onConnectedClientsChanged(clients);
3706             });
3707         }
3708 
3709         @Override
onInfoChanged(SoftApInfo softApInfo)3710         public void onInfoChanged(SoftApInfo softApInfo) {
3711             if (mVerboseLoggingEnabled) {
3712                 Log.v(TAG, "SoftApCallbackProxy: onInfoChange: softApInfo=" + softApInfo);
3713             }
3714 
3715             Binder.clearCallingIdentity();
3716             mExecutor.execute(() -> {
3717                 mCallback.onInfoChanged(softApInfo);
3718             });
3719         }
3720 
3721         @Override
onCapabilityChanged(SoftApCapability capability)3722         public void onCapabilityChanged(SoftApCapability capability) {
3723             if (mVerboseLoggingEnabled) {
3724                 Log.v(TAG, "SoftApCallbackProxy: onCapabilityChanged: SoftApCapability="
3725                         + capability);
3726             }
3727 
3728             Binder.clearCallingIdentity();
3729             mExecutor.execute(() -> {
3730                 mCallback.onCapabilityChanged(capability);
3731             });
3732         }
3733 
3734         @Override
onBlockedClientConnecting(@onNull WifiClient client, int blockedReason)3735         public void onBlockedClientConnecting(@NonNull WifiClient client, int blockedReason) {
3736             if (mVerboseLoggingEnabled) {
3737                 Log.v(TAG, "SoftApCallbackProxy: onBlockedClientConnecting: client=" + client
3738                         + " with reason = " + blockedReason);
3739             }
3740 
3741             Binder.clearCallingIdentity();
3742             mExecutor.execute(() -> {
3743                 mCallback.onBlockedClientConnecting(client, blockedReason);
3744             });
3745         }
3746     }
3747 
3748     /**
3749      * Registers a callback for Soft AP. See {@link SoftApCallback}. Caller will receive the
3750      * following callbacks on registration:
3751      * <ul>
3752      * <li> {@link SoftApCallback#onStateChanged(int, int)}</li>
3753      * <li> {@link SoftApCallback#onConnectedClientsChanged(List<WifiClient>)}</li>
3754      * <li> {@link SoftApCallback#onInfoChanged(SoftApInfo)}</li>
3755      * <li> {@link SoftApCallback#onCapabilityChanged(SoftApCapability)}</li>
3756      * </ul>
3757      * These will be dispatched on registration to provide the caller with the current state
3758      * (and are not an indication of any current change). Note that receiving an immediate
3759      * WIFI_AP_STATE_FAILED value for soft AP state indicates that the latest attempt to start
3760      * soft AP has failed. Caller can unregister a previously registered callback using
3761      * {@link #unregisterSoftApCallback}
3762      * <p>
3763      * Applications should have the
3764      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
3765      * without the permission will trigger a {@link java.lang.SecurityException}.
3766      * <p>
3767      *
3768      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
3769      *                 object.
3770      * @param callback Callback for soft AP events
3771      * @hide
3772      */
3773     @SystemApi
3774     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerSoftApCallback(@onNull @allbackExecutor Executor executor, @NonNull SoftApCallback callback)3775     public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
3776             @NonNull SoftApCallback callback) {
3777         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
3778         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3779         Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
3780 
3781         Binder binder = new Binder();
3782         try {
3783             mService.registerSoftApCallback(
3784                     binder, new SoftApCallbackProxy(executor, callback), callback.hashCode());
3785         } catch (RemoteException e) {
3786             throw e.rethrowFromSystemServer();
3787         }
3788     }
3789 
3790     /**
3791      * Allow callers to unregister a previously registered callback. After calling this method,
3792      * applications will no longer receive soft AP events.
3793      *
3794      * @param callback Callback to unregister for soft AP events
3795      *
3796      * @hide
3797      */
3798     @SystemApi
3799     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterSoftApCallback(@onNull SoftApCallback callback)3800     public void unregisterSoftApCallback(@NonNull SoftApCallback callback) {
3801         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
3802         Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
3803 
3804         try {
3805             mService.unregisterSoftApCallback(callback.hashCode());
3806         } catch (RemoteException e) {
3807             throw e.rethrowFromSystemServer();
3808         }
3809     }
3810 
3811     /**
3812      * LocalOnlyHotspotReservation that contains the {@link SoftApConfiguration} for the active
3813      * LocalOnlyHotspot request.
3814      * <p>
3815      * Applications requesting LocalOnlyHotspot for sharing will receive an instance of the
3816      * LocalOnlyHotspotReservation in the
3817      * {@link LocalOnlyHotspotCallback#onStarted(LocalOnlyHotspotReservation)} call.  This
3818      * reservation contains the relevant {@link SoftApConfiguration}.
3819      * When an application is done with the LocalOnlyHotspot, they should call {@link
3820      * LocalOnlyHotspotReservation#close()}.  Once this happens, the application will not receive
3821      * any further callbacks. If the LocalOnlyHotspot is stopped due to a
3822      * user triggered mode change, applications will be notified via the {@link
3823      * LocalOnlyHotspotCallback#onStopped()} callback.
3824      */
3825     public class LocalOnlyHotspotReservation implements AutoCloseable {
3826 
3827         private final CloseGuard mCloseGuard = new CloseGuard();
3828         private final SoftApConfiguration mSoftApConfig;
3829         private final WifiConfiguration mWifiConfig;
3830         private boolean mClosed = false;
3831 
3832         /** @hide */
3833         @VisibleForTesting
LocalOnlyHotspotReservation(SoftApConfiguration config)3834         public LocalOnlyHotspotReservation(SoftApConfiguration config) {
3835             mSoftApConfig = config;
3836             mWifiConfig = config.toWifiConfiguration();
3837             mCloseGuard.open("close");
3838         }
3839 
3840         /**
3841          * Returns the {@link WifiConfiguration} of the current Local Only Hotspot (LOHS).
3842          * May be null if hotspot enabled and security type is not
3843          * {@code WifiConfiguration.KeyMgmt.None} or {@code WifiConfiguration.KeyMgmt.WPA2_PSK}.
3844          *
3845          * @deprecated Use {@code WifiManager#getSoftApConfiguration()} to get the
3846          * LOHS configuration.
3847          */
3848         @Deprecated
3849         @Nullable
getWifiConfiguration()3850         public WifiConfiguration getWifiConfiguration() {
3851             return mWifiConfig;
3852         }
3853 
3854         /**
3855          * Returns the {@link SoftApConfiguration} of the current Local Only Hotspot (LOHS).
3856          */
3857         @NonNull
getSoftApConfiguration()3858         public SoftApConfiguration getSoftApConfiguration() {
3859             return mSoftApConfig;
3860         }
3861 
3862         @Override
close()3863         public void close() {
3864             try {
3865                 synchronized (mLock) {
3866                     if (!mClosed) {
3867                         mClosed = true;
3868                         stopLocalOnlyHotspot();
3869                         mCloseGuard.close();
3870                     }
3871                 }
3872             } catch (Exception e) {
3873                 Log.e(TAG, "Failed to stop Local Only Hotspot.");
3874             } finally {
3875                 Reference.reachabilityFence(this);
3876             }
3877         }
3878 
3879         @Override
finalize()3880         protected void finalize() throws Throwable {
3881             try {
3882                 if (mCloseGuard != null) {
3883                     mCloseGuard.warnIfOpen();
3884                 }
3885                 close();
3886             } finally {
3887                 super.finalize();
3888             }
3889         }
3890     }
3891 
3892     /**
3893      * Callback class for applications to receive updates about the LocalOnlyHotspot status.
3894      */
3895     public static class LocalOnlyHotspotCallback {
3896         /** @hide */
3897         public static final int REQUEST_REGISTERED = 0;
3898 
3899         public static final int ERROR_NO_CHANNEL = 1;
3900         public static final int ERROR_GENERIC = 2;
3901         public static final int ERROR_INCOMPATIBLE_MODE = 3;
3902         public static final int ERROR_TETHERING_DISALLOWED = 4;
3903 
3904         /** LocalOnlyHotspot start succeeded. */
onStarted(LocalOnlyHotspotReservation reservation)3905         public void onStarted(LocalOnlyHotspotReservation reservation) {};
3906 
3907         /**
3908          * LocalOnlyHotspot stopped.
3909          * <p>
3910          * The LocalOnlyHotspot can be disabled at any time by the user.  When this happens,
3911          * applications will be notified that it was stopped. This will not be invoked when an
3912          * application calls {@link LocalOnlyHotspotReservation#close()}.
3913          */
onStopped()3914         public void onStopped() {};
3915 
3916         /**
3917          * LocalOnlyHotspot failed to start.
3918          * <p>
3919          * Applications can attempt to call
3920          * {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback, Handler)} again at
3921          * a later time.
3922          * <p>
3923          * @param reason The reason for failure could be one of: {@link
3924          * #ERROR_TETHERING_DISALLOWED}, {@link #ERROR_INCOMPATIBLE_MODE},
3925          * {@link #ERROR_NO_CHANNEL}, or {@link #ERROR_GENERIC}.
3926          */
onFailed(int reason)3927         public void onFailed(int reason) { };
3928     }
3929 
3930     /**
3931      * Callback proxy for LocalOnlyHotspotCallback objects.
3932      */
3933     private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub {
3934         private final WeakReference<WifiManager> mWifiManager;
3935         private final Executor mExecutor;
3936         private final LocalOnlyHotspotCallback mCallback;
3937 
3938         /**
3939          * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor.  All
3940          * callbacks will run using the given executor.
3941          *
3942          * @param manager WifiManager
3943          * @param executor Executor for delivering callbacks.
3944          * @param callback LocalOnlyHotspotCallback to notify the calling application, or null.
3945          */
LocalOnlyHotspotCallbackProxy( @onNull WifiManager manager, @NonNull Executor executor, @Nullable LocalOnlyHotspotCallback callback)3946         LocalOnlyHotspotCallbackProxy(
3947                 @NonNull WifiManager manager,
3948                 @NonNull Executor executor,
3949                 @Nullable LocalOnlyHotspotCallback callback) {
3950             mWifiManager = new WeakReference<>(manager);
3951             mExecutor = executor;
3952             mCallback = callback;
3953         }
3954 
3955         @Override
onHotspotStarted(SoftApConfiguration config)3956         public void onHotspotStarted(SoftApConfiguration config) {
3957             WifiManager manager = mWifiManager.get();
3958             if (manager == null) return;
3959 
3960             if (config == null) {
3961                 Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
3962                 onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
3963                 return;
3964             }
3965             final LocalOnlyHotspotReservation reservation =
3966                     manager.new LocalOnlyHotspotReservation(config);
3967             if (mCallback == null) return;
3968             mExecutor.execute(() -> mCallback.onStarted(reservation));
3969         }
3970 
3971         @Override
onHotspotStopped()3972         public void onHotspotStopped() {
3973             WifiManager manager = mWifiManager.get();
3974             if (manager == null) return;
3975 
3976             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
3977             if (mCallback == null) return;
3978             mExecutor.execute(() -> mCallback.onStopped());
3979         }
3980 
3981         @Override
onHotspotFailed(int reason)3982         public void onHotspotFailed(int reason) {
3983             WifiManager manager = mWifiManager.get();
3984             if (manager == null) return;
3985 
3986             Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
3987                     + reason);
3988             if (mCallback == null) return;
3989             mExecutor.execute(() -> mCallback.onFailed(reason));
3990         }
3991     }
3992 
3993     /**
3994      * LocalOnlyHotspotSubscription that is an AutoCloseable object for tracking applications
3995      * watching for LocalOnlyHotspot changes.
3996      *
3997      * @hide
3998      */
3999     public class LocalOnlyHotspotSubscription implements AutoCloseable {
4000         private final CloseGuard mCloseGuard = new CloseGuard();
4001 
4002         /** @hide */
4003         @VisibleForTesting
LocalOnlyHotspotSubscription()4004         public LocalOnlyHotspotSubscription() {
4005             mCloseGuard.open("close");
4006         }
4007 
4008         @Override
close()4009         public void close() {
4010             try {
4011                 unregisterLocalOnlyHotspotObserver();
4012                 mCloseGuard.close();
4013             } catch (Exception e) {
4014                 Log.e(TAG, "Failed to unregister LocalOnlyHotspotObserver.");
4015             } finally {
4016                 Reference.reachabilityFence(this);
4017             }
4018         }
4019 
4020         @Override
finalize()4021         protected void finalize() throws Throwable {
4022             try {
4023                 if (mCloseGuard != null) {
4024                     mCloseGuard.warnIfOpen();
4025                 }
4026                 close();
4027             } finally {
4028                 super.finalize();
4029             }
4030         }
4031     }
4032 
4033     /**
4034      * Class to notify calling applications that watch for changes in LocalOnlyHotspot of updates.
4035      *
4036      * @hide
4037      */
4038     public static class LocalOnlyHotspotObserver {
4039         /**
4040          * Confirm registration for LocalOnlyHotspotChanges by returning a
4041          * LocalOnlyHotspotSubscription.
4042          */
onRegistered(LocalOnlyHotspotSubscription subscription)4043         public void onRegistered(LocalOnlyHotspotSubscription subscription) {};
4044 
4045         /**
4046          * LocalOnlyHotspot started with the supplied config.
4047          */
onStarted(SoftApConfiguration config)4048         public void onStarted(SoftApConfiguration config) {};
4049 
4050         /**
4051          * LocalOnlyHotspot stopped.
4052          */
onStopped()4053         public void onStopped() {};
4054     }
4055 
4056     /**
4057      * Callback proxy for LocalOnlyHotspotObserver objects.
4058      */
4059     private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub {
4060         private final WeakReference<WifiManager> mWifiManager;
4061         private final Executor mExecutor;
4062         private final LocalOnlyHotspotObserver mObserver;
4063 
4064         /**
4065          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
4066          * All callbacks will be delivered on the thread of the specified looper.
4067          *
4068          * @param manager WifiManager
4069          * @param executor Executor for delivering callbacks
4070          * @param observer LocalOnlyHotspotObserver to notify the calling application.
4071          */
LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor, final LocalOnlyHotspotObserver observer)4072         LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor,
4073                 final LocalOnlyHotspotObserver observer) {
4074             mWifiManager = new WeakReference<>(manager);
4075             mExecutor = executor;
4076             mObserver = observer;
4077         }
4078 
registered()4079         public void registered() throws RemoteException {
4080             WifiManager manager = mWifiManager.get();
4081             if (manager == null) return;
4082 
4083             mExecutor.execute(() ->
4084                     mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription()));
4085         }
4086 
4087         @Override
onHotspotStarted(SoftApConfiguration config)4088         public void onHotspotStarted(SoftApConfiguration config) {
4089             WifiManager manager = mWifiManager.get();
4090             if (manager == null) return;
4091 
4092             if (config == null) {
4093                 Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
4094                 return;
4095             }
4096             mExecutor.execute(() -> mObserver.onStarted(config));
4097         }
4098 
4099         @Override
onHotspotStopped()4100         public void onHotspotStopped() {
4101             WifiManager manager = mWifiManager.get();
4102             if (manager == null) return;
4103 
4104             mExecutor.execute(() -> mObserver.onStopped());
4105         }
4106 
4107         @Override
onHotspotFailed(int reason)4108         public void onHotspotFailed(int reason) {
4109             // do nothing
4110         }
4111     }
4112 
4113     /**
4114      * Callback proxy for ActionListener objects.
4115      */
4116     private class ActionListenerProxy extends IActionListener.Stub {
4117         private final String mActionTag;
4118         private final Handler mHandler;
4119         private final ActionListener mCallback;
4120 
ActionListenerProxy(String actionTag, Looper looper, ActionListener callback)4121         ActionListenerProxy(String actionTag, Looper looper, ActionListener callback) {
4122             mActionTag = actionTag;
4123             mHandler = new Handler(looper);
4124             mCallback = callback;
4125         }
4126 
4127         @Override
onSuccess()4128         public void onSuccess() {
4129             if (mVerboseLoggingEnabled) {
4130                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onSuccess");
4131             }
4132             mHandler.post(() -> {
4133                 mCallback.onSuccess();
4134             });
4135         }
4136 
4137         @Override
onFailure(@ctionListenerFailureReason int reason)4138         public void onFailure(@ActionListenerFailureReason int reason) {
4139             if (mVerboseLoggingEnabled) {
4140                 Log.v(TAG, "ActionListenerProxy:" + mActionTag + ": onFailure=" + reason);
4141             }
4142             mHandler.post(() -> {
4143                 mCallback.onFailure(reason);
4144             });
4145         }
4146     }
4147 
connectInternal(@ullable WifiConfiguration config, int networkId, @Nullable ActionListener listener)4148     private void connectInternal(@Nullable WifiConfiguration config, int networkId,
4149             @Nullable ActionListener listener) {
4150         ActionListenerProxy listenerProxy = null;
4151         Binder binder = null;
4152         if (listener != null) {
4153             listenerProxy = new ActionListenerProxy("connect", mLooper, listener);
4154             binder = new Binder();
4155         }
4156         try {
4157             mService.connect(config, networkId, binder, listenerProxy,
4158                     listener == null ? 0 : listener.hashCode());
4159         } catch (RemoteException e) {
4160             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
4161         } catch (SecurityException e) {
4162             if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
4163         }
4164     }
4165 
4166     /**
4167      * Connect to a network with the given configuration. The network also
4168      * gets added to the list of configured networks for the foreground user.
4169      *
4170      * For a new network, this function is used instead of a
4171      * sequence of addNetwork(), enableNetwork(), and reconnect()
4172      *
4173      * @param config the set of variables that describe the configuration,
4174      *            contained in a {@link WifiConfiguration} object.
4175      * @param listener for callbacks on success or failure. Can be null.
4176      * @throws IllegalStateException if the WifiManager instance needs to be
4177      * initialized again
4178      *
4179      * @hide
4180      */
4181     @SystemApi
4182     @RequiresPermission(anyOf = {
4183             android.Manifest.permission.NETWORK_SETTINGS,
4184             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4185             android.Manifest.permission.NETWORK_STACK
4186     })
connect(@onNull WifiConfiguration config, @Nullable ActionListener listener)4187     public void connect(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
4188         if (config == null) throw new IllegalArgumentException("config cannot be null");
4189         connectInternal(config, WifiConfiguration.INVALID_NETWORK_ID, listener);
4190     }
4191 
4192     /**
4193      * Connect to a network with the given networkId.
4194      *
4195      * This function is used instead of a enableNetwork() and reconnect()
4196      *
4197      * <li> This API will cause reconnect if the credentials of the current active
4198      * connection has been changed.</li>
4199      * <li> This API will cause reconnect if the current active connection is marked metered.</li>
4200      *
4201      * @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
4202      *        getConfiguredNetworks}.
4203      * @param listener for callbacks on success or failure. Can be null.
4204      * @throws IllegalStateException if the WifiManager instance needs to be
4205      * initialized again
4206      * @hide
4207      */
4208     @SystemApi
4209     @RequiresPermission(anyOf = {
4210             android.Manifest.permission.NETWORK_SETTINGS,
4211             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4212             android.Manifest.permission.NETWORK_STACK
4213     })
connect(int networkId, @Nullable ActionListener listener)4214     public void connect(int networkId, @Nullable ActionListener listener) {
4215         if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
4216         connectInternal(null, networkId, listener);
4217     }
4218 
4219     /**
4220      * Save the given network to the list of configured networks for the
4221      * foreground user. If the network already exists, the configuration
4222      * is updated. Any new network is enabled by default.
4223      *
4224      * For a new network, this function is used instead of a
4225      * sequence of addNetwork() and enableNetwork().
4226      *
4227      * For an existing network, it accomplishes the task of updateNetwork()
4228      *
4229      * <li> This API will cause reconnect if the credentials of the current active
4230      * connection has been changed.</li>
4231      * <li> This API will cause disconnect if the current active connection is marked metered.</li>
4232      *
4233      * @param config the set of variables that describe the configuration,
4234      *            contained in a {@link WifiConfiguration} object.
4235      * @param listener for callbacks on success or failure. Can be null.
4236      * @throws IllegalStateException if the WifiManager instance needs to be
4237      * initialized again
4238      * @hide
4239      */
4240     @SystemApi
4241     @RequiresPermission(anyOf = {
4242             android.Manifest.permission.NETWORK_SETTINGS,
4243             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4244             android.Manifest.permission.NETWORK_STACK
4245     })
save(@onNull WifiConfiguration config, @Nullable ActionListener listener)4246     public void save(@NonNull WifiConfiguration config, @Nullable ActionListener listener) {
4247         if (config == null) throw new IllegalArgumentException("config cannot be null");
4248         ActionListenerProxy listenerProxy = null;
4249         Binder binder = null;
4250         if (listener != null) {
4251             listenerProxy = new ActionListenerProxy("save", mLooper, listener);
4252             binder = new Binder();
4253         }
4254         try {
4255             mService.save(config, binder, listenerProxy,
4256                     listener == null ? 0 : listener.hashCode());
4257         } catch (RemoteException e) {
4258             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
4259         } catch (SecurityException e) {
4260             if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
4261         }
4262     }
4263 
4264     /**
4265      * Delete the network from the list of configured networks for the
4266      * foreground user.
4267      *
4268      * This function is used instead of a sequence of removeNetwork()
4269      *
4270      * @param config the set of variables that describe the configuration,
4271      *            contained in a {@link WifiConfiguration} object.
4272      * @param listener for callbacks on success or failure. Can be null.
4273      * @throws IllegalStateException if the WifiManager instance needs to be
4274      * initialized again
4275      * @hide
4276      */
4277     @SystemApi
4278     @RequiresPermission(anyOf = {
4279             android.Manifest.permission.NETWORK_SETTINGS,
4280             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4281             android.Manifest.permission.NETWORK_STACK
4282     })
forget(int netId, @Nullable ActionListener listener)4283     public void forget(int netId, @Nullable ActionListener listener) {
4284         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
4285         ActionListenerProxy listenerProxy = null;
4286         Binder binder = null;
4287         if (listener != null) {
4288             listenerProxy = new ActionListenerProxy("forget", mLooper, listener);
4289             binder = new Binder();
4290         }
4291         try {
4292             mService.forget(netId, binder, listenerProxy,
4293                     listener == null ? 0 : listener.hashCode());
4294         } catch (RemoteException e) {
4295             if (listenerProxy != null) listenerProxy.onFailure(ERROR);
4296         } catch (SecurityException e) {
4297             if (listenerProxy != null) listenerProxy.onFailure(NOT_AUTHORIZED);
4298         }
4299     }
4300 
4301     /**
4302      * Disable network
4303      *
4304      * @param netId is the network Id
4305      * @param listener for callbacks on success or failure. Can be null.
4306      * @throws IllegalStateException if the WifiManager instance needs to be
4307      * initialized again
4308      * @deprecated This API is deprecated. Use {@link #disableNetwork(int)} instead.
4309      * @hide
4310      */
4311     @SystemApi
4312     @RequiresPermission(anyOf = {
4313             android.Manifest.permission.NETWORK_SETTINGS,
4314             android.Manifest.permission.NETWORK_SETUP_WIZARD,
4315             android.Manifest.permission.NETWORK_STACK
4316     })
4317     @Deprecated
disable(int netId, @Nullable ActionListener listener)4318     public void disable(int netId, @Nullable ActionListener listener) {
4319         if (netId < 0) throw new IllegalArgumentException("Network id cannot be negative");
4320         // Simple wrapper which forwards the call to disableNetwork. This is a temporary
4321         // implementation until we can remove this API completely.
4322         boolean status = disableNetwork(netId);
4323         if (listener != null) {
4324             if (status) {
4325                 listener.onSuccess();
4326             } else {
4327                 listener.onFailure(ERROR);
4328             }
4329         }
4330     }
4331 
4332     /**
4333      * Enable/disable auto-join globally.
4334      *
4335      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
4336      * @hide
4337      */
4338     @SystemApi
4339     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoinGlobal(boolean allowAutojoin)4340     public void allowAutojoinGlobal(boolean allowAutojoin) {
4341         try {
4342             mService.allowAutojoinGlobal(allowAutojoin);
4343         } catch (RemoteException e) {
4344             throw e.rethrowFromSystemServer();
4345         }
4346     }
4347 
4348 
4349     /**
4350      * Sets the user choice for allowing auto-join to a network.
4351      * The updated choice will be made available through the updated config supplied by the
4352      * CONFIGURED_NETWORKS_CHANGED broadcast.
4353      *
4354      * @param netId the id of the network to allow/disallow auto-join for.
4355      * @param allowAutojoin true to allow auto-join, false to disallow auto-join
4356      * @hide
4357      */
4358     @SystemApi
4359     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoin(int netId, boolean allowAutojoin)4360     public void allowAutojoin(int netId, boolean allowAutojoin) {
4361         try {
4362             mService.allowAutojoin(netId, allowAutojoin);
4363         } catch (RemoteException e) {
4364             throw e.rethrowFromSystemServer();
4365         }
4366     }
4367 
4368     /**
4369      * Configure auto-join settings for a Passpoint profile.
4370      *
4371      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
4372      * @param allowAutojoin true to enable auto-join, false to disable auto-join.
4373      * @hide
4374      */
4375     @SystemApi
4376     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
allowAutojoinPasspoint(@onNull String fqdn, boolean allowAutojoin)4377     public void allowAutojoinPasspoint(@NonNull String fqdn, boolean allowAutojoin) {
4378         try {
4379             mService.allowAutojoinPasspoint(fqdn, allowAutojoin);
4380         } catch (RemoteException e) {
4381             throw e.rethrowFromSystemServer();
4382         }
4383     }
4384 
4385     /**
4386      * Configure MAC randomization setting for a Passpoint profile.
4387      * MAC randomization is enabled by default.
4388      *
4389      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
4390      * @param enable true to enable MAC randomization, false to disable MAC randomization.
4391      * @hide
4392      */
4393     @SystemApi
4394     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setMacRandomizationSettingPasspointEnabled(@onNull String fqdn, boolean enable)4395     public void setMacRandomizationSettingPasspointEnabled(@NonNull String fqdn, boolean enable) {
4396         try {
4397             mService.setMacRandomizationSettingPasspointEnabled(fqdn, enable);
4398         } catch (RemoteException e) {
4399             throw e.rethrowFromSystemServer();
4400         }
4401     }
4402 
4403     /**
4404      * Sets the user's choice of metered override for a Passpoint profile.
4405      *
4406      * @param fqdn the FQDN (fully qualified domain name) of the passpoint profile.
4407      * @param meteredOverride One of three values: {@link WifiConfiguration#METERED_OVERRIDE_NONE},
4408      *                        {@link WifiConfiguration#METERED_OVERRIDE_METERED},
4409      *                        {@link WifiConfiguration#METERED_OVERRIDE_NOT_METERED}
4410      * @hide
4411      */
4412     @SystemApi
4413     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setPasspointMeteredOverride(@onNull String fqdn, @WifiConfiguration.MeteredOverride int meteredOverride)4414     public void setPasspointMeteredOverride(@NonNull String fqdn,
4415             @WifiConfiguration.MeteredOverride int meteredOverride) {
4416         try {
4417             mService.setPasspointMeteredOverride(fqdn, meteredOverride);
4418         } catch (RemoteException e) {
4419             throw e.rethrowFromSystemServer();
4420         }
4421     }
4422 
4423     /**
4424      * Temporarily disable a network. Should always trigger with user disconnect network.
4425      *
4426      * @param network Input can be SSID or FQDN. And caller must ensure that the SSID passed thru
4427      *                this API matched the WifiConfiguration.SSID rules, and thus be surrounded by
4428      *                quotes.
4429      * @hide
4430      */
4431     @SystemApi
4432     @RequiresPermission(anyOf = {
4433             android.Manifest.permission.NETWORK_SETTINGS,
4434             android.Manifest.permission.NETWORK_STACK
4435     })
disableEphemeralNetwork(@onNull String network)4436     public void disableEphemeralNetwork(@NonNull String network) {
4437         if (TextUtils.isEmpty(network)) {
4438             throw new IllegalArgumentException("SSID cannot be null or empty!");
4439         }
4440         try {
4441             mService.disableEphemeralNetwork(network, mContext.getOpPackageName());
4442         } catch (RemoteException e) {
4443             throw e.rethrowFromSystemServer();
4444         }
4445     }
4446 
4447     /**
4448      * WPS suport has been deprecated from Client mode and this method will immediately trigger
4449      * {@link WpsCallback#onFailed(int)} with a generic error.
4450      *
4451      * @param config WPS configuration (does not support {@link WpsInfo#LABEL})
4452      * @param listener for callbacks on success or failure. Can be null.
4453      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
4454      * @deprecated This API is deprecated
4455      */
startWps(WpsInfo config, WpsCallback listener)4456     public void startWps(WpsInfo config, WpsCallback listener) {
4457         if (listener != null ) {
4458             listener.onFailed(ERROR);
4459         }
4460     }
4461 
4462     /**
4463      * WPS support has been deprecated from Client mode and this method will immediately trigger
4464      * {@link WpsCallback#onFailed(int)} with a generic error.
4465      *
4466      * @param listener for callbacks on success or failure. Can be null.
4467      * @throws IllegalStateException if the WifiManager instance needs to be initialized again
4468      * @deprecated This API is deprecated
4469      */
cancelWps(WpsCallback listener)4470     public void cancelWps(WpsCallback listener) {
4471         if (listener != null) {
4472             listener.onFailed(ERROR);
4473         }
4474     }
4475 
4476     /**
4477      * Allows an application to keep the Wi-Fi radio awake.
4478      * Normally the Wi-Fi radio may turn off when the user has not used the device in a while.
4479      * Acquiring a WifiLock will keep the radio on until the lock is released.  Multiple
4480      * applications may hold WifiLocks, and the radio will only be allowed to turn off when no
4481      * WifiLocks are held in any application.
4482      * <p>
4483      * Before using a WifiLock, consider carefully if your application requires Wi-Fi access, or
4484      * could function over a mobile network, if available.  A program that needs to download large
4485      * files should hold a WifiLock to ensure that the download will complete, but a program whose
4486      * network usage is occasional or low-bandwidth should not hold a WifiLock to avoid adversely
4487      * affecting battery life.
4488      * <p>
4489      * Note that WifiLocks cannot override the user-level "Wi-Fi Enabled" setting, nor Airplane
4490      * Mode.  They simply keep the radio from turning off when Wi-Fi is already on but the device
4491      * is idle.
4492      * <p>
4493      * Any application using a WifiLock must request the {@code android.permission.WAKE_LOCK}
4494      * permission in an {@code <uses-permission>} element of the application's manifest.
4495      */
4496     public class WifiLock {
4497         private String mTag;
4498         private final IBinder mBinder;
4499         private int mRefCount;
4500         int mLockType;
4501         private boolean mRefCounted;
4502         private boolean mHeld;
4503         private WorkSource mWorkSource;
4504 
WifiLock(int lockType, String tag)4505         private WifiLock(int lockType, String tag) {
4506             mTag = tag;
4507             mLockType = lockType;
4508             mBinder = new Binder();
4509             mRefCount = 0;
4510             mRefCounted = true;
4511             mHeld = false;
4512         }
4513 
4514         /**
4515          * Locks the Wi-Fi radio on until {@link #release} is called.
4516          *
4517          * If this WifiLock is reference-counted, each call to {@code acquire} will increment the
4518          * reference count, and the radio will remain locked as long as the reference count is
4519          * above zero.
4520          *
4521          * If this WifiLock is not reference-counted, the first call to {@code acquire} will lock
4522          * the radio, but subsequent calls will be ignored.  Only one call to {@link #release}
4523          * will be required, regardless of the number of times that {@code acquire} is called.
4524          */
acquire()4525         public void acquire() {
4526             synchronized (mBinder) {
4527                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
4528                     try {
4529                         mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
4530                         synchronized (WifiManager.this) {
4531                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
4532                                 mService.releaseWifiLock(mBinder);
4533                                 throw new UnsupportedOperationException(
4534                                             "Exceeded maximum number of wifi locks");
4535                             }
4536                             mActiveLockCount++;
4537                         }
4538                     } catch (RemoteException e) {
4539                         throw e.rethrowFromSystemServer();
4540                     }
4541                     mHeld = true;
4542                 }
4543             }
4544         }
4545 
4546         /**
4547          * Unlocks the Wi-Fi radio, allowing it to turn off when the device is idle.
4548          *
4549          * If this WifiLock is reference-counted, each call to {@code release} will decrement the
4550          * reference count, and the radio will be unlocked only when the reference count reaches
4551          * zero.  If the reference count goes below zero (that is, if {@code release} is called
4552          * a greater number of times than {@link #acquire}), an exception is thrown.
4553          *
4554          * If this WifiLock is not reference-counted, the first call to {@code release} (after
4555          * the radio was locked using {@link #acquire}) will unlock the radio, and subsequent
4556          * calls will be ignored.
4557          */
release()4558         public void release() {
4559             synchronized (mBinder) {
4560                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
4561                     try {
4562                         mService.releaseWifiLock(mBinder);
4563                         synchronized (WifiManager.this) {
4564                             mActiveLockCount--;
4565                         }
4566                     } catch (RemoteException e) {
4567                         throw e.rethrowFromSystemServer();
4568                     }
4569                     mHeld = false;
4570                 }
4571                 if (mRefCount < 0) {
4572                     throw new RuntimeException("WifiLock under-locked " + mTag);
4573                 }
4574             }
4575         }
4576 
4577         /**
4578          * Controls whether this is a reference-counted or non-reference-counted WifiLock.
4579          *
4580          * Reference-counted WifiLocks keep track of the number of calls to {@link #acquire} and
4581          * {@link #release}, and only allow the radio to sleep when every call to {@link #acquire}
4582          * has been balanced with a call to {@link #release}.  Non-reference-counted WifiLocks
4583          * lock the radio whenever {@link #acquire} is called and it is unlocked, and unlock the
4584          * radio whenever {@link #release} is called and it is locked.
4585          *
4586          * @param refCounted true if this WifiLock should keep a reference count
4587          */
setReferenceCounted(boolean refCounted)4588         public void setReferenceCounted(boolean refCounted) {
4589             mRefCounted = refCounted;
4590         }
4591 
4592         /**
4593          * Checks whether this WifiLock is currently held.
4594          *
4595          * @return true if this WifiLock is held, false otherwise
4596          */
isHeld()4597         public boolean isHeld() {
4598             synchronized (mBinder) {
4599                 return mHeld;
4600             }
4601         }
4602 
setWorkSource(WorkSource ws)4603         public void setWorkSource(WorkSource ws) {
4604             synchronized (mBinder) {
4605                 if (ws != null && ws.isEmpty()) {
4606                     ws = null;
4607                 }
4608                 boolean changed = true;
4609                 if (ws == null) {
4610                     mWorkSource = null;
4611                 } else {
4612                     ws = ws.withoutNames();
4613                     if (mWorkSource == null) {
4614                         changed = mWorkSource != null;
4615                         mWorkSource = new WorkSource(ws);
4616                     } else {
4617                         changed = !mWorkSource.equals(ws);
4618                         if (changed) {
4619                             mWorkSource.set(ws);
4620                         }
4621                     }
4622                 }
4623                 if (changed && mHeld) {
4624                     try {
4625                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
4626                     } catch (RemoteException e) {
4627                         throw e.rethrowFromSystemServer();
4628                     }
4629                 }
4630             }
4631         }
4632 
toString()4633         public String toString() {
4634             String s1, s2, s3;
4635             synchronized (mBinder) {
4636                 s1 = Integer.toHexString(System.identityHashCode(this));
4637                 s2 = mHeld ? "held; " : "";
4638                 if (mRefCounted) {
4639                     s3 = "refcounted: refcount = " + mRefCount;
4640                 } else {
4641                     s3 = "not refcounted";
4642                 }
4643                 return "WifiLock{ " + s1 + "; " + s2 + s3 + " }";
4644             }
4645         }
4646 
4647         @Override
finalize()4648         protected void finalize() throws Throwable {
4649             super.finalize();
4650             synchronized (mBinder) {
4651                 if (mHeld) {
4652                     try {
4653                         mService.releaseWifiLock(mBinder);
4654                         synchronized (WifiManager.this) {
4655                             mActiveLockCount--;
4656                         }
4657                     } catch (RemoteException e) {
4658                         throw e.rethrowFromSystemServer();
4659                     }
4660                 }
4661             }
4662         }
4663     }
4664 
4665     /**
4666      * Creates a new WifiLock.
4667      *
4668      * @param lockType the type of lock to create. See {@link #WIFI_MODE_FULL_HIGH_PERF}
4669      * and {@link #WIFI_MODE_FULL_LOW_LATENCY} for descriptions of the types of Wi-Fi locks.
4670      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
4671      *            never shown to the user under normal conditions, but should be descriptive
4672      *            enough to identify your application and the specific WifiLock within it, if it
4673      *            holds multiple WifiLocks.
4674      *
4675      * @return a new, unacquired WifiLock with the given tag.
4676      *
4677      * @see WifiLock
4678      */
createWifiLock(int lockType, String tag)4679     public WifiLock createWifiLock(int lockType, String tag) {
4680         return new WifiLock(lockType, tag);
4681     }
4682 
4683     /**
4684      * Creates a new WifiLock.
4685      *
4686      * @param tag a tag for the WifiLock to identify it in debugging messages.  This string is
4687      *            never shown to the user under normal conditions, but should be descriptive
4688      *            enough to identify your application and the specific WifiLock within it, if it
4689      *            holds multiple WifiLocks.
4690      *
4691      * @return a new, unacquired WifiLock with the given tag.
4692      *
4693      * @see WifiLock
4694      *
4695      * @deprecated This API is non-functional.
4696      */
4697     @Deprecated
createWifiLock(String tag)4698     public WifiLock createWifiLock(String tag) {
4699         return new WifiLock(WIFI_MODE_FULL, tag);
4700     }
4701 
4702     /**
4703      * Create a new MulticastLock
4704      *
4705      * @param tag a tag for the MulticastLock to identify it in debugging
4706      *            messages.  This string is never shown to the user under
4707      *            normal conditions, but should be descriptive enough to
4708      *            identify your application and the specific MulticastLock
4709      *            within it, if it holds multiple MulticastLocks.
4710      *
4711      * @return a new, unacquired MulticastLock with the given tag.
4712      *
4713      * @see MulticastLock
4714      */
createMulticastLock(String tag)4715     public MulticastLock createMulticastLock(String tag) {
4716         return new MulticastLock(tag);
4717     }
4718 
4719     /**
4720      * Allows an application to receive Wifi Multicast packets.
4721      * Normally the Wifi stack filters out packets not explicitly
4722      * addressed to this device.  Acquring a MulticastLock will
4723      * cause the stack to receive packets addressed to multicast
4724      * addresses.  Processing these extra packets can cause a noticeable
4725      * battery drain and should be disabled when not needed.
4726      */
4727     public class MulticastLock {
4728         private String mTag;
4729         private final IBinder mBinder;
4730         private int mRefCount;
4731         private boolean mRefCounted;
4732         private boolean mHeld;
4733 
MulticastLock(String tag)4734         private MulticastLock(String tag) {
4735             mTag = tag;
4736             mBinder = new Binder();
4737             mRefCount = 0;
4738             mRefCounted = true;
4739             mHeld = false;
4740         }
4741 
4742         /**
4743          * Locks Wifi Multicast on until {@link #release} is called.
4744          *
4745          * If this MulticastLock is reference-counted each call to
4746          * {@code acquire} will increment the reference count, and the
4747          * wifi interface will receive multicast packets as long as the
4748          * reference count is above zero.
4749          *
4750          * If this MulticastLock is not reference-counted, the first call to
4751          * {@code acquire} will turn on the multicast packets, but subsequent
4752          * calls will be ignored.  Only one call to {@link #release} will
4753          * be required, regardless of the number of times that {@code acquire}
4754          * is called.
4755          *
4756          * Note that other applications may also lock Wifi Multicast on.
4757          * Only they can relinquish their lock.
4758          *
4759          * Also note that applications cannot leave Multicast locked on.
4760          * When an app exits or crashes, any Multicast locks will be released.
4761          */
acquire()4762         public void acquire() {
4763             synchronized (mBinder) {
4764                 if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
4765                     try {
4766                         mService.acquireMulticastLock(mBinder, mTag);
4767                         synchronized (WifiManager.this) {
4768                             if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
4769                                 mService.releaseMulticastLock(mTag);
4770                                 throw new UnsupportedOperationException(
4771                                         "Exceeded maximum number of wifi locks");
4772                             }
4773                             mActiveLockCount++;
4774                         }
4775                     } catch (RemoteException e) {
4776                         throw e.rethrowFromSystemServer();
4777                     }
4778                     mHeld = true;
4779                 }
4780             }
4781         }
4782 
4783         /**
4784          * Unlocks Wifi Multicast, restoring the filter of packets
4785          * not addressed specifically to this device and saving power.
4786          *
4787          * If this MulticastLock is reference-counted, each call to
4788          * {@code release} will decrement the reference count, and the
4789          * multicast packets will only stop being received when the reference
4790          * count reaches zero.  If the reference count goes below zero (that
4791          * is, if {@code release} is called a greater number of times than
4792          * {@link #acquire}), an exception is thrown.
4793          *
4794          * If this MulticastLock is not reference-counted, the first call to
4795          * {@code release} (after the radio was multicast locked using
4796          * {@link #acquire}) will unlock the multicast, and subsequent calls
4797          * will be ignored.
4798          *
4799          * Note that if any other Wifi Multicast Locks are still outstanding
4800          * this {@code release} call will not have an immediate effect.  Only
4801          * when all applications have released all their Multicast Locks will
4802          * the Multicast filter be turned back on.
4803          *
4804          * Also note that when an app exits or crashes all of its Multicast
4805          * Locks will be automatically released.
4806          */
release()4807         public void release() {
4808             synchronized (mBinder) {
4809                 if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
4810                     try {
4811                         mService.releaseMulticastLock(mTag);
4812                         synchronized (WifiManager.this) {
4813                             mActiveLockCount--;
4814                         }
4815                     } catch (RemoteException e) {
4816                         throw e.rethrowFromSystemServer();
4817                     }
4818                     mHeld = false;
4819                 }
4820                 if (mRefCount < 0) {
4821                     throw new RuntimeException("MulticastLock under-locked "
4822                             + mTag);
4823                 }
4824             }
4825         }
4826 
4827         /**
4828          * Controls whether this is a reference-counted or non-reference-
4829          * counted MulticastLock.
4830          *
4831          * Reference-counted MulticastLocks keep track of the number of calls
4832          * to {@link #acquire} and {@link #release}, and only stop the
4833          * reception of multicast packets when every call to {@link #acquire}
4834          * has been balanced with a call to {@link #release}.  Non-reference-
4835          * counted MulticastLocks allow the reception of multicast packets
4836          * whenever {@link #acquire} is called and stop accepting multicast
4837          * packets whenever {@link #release} is called.
4838          *
4839          * @param refCounted true if this MulticastLock should keep a reference
4840          * count
4841          */
setReferenceCounted(boolean refCounted)4842         public void setReferenceCounted(boolean refCounted) {
4843             mRefCounted = refCounted;
4844         }
4845 
4846         /**
4847          * Checks whether this MulticastLock is currently held.
4848          *
4849          * @return true if this MulticastLock is held, false otherwise
4850          */
isHeld()4851         public boolean isHeld() {
4852             synchronized (mBinder) {
4853                 return mHeld;
4854             }
4855         }
4856 
toString()4857         public String toString() {
4858             String s1, s2, s3;
4859             synchronized (mBinder) {
4860                 s1 = Integer.toHexString(System.identityHashCode(this));
4861                 s2 = mHeld ? "held; " : "";
4862                 if (mRefCounted) {
4863                     s3 = "refcounted: refcount = " + mRefCount;
4864                 } else {
4865                     s3 = "not refcounted";
4866                 }
4867                 return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }";
4868             }
4869         }
4870 
4871         @Override
finalize()4872         protected void finalize() throws Throwable {
4873             super.finalize();
4874             setReferenceCounted(false);
4875             release();
4876         }
4877     }
4878 
4879     /**
4880      * Check multicast filter status.
4881      *
4882      * @return true if multicast packets are allowed.
4883      *
4884      * @hide pending API council approval
4885      */
isMulticastEnabled()4886     public boolean isMulticastEnabled() {
4887         try {
4888             return mService.isMulticastEnabled();
4889         } catch (RemoteException e) {
4890             throw e.rethrowFromSystemServer();
4891         }
4892     }
4893 
4894     /**
4895      * Initialize the multicast filtering to 'on'
4896      * @hide no intent to publish
4897      */
4898     @UnsupportedAppUsage
initializeMulticastFiltering()4899     public boolean initializeMulticastFiltering() {
4900         try {
4901             mService.initializeMulticastFiltering();
4902             return true;
4903         } catch (RemoteException e) {
4904             throw e.rethrowFromSystemServer();
4905         }
4906     }
4907 
4908     /**
4909      * Set Wi-Fi verbose logging level from developer settings.
4910      *
4911      * @param enable true to enable verbose logging, false to disable.
4912      *
4913      * @hide
4914      */
4915     @SystemApi
4916     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setVerboseLoggingEnabled(boolean enable)4917     public void setVerboseLoggingEnabled(boolean enable) {
4918         enableVerboseLogging(enable ? 1 : 0);
4919     }
4920 
4921     /** @hide */
4922     @UnsupportedAppUsage(
4923             maxTargetSdk = Build.VERSION_CODES.Q,
4924             publicAlternatives = "Use {@code #setVerboseLoggingEnabled(boolean)} instead."
4925     )
4926     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
enableVerboseLogging(int verbose)4927     public void enableVerboseLogging (int verbose) {
4928         try {
4929             mService.enableVerboseLogging(verbose);
4930         } catch (Exception e) {
4931             //ignore any failure here
4932             Log.e(TAG, "enableVerboseLogging " + e.toString());
4933         }
4934     }
4935 
4936     /**
4937      * Get the persisted Wi-Fi verbose logging level, set by
4938      * {@link #setVerboseLoggingEnabled(boolean)}.
4939      * No permissions are required to call this method.
4940      *
4941      * @return true to indicate that verbose logging is enabled, false to indicate that verbose
4942      * logging is disabled.
4943      *
4944      * @hide
4945      */
4946     @SystemApi
isVerboseLoggingEnabled()4947     public boolean isVerboseLoggingEnabled() {
4948         return getVerboseLoggingLevel() > 0;
4949     }
4950 
4951     /** @hide */
4952     // TODO(b/145484145): remove once SUW stops calling this via reflection
4953     @UnsupportedAppUsage(
4954             maxTargetSdk = Build.VERSION_CODES.Q,
4955             publicAlternatives = "Use {@code #isVerboseLoggingEnabled()} instead."
4956     )
getVerboseLoggingLevel()4957     public int getVerboseLoggingLevel() {
4958         try {
4959             return mService.getVerboseLoggingLevel();
4960         } catch (RemoteException e) {
4961             throw e.rethrowFromSystemServer();
4962         }
4963     }
4964 
4965     /**
4966      * Removes all saved Wi-Fi networks, Passpoint configurations, ephemeral networks, Network
4967      * Requests, and Network Suggestions.
4968      *
4969      * @hide
4970      */
4971     @SystemApi
4972     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
factoryReset()4973     public void factoryReset() {
4974         try {
4975             mService.factoryReset(mContext.getOpPackageName());
4976         } catch (RemoteException e) {
4977             throw e.rethrowFromSystemServer();
4978         }
4979     }
4980 
4981     /**
4982      * Get {@link Network} object of current wifi network, or null if not connected.
4983      * @hide
4984      */
4985     @Nullable
4986     @SystemApi
4987     @RequiresPermission(anyOf = {
4988             android.Manifest.permission.NETWORK_SETTINGS,
4989             android.Manifest.permission.NETWORK_SETUP_WIZARD
4990     })
getCurrentNetwork()4991     public Network getCurrentNetwork() {
4992         try {
4993             return mService.getCurrentNetwork();
4994         } catch (RemoteException e) {
4995             throw e.rethrowFromSystemServer();
4996         }
4997     }
4998 
4999     /**
5000      * Deprecated
5001      * returns false
5002      * @hide
5003      * @deprecated
5004      */
setEnableAutoJoinWhenAssociated(boolean enabled)5005     public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
5006         return false;
5007     }
5008 
5009     /**
5010      * Deprecated
5011      * returns false
5012      * @hide
5013      * @deprecated
5014      */
getEnableAutoJoinWhenAssociated()5015     public boolean getEnableAutoJoinWhenAssociated() {
5016         return false;
5017     }
5018 
5019     /**
5020      * Returns a byte stream representing the data that needs to be backed up to save the
5021      * current Wifi state.
5022      * This Wifi state can be restored by calling {@link #restoreBackupData(byte[])}.
5023      * @hide
5024      */
5025     @NonNull
5026     @SystemApi
5027     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveBackupData()5028     public byte[] retrieveBackupData() {
5029         try {
5030             return mService.retrieveBackupData();
5031         } catch (RemoteException e) {
5032             throw e.rethrowFromSystemServer();
5033         }
5034     }
5035 
5036     /**
5037      * Restore state from the backed up data.
5038      * @param data byte stream in the same format produced by {@link #retrieveBackupData()}
5039      * @hide
5040      */
5041     @SystemApi
5042     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreBackupData(@onNull byte[] data)5043     public void restoreBackupData(@NonNull byte[] data) {
5044         try {
5045             mService.restoreBackupData(data);
5046         } catch (RemoteException e) {
5047             throw e.rethrowFromSystemServer();
5048         }
5049     }
5050 
5051     /**
5052      * Returns a byte stream representing the data that needs to be backed up to save the
5053      * current soft ap config data.
5054      *
5055      * This soft ap config can be restored by calling {@link #restoreSoftApBackupData(byte[])}
5056      * @hide
5057      */
5058     @NonNull
5059     @SystemApi
5060     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
retrieveSoftApBackupData()5061     public byte[] retrieveSoftApBackupData() {
5062         try {
5063             return mService.retrieveSoftApBackupData();
5064         } catch (RemoteException e) {
5065             throw e.rethrowFromSystemServer();
5066         }
5067     }
5068 
5069     /**
5070      * Returns soft ap config from the backed up data or null if data is invalid.
5071      * @param data byte stream in the same format produced by {@link #retrieveSoftApBackupData()}
5072      *
5073      * @hide
5074      */
5075     @Nullable
5076     @SystemApi
5077     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSoftApBackupData(@onNull byte[] data)5078     public SoftApConfiguration restoreSoftApBackupData(@NonNull byte[] data) {
5079         try {
5080             return mService.restoreSoftApBackupData(data);
5081         } catch (RemoteException e) {
5082             throw e.rethrowFromSystemServer();
5083         }
5084     }
5085 
5086     /**
5087      * Restore state from the older version of back up data.
5088      * The old backup data was essentially a backup of wpa_supplicant.conf
5089      * and ipconfig.txt file.
5090      * @param supplicantData bytes representing wpa_supplicant.conf
5091      * @param ipConfigData bytes representing ipconfig.txt
5092      * @hide
5093      */
5094     @SystemApi
5095     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
restoreSupplicantBackupData( @onNull byte[] supplicantData, @NonNull byte[] ipConfigData)5096     public void restoreSupplicantBackupData(
5097             @NonNull byte[] supplicantData, @NonNull byte[] ipConfigData) {
5098         try {
5099             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
5100         } catch (RemoteException e) {
5101             throw e.rethrowFromSystemServer();
5102         }
5103     }
5104 
5105     /**
5106      * Start subscription provisioning flow
5107      *
5108      * @param provider {@link OsuProvider} to provision with
5109      * @param executor the Executor on which to run the callback.
5110      * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
5111      * @hide
5112      */
5113     @SystemApi
5114     @RequiresPermission(anyOf = {
5115             android.Manifest.permission.NETWORK_SETTINGS,
5116             android.Manifest.permission.NETWORK_SETUP_WIZARD
5117     })
startSubscriptionProvisioning(@onNull OsuProvider provider, @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback)5118     public void startSubscriptionProvisioning(@NonNull OsuProvider provider,
5119             @NonNull @CallbackExecutor Executor executor, @NonNull ProvisioningCallback callback) {
5120         // Verify arguments
5121         if (executor == null) {
5122             throw new IllegalArgumentException("executor must not be null");
5123         }
5124         if (callback == null) {
5125             throw new IllegalArgumentException("callback must not be null");
5126         }
5127         try {
5128             mService.startSubscriptionProvisioning(provider,
5129                     new ProvisioningCallbackProxy(executor, callback));
5130         } catch (RemoteException e) {
5131             throw e.rethrowFromSystemServer();
5132         }
5133     }
5134 
5135     /**
5136      * Helper class to support OSU Provisioning callbacks
5137      */
5138     private static class ProvisioningCallbackProxy extends IProvisioningCallback.Stub {
5139         private final Executor mExecutor;
5140         private final ProvisioningCallback mCallback;
5141 
ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback)5142         ProvisioningCallbackProxy(Executor executor, ProvisioningCallback callback) {
5143             mExecutor = executor;
5144             mCallback = callback;
5145         }
5146 
5147         @Override
onProvisioningStatus(int status)5148         public void onProvisioningStatus(int status) {
5149             mExecutor.execute(() -> mCallback.onProvisioningStatus(status));
5150         }
5151 
5152         @Override
onProvisioningFailure(int status)5153         public void onProvisioningFailure(int status) {
5154             mExecutor.execute(() -> mCallback.onProvisioningFailure(status));
5155         }
5156 
5157         @Override
onProvisioningComplete()5158         public void onProvisioningComplete() {
5159             mExecutor.execute(() -> mCallback.onProvisioningComplete());
5160         }
5161     }
5162 
5163     /**
5164      * Interface for Traffic state callback. Should be extended by applications and set when
5165      * calling {@link #registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}.
5166      * @hide
5167      */
5168     @SystemApi
5169     public interface TrafficStateCallback {
5170         /** @hide */
5171         @Retention(RetentionPolicy.SOURCE)
5172         @IntDef(prefix = {"DATA_ACTIVITY_"}, value = {
5173                 DATA_ACTIVITY_NONE,
5174                 DATA_ACTIVITY_IN,
5175                 DATA_ACTIVITY_OUT,
5176                 DATA_ACTIVITY_INOUT})
5177         @interface DataActivity {}
5178 
5179         // Lowest bit indicates data reception and the second lowest bit indicates data transmitted
5180         /** No data in or out */
5181         int DATA_ACTIVITY_NONE         = 0x00;
5182         /** Data in, no data out */
5183         int DATA_ACTIVITY_IN           = 0x01;
5184         /** Data out, no data in */
5185         int DATA_ACTIVITY_OUT          = 0x02;
5186         /** Data in and out */
5187         int DATA_ACTIVITY_INOUT        = 0x03;
5188 
5189         /**
5190          * Callback invoked to inform clients about the current traffic state.
5191          *
5192          * @param state One of the values: {@link #DATA_ACTIVITY_NONE}, {@link #DATA_ACTIVITY_IN},
5193          * {@link #DATA_ACTIVITY_OUT} & {@link #DATA_ACTIVITY_INOUT}.
5194          */
onStateChanged(@ataActivity int state)5195         void onStateChanged(@DataActivity int state);
5196     }
5197 
5198     /**
5199      * Callback proxy for TrafficStateCallback objects.
5200      *
5201      * @hide
5202      */
5203     private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub {
5204         private final Executor mExecutor;
5205         private final TrafficStateCallback mCallback;
5206 
TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback)5207         TrafficStateCallbackProxy(Executor executor, TrafficStateCallback callback) {
5208             mExecutor = executor;
5209             mCallback = callback;
5210         }
5211 
5212         @Override
onStateChanged(int state)5213         public void onStateChanged(int state) {
5214             if (mVerboseLoggingEnabled) {
5215                 Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state);
5216             }
5217             Binder.clearCallingIdentity();
5218             mExecutor.execute(() -> {
5219                 mCallback.onStateChanged(state);
5220             });
5221         }
5222     }
5223 
5224     /**
5225      * Registers a callback for monitoring traffic state. See {@link TrafficStateCallback}. These
5226      * callbacks will be invoked periodically by platform to inform clients about the current
5227      * traffic state. Caller can unregister a previously registered callback using
5228      * {@link #unregisterTrafficStateCallback(TrafficStateCallback)}
5229      * <p>
5230      * Applications should have the
5231      * {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
5232      * without the permission will trigger a {@link java.lang.SecurityException}.
5233      * <p>
5234      *
5235      * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
5236      *                 object.
5237      * @param callback Callback for traffic state events
5238      * @hide
5239      */
5240     @SystemApi
5241     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
registerTrafficStateCallback(@onNull @allbackExecutor Executor executor, @NonNull TrafficStateCallback callback)5242     public void registerTrafficStateCallback(@NonNull @CallbackExecutor Executor executor,
5243                                              @NonNull TrafficStateCallback callback) {
5244         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5245         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5246         Log.v(TAG, "registerTrafficStateCallback: callback=" + callback + ", executor=" + executor);
5247 
5248         Binder binder = new Binder();
5249         try {
5250             mService.registerTrafficStateCallback(
5251                     binder, new TrafficStateCallbackProxy(executor, callback), callback.hashCode());
5252         } catch (RemoteException e) {
5253             throw e.rethrowFromSystemServer();
5254         }
5255     }
5256 
5257     /**
5258      * Allow callers to unregister a previously registered callback. After calling this method,
5259      * applications will no longer receive traffic state notifications.
5260      *
5261      * @param callback Callback to unregister for traffic state events
5262      * @hide
5263      */
5264     @SystemApi
5265     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
unregisterTrafficStateCallback(@onNull TrafficStateCallback callback)5266     public void unregisterTrafficStateCallback(@NonNull TrafficStateCallback callback) {
5267         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5268         Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
5269 
5270         try {
5271             mService.unregisterTrafficStateCallback(callback.hashCode());
5272         } catch (RemoteException e) {
5273             throw e.rethrowFromSystemServer();
5274         }
5275     }
5276 
5277     /**
5278      * Helper method to update the local verbose logging flag based on the verbose logging
5279      * level from wifi service.
5280      */
updateVerboseLoggingEnabledFromService()5281     private void updateVerboseLoggingEnabledFromService() {
5282         mVerboseLoggingEnabled = isVerboseLoggingEnabled();
5283     }
5284 
5285     /**
5286      * @return true if this device supports WPA3-Personal SAE
5287      */
isWpa3SaeSupported()5288     public boolean isWpa3SaeSupported() {
5289         return isFeatureSupported(WIFI_FEATURE_WPA3_SAE);
5290     }
5291 
5292     /**
5293      * @return true if this device supports WPA3-Enterprise Suite-B-192
5294      */
isWpa3SuiteBSupported()5295     public boolean isWpa3SuiteBSupported() {
5296         return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B);
5297     }
5298 
5299     /**
5300      * @return true if this device supports Wi-Fi Enhanced Open (OWE)
5301      */
isEnhancedOpenSupported()5302     public boolean isEnhancedOpenSupported() {
5303         return isFeatureSupported(WIFI_FEATURE_OWE);
5304     }
5305 
5306     /**
5307      * Wi-Fi Easy Connect (DPP) introduces standardized mechanisms to simplify the provisioning and
5308      * configuration of Wi-Fi devices.
5309      * For more details, visit <a href="https://www.wi-fi.org/">https://www.wi-fi.org/</a> and
5310      * search for "Easy Connect" or "Device Provisioning Protocol specification".
5311      *
5312      * @return true if this device supports Wi-Fi Easy-connect (Device Provisioning Protocol)
5313      */
isEasyConnectSupported()5314     public boolean isEasyConnectSupported() {
5315         return isFeatureSupported(WIFI_FEATURE_DPP);
5316     }
5317 
5318     /**
5319      * @return true if this device supports WAPI.
5320      */
isWapiSupported()5321     public boolean isWapiSupported() {
5322         return isFeatureSupported(WIFI_FEATURE_WAPI);
5323     }
5324 
5325     /**
5326      * Gets the factory Wi-Fi MAC addresses.
5327      * @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
5328      * if failed.
5329      * @hide
5330      */
5331     @NonNull
5332     @SystemApi
5333     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
getFactoryMacAddresses()5334     public String[] getFactoryMacAddresses() {
5335         try {
5336             return mService.getFactoryMacAddresses();
5337         } catch (RemoteException e) {
5338             throw e.rethrowFromSystemServer();
5339         }
5340     }
5341 
5342     /** @hide */
5343     @Retention(RetentionPolicy.SOURCE)
5344     @IntDef(prefix = {"DEVICE_MOBILITY_STATE_"}, value = {
5345             DEVICE_MOBILITY_STATE_UNKNOWN,
5346             DEVICE_MOBILITY_STATE_HIGH_MVMT,
5347             DEVICE_MOBILITY_STATE_LOW_MVMT,
5348             DEVICE_MOBILITY_STATE_STATIONARY})
5349     public @interface DeviceMobilityState {}
5350 
5351     /**
5352      * Unknown device mobility state
5353      *
5354      * @see #setDeviceMobilityState(int)
5355      *
5356      * @hide
5357      */
5358     @SystemApi
5359     public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0;
5360 
5361     /**
5362      * High movement device mobility state.
5363      * e.g. on a bike, in a motor vehicle
5364      *
5365      * @see #setDeviceMobilityState(int)
5366      *
5367      * @hide
5368      */
5369     @SystemApi
5370     public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1;
5371 
5372     /**
5373      * Low movement device mobility state.
5374      * e.g. walking, running
5375      *
5376      * @see #setDeviceMobilityState(int)
5377      *
5378      * @hide
5379      */
5380     @SystemApi
5381     public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2;
5382 
5383     /**
5384      * Stationary device mobility state
5385      *
5386      * @see #setDeviceMobilityState(int)
5387      *
5388      * @hide
5389      */
5390     @SystemApi
5391     public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3;
5392 
5393     /**
5394      * Updates the device mobility state. Wifi uses this information to adjust the interval between
5395      * Wifi scans in order to balance power consumption with scan accuracy.
5396      * The default mobility state when the device boots is {@link #DEVICE_MOBILITY_STATE_UNKNOWN}.
5397      * This API should be called whenever there is a change in the mobility state.
5398      * @param state the updated device mobility state
5399      * @hide
5400      */
5401     @SystemApi
5402     @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
setDeviceMobilityState(@eviceMobilityState int state)5403     public void setDeviceMobilityState(@DeviceMobilityState int state) {
5404         try {
5405             mService.setDeviceMobilityState(state);
5406         } catch (RemoteException e) {
5407             throw e.rethrowFromSystemServer();
5408         }
5409     }
5410 
5411     /* Easy Connect - AKA Device Provisioning Protocol (DPP) */
5412 
5413     /**
5414      * Easy Connect Network role: Station.
5415      *
5416      * @hide
5417      */
5418     @SystemApi
5419     public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0;
5420 
5421     /**
5422      * Easy Connect Network role: Access Point.
5423      *
5424      * @hide
5425      */
5426     @SystemApi
5427     public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1;
5428 
5429     /** @hide */
5430     @IntDef(prefix = {"EASY_CONNECT_NETWORK_ROLE_"}, value = {
5431             EASY_CONNECT_NETWORK_ROLE_STA,
5432             EASY_CONNECT_NETWORK_ROLE_AP,
5433     })
5434     @Retention(RetentionPolicy.SOURCE)
5435     public @interface EasyConnectNetworkRole {
5436     }
5437 
5438     /**
5439      * Start Easy Connect (DPP) in Configurator-Initiator role. The current device will initiate
5440      * Easy Connect bootstrapping with a peer, and configure the peer with the SSID and password of
5441      * the specified network using the Easy Connect protocol on an encrypted link.
5442      *
5443      * @param enrolleeUri         URI of the Enrollee obtained separately (e.g. QR code scanning)
5444      * @param selectedNetworkId   Selected network ID to be sent to the peer
5445      * @param enrolleeNetworkRole The network role of the enrollee
5446      * @param callback            Callback for status updates
5447      * @param executor            The Executor on which to run the callback.
5448      * @hide
5449      */
5450     @SystemApi
5451     @RequiresPermission(anyOf = {
5452             android.Manifest.permission.NETWORK_SETTINGS,
5453             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsConfiguratorInitiator(@onNull String enrolleeUri, int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)5454     public void startEasyConnectAsConfiguratorInitiator(@NonNull String enrolleeUri,
5455             int selectedNetworkId, @EasyConnectNetworkRole int enrolleeNetworkRole,
5456             @NonNull @CallbackExecutor Executor executor,
5457             @NonNull EasyConnectStatusCallback callback) {
5458         Binder binder = new Binder();
5459         try {
5460             mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
5461                     enrolleeNetworkRole, new EasyConnectCallbackProxy(executor, callback));
5462         } catch (RemoteException e) {
5463             throw e.rethrowFromSystemServer();
5464         }
5465     }
5466 
5467     /**
5468      * Start Easy Connect (DPP) in Enrollee-Initiator role. The current device will initiate Easy
5469      * Connect bootstrapping with a peer, and receive the SSID and password from the peer
5470      * configurator.
5471      *
5472      * @param configuratorUri URI of the Configurator obtained separately (e.g. QR code scanning)
5473      * @param callback        Callback for status updates
5474      * @param executor        The Executor on which to run the callback.
5475      * @hide
5476      */
5477     @SystemApi
5478     @RequiresPermission(anyOf = {
5479             android.Manifest.permission.NETWORK_SETTINGS,
5480             android.Manifest.permission.NETWORK_SETUP_WIZARD})
startEasyConnectAsEnrolleeInitiator(@onNull String configuratorUri, @NonNull @CallbackExecutor Executor executor, @NonNull EasyConnectStatusCallback callback)5481     public void startEasyConnectAsEnrolleeInitiator(@NonNull String configuratorUri,
5482             @NonNull @CallbackExecutor Executor executor,
5483             @NonNull EasyConnectStatusCallback callback) {
5484         Binder binder = new Binder();
5485         try {
5486             mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
5487                     new EasyConnectCallbackProxy(executor, callback));
5488         } catch (RemoteException e) {
5489             throw e.rethrowFromSystemServer();
5490         }
5491     }
5492 
5493     /**
5494      * Stop or abort a current Easy Connect (DPP) session. This call, once processed, will
5495      * terminate any ongoing transaction, and clean up all associated resources. Caller should not
5496      * expect any callbacks once this call is made. However, due to the asynchronous nature of
5497      * this call, a callback may be fired if it was already pending in the queue.
5498      *
5499      * @hide
5500      */
5501     @SystemApi
5502     @RequiresPermission(anyOf = {
5503             android.Manifest.permission.NETWORK_SETTINGS,
5504             android.Manifest.permission.NETWORK_SETUP_WIZARD})
stopEasyConnectSession()5505     public void stopEasyConnectSession() {
5506         try {
5507             /* Request lower layers to stop/abort and clear resources */
5508             mService.stopDppSession();
5509         } catch (RemoteException e) {
5510             throw e.rethrowFromSystemServer();
5511         }
5512     }
5513 
5514     /**
5515      * Helper class to support Easy Connect (DPP) callbacks
5516      *
5517      * @hide
5518      */
5519     private static class EasyConnectCallbackProxy extends IDppCallback.Stub {
5520         private final Executor mExecutor;
5521         private final EasyConnectStatusCallback mEasyConnectStatusCallback;
5522 
EasyConnectCallbackProxy(Executor executor, EasyConnectStatusCallback easyConnectStatusCallback)5523         EasyConnectCallbackProxy(Executor executor,
5524                 EasyConnectStatusCallback easyConnectStatusCallback) {
5525             mExecutor = executor;
5526             mEasyConnectStatusCallback = easyConnectStatusCallback;
5527         }
5528 
5529         @Override
onSuccessConfigReceived(int newNetworkId)5530         public void onSuccessConfigReceived(int newNetworkId) {
5531             Log.d(TAG, "Easy Connect onSuccessConfigReceived callback");
5532             Binder.clearCallingIdentity();
5533             mExecutor.execute(() -> {
5534                 mEasyConnectStatusCallback.onEnrolleeSuccess(newNetworkId);
5535             });
5536         }
5537 
5538         @Override
onSuccess(int status)5539         public void onSuccess(int status) {
5540             Log.d(TAG, "Easy Connect onSuccess callback");
5541             Binder.clearCallingIdentity();
5542             mExecutor.execute(() -> {
5543                 mEasyConnectStatusCallback.onConfiguratorSuccess(status);
5544             });
5545         }
5546 
5547         @Override
onFailure(int status, String ssid, String channelList, int[] operatingClassArray)5548         public void onFailure(int status, String ssid, String channelList,
5549                 int[] operatingClassArray) {
5550             Log.d(TAG, "Easy Connect onFailure callback");
5551             Binder.clearCallingIdentity();
5552             mExecutor.execute(() -> {
5553                 SparseArray<int[]> channelListArray = parseDppChannelList(channelList);
5554                 mEasyConnectStatusCallback.onFailure(status, ssid, channelListArray,
5555                         operatingClassArray);
5556             });
5557         }
5558 
5559         @Override
onProgress(int status)5560         public void onProgress(int status) {
5561             Log.d(TAG, "Easy Connect onProgress callback");
5562             Binder.clearCallingIdentity();
5563             mExecutor.execute(() -> {
5564                 mEasyConnectStatusCallback.onProgress(status);
5565             });
5566         }
5567     }
5568 
5569     /**
5570      * Interface for Wi-Fi usability statistics listener. Should be implemented by applications and
5571      * set when calling {@link WifiManager#addOnWifiUsabilityStatsListener(Executor,
5572      * OnWifiUsabilityStatsListener)}.
5573      *
5574      * @hide
5575      */
5576     @SystemApi
5577     public interface OnWifiUsabilityStatsListener {
5578         /**
5579          * Called when Wi-Fi usability statistics is updated.
5580          *
5581          * @param seqNum The sequence number of statistics, used to derive the timing of updated
5582          *               Wi-Fi usability statistics, set by framework and incremented by one after
5583          *               each update.
5584          * @param isSameBssidAndFreq The flag to indicate whether the BSSID and the frequency of
5585          *                           network stays the same or not relative to the last update of
5586          *                           Wi-Fi usability stats.
5587          * @param stats The updated Wi-Fi usability statistics.
5588          */
onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, @NonNull WifiUsabilityStatsEntry stats)5589         void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
5590                 @NonNull WifiUsabilityStatsEntry stats);
5591     }
5592 
5593     /**
5594      * Adds a listener for Wi-Fi usability statistics. See {@link OnWifiUsabilityStatsListener}.
5595      * Multiple listeners can be added. Callers will be invoked periodically by framework to
5596      * inform clients about the current Wi-Fi usability statistics. Callers can remove a previously
5597      * added listener using {@link removeOnWifiUsabilityStatsListener}.
5598      *
5599      * @param executor The executor on which callback will be invoked.
5600      * @param listener Listener for Wifi usability statistics.
5601      *
5602      * @hide
5603      */
5604     @SystemApi
5605     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
addOnWifiUsabilityStatsListener(@onNull @allbackExecutor Executor executor, @NonNull OnWifiUsabilityStatsListener listener)5606     public void addOnWifiUsabilityStatsListener(@NonNull @CallbackExecutor Executor executor,
5607             @NonNull OnWifiUsabilityStatsListener listener) {
5608         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5609         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
5610         if (mVerboseLoggingEnabled) {
5611             Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
5612         }
5613         try {
5614             mService.addOnWifiUsabilityStatsListener(new Binder(),
5615                     new IOnWifiUsabilityStatsListener.Stub() {
5616                         @Override
5617                         public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
5618                                 WifiUsabilityStatsEntry stats) {
5619                             if (mVerboseLoggingEnabled) {
5620                                 Log.v(TAG, "OnWifiUsabilityStatsListener: "
5621                                         + "onWifiUsabilityStats: seqNum=" + seqNum);
5622                             }
5623                             Binder.clearCallingIdentity();
5624                             executor.execute(() -> listener.onWifiUsabilityStats(
5625                                     seqNum, isSameBssidAndFreq, stats));
5626                         }
5627                     },
5628                     listener.hashCode()
5629             );
5630         } catch (RemoteException e) {
5631             throw e.rethrowFromSystemServer();
5632         }
5633     }
5634 
5635     /**
5636      * Allow callers to remove a previously registered listener. After calling this method,
5637      * applications will no longer receive Wi-Fi usability statistics.
5638      *
5639      * @param listener Listener to remove the Wi-Fi usability statistics.
5640      *
5641      * @hide
5642      */
5643     @SystemApi
5644     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
removeOnWifiUsabilityStatsListener(@onNull OnWifiUsabilityStatsListener listener)5645     public void removeOnWifiUsabilityStatsListener(@NonNull OnWifiUsabilityStatsListener listener) {
5646         if (listener == null) throw new IllegalArgumentException("listener cannot be null");
5647         if (mVerboseLoggingEnabled) {
5648             Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
5649         }
5650         try {
5651             mService.removeOnWifiUsabilityStatsListener(listener.hashCode());
5652         } catch (RemoteException e) {
5653             throw e.rethrowFromSystemServer();
5654         }
5655     }
5656 
5657     /**
5658      * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
5659      * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
5660      * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
5661      * is used to quantify whether Wi-Fi is usable in a future time.
5662      *
5663      * @param seqNum Sequence number of the Wi-Fi usability score.
5664      * @param score The Wi-Fi usability score, expected range: [0, 100].
5665      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
5666      *                             expected range: [0, 30].
5667      *
5668      * @hide
5669      */
5670     @SystemApi
5671     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)5672     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
5673         try {
5674             mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
5675         } catch (RemoteException e) {
5676             throw e.rethrowFromSystemServer();
5677         }
5678     }
5679 
5680     /**
5681      * Abstract class for scan results callback. Should be extended by applications and set when
5682      * calling {@link WifiManager#registerScanResultsCallback(Executor, ScanResultsCallback)}.
5683      */
5684     public abstract static class ScanResultsCallback {
5685         private final ScanResultsCallbackProxy mScanResultsCallbackProxy;
5686 
ScanResultsCallback()5687         public ScanResultsCallback() {
5688             mScanResultsCallbackProxy = new ScanResultsCallbackProxy();
5689         }
5690 
5691         /**
5692          * Called when new scan results are available.
5693          * Clients should use {@link WifiManager#getScanResults()} to get the scan results.
5694          */
onScanResultsAvailable()5695         public abstract void onScanResultsAvailable();
5696 
getProxy()5697         /*package*/ @NonNull ScanResultsCallbackProxy getProxy() {
5698             return mScanResultsCallbackProxy;
5699         }
5700 
5701         private static class ScanResultsCallbackProxy extends IScanResultsCallback.Stub {
5702             private final Object mLock = new Object();
5703             @Nullable @GuardedBy("mLock") private Executor mExecutor;
5704             @Nullable @GuardedBy("mLock") private ScanResultsCallback mCallback;
5705 
ScanResultsCallbackProxy()5706             ScanResultsCallbackProxy() {
5707                 mCallback = null;
5708                 mExecutor = null;
5709             }
5710 
initProxy(@onNull Executor executor, @NonNull ScanResultsCallback callback)5711             /*package*/ void initProxy(@NonNull Executor executor,
5712                     @NonNull ScanResultsCallback callback) {
5713                 synchronized (mLock) {
5714                     mExecutor = executor;
5715                     mCallback = callback;
5716                 }
5717             }
5718 
cleanUpProxy()5719             /*package*/ void cleanUpProxy() {
5720                 synchronized (mLock) {
5721                     mExecutor = null;
5722                     mCallback = null;
5723                 }
5724             }
5725 
5726             @Override
onScanResultsAvailable()5727             public void onScanResultsAvailable() {
5728                 ScanResultsCallback callback;
5729                 Executor executor;
5730                 synchronized (mLock) {
5731                     executor = mExecutor;
5732                     callback = mCallback;
5733                 }
5734                 if (callback == null || executor == null) {
5735                     return;
5736                 }
5737                 Binder.clearCallingIdentity();
5738                 executor.execute(callback::onScanResultsAvailable);
5739             }
5740         }
5741 
5742     }
5743 
5744     /**
5745      * Register a callback for Scan Results. See {@link ScanResultsCallback}.
5746      * Caller will receive the event when scan results are available.
5747      * Caller should use {@link WifiManager#getScanResults()} requires
5748      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results.
5749      * Caller can remove a previously registered callback using
5750      * {@link WifiManager#unregisterScanResultsCallback(ScanResultsCallback)}
5751      * Same caller can add multiple listeners.
5752      * <p>
5753      * Applications should have the
5754      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permission. Callers
5755      * without the permission will trigger a {@link java.lang.SecurityException}.
5756      * <p>
5757      *
5758      * @param executor The executor to execute the callback of the {@code callback} object.
5759      * @param callback callback for Scan Results events
5760      */
5761 
5762     @RequiresPermission(ACCESS_WIFI_STATE)
registerScanResultsCallback(@onNull @allbackExecutor Executor executor, @NonNull ScanResultsCallback callback)5763     public void registerScanResultsCallback(@NonNull @CallbackExecutor Executor executor,
5764             @NonNull ScanResultsCallback callback) {
5765         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
5766         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5767 
5768         Log.v(TAG, "registerScanResultsCallback: callback=" + callback
5769                 + ", executor=" + executor);
5770         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
5771         proxy.initProxy(executor, callback);
5772         try {
5773             mService.registerScanResultsCallback(proxy);
5774         } catch (RemoteException e) {
5775             throw e.rethrowFromSystemServer();
5776         }
5777     }
5778 
5779     /**
5780      * Allow callers to unregister a previously registered callback. After calling this method,
5781      * applications will no longer receive Scan Results events.
5782      *
5783      * @param callback callback to unregister for Scan Results events
5784      */
5785     @RequiresPermission(ACCESS_WIFI_STATE)
unregisterScanResultsCallback(@onNull ScanResultsCallback callback)5786     public void unregisterScanResultsCallback(@NonNull ScanResultsCallback callback) {
5787         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
5788         Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback);
5789         ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
5790         try {
5791             mService.unregisterScanResultsCallback(proxy);
5792         } catch (RemoteException e) {
5793             throw e.rethrowFromSystemServer();
5794         } finally {
5795             proxy.cleanUpProxy();
5796         }
5797     }
5798 
5799     /**
5800      * Interface for suggestion connection status listener.
5801      * Should be implemented by applications and set when calling
5802      * {@link WifiManager#addSuggestionConnectionStatusListener(
5803      * Executor, SuggestionConnectionStatusListener)}.
5804      */
5805     public interface SuggestionConnectionStatusListener {
5806 
5807         /**
5808          * Called when the framework attempted to connect to a suggestion provided by the
5809          * registering app, but the connection to the suggestion failed.
5810          * @param wifiNetworkSuggestion The suggestion which failed to connect.
5811          * @param failureReason the connection failure reason code. One of
5812          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION},
5813          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION},
5814          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING}
5815          * {@link #STATUS_SUGGESTION_CONNECTION_FAILURE_UNKNOWN}
5816          */
onConnectionStatus( @onNull WifiNetworkSuggestion wifiNetworkSuggestion, @SuggestionConnectionStatusCode int failureReason)5817         void onConnectionStatus(
5818                 @NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
5819                 @SuggestionConnectionStatusCode int failureReason);
5820     }
5821 
5822     private class SuggestionConnectionStatusListenerProxy extends
5823             ISuggestionConnectionStatusListener.Stub {
5824         private final Executor mExecutor;
5825         private final SuggestionConnectionStatusListener mListener;
5826 
SuggestionConnectionStatusListenerProxy(@onNull Executor executor, @NonNull SuggestionConnectionStatusListener listener)5827         SuggestionConnectionStatusListenerProxy(@NonNull Executor executor,
5828                 @NonNull SuggestionConnectionStatusListener listener) {
5829             mExecutor = executor;
5830             mListener = listener;
5831         }
5832 
5833         @Override
onConnectionStatus(@onNull WifiNetworkSuggestion wifiNetworkSuggestion, int failureReason)5834         public void onConnectionStatus(@NonNull WifiNetworkSuggestion wifiNetworkSuggestion,
5835                 int failureReason) {
5836             mExecutor.execute(() ->
5837                     mListener.onConnectionStatus(wifiNetworkSuggestion, failureReason));
5838         }
5839 
5840     }
5841 
5842     /**
5843      * Add a listener for suggestion networks. See {@link SuggestionConnectionStatusListener}.
5844      * Caller will receive the event when suggested network have connection failure.
5845      * Caller can remove a previously registered listener using
5846      * {@link WifiManager#removeSuggestionConnectionStatusListener(
5847      * SuggestionConnectionStatusListener)}
5848      * Same caller can add multiple listeners to monitor the event.
5849      * <p>
5850      * Applications should have the
5851      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and
5852      * {@link android.Manifest.permission#ACCESS_WIFI_STATE} permissions.
5853      * Callers without the permission will trigger a {@link java.lang.SecurityException}.
5854      * <p>
5855      *
5856      * @param executor The executor to execute the listener of the {@code listener} object.
5857      * @param listener listener for suggestion network connection failure.
5858      */
5859     @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
addSuggestionConnectionStatusListener(@onNull @allbackExecutor Executor executor, @NonNull SuggestionConnectionStatusListener listener)5860     public void addSuggestionConnectionStatusListener(@NonNull @CallbackExecutor Executor executor,
5861             @NonNull SuggestionConnectionStatusListener listener) {
5862         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
5863         if (executor == null) throw new IllegalArgumentException("Executor cannot be null");
5864         Log.v(TAG, "addSuggestionConnectionStatusListener listener=" + listener
5865                 + ", executor=" + executor);
5866         try {
5867             mService.registerSuggestionConnectionStatusListener(new Binder(),
5868                     new SuggestionConnectionStatusListenerProxy(executor, listener),
5869                     listener.hashCode(), mContext.getOpPackageName(), mContext.getAttributionTag());
5870         } catch (RemoteException e) {
5871             throw e.rethrowFromSystemServer();
5872         }
5873 
5874     }
5875 
5876     /**
5877      * Allow callers to remove a previously registered listener. After calling this method,
5878      * applications will no longer receive suggestion connection events through that listener.
5879      *
5880      * @param listener listener to remove.
5881      */
5882     @RequiresPermission(ACCESS_WIFI_STATE)
removeSuggestionConnectionStatusListener( @onNull SuggestionConnectionStatusListener listener)5883     public void removeSuggestionConnectionStatusListener(
5884             @NonNull SuggestionConnectionStatusListener listener) {
5885         if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
5886         Log.v(TAG, "removeSuggestionConnectionStatusListener: listener=" + listener);
5887         try {
5888             mService.unregisterSuggestionConnectionStatusListener(listener.hashCode(),
5889                     mContext.getOpPackageName());
5890         } catch (RemoteException e) {
5891             throw e.rethrowFromSystemServer();
5892         }
5893     }
5894 
5895     /**
5896      * Parse the list of channels the DPP enrollee reports when it fails to find an AP.
5897      *
5898      * @param channelList List of channels in the format defined in the DPP specification.
5899      * @return A parsed sparse array, where the operating class is the key.
5900      * @hide
5901      */
5902     @VisibleForTesting
parseDppChannelList(String channelList)5903     public static SparseArray<int[]> parseDppChannelList(String channelList) {
5904         SparseArray<int[]> channelListArray = new SparseArray<>();
5905 
5906         if (TextUtils.isEmpty(channelList)) {
5907             return channelListArray;
5908         }
5909         StringTokenizer str = new StringTokenizer(channelList, ",");
5910         String classStr = null;
5911         List<Integer> channelsInClass = new ArrayList<>();
5912 
5913         try {
5914             while (str.hasMoreElements()) {
5915                 String cur = str.nextToken();
5916 
5917                 /**
5918                  * Example for a channel list:
5919                  *
5920                  * 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,
5921                  * 116,120,124,128,132,136,140,0/144,124/149,153,157,161,125/165
5922                  *
5923                  * Detect operating class by the delimiter of '/' and use a string tokenizer with
5924                  * ',' as a delimiter.
5925                  */
5926                 int classDelim = cur.indexOf('/');
5927                 if (classDelim != -1) {
5928                     if (classStr != null) {
5929                         // Store the last channel array in the sparse array, where the operating
5930                         // class is the key (as an integer).
5931                         int[] channelsArray = new int[channelsInClass.size()];
5932                         for (int i = 0; i < channelsInClass.size(); i++) {
5933                             channelsArray[i] = channelsInClass.get(i);
5934                         }
5935                         channelListArray.append(Integer.parseInt(classStr), channelsArray);
5936                         channelsInClass = new ArrayList<>();
5937                     }
5938 
5939                     // Init a new operating class and store the first channel
5940                     classStr = cur.substring(0, classDelim);
5941                     String channelStr = cur.substring(classDelim + 1);
5942                     channelsInClass.add(Integer.parseInt(channelStr));
5943                 } else {
5944                     if (classStr == null) {
5945                         // Invalid format
5946                         Log.e(TAG, "Cannot parse DPP channel list");
5947                         return new SparseArray<>();
5948                     }
5949                     channelsInClass.add(Integer.parseInt(cur));
5950                 }
5951             }
5952 
5953             // Store the last array
5954             if (classStr != null) {
5955                 int[] channelsArray = new int[channelsInClass.size()];
5956                 for (int i = 0; i < channelsInClass.size(); i++) {
5957                     channelsArray[i] = channelsInClass.get(i);
5958                 }
5959                 channelListArray.append(Integer.parseInt(classStr), channelsArray);
5960             }
5961             return channelListArray;
5962         } catch (NumberFormatException e) {
5963             Log.e(TAG, "Cannot parse DPP channel list");
5964             return new SparseArray<>();
5965         }
5966     }
5967 
5968     /**
5969      * Callback interface for framework to receive network status updates and trigger of updating
5970      * {@link WifiUsabilityStatsEntry}.
5971      *
5972      * @hide
5973      */
5974     @SystemApi
5975     public interface ScoreUpdateObserver {
5976         /**
5977          * Called by applications to indicate network status.
5978          *
5979          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
5980          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
5981          * @param score The score representing link quality of current Wi-Fi network connection.
5982          *              Populated by connected network scorer in applications..
5983          */
notifyScoreUpdate(int sessionId, int score)5984         void notifyScoreUpdate(int sessionId, int score);
5985 
5986         /**
5987          * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
5988          * To receive update applications need to add WifiUsabilityStatsEntry listener. See
5989          * {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
5990          *
5991          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
5992          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
5993          */
triggerUpdateOfWifiUsabilityStats(int sessionId)5994         void triggerUpdateOfWifiUsabilityStats(int sessionId);
5995     }
5996 
5997     /**
5998      * Callback proxy for {@link ScoreUpdateObserver} objects.
5999      *
6000      * @hide
6001      */
6002     private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
6003         private final IScoreUpdateObserver mScoreUpdateObserver;
6004 
ScoreUpdateObserverProxy(IScoreUpdateObserver observer)6005         private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
6006             mScoreUpdateObserver = observer;
6007         }
6008 
6009         @Override
notifyScoreUpdate(int sessionId, int score)6010         public void notifyScoreUpdate(int sessionId, int score) {
6011             try {
6012                 mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
6013             } catch (RemoteException e) {
6014                 throw e.rethrowFromSystemServer();
6015             }
6016         }
6017 
6018         @Override
triggerUpdateOfWifiUsabilityStats(int sessionId)6019         public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
6020             try {
6021                 mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
6022             } catch (RemoteException e) {
6023                 throw e.rethrowFromSystemServer();
6024             }
6025         }
6026     }
6027 
6028     /**
6029      * Interface for Wi-Fi connected network scorer. Should be implemented by applications and set
6030      * when calling
6031      * {@link WifiManager#setWifiConnectedNetworkScorer(Executor, WifiConnectedNetworkScorer)}.
6032      *
6033      * @hide
6034      */
6035     @SystemApi
6036     public interface WifiConnectedNetworkScorer {
6037         /**
6038          * Called by framework to indicate the start of a network connection.
6039          * @param sessionId The ID to indicate current Wi-Fi network connection.
6040          */
onStart(int sessionId)6041         void onStart(int sessionId);
6042 
6043         /**
6044          * Called by framework to indicate the end of a network connection.
6045          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
6046          *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
6047          */
onStop(int sessionId)6048         void onStop(int sessionId);
6049 
6050         /**
6051          * Framework sets callback for score change events after application sets its scorer.
6052          * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
6053          * implemented and instantiated by framework.
6054          */
onSetScoreUpdateObserver(@onNull ScoreUpdateObserver observerImpl)6055         void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
6056     }
6057 
6058     /**
6059      * Callback proxy for {@link WifiConnectedNetworkScorer} objects.
6060      *
6061      * @hide
6062      */
6063     private class WifiConnectedNetworkScorerProxy extends IWifiConnectedNetworkScorer.Stub {
6064         private Executor mExecutor;
6065         private WifiConnectedNetworkScorer mScorer;
6066 
WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer)6067         WifiConnectedNetworkScorerProxy(Executor executor, WifiConnectedNetworkScorer scorer) {
6068             mExecutor = executor;
6069             mScorer = scorer;
6070         }
6071 
6072         @Override
onStart(int sessionId)6073         public void onStart(int sessionId) {
6074             if (mVerboseLoggingEnabled) {
6075                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionId=" + sessionId);
6076             }
6077             Binder.clearCallingIdentity();
6078             mExecutor.execute(() -> mScorer.onStart(sessionId));
6079         }
6080 
6081         @Override
onStop(int sessionId)6082         public void onStop(int sessionId) {
6083             if (mVerboseLoggingEnabled) {
6084                 Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
6085             }
6086             Binder.clearCallingIdentity();
6087             mExecutor.execute(() -> mScorer.onStop(sessionId));
6088         }
6089 
6090         @Override
onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl)6091         public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
6092             if (mVerboseLoggingEnabled) {
6093                 Log.v(TAG, "WifiConnectedNetworkScorer: "
6094                         + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
6095             }
6096             Binder.clearCallingIdentity();
6097             mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
6098                     new ScoreUpdateObserverProxy(observerImpl)));
6099         }
6100     }
6101 
6102     /**
6103      * Set a callback for Wi-Fi connected network scorer.  See {@link WifiConnectedNetworkScorer}.
6104      * Only a single scorer can be set. Caller will be invoked periodically by framework to inform
6105      * client about start and stop of Wi-Fi connection. Caller can clear a previously set scorer
6106      * using {@link clearWifiConnectedNetworkScorer()}.
6107      *
6108      * @param executor The executor on which callback will be invoked.
6109      * @param scorer Scorer for Wi-Fi network implemented by application.
6110      * @return true Scorer is set successfully.
6111      *
6112      * @hide
6113      */
6114     @SystemApi
6115     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
setWifiConnectedNetworkScorer(@onNull @allbackExecutor Executor executor, @NonNull WifiConnectedNetworkScorer scorer)6116     public boolean setWifiConnectedNetworkScorer(@NonNull @CallbackExecutor Executor executor,
6117             @NonNull WifiConnectedNetworkScorer scorer) {
6118         if (executor == null) throw new IllegalArgumentException("executor cannot be null");
6119         if (scorer == null) throw new IllegalArgumentException("scorer cannot be null");
6120         if (mVerboseLoggingEnabled) {
6121             Log.v(TAG, "setWifiConnectedNetworkScorer: scorer=" + scorer);
6122         }
6123         try {
6124             return mService.setWifiConnectedNetworkScorer(new Binder(),
6125                     new WifiConnectedNetworkScorerProxy(executor, scorer));
6126         } catch (RemoteException e) {
6127             throw e.rethrowFromSystemServer();
6128         }
6129     }
6130 
6131     /**
6132      * Allow caller to clear a previously set scorer. After calling this method,
6133      * client will no longer receive information about start and stop of Wi-Fi connection.
6134      *
6135      * @hide
6136      */
6137     @SystemApi
6138     @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
clearWifiConnectedNetworkScorer()6139     public void clearWifiConnectedNetworkScorer() {
6140         if (mVerboseLoggingEnabled) {
6141             Log.v(TAG, "clearWifiConnectedNetworkScorer");
6142         }
6143         try {
6144             mService.clearWifiConnectedNetworkScorer();
6145         } catch (RemoteException e) {
6146             throw e.rethrowFromSystemServer();
6147         }
6148     }
6149 
6150     /**
6151      * Enable/disable wifi scan throttling from 3rd party apps.
6152      *
6153      * <p>
6154      * The throttling limits for apps are described in
6155      * <a href="Wi-Fi Scan Throttling">
6156      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
6157      * </p>
6158      *
6159      * @param enable true to allow scan throttling, false to disallow scan throttling.
6160      * @hide
6161      */
6162     @SystemApi
6163     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setScanThrottleEnabled(boolean enable)6164     public void setScanThrottleEnabled(boolean enable) {
6165         try {
6166             mService.setScanThrottleEnabled(enable);
6167         } catch (RemoteException e) {
6168             throw e.rethrowFromSystemServer();
6169         }
6170     }
6171 
6172     /**
6173      * Get the persisted Wi-Fi scan throttle state. Defaults to true, unless changed by the user via
6174      * Developer options.
6175      *
6176      * <p>
6177      * The throttling limits for apps are described in
6178      * <a href="Wi-Fi Scan Throttling">
6179      * https://developer.android.com/guide/topics/connectivity/wifi-scan#wifi-scan-throttling</a>
6180      * </p>
6181      *
6182      * @return true to indicate that scan throttling is enabled, false to indicate that scan
6183      * throttling is disabled.
6184      */
6185     @RequiresPermission(ACCESS_WIFI_STATE)
isScanThrottleEnabled()6186     public boolean isScanThrottleEnabled() {
6187         try {
6188             return mService.isScanThrottleEnabled();
6189         } catch (RemoteException e) {
6190             throw e.rethrowFromSystemServer();
6191         }
6192     }
6193 
6194     /**
6195      * Enable/disable wifi auto wakeup feature.
6196      *
6197      * <p>
6198      * The feature is described in
6199      * <a href="Wi-Fi Turn on automatically">
6200      * https://source.android.com/devices/tech/connect/wifi-infrastructure
6201      * #turn_on_wi-fi_automatically
6202      * </a>
6203      *
6204      * @param enable true to enable, false to disable.
6205      * @hide
6206      */
6207     @SystemApi
6208     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
setAutoWakeupEnabled(boolean enable)6209     public void setAutoWakeupEnabled(boolean enable) {
6210         try {
6211             mService.setAutoWakeupEnabled(enable);
6212         } catch (RemoteException e) {
6213             throw e.rethrowFromSystemServer();
6214         }
6215     }
6216 
6217     /**
6218      * Get the persisted Wi-Fi auto wakeup feature state. Defaults to false, unless changed by the
6219      * user via Settings.
6220      *
6221      * <p>
6222      * The feature is described in
6223      * <a href="Wi-Fi Turn on automatically">
6224      * https://source.android.com/devices/tech/connect/wifi-infrastructure
6225      * #turn_on_wi-fi_automatically
6226      * </a>
6227      *
6228      * @return true to indicate that wakeup feature is enabled, false to indicate that wakeup
6229      * feature is disabled.
6230      */
6231     @RequiresPermission(ACCESS_WIFI_STATE)
isAutoWakeupEnabled()6232     public boolean isAutoWakeupEnabled() {
6233         try {
6234             return mService.isAutoWakeupEnabled();
6235         } catch (RemoteException e) {
6236             throw e.rethrowFromSystemServer();
6237         }
6238     }
6239 }
6240