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