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