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