• 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.NEARBY_WIFI_DEVICES;
20 
21 import android.Manifest;
22 import android.annotation.CallbackExecutor;
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SuppressLint;
28 import android.annotation.SystemApi;
29 import android.annotation.SystemService;
30 import android.content.Context;
31 import android.os.Binder;
32 import android.os.Build;
33 import android.os.Bundle;
34 import android.os.Looper;
35 import android.os.Parcel;
36 import android.os.Parcelable;
37 import android.os.Process;
38 import android.os.RemoteException;
39 import android.os.WorkSource;
40 import android.text.TextUtils;
41 import android.util.Log;
42 
43 import androidx.annotation.RequiresApi;
44 
45 import com.android.internal.util.Protocol;
46 import com.android.modules.utils.build.SdkLevel;
47 
48 import java.lang.annotation.Retention;
49 import java.lang.annotation.RetentionPolicy;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.HashMap;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Objects;
56 import java.util.concurrent.Executor;
57 
58 /**
59  * This class provides a way to scan the Wifi universe around the device
60  * @hide
61  */
62 @SystemApi
63 @SystemService(Context.WIFI_SCANNING_SERVICE)
64 public class WifiScanner {
65 
66     /** @hide */
67     public static final int WIFI_BAND_INDEX_24_GHZ = 0;
68     /** @hide */
69     public static final int WIFI_BAND_INDEX_5_GHZ = 1;
70     /** @hide */
71     public static final int WIFI_BAND_INDEX_5_GHZ_DFS_ONLY = 2;
72     /** @hide */
73     public static final int WIFI_BAND_INDEX_6_GHZ = 3;
74     /** @hide */
75     public static final int WIFI_BAND_INDEX_60_GHZ = 4;
76     /** @hide */
77     public static final int WIFI_BAND_COUNT = 5;
78 
79     /** @hide */
80     @Retention(RetentionPolicy.SOURCE)
81     @IntDef(prefix = {"WIFI_BAND_INDEX_"}, value = {
82             WIFI_BAND_INDEX_24_GHZ,
83             WIFI_BAND_INDEX_5_GHZ,
84             WIFI_BAND_INDEX_5_GHZ_DFS_ONLY,
85             WIFI_BAND_INDEX_6_GHZ,
86             WIFI_BAND_INDEX_60_GHZ})
87     public @interface WifiBandIndex {}
88 
89     /** no band specified; use channel list instead */
90     public static final int WIFI_BAND_UNSPECIFIED = 0;
91     /** 2.4 GHz band */
92     public static final int WIFI_BAND_24_GHZ = 1 << WIFI_BAND_INDEX_24_GHZ;
93     /** 5 GHz band excluding DFS channels */
94     public static final int WIFI_BAND_5_GHZ = 1 << WIFI_BAND_INDEX_5_GHZ;
95     /** DFS channels from 5 GHz band only */
96     public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
97     /** 6 GHz band */
98     public static final int WIFI_BAND_6_GHZ = 1 << WIFI_BAND_INDEX_6_GHZ;
99     /** 60 GHz band */
100     public static final int WIFI_BAND_60_GHZ = 1 << WIFI_BAND_INDEX_60_GHZ;
101 
102     /**
103      * Combination of bands
104      * Note that those are only the common band combinations,
105      * other combinations can be created by combining any of the basic bands above
106      */
107     /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
108     public static final int WIFI_BAND_BOTH = WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ;
109     /**
110      * 2.4Ghz band + DFS channels from 5 GHz band only
111      * @hide
112      */
113     public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS  =
114             WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
115     /** 5 GHz band including DFS channels */
116     public static final int WIFI_BAND_5_GHZ_WITH_DFS  = WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
117     /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
118     public static final int WIFI_BAND_BOTH_WITH_DFS =
119             WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
120     /** 2.4 GHz band and 5 GHz band (no DFS channels) and 6 GHz */
121     public static final int WIFI_BAND_24_5_6_GHZ = WIFI_BAND_BOTH | WIFI_BAND_6_GHZ;
122     /** 2.4 GHz band and 5 GHz band; with DFS channels and 6 GHz */
123     public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ =
124             WIFI_BAND_BOTH_WITH_DFS | WIFI_BAND_6_GHZ;
125     /** @hide */
126     public static final int WIFI_BAND_24_5_6_60_GHZ =
127             WIFI_BAND_24_5_6_GHZ | WIFI_BAND_60_GHZ;
128     /** @hide */
129     public static final int WIFI_BAND_24_5_WITH_DFS_6_60_GHZ =
130             WIFI_BAND_24_5_6_60_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
131 
132     /** @hide */
133     @Retention(RetentionPolicy.SOURCE)
134     @IntDef(prefix = {"WIFI_BAND_"}, value = {
135             WIFI_BAND_UNSPECIFIED,
136             WIFI_BAND_24_GHZ,
137             WIFI_BAND_5_GHZ,
138             WIFI_BAND_BOTH,
139             WIFI_BAND_5_GHZ_DFS_ONLY,
140             WIFI_BAND_24_GHZ_WITH_5GHZ_DFS,
141             WIFI_BAND_5_GHZ_WITH_DFS,
142             WIFI_BAND_BOTH_WITH_DFS,
143             WIFI_BAND_6_GHZ,
144             WIFI_BAND_24_5_6_GHZ,
145             WIFI_BAND_24_5_WITH_DFS_6_GHZ,
146             WIFI_BAND_60_GHZ,
147             WIFI_BAND_24_5_6_60_GHZ,
148             WIFI_BAND_24_5_WITH_DFS_6_60_GHZ})
149     public @interface WifiBand {}
150 
151     /**
152      * All bands
153      * @hide
154      */
155     public static final int WIFI_BAND_ALL = (1 << WIFI_BAND_COUNT) - 1;
156 
157     /** Minimum supported scanning period */
158     public static final int MIN_SCAN_PERIOD_MS = 1000;
159     /** Maximum supported scanning period */
160     public static final int MAX_SCAN_PERIOD_MS = 1024000;
161 
162     /** No Error */
163     public static final int REASON_SUCCEEDED = 0;
164     /** Unknown error */
165     public static final int REASON_UNSPECIFIED = -1;
166     /** Invalid listener */
167     public static final int REASON_INVALID_LISTENER = -2;
168     /** Invalid request */
169     public static final int REASON_INVALID_REQUEST = -3;
170     /** Invalid request */
171     public static final int REASON_NOT_AUTHORIZED = -4;
172     /** An outstanding request with the same listener hasn't finished yet. */
173     public static final int REASON_DUPLICATE_REQEUST = -5;
174     /** Busy - Due to Connection in progress, processing another scan request etc. */
175     public static final int REASON_BUSY = -6;
176     /** Abort - Due to another high priority operation like roaming, offload scan etc. */
177     public static final int REASON_ABORT = -7;
178     /** No such device - Wrong interface or interface doesn't exist. */
179     public static final int REASON_NO_DEVICE = -8;
180     /** Invalid argument - Wrong/unsupported argument passed in scan params. */
181     public static final int REASON_INVALID_ARGS = -9;
182     /** Timeout - Device didn't respond back with scan results */
183     public static final int REASON_TIMEOUT = -10;
184 
185     /** @hide */
186     @Retention(RetentionPolicy.SOURCE)
187     @IntDef(prefix = { "REASON_" }, value = {
188             REASON_SUCCEEDED,
189             REASON_UNSPECIFIED,
190             REASON_INVALID_LISTENER,
191             REASON_INVALID_REQUEST,
192             REASON_NOT_AUTHORIZED,
193             REASON_DUPLICATE_REQEUST,
194             REASON_BUSY,
195             REASON_ABORT,
196             REASON_NO_DEVICE,
197             REASON_INVALID_ARGS,
198             REASON_TIMEOUT,
199     })
200     public @interface ScanStatusCode {}
201 
202     /** @hide */
203     public static final String GET_AVAILABLE_CHANNELS_EXTRA = "Channels";
204 
205     /**
206      * This constant is used for {@link ScanSettings#setRnrSetting(int)}.
207      * <p>
208      * Scan 6Ghz APs co-located with 2.4/5Ghz APs using Reduced Neighbor Report (RNR) if the 6Ghz
209      * band is explicitly requested to be scanned and the current country code supports scanning
210      * of at least one 6Ghz channel. The 6Ghz band is explicitly requested if the
211      * ScanSetting.band parameter is set to one of:
212      * <li> {@link #WIFI_BAND_6_GHZ} </li>
213      * <li> {@link #WIFI_BAND_24_5_6_GHZ} </li>
214      * <li> {@link #WIFI_BAND_24_5_WITH_DFS_6_GHZ} </li>
215      * <li> {@link #WIFI_BAND_24_5_6_60_GHZ} </li>
216      * <li> {@link #WIFI_BAND_24_5_WITH_DFS_6_60_GHZ} </li>
217      * <li> {@link #WIFI_BAND_ALL} </li>
218      **/
219     public static final int WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED = 0;
220     /**
221      * This constant is used for {@link ScanSettings#setRnrSetting(int)}.
222      * <p>
223      * Request to scan 6Ghz APs co-located with 2.4/5Ghz APs using Reduced Neighbor Report (RNR)
224      * when the current country code supports scanning of at least one 6Ghz channel.
225      **/
226     public static final int WIFI_RNR_ENABLED = 1;
227     /**
228      * This constant is used for {@link ScanSettings#setRnrSetting(int)}.
229      * <p>
230      * Do not request to scan 6Ghz APs co-located with 2.4/5Ghz APs using
231      * Reduced Neighbor Report (RNR)
232      **/
233     public static final int WIFI_RNR_NOT_NEEDED = 2;
234 
235     /** @hide */
236     @Retention(RetentionPolicy.SOURCE)
237     @IntDef(prefix = {"RNR_"}, value = {
238             WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED,
239             WIFI_RNR_ENABLED,
240             WIFI_RNR_NOT_NEEDED})
241     public @interface RnrSetting {}
242 
243     /**
244      * Maximum length in bytes of all vendor specific information elements (IEs) allowed to set.
245      * @hide
246      */
247     public static final int WIFI_SCANNER_SETTINGS_VENDOR_ELEMENTS_MAX_LEN = 512;
248 
249     /**
250      * Information Element head: id (1 byte) + length (1 byte)
251      * @hide
252      */
253     public static final int WIFI_IE_HEAD_LEN = 2;
254 
255     /**
256      * Generic action callback invocation interface
257      *  @hide
258      */
259     @SystemApi
260     public static interface ActionListener {
onSuccess()261         public void onSuccess();
onFailure(int reason, String description)262         public void onFailure(int reason, String description);
263     }
264 
265     /**
266      * Test if scan is a full scan. i.e. scanning all available bands.
267      * For backward compatibility, since some apps don't include 6GHz or 60Ghz in their requests
268      * yet, lacking 6GHz or 60Ghz band does not cause the result to be false.
269      *
270      * @param bandsScanned bands that are fully scanned
271      * @param excludeDfs when true, DFS band is excluded from the check
272      * @return true if all bands are scanned, false otherwise
273      *
274      * @hide
275      */
isFullBandScan(@ifiBand int bandsScanned, boolean excludeDfs)276     public static boolean isFullBandScan(@WifiBand int bandsScanned, boolean excludeDfs) {
277         return (bandsScanned | WIFI_BAND_6_GHZ | WIFI_BAND_60_GHZ
278                 | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
279                 == WIFI_BAND_ALL;
280     }
281 
282     /**
283      * Returns a list of all the possible channels for the given band(s).
284      *
285      * @param band one of the WifiScanner#WIFI_BAND_* constants, e.g. {@link #WIFI_BAND_24_GHZ}
286      * @return a list of all the frequencies, in MHz, for the given band(s) e.g. channel 1 is
287      * 2412, or null if an error occurred.
288      */
289     @NonNull
290     @RequiresPermission(NEARBY_WIFI_DEVICES)
getAvailableChannels(int band)291     public List<Integer> getAvailableChannels(int band) {
292         try {
293             Bundle extras = new Bundle();
294             if (SdkLevel.isAtLeastS()) {
295                 extras.putParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE,
296                         mContext.getAttributionSource());
297             }
298             Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName(),
299                     mContext.getAttributionTag(), extras);
300             List<Integer> channels = bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
301             return channels == null ? new ArrayList<>() : channels;
302         } catch (RemoteException e) {
303             throw e.rethrowFromSystemServer();
304         }
305     }
306 
307     private class ServiceListener extends IWifiScannerListener.Stub {
308         private ActionListener mActionListener;
309         private Executor mExecutor;
310 
ServiceListener(ActionListener listener, Executor executor)311         ServiceListener(ActionListener listener, Executor executor) {
312             mActionListener = listener;
313             mExecutor = executor;
314         }
315 
316         @Override
onSuccess()317         public void onSuccess() {
318             if (mActionListener == null) return;
319             Binder.clearCallingIdentity();
320             mExecutor.execute(mActionListener::onSuccess);
321         }
322 
323         @Override
onFailure(int reason, String description)324         public void onFailure(int reason, String description) {
325             if (mActionListener == null) return;
326             Binder.clearCallingIdentity();
327             mExecutor.execute(() ->
328                     mActionListener.onFailure(reason, description));
329             removeListener(mActionListener);
330         }
331 
332         /**
333          * reports results retrieved from background scan and single shot scans
334          */
335         @Override
onResults(WifiScanner.ScanData[] results)336         public void onResults(WifiScanner.ScanData[] results) {
337             if (mActionListener == null) return;
338             if (!(mActionListener instanceof ScanListener)) return;
339             ScanListener scanListener = (ScanListener) mActionListener;
340             Binder.clearCallingIdentity();
341             mExecutor.execute(
342                     () -> scanListener.onResults(results));
343         }
344 
345         /**
346          * reports full scan result for each access point found in scan
347          */
348         @Override
onFullResult(ScanResult fullScanResult)349         public void onFullResult(ScanResult fullScanResult) {
350             if (mActionListener == null) return;
351             if (!(mActionListener instanceof ScanListener)) return;
352             ScanListener scanListener = (ScanListener) mActionListener;
353             Binder.clearCallingIdentity();
354             mExecutor.execute(
355                     () -> scanListener.onFullResult(fullScanResult));
356         }
357 
358         @Override
onSingleScanCompleted()359         public void onSingleScanCompleted() {
360             if (DBG) Log.d(TAG, "single scan completed");
361             removeListener(mActionListener);
362         }
363 
364         /**
365          * Invoked when one of the PNO networks are found in scan results.
366          */
367         @Override
onPnoNetworkFound(ScanResult[] results)368         public void onPnoNetworkFound(ScanResult[] results) {
369             if (mActionListener == null) return;
370             if (!(mActionListener instanceof PnoScanListener)) return;
371             PnoScanListener pnoScanListener = (PnoScanListener) mActionListener;
372             Binder.clearCallingIdentity();
373             mExecutor.execute(
374                     () -> pnoScanListener.onPnoNetworkFound(results));
375         }
376     }
377 
378     /**
379      * provides channel specification for scanning
380      */
381     public static class ChannelSpec {
382         /**
383          * channel frequency in MHz; for example channel 1 is specified as 2412
384          */
385         public int frequency;
386         /**
387          * if true, scan this channel in passive fashion.
388          * This flag is ignored on DFS channel specification.
389          * @hide
390          */
391         public boolean passive;                                    /* ignored on DFS channels */
392         /**
393          * how long to dwell on this channel
394          * @hide
395          */
396         public int dwellTimeMS;                                    /* not supported for now */
397 
398         /**
399          * default constructor for channel spec
400          */
ChannelSpec(int frequency)401         public ChannelSpec(int frequency) {
402             this.frequency = frequency;
403             passive = false;
404             dwellTimeMS = 0;
405         }
406     }
407 
408     /**
409      * reports {@link ScanListener#onResults} when underlying buffers are full
410      * this is simply the lack of the {@link #REPORT_EVENT_AFTER_EACH_SCAN} flag
411      * @deprecated It is not supported anymore.
412      */
413     @Deprecated
414     public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
415     /**
416      * reports {@link ScanListener#onResults} after each scan
417      */
418     public static final int REPORT_EVENT_AFTER_EACH_SCAN = (1 << 0);
419     /**
420      * reports {@link ScanListener#onFullResult} whenever each beacon is discovered
421      */
422     public static final int REPORT_EVENT_FULL_SCAN_RESULT = (1 << 1);
423     /**
424      * Do not place scans in the chip's scan history buffer
425      */
426     public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
427 
428     /**
429      * Optimize the scan for lower latency.
430      * @see ScanSettings#type
431      */
432     public static final int SCAN_TYPE_LOW_LATENCY = 0;
433     /**
434      * Optimize the scan for lower power usage.
435      * @see ScanSettings#type
436      */
437     public static final int SCAN_TYPE_LOW_POWER = 1;
438     /**
439      * Optimize the scan for higher accuracy.
440      * @see ScanSettings#type
441      */
442     public static final int SCAN_TYPE_HIGH_ACCURACY = 2;
443     /**
444      * Max valid value of SCAN_TYPE_
445      * @hide
446      */
447     public static final int SCAN_TYPE_MAX = 2;
448 
449     /** {@hide} */
450     public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
451     /** {@hide} */
452     public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource";
453     /** {@hide} */
454     public static final String REQUEST_PACKAGE_NAME_KEY = "PackageName";
455     /** {@hide} */
456     public static final String REQUEST_FEATURE_ID_KEY = "FeatureId";
457 
458     /**
459      * scan configuration parameters to be sent to {@link #startBackgroundScan}
460      */
461     public static class ScanSettings implements Parcelable {
462         /** Hidden network to be scanned for. */
463         public static class HiddenNetwork {
464             /** SSID of the network */
465             @NonNull
466             public final String ssid;
467 
468             /** Default constructor for HiddenNetwork. */
HiddenNetwork(@onNull String ssid)469             public HiddenNetwork(@NonNull String ssid) {
470                 this.ssid = ssid;
471             }
472         }
473 
474         /** one of the WIFI_BAND values */
475         public int band;
476         /**
477          * one of the {@code WIFI_RNR_*} values.
478          */
479         private int mRnrSetting = WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED;
480 
481         /**
482          * See {@link #set6GhzPscOnlyEnabled}
483          */
484         private boolean mEnable6GhzPsc = false;
485 
486         /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
487         public ChannelSpec[] channels;
488         /**
489          * List of hidden networks to scan for. Explicit probe requests are sent out for such
490          * networks during scan. Only valid for single scan requests.
491          */
492         @NonNull
493         @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
494         public final List<HiddenNetwork> hiddenNetworks = new ArrayList<>();
495 
496         /**
497          * vendor IEs -- list of ScanResult.InformationElement, configured by App
498          * see {@link #setVendorIes(List)}
499          */
500         @NonNull
501         private List<ScanResult.InformationElement> mVendorIes = new ArrayList<>();
502 
503         /**
504          * period of background scan; in millisecond, 0 => single shot scan
505          * @deprecated Background scan support has always been hardware vendor dependent. This
506          * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
507          * ScanListener)} instead for single scans.
508          */
509         @Deprecated
510         public int periodInMs;
511         /**
512          * must have a valid REPORT_EVENT value
513          * @deprecated Background scan support has always been hardware vendor dependent. This
514          * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
515          * ScanListener)} instead for single scans.
516          */
517         @Deprecated
518         public int reportEvents;
519         /**
520          * defines number of bssids to cache from each scan
521          * @deprecated Background scan support has always been hardware vendor dependent. This
522          * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
523          * ScanListener)} instead for single scans.
524          */
525         @Deprecated
526         public int numBssidsPerScan;
527         /**
528          * defines number of scans to cache; use it with REPORT_EVENT_AFTER_BUFFER_FULL
529          * to wake up at fixed interval
530          * @deprecated Background scan support has always been hardware vendor dependent. This
531          * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
532          * ScanListener)} instead for single scans.
533          */
534         @Deprecated
535         public int maxScansToCache;
536         /**
537          * if maxPeriodInMs is non zero or different than period, then this bucket is
538          * a truncated binary exponential backoff bucket and the scan period will grow
539          * exponentially as per formula: actual_period(N) = period * (2 ^ (N/stepCount))
540          * to maxPeriodInMs
541          * @deprecated Background scan support has always been hardware vendor dependent. This
542          * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
543          * ScanListener)} instead for single scans.
544          */
545         @Deprecated
546         public int maxPeriodInMs;
547         /**
548          * for truncated binary exponential back off bucket, number of scans to perform
549          * for a given period
550          * @deprecated Background scan support has always been hardware vendor dependent. This
551          * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
552          * ScanListener)} instead for single scans.
553          */
554         @Deprecated
555         public int stepCount;
556         /**
557          * Flag to indicate if the scan settings are targeted for PNO scan.
558          * {@hide}
559          */
560         public boolean isPnoScan;
561         /**
562          * Indicate the type of scan to be performed by the wifi chip.
563          *
564          * On devices with multiple hardware radio chains (and hence different modes of scan),
565          * this type serves as an indication to the hardware on what mode of scan to perform.
566          * Only apps holding {@link android.Manifest.permission.NETWORK_STACK} permission can set
567          * this value.
568          *
569          * Note: This serves as an intent and not as a stipulation, the wifi chip
570          * might honor or ignore the indication based on the current radio conditions. Always
571          * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration
572          * used to receive the corresponding scan result.
573          *
574          * One of {@link #SCAN_TYPE_LOW_LATENCY}, {@link #SCAN_TYPE_LOW_POWER},
575          * {@link #SCAN_TYPE_HIGH_ACCURACY}.
576          * Default value: {@link #SCAN_TYPE_LOW_LATENCY}.
577          */
578         @WifiAnnotations.ScanType
579         @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
580         public int type = SCAN_TYPE_LOW_LATENCY;
581         /**
582          * This scan request may ignore location settings while receiving scans. This should only
583          * be used in emergency situations.
584          * {@hide}
585          */
586         @SystemApi
587         public boolean ignoreLocationSettings;
588         /**
589          * This scan request will be hidden from app-ops noting for location information. This
590          * should only be used by FLP/NLP module on the device which is using the scan results to
591          * compute results for behalf on their clients. FLP/NLP module using this flag should ensure
592          * that they note in app-ops the eventual delivery of location information computed using
593          * these results to their client .
594          * {@hide}
595          */
596         @SystemApi
597         public boolean hideFromAppOps;
598 
599         /**
600          * Configure whether it is needed to scan 6Ghz non Preferred Scanning Channels when scanning
601          * {@link #WIFI_BAND_6_GHZ}. If set to true and a band that contains
602          * {@link #WIFI_BAND_6_GHZ} is configured for scanning, then only scan 6Ghz PSC channels in
603          * addition to any other bands configured for scanning. Note, 6Ghz non-PSC channels that
604          * are co-located with 2.4/5Ghz APs could still be scanned via the
605          * {@link #setRnrSetting(int)} API.
606          *
607          * <p>
608          * For example, given a ScanSettings with band set to {@link #WIFI_BAND_24_5_WITH_DFS_6_GHZ}
609          * If this API is set to "true" then the ScanSettings is configured to scan all of 2.4Ghz
610          * + all of 5Ghz(DFS and non-DFS) + 6Ghz PSC channels. If this API is set to "false", then
611          * the ScanSetting is configured to scan all of 2.4Ghz + all of 5Ghz(DFS and non_DFS)
612          * + all of 6Ghz channels.
613          * @param enable true to only scan 6Ghz PSC channels, false to scan all 6Ghz channels.
614          */
615         @RequiresApi(Build.VERSION_CODES.S)
set6GhzPscOnlyEnabled(boolean enable)616         public void set6GhzPscOnlyEnabled(boolean enable) {
617             if (!SdkLevel.isAtLeastS()) {
618                 throw new UnsupportedOperationException();
619             }
620             mEnable6GhzPsc = enable;
621         }
622 
623         /**
624          * See {@link #set6GhzPscOnlyEnabled}
625          */
626         @RequiresApi(Build.VERSION_CODES.S)
is6GhzPscOnlyEnabled()627         public boolean is6GhzPscOnlyEnabled() {
628             if (!SdkLevel.isAtLeastS()) {
629                 throw new UnsupportedOperationException();
630             }
631             return mEnable6GhzPsc;
632         }
633 
634         /**
635          * Configure when to scan 6Ghz APs co-located with 2.4/5Ghz APs using Reduced
636          * Neighbor Report (RNR).
637          * @param rnrSetting one of the {@code WIFI_RNR_*} values
638          */
639         @RequiresApi(Build.VERSION_CODES.S)
setRnrSetting(@nrSetting int rnrSetting)640         public void setRnrSetting(@RnrSetting int rnrSetting) {
641             if (!SdkLevel.isAtLeastS()) {
642                 throw new UnsupportedOperationException();
643             }
644             if (rnrSetting < WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED
645                     || rnrSetting > WIFI_RNR_NOT_NEEDED) {
646                 throw new IllegalArgumentException("Invalid rnrSetting");
647             }
648             mRnrSetting = rnrSetting;
649         }
650 
651         /**
652          * See {@link #setRnrSetting}
653          */
654         @RequiresApi(Build.VERSION_CODES.S)
getRnrSetting()655         public @RnrSetting int getRnrSetting() {
656             if (!SdkLevel.isAtLeastS()) {
657                 throw new UnsupportedOperationException();
658             }
659             return mRnrSetting;
660         }
661 
662         /**
663          * Set vendor IEs in scan probe req.
664          *
665          * @param vendorIes List of ScanResult.InformationElement configured by App.
666          */
667         @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
setVendorIes(@onNull List<ScanResult.InformationElement> vendorIes)668         public void setVendorIes(@NonNull List<ScanResult.InformationElement> vendorIes) {
669             if (!SdkLevel.isAtLeastU()) {
670                 throw new UnsupportedOperationException();
671             }
672 
673             mVendorIes.clear();
674             int totalBytes = 0;
675             for (ScanResult.InformationElement e : vendorIes) {
676                 if (e.id != ScanResult.InformationElement.EID_VSA) {
677                     throw new IllegalArgumentException("received InformationElement which is not "
678                             + "a Vendor Specific IE (VSIE). VSIEs have an ID = ScanResult"
679                             + ".InformationElement.EID_VSA.");
680                 }
681                 if (e.bytes == null || e.bytes.length > 0xff) {
682                     throw new IllegalArgumentException("received InformationElement whose payload "
683                             + "is null or size is greater than 255.");
684                 }
685                 // The total bytes of an IE is EID (1 byte) + length (1 byte) + payload length.
686                 totalBytes += WIFI_IE_HEAD_LEN + e.bytes.length;
687                 if (totalBytes > WIFI_SCANNER_SETTINGS_VENDOR_ELEMENTS_MAX_LEN) {
688                     throw new IllegalArgumentException(
689                             "received InformationElement whose total size is greater than "
690                                     + WIFI_SCANNER_SETTINGS_VENDOR_ELEMENTS_MAX_LEN + ".");
691                 }
692             }
693             mVendorIes.addAll(vendorIes);
694         }
695 
696         /**
697          * See {@link #setVendorIes(List)}
698          */
699         @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
getVendorIes()700         public @NonNull List<ScanResult.InformationElement> getVendorIes() {
701             if (!SdkLevel.isAtLeastU()) {
702                 throw new UnsupportedOperationException();
703             }
704             return mVendorIes;
705         }
706 
707         /** Implement the Parcelable interface {@hide} */
describeContents()708         public int describeContents() {
709             return 0;
710         }
711 
712         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)713         public void writeToParcel(Parcel dest, int flags) {
714             dest.writeInt(band);
715             dest.writeInt(periodInMs);
716             dest.writeInt(reportEvents);
717             dest.writeInt(numBssidsPerScan);
718             dest.writeInt(maxScansToCache);
719             dest.writeInt(maxPeriodInMs);
720             dest.writeInt(stepCount);
721             dest.writeInt(isPnoScan ? 1 : 0);
722             dest.writeInt(type);
723             dest.writeInt(ignoreLocationSettings ? 1 : 0);
724             dest.writeInt(hideFromAppOps ? 1 : 0);
725             dest.writeInt(mRnrSetting);
726             dest.writeBoolean(mEnable6GhzPsc);
727             if (channels != null) {
728                 dest.writeInt(channels.length);
729                 for (int i = 0; i < channels.length; i++) {
730                     dest.writeInt(channels[i].frequency);
731                     dest.writeInt(channels[i].dwellTimeMS);
732                     dest.writeInt(channels[i].passive ? 1 : 0);
733                 }
734             } else {
735                 dest.writeInt(0);
736             }
737             dest.writeInt(hiddenNetworks.size());
738             for (HiddenNetwork hiddenNetwork : hiddenNetworks) {
739                 dest.writeString(hiddenNetwork.ssid);
740             }
741             dest.writeTypedList(mVendorIes);
742         }
743 
744         /** Implement the Parcelable interface */
745         public static final @NonNull Creator<ScanSettings> CREATOR =
746                 new Creator<ScanSettings>() {
747                     public ScanSettings createFromParcel(Parcel in) {
748                         ScanSettings settings = new ScanSettings();
749                         settings.band = in.readInt();
750                         settings.periodInMs = in.readInt();
751                         settings.reportEvents = in.readInt();
752                         settings.numBssidsPerScan = in.readInt();
753                         settings.maxScansToCache = in.readInt();
754                         settings.maxPeriodInMs = in.readInt();
755                         settings.stepCount = in.readInt();
756                         settings.isPnoScan = in.readInt() == 1;
757                         settings.type = in.readInt();
758                         settings.ignoreLocationSettings = in.readInt() == 1;
759                         settings.hideFromAppOps = in.readInt() == 1;
760                         settings.mRnrSetting = in.readInt();
761                         settings.mEnable6GhzPsc = in.readBoolean();
762                         int num_channels = in.readInt();
763                         settings.channels = new ChannelSpec[num_channels];
764                         for (int i = 0; i < num_channels; i++) {
765                             int frequency = in.readInt();
766                             ChannelSpec spec = new ChannelSpec(frequency);
767                             spec.dwellTimeMS = in.readInt();
768                             spec.passive = in.readInt() == 1;
769                             settings.channels[i] = spec;
770                         }
771                         int numNetworks = in.readInt();
772                         settings.hiddenNetworks.clear();
773                         for (int i = 0; i < numNetworks; i++) {
774                             String ssid = in.readString();
775                             settings.hiddenNetworks.add(new HiddenNetwork(ssid));
776                         }
777                         in.readTypedList(settings.mVendorIes,
778                                 ScanResult.InformationElement.CREATOR);
779                         return settings;
780                     }
781 
782                     public ScanSettings[] newArray(int size) {
783                         return new ScanSettings[size];
784                     }
785                 };
786     }
787 
788     /**
789      * All the information garnered from a single scan
790      */
791     public static class ScanData implements Parcelable {
792         /** scan identifier */
793         private int mId;
794         /** additional information about scan
795          * 0 => no special issues encountered in the scan
796          * non-zero => scan was truncated, so results may not be complete
797          */
798         private int mFlags;
799         /**
800          * Indicates the buckets that were scanned to generate these results.
801          * This is not relevant to WifiScanner API users and is used internally.
802          * {@hide}
803          */
804         private int mBucketsScanned;
805         /**
806          * Bands scanned. One of the WIFI_BAND values.
807          * Will be {@link #WIFI_BAND_UNSPECIFIED} if the list of channels do not fully cover
808          * any of the bands.
809          * {@hide}
810          */
811         private int mScannedBands;
812         /** all scan results discovered in this scan, sorted by timestamp in ascending order */
813         private final List<ScanResult> mResults;
814 
ScanData()815         ScanData() {
816             mResults = new ArrayList<>();
817         }
818 
ScanData(int id, int flags, ScanResult[] results)819         public ScanData(int id, int flags, ScanResult[] results) {
820             mId = id;
821             mFlags = flags;
822             mResults = new ArrayList<>(Arrays.asList(results));
823         }
824 
825         /** {@hide} */
ScanData(int id, int flags, int bucketsScanned, int bandsScanned, ScanResult[] results)826         public ScanData(int id, int flags, int bucketsScanned, int bandsScanned,
827                         ScanResult[] results) {
828             this(id, flags, bucketsScanned, bandsScanned, new ArrayList<>(Arrays.asList(results)));
829         }
830 
831         /** {@hide} */
ScanData(int id, int flags, int bucketsScanned, int bandsScanned, List<ScanResult> results)832         public ScanData(int id, int flags, int bucketsScanned, int bandsScanned,
833                         List<ScanResult> results) {
834             mId = id;
835             mFlags = flags;
836             mBucketsScanned = bucketsScanned;
837             mScannedBands = bandsScanned;
838             mResults = results;
839         }
840 
ScanData(ScanData s)841         public ScanData(ScanData s) {
842             mId = s.mId;
843             mFlags = s.mFlags;
844             mBucketsScanned = s.mBucketsScanned;
845             mScannedBands = s.mScannedBands;
846             mResults = new ArrayList<>();
847             for (ScanResult scanResult : s.mResults) {
848                 mResults.add(new ScanResult(scanResult));
849             }
850         }
851 
getId()852         public int getId() {
853             return mId;
854         }
855 
getFlags()856         public int getFlags() {
857             return mFlags;
858         }
859 
860         /** {@hide} */
getBucketsScanned()861         public int getBucketsScanned() {
862             return mBucketsScanned;
863         }
864 
865         /**
866          * Retrieve the bands that were fully scanned for this ScanData instance. "fully" here
867          * refers to all the channels available in the band based on the current regulatory
868          * domain.
869          *
870          * @return Bitmask of {@link #WIFI_BAND_24_GHZ}, {@link #WIFI_BAND_5_GHZ},
871          * {@link #WIFI_BAND_5_GHZ_DFS_ONLY}, {@link #WIFI_BAND_6_GHZ} & {@link #WIFI_BAND_60_GHZ}
872          * values. Each bit is set only if all the channels in the corresponding band is scanned.
873          * Will be {@link #WIFI_BAND_UNSPECIFIED} if the list of channels do not fully cover
874          * any of the bands.
875          * <p>
876          * For ex:
877          * <li> Scenario 1:  Fully scanned 2.4Ghz band, partially scanned 5Ghz band
878          *      - Returns {@link #WIFI_BAND_24_GHZ}
879          * </li>
880          * <li> Scenario 2:  Partially scanned 2.4Ghz band and 5Ghz band
881          *      - Returns {@link #WIFI_BAND_UNSPECIFIED}
882          * </li>
883          * </p>
884          */
getScannedBands()885         public @WifiBand int getScannedBands() {
886             return getScannedBandsInternal();
887         }
888 
889         /**
890          * Same as {@link #getScannedBands()}. For use in the wifi stack without version check.
891          *
892          * {@hide}
893          */
getScannedBandsInternal()894         public @WifiBand int getScannedBandsInternal() {
895             return mScannedBands;
896         }
897 
getResults()898         public ScanResult[] getResults() {
899             return mResults.toArray(new ScanResult[0]);
900         }
901 
902         /** {@hide} */
addResults(@onNull ScanResult[] newResults)903         public void addResults(@NonNull ScanResult[] newResults) {
904             for (ScanResult result : newResults) {
905                 mResults.add(new ScanResult(result));
906             }
907         }
908 
909         /** {@hide} */
addResults(@onNull ScanData s)910         public void addResults(@NonNull ScanData s) {
911             mScannedBands |= s.mScannedBands;
912             mFlags |= s.mFlags;
913             addResults(s.getResults());
914         }
915 
916         /** {@hide} */
isFullBandScanResults()917         public boolean isFullBandScanResults() {
918             return (mScannedBands & WifiScanner.WIFI_BAND_24_GHZ) != 0
919                 && (mScannedBands & WifiScanner.WIFI_BAND_5_GHZ) != 0;
920         }
921 
922         /** Implement the Parcelable interface {@hide} */
describeContents()923         public int describeContents() {
924             return 0;
925         }
926 
927         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)928         public void writeToParcel(Parcel dest, int flags) {
929             dest.writeInt(mId);
930             dest.writeInt(mFlags);
931             dest.writeInt(mBucketsScanned);
932             dest.writeInt(mScannedBands);
933             dest.writeParcelableList(mResults, 0);
934         }
935 
936         /** Implement the Parcelable interface {@hide} */
937         public static final @NonNull Creator<ScanData> CREATOR =
938                 new Creator<ScanData>() {
939                     public ScanData createFromParcel(Parcel in) {
940                         int id = in.readInt();
941                         int flags = in.readInt();
942                         int bucketsScanned = in.readInt();
943                         int bandsScanned = in.readInt();
944                         List<ScanResult> results = new ArrayList<>();
945                         in.readParcelableList(results, ScanResult.class.getClassLoader());
946                         return new ScanData(id, flags, bucketsScanned, bandsScanned, results);
947                     }
948 
949                     public ScanData[] newArray(int size) {
950                         return new ScanData[size];
951                     }
952                 };
953     }
954 
955     public static class ParcelableScanData implements Parcelable {
956 
957         public ScanData mResults[];
958 
ParcelableScanData(ScanData[] results)959         public ParcelableScanData(ScanData[] results) {
960             mResults = results;
961         }
962 
getResults()963         public ScanData[] getResults() {
964             return mResults;
965         }
966 
967         /** Implement the Parcelable interface {@hide} */
describeContents()968         public int describeContents() {
969             return 0;
970         }
971 
972         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)973         public void writeToParcel(Parcel dest, int flags) {
974             if (mResults != null) {
975                 dest.writeInt(mResults.length);
976                 for (int i = 0; i < mResults.length; i++) {
977                     ScanData result = mResults[i];
978                     result.writeToParcel(dest, flags);
979                 }
980             } else {
981                 dest.writeInt(0);
982             }
983         }
984 
985         /** Implement the Parcelable interface {@hide} */
986         public static final @NonNull Creator<ParcelableScanData> CREATOR =
987                 new Creator<ParcelableScanData>() {
988                     public ParcelableScanData createFromParcel(Parcel in) {
989                         int n = in.readInt();
990                         ScanData results[] = new ScanData[n];
991                         for (int i = 0; i < n; i++) {
992                             results[i] = ScanData.CREATOR.createFromParcel(in);
993                         }
994                         return new ParcelableScanData(results);
995                     }
996 
997                     public ParcelableScanData[] newArray(int size) {
998                         return new ParcelableScanData[size];
999                     }
1000                 };
1001     }
1002 
1003     public static class ParcelableScanResults implements Parcelable {
1004 
1005         public ScanResult mResults[];
1006 
ParcelableScanResults(ScanResult[] results)1007         public ParcelableScanResults(ScanResult[] results) {
1008             mResults = results;
1009         }
1010 
getResults()1011         public ScanResult[] getResults() {
1012             return mResults;
1013         }
1014 
1015         /** Implement the Parcelable interface {@hide} */
describeContents()1016         public int describeContents() {
1017             return 0;
1018         }
1019 
1020         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)1021         public void writeToParcel(Parcel dest, int flags) {
1022             if (mResults != null) {
1023                 dest.writeInt(mResults.length);
1024                 for (int i = 0; i < mResults.length; i++) {
1025                     ScanResult result = mResults[i];
1026                     result.writeToParcel(dest, flags);
1027                 }
1028             } else {
1029                 dest.writeInt(0);
1030             }
1031         }
1032 
1033         /** Implement the Parcelable interface {@hide} */
1034         public static final @NonNull Creator<ParcelableScanResults> CREATOR =
1035                 new Creator<ParcelableScanResults>() {
1036                     public ParcelableScanResults createFromParcel(Parcel in) {
1037                         int n = in.readInt();
1038                         ScanResult results[] = new ScanResult[n];
1039                         for (int i = 0; i < n; i++) {
1040                             results[i] = ScanResult.CREATOR.createFromParcel(in);
1041                         }
1042                         return new ParcelableScanResults(results);
1043                     }
1044 
1045                     public ParcelableScanResults[] newArray(int size) {
1046                         return new ParcelableScanResults[size];
1047                     }
1048                 };
1049     }
1050 
1051     /** {@hide} */
1052     public static final String PNO_PARAMS_PNO_SETTINGS_KEY = "PnoSettings";
1053     /** {@hide} */
1054     public static final String PNO_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
1055     /**
1056      * PNO scan configuration parameters to be sent to {@link #startPnoScan}.
1057      * Note: This structure needs to be in sync with |wifi_epno_params| struct in gscan HAL API.
1058      * {@hide}
1059      */
1060     public static class PnoSettings implements Parcelable {
1061         /**
1062          * Pno network to be added to the PNO scan filtering.
1063          * {@hide}
1064          */
1065         public static class PnoNetwork {
1066             /*
1067              * Pno flags bitmask to be set in {@link #PnoNetwork.flags}
1068              */
1069             /** Whether directed scan needs to be performed (for hidden SSIDs) */
1070             public static final byte FLAG_DIRECTED_SCAN = (1 << 0);
1071             /** Whether PNO event shall be triggered if the network is found on A band */
1072             public static final byte FLAG_A_BAND = (1 << 1);
1073             /** Whether PNO event shall be triggered if the network is found on G band */
1074             public static final byte FLAG_G_BAND = (1 << 2);
1075             /**
1076              * Whether strict matching is required
1077              * If required then the firmware must store the network's SSID and not just a hash
1078              */
1079             public static final byte FLAG_STRICT_MATCH = (1 << 3);
1080             /**
1081              * If this SSID should be considered the same network as the currently connected
1082              * one for scoring.
1083              */
1084             public static final byte FLAG_SAME_NETWORK = (1 << 4);
1085 
1086             /*
1087              * Code for matching the beacon AUTH IE - additional codes. Bitmask to be set in
1088              * {@link #PnoNetwork.authBitField}
1089              */
1090             /** Open Network */
1091             public static final byte AUTH_CODE_OPEN = (1 << 0);
1092             /** WPA_PSK or WPA2PSK */
1093             public static final byte AUTH_CODE_PSK = (1 << 1);
1094             /** any EAPOL */
1095             public static final byte AUTH_CODE_EAPOL = (1 << 2);
1096 
1097             /** SSID of the network */
1098             public String ssid;
1099             /** Bitmask of the FLAG_XXX */
1100             public byte flags = 0;
1101             /** Bitmask of the ATUH_XXX */
1102             public byte authBitField = 0;
1103             /** frequencies on which the particular network needs to be scanned for */
1104             public int[] frequencies = {};
1105 
1106             /**
1107              * default constructor for PnoNetwork
1108              */
PnoNetwork(String ssid)1109             public PnoNetwork(String ssid) {
1110                 this.ssid = ssid;
1111             }
1112 
1113             @Override
hashCode()1114             public int hashCode() {
1115                 return Objects.hash(ssid, flags, authBitField);
1116             }
1117 
1118             @Override
equals(Object obj)1119             public boolean equals(Object obj) {
1120                 if (this == obj) {
1121                     return true;
1122                 }
1123                 if (!(obj instanceof PnoNetwork)) {
1124                     return false;
1125                 }
1126                 PnoNetwork lhs = (PnoNetwork) obj;
1127                 return TextUtils.equals(this.ssid, lhs.ssid)
1128                         && this.flags == lhs.flags
1129                         && this.authBitField == lhs.authBitField;
1130             }
1131         }
1132 
1133         /** Connected vs Disconnected PNO flag {@hide} */
1134         public boolean isConnected;
1135         /** Minimum 5GHz RSSI for a BSSID to be considered */
1136         public int min5GHzRssi;
1137         /** Minimum 2.4GHz RSSI for a BSSID to be considered */
1138         public int min24GHzRssi;
1139         /** Minimum 6GHz RSSI for a BSSID to be considered */
1140         public int min6GHzRssi;
1141         /** Iterations of Pno scan */
1142         public int scanIterations;
1143         /** Multiplier of Pno scan interval */
1144         public int scanIntervalMultiplier;
1145         /** Pno Network filter list */
1146         public PnoNetwork[] networkList;
1147 
1148         /** Implement the Parcelable interface {@hide} */
describeContents()1149         public int describeContents() {
1150             return 0;
1151         }
1152 
1153         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)1154         public void writeToParcel(Parcel dest, int flags) {
1155             dest.writeInt(isConnected ? 1 : 0);
1156             dest.writeInt(min5GHzRssi);
1157             dest.writeInt(min24GHzRssi);
1158             dest.writeInt(min6GHzRssi);
1159             dest.writeInt(scanIterations);
1160             dest.writeInt(scanIntervalMultiplier);
1161             if (networkList != null) {
1162                 dest.writeInt(networkList.length);
1163                 for (int i = 0; i < networkList.length; i++) {
1164                     dest.writeString(networkList[i].ssid);
1165                     dest.writeByte(networkList[i].flags);
1166                     dest.writeByte(networkList[i].authBitField);
1167                     dest.writeIntArray(networkList[i].frequencies);
1168                 }
1169             } else {
1170                 dest.writeInt(0);
1171             }
1172         }
1173 
1174         /** Implement the Parcelable interface {@hide} */
1175         public static final @NonNull Creator<PnoSettings> CREATOR =
1176                 new Creator<PnoSettings>() {
1177                     public PnoSettings createFromParcel(Parcel in) {
1178                         PnoSettings settings = new PnoSettings();
1179                         settings.isConnected = in.readInt() == 1;
1180                         settings.min5GHzRssi = in.readInt();
1181                         settings.min24GHzRssi = in.readInt();
1182                         settings.min6GHzRssi = in.readInt();
1183                         settings.scanIterations = in.readInt();
1184                         settings.scanIntervalMultiplier = in.readInt();
1185                         int numNetworks = in.readInt();
1186                         settings.networkList = new PnoNetwork[numNetworks];
1187                         for (int i = 0; i < numNetworks; i++) {
1188                             String ssid = in.readString();
1189                             PnoNetwork network = new PnoNetwork(ssid);
1190                             network.flags = in.readByte();
1191                             network.authBitField = in.readByte();
1192                             network.frequencies = in.createIntArray();
1193                             settings.networkList[i] = network;
1194                         }
1195                         return settings;
1196                     }
1197 
1198                     public PnoSettings[] newArray(int size) {
1199                         return new PnoSettings[size];
1200                     }
1201                 };
1202 
1203     }
1204 
1205     /**
1206      * interface to get scan events on; specify this on {@link #startBackgroundScan} or
1207      * {@link #startScan}
1208      */
1209     public interface ScanListener extends ActionListener {
1210         /**
1211          * Framework co-ordinates scans across multiple apps; so it may not give exactly the
1212          * same period requested. If period of a scan is changed; it is reported by this event.
1213          * @deprecated Background scan support has always been hardware vendor dependent. This
1214          * support may not be present on newer devices. Use {@link #startScan(ScanSettings,
1215          * ScanListener)} instead for single scans.
1216          */
1217         @Deprecated
onPeriodChanged(int periodInMs)1218         public void onPeriodChanged(int periodInMs);
1219         /**
1220          * reports results retrieved from background scan and single shot scans
1221          */
onResults(ScanData[] results)1222         public void onResults(ScanData[] results);
1223         /**
1224          * reports full scan result for each access point found in scan
1225          */
onFullResult(ScanResult fullScanResult)1226         public void onFullResult(ScanResult fullScanResult);
1227     }
1228 
1229     /**
1230      * interface to get PNO scan events on; specify this on {@link #startDisconnectedPnoScan} and
1231      * {@link #startConnectedPnoScan}.
1232      * {@hide}
1233      */
1234     public interface PnoScanListener extends ScanListener {
1235         /**
1236          * Invoked when one of the PNO networks are found in scan results.
1237          */
onPnoNetworkFound(ScanResult[] results)1238         void onPnoNetworkFound(ScanResult[] results);
1239     }
1240 
1241     /**
1242      * Enable/Disable wifi scanning.
1243      *
1244      * @param enable set to true to enable scanning, set to false to disable all types of scanning.
1245      *
1246      * @see WifiManager#ACTION_WIFI_SCAN_AVAILABILITY_CHANGED
1247      * {@hide}
1248      */
1249     @SystemApi
1250     @RequiresPermission(Manifest.permission.NETWORK_STACK)
setScanningEnabled(boolean enable)1251     public void setScanningEnabled(boolean enable) {
1252         try {
1253             mService.setScanningEnabled(enable, Process.myTid(), mContext.getOpPackageName());
1254         } catch (RemoteException e) {
1255             throw e.rethrowFromSystemServer();
1256         }
1257     }
1258 
1259     /**
1260      * Register a listener that will receive results from all single scans.
1261      * Either the {@link ScanListener#onSuccess()} or  {@link ScanListener#onFailure(int, String)}
1262      * method will be called once when the listener is registered.
1263      * Afterwards (assuming onSuccess was called), all subsequent single scan results will be
1264      * delivered to the listener. It is possible that onFullResult will not be called for all
1265      * results of the first scan if the listener was registered during the scan.
1266      * <p>
1267      * On {@link android.os.Build.VERSION_CODES#TIRAMISU} or above this API can be called by
1268      * an app with either {@link android.Manifest.permission#LOCATION_HARDWARE} or
1269      * {@link android.Manifest.permission#NETWORK_STACK}. On platform versions prior to
1270      * {@link android.os.Build.VERSION_CODES#TIRAMISU}, the caller must have
1271      * {@link android.Manifest.permission#NETWORK_STACK}.
1272      *
1273      * @param executor the Executor on which to run the callback.
1274      * @param listener specifies the object to report events to. This object is also treated as a
1275      *                 key for this request, and must also be specified to cancel the request.
1276      *                 Multiple requests should also not share this object.
1277      * @throws SecurityException if the caller does not have permission.
1278      */
1279     @RequiresPermission(anyOf = {
1280             Manifest.permission.LOCATION_HARDWARE,
1281             Manifest.permission.NETWORK_STACK})
registerScanListener(@onNull @allbackExecutor Executor executor, @NonNull ScanListener listener)1282     public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
1283             @NonNull ScanListener listener) {
1284         Objects.requireNonNull(executor, "executor cannot be null");
1285         Objects.requireNonNull(listener, "listener cannot be null");
1286         ServiceListener serviceListener = new ServiceListener(listener, executor);
1287         if (!addListener(listener, serviceListener)) {
1288             Binder.clearCallingIdentity();
1289             executor.execute(() ->
1290                     // TODO: fix the typo in WifiScanner system API.
1291                     listener.onFailure(REASON_DUPLICATE_REQEUST, // NOTYPO
1292                             "Outstanding request with same key not stopped yet"));
1293             return;
1294         }
1295         try {
1296             mService.registerScanListener(serviceListener,
1297                     mContext.getOpPackageName(),
1298                     mContext.getAttributionTag());
1299         } catch (RemoteException e) {
1300             Log.e(TAG, "Failed to register listener " + listener);
1301             removeListener(listener);
1302             throw e.rethrowFromSystemServer();
1303         }
1304     }
1305 
1306     /**
1307      * Overload of {@link #registerScanListener(Executor, ScanListener)} that executes the callback
1308      * synchronously.
1309      * @hide
1310      */
1311     @RequiresPermission(Manifest.permission.NETWORK_STACK)
registerScanListener(@onNull ScanListener listener)1312     public void registerScanListener(@NonNull ScanListener listener) {
1313         registerScanListener(new SynchronousExecutor(), listener);
1314     }
1315 
1316     /**
1317      * Deregister a listener for ongoing single scans
1318      * @param listener specifies which scan to cancel; must be same object as passed in {@link
1319      *  #registerScanListener}
1320      */
unregisterScanListener(@onNull ScanListener listener)1321     public void unregisterScanListener(@NonNull ScanListener listener) {
1322         Objects.requireNonNull(listener, "listener cannot be null");
1323         ServiceListener serviceListener = getServiceListener(listener);
1324         if (serviceListener == null) {
1325             Log.e(TAG, "listener does not exist");
1326             return;
1327         }
1328         try {
1329             mService.unregisterScanListener(serviceListener, mContext.getOpPackageName(),
1330                     mContext.getAttributionTag());
1331         } catch (RemoteException e) {
1332             Log.e(TAG, "failed to unregister listener");
1333             throw e.rethrowFromSystemServer();
1334         } finally {
1335             removeListener(listener);
1336         }
1337     }
1338 
1339     /**
1340      * Check whether the Wi-Fi subsystem has started a scan and is waiting for scan results.
1341      * @return true if a scan initiated via
1342      *         {@link WifiScanner#startScan(ScanSettings, ScanListener)} or
1343      *         {@link WifiManager#startScan()} is in progress.
1344      *         false if there is currently no scanning initiated by {@link WifiScanner} or
1345      *         {@link WifiManager}, but it's still possible the wifi radio is scanning for
1346      *         another reason.
1347      * @hide
1348      */
1349     @SystemApi
1350     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
isScanning()1351     public boolean isScanning() {
1352         try {
1353             return mService.isScanning();
1354         } catch (RemoteException e) {
1355             throw e.rethrowFromSystemServer();
1356         }
1357     }
1358 
1359     /** start wifi scan in background
1360      * @param settings specifies various parameters for the scan; for more information look at
1361      * {@link ScanSettings}
1362      * @param listener specifies the object to report events to. This object is also treated as a
1363      *                 key for this scan, and must also be specified to cancel the scan. Multiple
1364      *                 scans should also not share this object.
1365      */
1366     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
startBackgroundScan(ScanSettings settings, ScanListener listener)1367     public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
1368         startBackgroundScan(settings, listener, null);
1369     }
1370 
1371     /** start wifi scan in background
1372      * @param settings specifies various parameters for the scan; for more information look at
1373      * {@link ScanSettings}
1374      * @param workSource WorkSource to blame for power usage
1375      * @param listener specifies the object to report events to. This object is also treated as a
1376      *                 key for this scan, and must also be specified to cancel the scan. Multiple
1377      *                 scans should also not share this object.
1378      * @deprecated Background scan support has always been hardware vendor dependent. This support
1379      * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}
1380      * instead for single scans.
1381      */
1382     @Deprecated
1383     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
startBackgroundScan(ScanSettings settings, ScanListener listener, WorkSource workSource)1384     public void startBackgroundScan(ScanSettings settings, ScanListener listener,
1385             WorkSource workSource) {
1386         Objects.requireNonNull(listener, "listener cannot be null");
1387         if (getServiceListener(listener) != null) return;
1388         ServiceListener serviceListener = new ServiceListener(listener, new SynchronousExecutor());
1389         if (!addListener(listener, serviceListener)) {
1390             Log.e(TAG, "listener already exist!");
1391             return;
1392         }
1393         try {
1394             mService.startBackgroundScan(serviceListener, settings, workSource,
1395                     mContext.getOpPackageName(), mContext.getAttributionTag());
1396         } catch (RemoteException e) {
1397             throw e.rethrowFromSystemServer();
1398         }
1399     }
1400 
1401     /**
1402      * stop an ongoing wifi scan
1403      * @param listener specifies which scan to cancel; must be same object as passed in {@link
1404      *  #startBackgroundScan}
1405      * @deprecated Background scan support has always been hardware vendor dependent. This support
1406      * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}
1407      * instead for single scans.
1408      */
1409     @Deprecated
1410     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
stopBackgroundScan(ScanListener listener)1411     public void stopBackgroundScan(ScanListener listener) {
1412         Objects.requireNonNull(listener, "listener cannot be null");
1413         ServiceListener serviceListener = getServiceListener(listener);
1414         if (serviceListener == null) {
1415             Log.e(TAG, "listener does not exist");
1416             return;
1417         }
1418         try {
1419             mService.stopBackgroundScan(serviceListener, mContext.getOpPackageName(),
1420                     mContext.getAttributionTag());
1421         } catch (RemoteException e) {
1422             throw e.rethrowFromSystemServer();
1423         } finally {
1424             removeListener(listener);
1425         }
1426     }
1427 
1428     /**
1429      * reports currently available scan results on appropriate listeners
1430      * @return true if all scan results were reported correctly
1431      * @deprecated Background scan support has always been hardware vendor dependent. This support
1432      * may not be present on newer devices. Use {@link #startScan(ScanSettings, ScanListener)}
1433      * instead for single scans.
1434      */
1435     @Deprecated
1436     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
getScanResults()1437     public boolean getScanResults() {
1438         try {
1439             return mService.getScanResults(mContext.getOpPackageName(),
1440                     mContext.getAttributionTag());
1441         } catch (RemoteException e) {
1442             throw e.rethrowFromSystemServer();
1443         }
1444     }
1445 
1446     /**
1447      * starts a single scan and reports results asynchronously
1448      * @param settings specifies various parameters for the scan; for more information look at
1449      * {@link ScanSettings}
1450      * @param listener specifies the object to report events to. This object is also treated as a
1451      *                 key for this scan, and must also be specified to cancel the scan. Multiple
1452      *                 scans should also not share this object.
1453      */
1454     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
startScan(ScanSettings settings, ScanListener listener)1455     public void startScan(ScanSettings settings, ScanListener listener) {
1456         startScan(settings, listener, null);
1457     }
1458 
1459     /**
1460      * starts a single scan and reports results asynchronously
1461      * @param settings specifies various parameters for the scan; for more information look at
1462      * {@link ScanSettings}
1463      * @param listener specifies the object to report events to. This object is also treated as a
1464      *                 key for this scan, and must also be specified to cancel the scan. Multiple
1465      *                 scans should also not share this object.
1466      * @param workSource WorkSource to blame for power usage
1467      */
1468     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
startScan(ScanSettings settings, ScanListener listener, WorkSource workSource)1469     public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
1470         startScan(settings, new SynchronousExecutor(), listener, workSource);
1471     }
1472 
1473     /**
1474      * starts a single scan and reports results asynchronously
1475      * @param settings specifies various parameters for the scan; for more information look at
1476      * {@link ScanSettings}
1477      * @param executor the Executor on which to run the callback.
1478      * @param listener specifies the object to report events to. This object is also treated as a
1479      *                 key for this scan, and must also be specified to cancel the scan. Multiple
1480      *                 scans should also not share this object.
1481      * @param workSource WorkSource to blame for power usage
1482      * @hide
1483      */
1484     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor, ScanListener listener, WorkSource workSource)1485     public void startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor,
1486             ScanListener listener, WorkSource workSource) {
1487         Objects.requireNonNull(listener, "listener cannot be null");
1488         if (getServiceListener(listener) != null) return;
1489         ServiceListener serviceListener = new ServiceListener(listener, executor);
1490         if (!addListener(listener, serviceListener)) {
1491             Log.e(TAG, "listener already exist!");
1492             return;
1493         }
1494         try {
1495             mService.startScan(serviceListener, settings, workSource,
1496                     mContext.getOpPackageName(),
1497                     mContext.getAttributionTag());
1498         } catch (RemoteException e) {
1499             throw e.rethrowFromSystemServer();
1500         }
1501     }
1502 
1503     /**
1504      * stops an ongoing single shot scan; only useful after {@link #startScan} if onResults()
1505      * hasn't been called on the listener, ignored otherwise
1506      * @param listener
1507      */
1508     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
stopScan(ScanListener listener)1509     public void stopScan(ScanListener listener) {
1510         Objects.requireNonNull(listener, "listener cannot be null");
1511         ServiceListener serviceListener = getServiceListener(listener);
1512         if (serviceListener == null) {
1513             Log.e(TAG, "listener does not exist");
1514             return;
1515         }
1516         try {
1517             mService.stopScan(serviceListener, mContext.getOpPackageName(),
1518                     mContext.getAttributionTag());
1519         } catch (RemoteException e) {
1520             throw e.rethrowFromSystemServer();
1521         } finally {
1522             removeListener(listener);
1523         }
1524     }
1525 
1526     /**
1527      * Retrieve the most recent scan results from a single scan request.
1528      */
1529     @NonNull
1530     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
getSingleScanResults()1531     public List<ScanResult> getSingleScanResults() {
1532         try {
1533             return mService.getSingleScanResults(mContext.getPackageName(),
1534                     mContext.getAttributionTag());
1535         } catch (RemoteException e) {
1536             throw e.rethrowFromSystemServer();
1537         }
1538     }
1539 
startPnoScan(PnoScanListener listener, Executor executor, ScanSettings scanSettings, PnoSettings pnoSettings)1540     private void startPnoScan(PnoScanListener listener, Executor executor,
1541             ScanSettings scanSettings, PnoSettings pnoSettings) {
1542         // Set the PNO scan flag.
1543         scanSettings.isPnoScan = true;
1544         if (getServiceListener(listener) != null) return;
1545         ServiceListener serviceListener = new ServiceListener(listener, executor);
1546         if (!addListener(listener, serviceListener)) {
1547             Log.w(TAG, "listener already exist!");
1548         }
1549         try {
1550             mService.startPnoScan(serviceListener, scanSettings, pnoSettings,
1551                     mContext.getOpPackageName(),
1552                     mContext.getAttributionTag());
1553         } catch (RemoteException e) {
1554             throw e.rethrowFromSystemServer();
1555         }
1556     }
1557 
1558     /**
1559      * Start wifi connected PNO scan
1560      * @param scanSettings specifies various parameters for the scan; for more information look at
1561      * {@link ScanSettings}
1562      * @param pnoSettings specifies various parameters for PNO; for more information look at
1563      * {@link PnoSettings}
1564      * @param executor the Executor on which to run the callback.
1565      * @param listener specifies the object to report events to. This object is also treated as a
1566      *                 key for this scan, and must also be specified to cancel the scan. Multiple
1567      *                 scans should also not share this object.
1568      * {@hide}
1569      */
startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, @NonNull @CallbackExecutor Executor executor, PnoScanListener listener)1570     public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
1571             @NonNull @CallbackExecutor Executor executor, PnoScanListener listener) {
1572         Objects.requireNonNull(listener, "listener cannot be null");
1573         Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
1574         pnoSettings.isConnected = true;
1575         startPnoScan(listener, executor, scanSettings, pnoSettings);
1576     }
1577     /**
1578      * Start wifi disconnected PNO scan
1579      * @param scanSettings specifies various parameters for the scan; for more information look at
1580      * {@link ScanSettings}
1581      * @param pnoSettings specifies various parameters for PNO; for more information look at
1582      * {@link PnoSettings}
1583      * @param listener specifies the object to report events to. This object is also treated as a
1584      *                 key for this scan, and must also be specified to cancel the scan. Multiple
1585      *                 scans should also not share this object.
1586      * {@hide}
1587      */
1588     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, @NonNull @CallbackExecutor Executor executor, PnoScanListener listener)1589     public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
1590             @NonNull @CallbackExecutor Executor executor, PnoScanListener listener) {
1591         Objects.requireNonNull(listener, "listener cannot be null");
1592         Objects.requireNonNull(pnoSettings, "pnoSettings cannot be null");
1593         pnoSettings.isConnected = false;
1594         startPnoScan(listener, executor, scanSettings, pnoSettings);
1595     }
1596     /**
1597      * Stop an ongoing wifi PNO scan
1598      * @param listener specifies which scan to cancel; must be same object as passed in {@link
1599      *  #startPnoScan}
1600      * {@hide}
1601      */
1602     @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
stopPnoScan(ScanListener listener)1603     public void stopPnoScan(ScanListener listener) {
1604         Objects.requireNonNull(listener, "listener cannot be null");
1605         ServiceListener serviceListener = getServiceListener(listener);
1606         if (serviceListener == null) {
1607             Log.e(TAG, "listener does not exist");
1608             return;
1609         }
1610         try {
1611             mService.stopPnoScan(serviceListener, mContext.getOpPackageName(),
1612                     mContext.getAttributionTag());
1613         } catch (RemoteException e) {
1614             throw e.rethrowFromSystemServer();
1615         } finally {
1616             removeListener(listener);
1617         }
1618     }
1619 
1620     /**
1621      * Enable verbose logging. For internal use by wifi framework only.
1622      * @param enabled whether verbose logging is enabled
1623      * @hide
1624      */
1625     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
enableVerboseLogging(boolean enabled)1626     public void enableVerboseLogging(boolean enabled) {
1627         try {
1628             mService.enableVerboseLogging(enabled);
1629         } catch (RemoteException e) {
1630             throw e.rethrowFromSystemServer();
1631         }
1632     }
1633 
1634     /** specifies information about an access point of interest */
1635     @Deprecated
1636     public static class BssidInfo {
1637         /** bssid of the access point; in XX:XX:XX:XX:XX:XX format */
1638         public String bssid;
1639         /** low signal strength threshold; more information at {@link ScanResult#level} */
1640         public int low;                                            /* minimum RSSI */
1641         /** high signal threshold; more information at {@link ScanResult#level} */
1642         public int high;                                           /* maximum RSSI */
1643         /** channel frequency (in KHz) where you may find this BSSID */
1644         public int frequencyHint;
1645     }
1646 
1647     /** @hide */
1648     @SystemApi
1649     @Deprecated
1650     public static class WifiChangeSettings implements Parcelable {
1651         public int rssiSampleSize;                          /* sample size for RSSI averaging */
1652         public int lostApSampleSize;                        /* samples to confirm AP's loss */
1653         public int unchangedSampleSize;                     /* samples to confirm no change */
1654         public int minApsBreachingThreshold;                /* change threshold to trigger event */
1655         public int periodInMs;                              /* scan period in millisecond */
1656         public BssidInfo[] bssidInfos;
1657 
1658         /** Implement the Parcelable interface {@hide} */
describeContents()1659         public int describeContents() {
1660             return 0;
1661         }
1662 
1663         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)1664         public void writeToParcel(Parcel dest, int flags) {
1665         }
1666 
1667         /** Implement the Parcelable interface {@hide} */
1668         public static final @NonNull Creator<WifiChangeSettings> CREATOR =
1669                 new Creator<WifiChangeSettings>() {
1670                     public WifiChangeSettings createFromParcel(Parcel in) {
1671                         return new WifiChangeSettings();
1672                     }
1673 
1674                     public WifiChangeSettings[] newArray(int size) {
1675                         return new WifiChangeSettings[size];
1676                     }
1677                 };
1678 
1679     }
1680 
1681     /** configure WifiChange detection
1682      * @param rssiSampleSize number of samples used for RSSI averaging
1683      * @param lostApSampleSize number of samples to confirm an access point's loss
1684      * @param unchangedSampleSize number of samples to confirm there are no changes
1685      * @param minApsBreachingThreshold minimum number of access points that need to be
1686      *                                 out of range to detect WifiChange
1687      * @param periodInMs indicates period of scan to find changes
1688      * @param bssidInfos access points to watch
1689      */
1690     @Deprecated
1691     @SuppressLint("RequiresPermission")
configureWifiChange( int rssiSampleSize, int lostApSampleSize, int unchangedSampleSize, int minApsBreachingThreshold, int periodInMs, BssidInfo[] bssidInfos )1692     public void configureWifiChange(
1693             int rssiSampleSize,                             /* sample size for RSSI averaging */
1694             int lostApSampleSize,                           /* samples to confirm AP's loss */
1695             int unchangedSampleSize,                        /* samples to confirm no change */
1696             int minApsBreachingThreshold,                   /* change threshold to trigger event */
1697             int periodInMs,                                 /* period of scan */
1698             BssidInfo[] bssidInfos                          /* signal thresholds to cross */
1699             )
1700     {
1701         throw new UnsupportedOperationException();
1702     }
1703 
1704     /**
1705      * interface to get wifi change events on; use this on {@link #startTrackingWifiChange}
1706      */
1707     @Deprecated
1708     public interface WifiChangeListener extends ActionListener {
1709         /** indicates that changes were detected in wifi environment
1710          * @param results indicate the access points that exhibited change
1711          */
onChanging(ScanResult[] results)1712         public void onChanging(ScanResult[] results);           /* changes are found */
1713         /** indicates that no wifi changes are being detected for a while
1714          * @param results indicate the access points that are bing monitored for change
1715          */
onQuiescence(ScanResult[] results)1716         public void onQuiescence(ScanResult[] results);         /* changes settled down */
1717     }
1718 
1719     /**
1720      * track changes in wifi environment
1721      * @param listener object to report events on; this object must be unique and must also be
1722      *                 provided on {@link #stopTrackingWifiChange}
1723      */
1724     @Deprecated
1725     @SuppressLint("RequiresPermission")
startTrackingWifiChange(WifiChangeListener listener)1726     public void startTrackingWifiChange(WifiChangeListener listener) {
1727         throw new UnsupportedOperationException();
1728     }
1729 
1730     /**
1731      * stop tracking changes in wifi environment
1732      * @param listener object that was provided to report events on {@link
1733      * #stopTrackingWifiChange}
1734      */
1735     @Deprecated
1736     @SuppressLint("RequiresPermission")
stopTrackingWifiChange(WifiChangeListener listener)1737     public void stopTrackingWifiChange(WifiChangeListener listener) {
1738         throw new UnsupportedOperationException();
1739     }
1740 
1741     /** @hide */
1742     @SystemApi
1743     @Deprecated
1744     @SuppressLint("RequiresPermission")
configureWifiChange(WifiChangeSettings settings)1745     public void configureWifiChange(WifiChangeSettings settings) {
1746         throw new UnsupportedOperationException();
1747     }
1748 
1749     /** interface to receive hotlist events on; use this on {@link #setHotlist} */
1750     @Deprecated
1751     public static interface BssidListener extends ActionListener {
1752         /** indicates that access points were found by on going scans
1753          * @param results list of scan results, one for each access point visible currently
1754          */
onFound(ScanResult[] results)1755         public void onFound(ScanResult[] results);
1756         /** indicates that access points were missed by on going scans
1757          * @param results list of scan results, for each access point that is not visible anymore
1758          */
onLost(ScanResult[] results)1759         public void onLost(ScanResult[] results);
1760     }
1761 
1762     /** @hide */
1763     @SystemApi
1764     @Deprecated
1765     public static class HotlistSettings implements Parcelable {
1766         public BssidInfo[] bssidInfos;
1767         public int apLostThreshold;
1768 
1769         /** Implement the Parcelable interface {@hide} */
describeContents()1770         public int describeContents() {
1771             return 0;
1772         }
1773 
1774         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)1775         public void writeToParcel(Parcel dest, int flags) {
1776         }
1777 
1778         /** Implement the Parcelable interface {@hide} */
1779         public static final @NonNull Creator<HotlistSettings> CREATOR =
1780                 new Creator<HotlistSettings>() {
1781                     public HotlistSettings createFromParcel(Parcel in) {
1782                         HotlistSettings settings = new HotlistSettings();
1783                         return settings;
1784                     }
1785 
1786                     public HotlistSettings[] newArray(int size) {
1787                         return new HotlistSettings[size];
1788                     }
1789                 };
1790     }
1791 
1792     /**
1793      * set interesting access points to find
1794      * @param bssidInfos access points of interest
1795      * @param apLostThreshold number of scans needed to indicate that AP is lost
1796      * @param listener object provided to report events on; this object must be unique and must
1797      *                 also be provided on {@link #stopTrackingBssids}
1798      */
1799     @Deprecated
1800     @SuppressLint("RequiresPermission")
startTrackingBssids(BssidInfo[] bssidInfos, int apLostThreshold, BssidListener listener)1801     public void startTrackingBssids(BssidInfo[] bssidInfos,
1802                                     int apLostThreshold, BssidListener listener) {
1803         throw new UnsupportedOperationException();
1804     }
1805 
1806     /**
1807      * remove tracking of interesting access points
1808      * @param listener same object provided in {@link #startTrackingBssids}
1809      */
1810     @Deprecated
1811     @SuppressLint("RequiresPermission")
stopTrackingBssids(BssidListener listener)1812     public void stopTrackingBssids(BssidListener listener) {
1813         throw new UnsupportedOperationException();
1814     }
1815 
1816 
1817     /* private members and methods */
1818 
1819     private static final String TAG = "WifiScanner";
1820     private static final boolean DBG = false;
1821 
1822     /* commands for Wifi Service */
1823     private static final int BASE = Protocol.BASE_WIFI_SCANNER;
1824 
1825     /** @hide */
1826     public static final int CMD_START_BACKGROUND_SCAN       = BASE + 2;
1827     /** @hide */
1828     public static final int CMD_STOP_BACKGROUND_SCAN        = BASE + 3;
1829     /** @hide */
1830     public static final int CMD_GET_SCAN_RESULTS            = BASE + 4;
1831     /** @hide */
1832     public static final int CMD_SCAN_RESULT                 = BASE + 5;
1833     /** @hide */
1834     public static final int CMD_OP_SUCCEEDED                = BASE + 17;
1835     /** @hide */
1836     public static final int CMD_OP_FAILED                   = BASE + 18;
1837     /** @hide */
1838     public static final int CMD_FULL_SCAN_RESULT            = BASE + 20;
1839     /** @hide */
1840     public static final int CMD_START_SINGLE_SCAN           = BASE + 21;
1841     /** @hide */
1842     public static final int CMD_STOP_SINGLE_SCAN            = BASE + 22;
1843     /** @hide */
1844     public static final int CMD_SINGLE_SCAN_COMPLETED       = BASE + 23;
1845     /** @hide */
1846     public static final int CMD_START_PNO_SCAN              = BASE + 24;
1847     /** @hide */
1848     public static final int CMD_STOP_PNO_SCAN               = BASE + 25;
1849     /** @hide */
1850     public static final int CMD_PNO_NETWORK_FOUND           = BASE + 26;
1851     /** @hide */
1852     public static final int CMD_REGISTER_SCAN_LISTENER      = BASE + 27;
1853     /** @hide */
1854     public static final int CMD_DEREGISTER_SCAN_LISTENER    = BASE + 28;
1855     /** @hide */
1856     public static final int CMD_GET_SINGLE_SCAN_RESULTS     = BASE + 29;
1857     /** @hide */
1858     public static final int CMD_ENABLE                      = BASE + 30;
1859     /** @hide */
1860     public static final int CMD_DISABLE                     = BASE + 31;
1861 
1862     private Context mContext;
1863     private IWifiScanner mService;
1864 
1865     private final Object mListenerMapLock = new Object();
1866     private final Map<ActionListener, ServiceListener> mListenerMap = new HashMap<>();
1867 
1868     /**
1869      * Create a new WifiScanner instance.
1870      * Applications will almost always want to use
1871      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
1872      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
1873      *
1874      * @param context the application context
1875      * @param service the Binder interface for {@link Context#WIFI_SCANNING_SERVICE}
1876      * @param looper the Looper used to deliver callbacks
1877      *
1878      * @hide
1879      */
WifiScanner(@onNull Context context, @NonNull IWifiScanner service, @NonNull Looper looper)1880     public WifiScanner(@NonNull Context context, @NonNull IWifiScanner service,
1881             @NonNull Looper looper) {
1882         mContext = context;
1883         mService = service;
1884     }
1885 
1886     // Add a listener into listener map. If the listener already exists, return INVALID_KEY and
1887     // send an error message to internal handler; Otherwise add the listener to the listener map and
1888     // return the key of the listener.
addListener(ActionListener listener, ServiceListener serviceListener)1889     private boolean addListener(ActionListener listener, ServiceListener serviceListener) {
1890         synchronized (mListenerMapLock) {
1891             boolean keyExists = mListenerMap.containsKey(listener);
1892             // Note we need to put the listener into listener map even if it's a duplicate as the
1893             // internal handler will need the key to find the listener. In case of duplicates,
1894             // removing duplicate key logic will be handled in internal handler.
1895             if (keyExists) {
1896                 if (DBG) Log.d(TAG, "listener key already exists");
1897                 return false;
1898             }
1899             mListenerMap.put(listener, serviceListener);
1900             return true;
1901         }
1902     }
1903 
getServiceListener(ActionListener listener)1904     private ServiceListener getServiceListener(ActionListener listener) {
1905         if (listener == null) return null;
1906         synchronized (mListenerMapLock) {
1907             return mListenerMap.get(listener);
1908         }
1909     }
1910 
removeListener(ActionListener listener)1911     private void removeListener(ActionListener listener) {
1912         if (listener == null) return;
1913         synchronized (mListenerMapLock) {
1914             mListenerMap.remove(listener);
1915         }
1916     }
1917 
1918 }
1919