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 android.annotation.NonNull; 20 import android.annotation.SystemApi; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.nio.ByteBuffer; 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.Objects; 31 32 /** 33 * Describes information about a detected access point. In addition 34 * to the attributes described here, the supplicant keeps track of 35 * {@code quality}, {@code noise}, and {@code maxbitrate} attributes, 36 * but does not currently report them to external clients. 37 */ 38 public class ScanResult implements Parcelable { 39 /** 40 * The network name. 41 */ 42 public String SSID; 43 44 /** 45 * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide 46 */ 47 @UnsupportedAppUsage 48 public WifiSsid wifiSsid; 49 50 /** 51 * The address of the access point. 52 */ 53 public String BSSID; 54 55 /** 56 * The HESSID from the beacon. 57 * @hide 58 */ 59 @UnsupportedAppUsage 60 public long hessid; 61 62 /** 63 * The ANQP Domain ID from the Hotspot 2.0 Indication element, if present. 64 * @hide 65 */ 66 @UnsupportedAppUsage 67 public int anqpDomainId; 68 69 /* 70 * This field is equivalent to the |flags|, rather than the |capabilities| field 71 * of the per-BSS scan results returned by WPA supplicant. See the definition of 72 * |struct wpa_bss| in wpa_supplicant/bss.h for more details. 73 */ 74 /** 75 * Describes the authentication, key management, and encryption schemes 76 * supported by the access point. 77 */ 78 public String capabilities; 79 80 /** 81 * @hide 82 * No security protocol. 83 */ 84 public static final int PROTOCOL_NONE = 0; 85 /** 86 * @hide 87 * Security protocol type: WPA version 1. 88 */ 89 public static final int PROTOCOL_WPA = 1; 90 /** 91 * @hide 92 * Security protocol type: RSN, for WPA version 2, and version 3. 93 */ 94 public static final int PROTOCOL_RSN = 2; 95 /** 96 * @hide 97 * Security protocol type: 98 * OSU Server-only authenticated layer 2 Encryption Network. 99 * Used for Hotspot 2.0. 100 */ 101 public static final int PROTOCOL_OSEN = 3; 102 103 /** 104 * @hide 105 * No security key management scheme. 106 */ 107 public static final int KEY_MGMT_NONE = 0; 108 /** 109 * @hide 110 * Security key management scheme: PSK. 111 */ 112 public static final int KEY_MGMT_PSK = 1; 113 /** 114 * @hide 115 * Security key management scheme: EAP. 116 */ 117 public static final int KEY_MGMT_EAP = 2; 118 /** 119 * @hide 120 * Security key management scheme: FT_PSK. 121 */ 122 public static final int KEY_MGMT_FT_PSK = 3; 123 /** 124 * @hide 125 * Security key management scheme: FT_EAP. 126 */ 127 public static final int KEY_MGMT_FT_EAP = 4; 128 /** 129 * @hide 130 * Security key management scheme: PSK_SHA256 131 */ 132 public static final int KEY_MGMT_PSK_SHA256 = 5; 133 /** 134 * @hide 135 * Security key management scheme: EAP_SHA256. 136 */ 137 public static final int KEY_MGMT_EAP_SHA256 = 6; 138 /** 139 * @hide 140 * Security key management scheme: OSEN. 141 * Used for Hotspot 2.0. 142 */ 143 public static final int KEY_MGMT_OSEN = 7; 144 /** 145 * @hide 146 * Security key management scheme: SAE. 147 */ 148 public static final int KEY_MGMT_SAE = 8; 149 /** 150 * @hide 151 * Security key management scheme: OWE. 152 */ 153 public static final int KEY_MGMT_OWE = 9; 154 /** 155 * @hide 156 * Security key management scheme: SUITE_B_192. 157 */ 158 public static final int KEY_MGMT_EAP_SUITE_B_192 = 10; 159 /** 160 * @hide 161 * Security key management scheme: FT_SAE. 162 */ 163 public static final int KEY_MGMT_FT_SAE = 11; 164 /** 165 * @hide 166 * Security key management scheme: OWE in transition mode. 167 */ 168 public static final int KEY_MGMT_OWE_TRANSITION = 12; 169 /** 170 * @hide 171 * No cipher suite. 172 */ 173 public static final int CIPHER_NONE = 0; 174 /** 175 * @hide 176 * No group addressed, only used for group data cipher. 177 */ 178 public static final int CIPHER_NO_GROUP_ADDRESSED = 1; 179 /** 180 * @hide 181 * Cipher suite: TKIP 182 */ 183 public static final int CIPHER_TKIP = 2; 184 /** 185 * @hide 186 * Cipher suite: CCMP 187 */ 188 public static final int CIPHER_CCMP = 3; 189 /** 190 * @hide 191 * Cipher suite: GCMP 192 */ 193 public static final int CIPHER_GCMP_256 = 4; 194 195 /** 196 * The detected signal level in dBm, also known as the RSSI. 197 * 198 * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into 199 * an absolute signal level which can be displayed to a user. 200 */ 201 public int level; 202 /** 203 * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating 204 * with the access point. 205 */ 206 public int frequency; 207 208 /** 209 * AP Channel bandwidth is 20 MHZ 210 */ 211 public static final int CHANNEL_WIDTH_20MHZ = 0; 212 /** 213 * AP Channel bandwidth is 40 MHZ 214 */ 215 public static final int CHANNEL_WIDTH_40MHZ = 1; 216 /** 217 * AP Channel bandwidth is 80 MHZ 218 */ 219 public static final int CHANNEL_WIDTH_80MHZ = 2; 220 /** 221 * AP Channel bandwidth is 160 MHZ 222 */ 223 public static final int CHANNEL_WIDTH_160MHZ = 3; 224 /** 225 * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ 226 */ 227 public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; 228 229 /** 230 * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ}, 231 * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ} 232 * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}. 233 */ 234 public int channelWidth; 235 236 /** 237 * Not used if the AP bandwidth is 20 MHz 238 * If the AP use 40, 80 or 160 MHz, this is the center frequency (in MHz) 239 * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz) 240 */ 241 public int centerFreq0; 242 243 /** 244 * Only used if the AP bandwidth is 80 + 80 MHz 245 * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz) 246 */ 247 public int centerFreq1; 248 249 /** 250 * @deprecated use is80211mcResponder() instead 251 * @hide 252 */ 253 @UnsupportedAppUsage 254 public boolean is80211McRTTResponder; 255 256 /** 257 * timestamp in microseconds (since boot) when 258 * this result was last seen. 259 */ 260 public long timestamp; 261 262 /** 263 * Timestamp representing date when this result was last seen, in milliseconds from 1970 264 * {@hide} 265 */ 266 @UnsupportedAppUsage 267 public long seen; 268 269 /** 270 * On devices with multiple hardware radio chains, this class provides metadata about 271 * each radio chain that was used to receive this scan result (probe response or beacon). 272 * {@hide} 273 */ 274 public static class RadioChainInfo { 275 /** Vendor defined id for a radio chain. */ 276 public int id; 277 /** Detected signal level in dBm (also known as the RSSI) on this radio chain. */ 278 public int level; 279 280 @Override toString()281 public String toString() { 282 return "RadioChainInfo: id=" + id + ", level=" + level; 283 } 284 285 @Override equals(Object otherObj)286 public boolean equals(Object otherObj) { 287 if (this == otherObj) { 288 return true; 289 } 290 if (!(otherObj instanceof RadioChainInfo)) { 291 return false; 292 } 293 RadioChainInfo other = (RadioChainInfo) otherObj; 294 return id == other.id && level == other.level; 295 } 296 297 @Override hashCode()298 public int hashCode() { 299 return Objects.hash(id, level); 300 } 301 }; 302 303 /** 304 * Information about the list of the radio chains used to receive this scan result 305 * (probe response or beacon). 306 * 307 * For Example: On devices with 2 hardware radio chains, this list could hold 1 or 2 308 * entries based on whether this scan result was received using one or both the chains. 309 * {@hide} 310 */ 311 public RadioChainInfo[] radioChainInfos; 312 313 /** 314 * Status indicating the scan result does not correspond to a user's saved configuration 315 * @hide 316 * @removed 317 */ 318 @SystemApi 319 public boolean untrusted; 320 321 /** 322 * Number of time autojoin used it 323 * @hide 324 */ 325 @UnsupportedAppUsage 326 public int numUsage; 327 328 /** 329 * The approximate distance to the AP in centimeter, if available. Else 330 * {@link UNSPECIFIED}. 331 * {@hide} 332 */ 333 @UnsupportedAppUsage 334 public int distanceCm; 335 336 /** 337 * The standard deviation of the distance to the access point, if available. 338 * Else {@link UNSPECIFIED}. 339 * {@hide} 340 */ 341 @UnsupportedAppUsage 342 public int distanceSdCm; 343 344 /** {@hide} */ 345 public static final long FLAG_PASSPOINT_NETWORK = 0x0000000000000001; 346 347 /** {@hide} */ 348 public static final long FLAG_80211mc_RESPONDER = 0x0000000000000002; 349 350 /* 351 * These flags are specific to the ScanResult class, and are not related to the |flags| 352 * field of the per-BSS scan results from WPA supplicant. 353 */ 354 /** 355 * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}. 356 * {@hide} 357 */ 358 @UnsupportedAppUsage 359 public long flags; 360 361 /** 362 * sets a flag in {@link #flags} field 363 * @param flag flag to set 364 * @hide 365 */ setFlag(long flag)366 public void setFlag(long flag) { 367 flags |= flag; 368 } 369 370 /** 371 * clears a flag in {@link #flags} field 372 * @param flag flag to set 373 * @hide 374 */ clearFlag(long flag)375 public void clearFlag(long flag) { 376 flags &= ~flag; 377 } 378 is80211mcResponder()379 public boolean is80211mcResponder() { 380 return (flags & FLAG_80211mc_RESPONDER) != 0; 381 } 382 isPasspointNetwork()383 public boolean isPasspointNetwork() { 384 return (flags & FLAG_PASSPOINT_NETWORK) != 0; 385 } 386 387 /** 388 * Indicates venue name (such as 'San Francisco Airport') published by access point; only 389 * available on Passpoint network and if published by access point. 390 */ 391 public CharSequence venueName; 392 393 /** 394 * Indicates Passpoint operator name published by access point. 395 */ 396 public CharSequence operatorFriendlyName; 397 398 /** 399 * {@hide} 400 */ 401 public final static int UNSPECIFIED = -1; 402 /** 403 * @hide 404 */ is24GHz()405 public boolean is24GHz() { 406 return ScanResult.is24GHz(frequency); 407 } 408 409 /** 410 * @hide 411 * TODO: makes real freq boundaries 412 */ is24GHz(int freq)413 public static boolean is24GHz(int freq) { 414 return freq > 2400 && freq < 2500; 415 } 416 417 /** 418 * @hide 419 */ is5GHz()420 public boolean is5GHz() { 421 return ScanResult.is5GHz(frequency); 422 } 423 424 /** 425 * @hide 426 * TODO: makes real freq boundaries 427 */ is5GHz(int freq)428 public static boolean is5GHz(int freq) { 429 return freq > 4900 && freq < 5900; 430 } 431 432 /** 433 * @hide 434 * anqp lines from supplicant BSS response 435 */ 436 @UnsupportedAppUsage 437 public List<String> anqpLines; 438 439 /** 440 * information elements from beacon. 441 */ 442 public static class InformationElement { 443 /** @hide */ 444 @UnsupportedAppUsage 445 public static final int EID_SSID = 0; 446 /** @hide */ 447 @UnsupportedAppUsage 448 public static final int EID_SUPPORTED_RATES = 1; 449 /** @hide */ 450 @UnsupportedAppUsage 451 public static final int EID_TIM = 5; 452 /** @hide */ 453 @UnsupportedAppUsage 454 public static final int EID_BSS_LOAD = 11; 455 /** @hide */ 456 @UnsupportedAppUsage 457 public static final int EID_ERP = 42; 458 /** @hide */ 459 public static final int EID_HT_CAPABILITIES = 45; 460 /** @hide */ 461 @UnsupportedAppUsage 462 public static final int EID_RSN = 48; 463 /** @hide */ 464 @UnsupportedAppUsage 465 public static final int EID_EXTENDED_SUPPORTED_RATES = 50; 466 /** @hide */ 467 @UnsupportedAppUsage 468 public static final int EID_HT_OPERATION = 61; 469 /** @hide */ 470 @UnsupportedAppUsage 471 public static final int EID_INTERWORKING = 107; 472 /** @hide */ 473 @UnsupportedAppUsage 474 public static final int EID_ROAMING_CONSORTIUM = 111; 475 /** @hide */ 476 @UnsupportedAppUsage 477 public static final int EID_EXTENDED_CAPS = 127; 478 /** @hide */ 479 public static final int EID_VHT_CAPABILITIES = 191; 480 /** @hide */ 481 @UnsupportedAppUsage 482 public static final int EID_VHT_OPERATION = 192; 483 /** @hide */ 484 @UnsupportedAppUsage 485 public static final int EID_VSA = 221; 486 487 /** @hide */ 488 @UnsupportedAppUsage 489 public int id; 490 /** @hide */ 491 @UnsupportedAppUsage 492 public byte[] bytes; 493 494 /** @hide */ InformationElement()495 public InformationElement() { 496 } 497 InformationElement(@onNull InformationElement rhs)498 public InformationElement(@NonNull InformationElement rhs) { 499 this.id = rhs.id; 500 this.bytes = rhs.bytes.clone(); 501 } 502 503 /** 504 * The element ID of the information element. Defined in the IEEE 802.11-2016 spec 505 * Table 9-77. 506 */ getId()507 public int getId() { 508 return id; 509 } 510 511 /** 512 * Get the specific content of the information element. 513 */ 514 @NonNull getBytes()515 public ByteBuffer getBytes() { 516 return ByteBuffer.wrap(bytes).asReadOnlyBuffer(); 517 } 518 } 519 520 /** 521 * information elements found in the beacon. 522 * @hide 523 */ 524 @UnsupportedAppUsage 525 public InformationElement[] informationElements; 526 /** 527 * Get all information elements found in the beacon. 528 */ 529 @NonNull getInformationElements()530 public List<InformationElement> getInformationElements() { 531 return Collections.unmodifiableList(Arrays.asList(informationElements)); 532 } 533 534 /** ANQP response elements. 535 * @hide 536 */ 537 public AnqpInformationElement[] anqpElements; 538 539 /** 540 * Flag indicating if this AP is a carrier AP. The determination is based 541 * on the AP's SSID and if AP is using EAP security. 542 * 543 * @hide 544 */ 545 public boolean isCarrierAp; 546 547 /** 548 * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP. 549 * 550 * @hide 551 */ 552 public int carrierApEapType; 553 554 /** 555 * The name of the carrier that's associated with this AP if it is a carrier AP. 556 * 557 * @hide 558 */ 559 public String carrierName; 560 561 /** {@hide} */ ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId, byte[] osuProviders, String caps, int level, int frequency, long tsf)562 public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId, 563 byte[] osuProviders, String caps, int level, int frequency, long tsf) { 564 this.wifiSsid = wifiSsid; 565 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 566 this.BSSID = BSSID; 567 this.hessid = hessid; 568 this.anqpDomainId = anqpDomainId; 569 if (osuProviders != null) { 570 this.anqpElements = new AnqpInformationElement[1]; 571 this.anqpElements[0] = 572 new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID, 573 AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders); 574 } 575 this.capabilities = caps; 576 this.level = level; 577 this.frequency = frequency; 578 this.timestamp = tsf; 579 this.distanceCm = UNSPECIFIED; 580 this.distanceSdCm = UNSPECIFIED; 581 this.channelWidth = UNSPECIFIED; 582 this.centerFreq0 = UNSPECIFIED; 583 this.centerFreq1 = UNSPECIFIED; 584 this.flags = 0; 585 this.isCarrierAp = false; 586 this.carrierApEapType = UNSPECIFIED; 587 this.carrierName = null; 588 this.radioChainInfos = null; 589 } 590 591 /** {@hide} */ ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, long tsf, int distCm, int distSdCm)592 public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, 593 long tsf, int distCm, int distSdCm) { 594 this.wifiSsid = wifiSsid; 595 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 596 this.BSSID = BSSID; 597 this.capabilities = caps; 598 this.level = level; 599 this.frequency = frequency; 600 this.timestamp = tsf; 601 this.distanceCm = distCm; 602 this.distanceSdCm = distSdCm; 603 this.channelWidth = UNSPECIFIED; 604 this.centerFreq0 = UNSPECIFIED; 605 this.centerFreq1 = UNSPECIFIED; 606 this.flags = 0; 607 this.isCarrierAp = false; 608 this.carrierApEapType = UNSPECIFIED; 609 this.carrierName = null; 610 this.radioChainInfos = null; 611 } 612 613 /** {@hide} */ ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder)614 public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, 615 int level, int frequency, 616 long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, 617 boolean is80211McRTTResponder) { 618 this.SSID = Ssid; 619 this.BSSID = BSSID; 620 this.hessid = hessid; 621 this.anqpDomainId = anqpDomainId; 622 this.capabilities = caps; 623 this.level = level; 624 this.frequency = frequency; 625 this.timestamp = tsf; 626 this.distanceCm = distCm; 627 this.distanceSdCm = distSdCm; 628 this.channelWidth = channelWidth; 629 this.centerFreq0 = centerFreq0; 630 this.centerFreq1 = centerFreq1; 631 if (is80211McRTTResponder) { 632 this.flags = FLAG_80211mc_RESPONDER; 633 } else { 634 this.flags = 0; 635 } 636 this.isCarrierAp = false; 637 this.carrierApEapType = UNSPECIFIED; 638 this.carrierName = null; 639 this.radioChainInfos = null; 640 } 641 642 /** {@hide} */ ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder)643 public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId, 644 String caps, int level, 645 int frequency, long tsf, int distCm, int distSdCm, int channelWidth, 646 int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) { 647 this(Ssid, BSSID, hessid, anqpDomainId, caps, level, frequency, tsf, distCm, 648 distSdCm, channelWidth, centerFreq0, centerFreq1, is80211McRTTResponder); 649 this.wifiSsid = wifiSsid; 650 } 651 652 /** copy constructor */ ScanResult(@onNull ScanResult source)653 public ScanResult(@NonNull ScanResult source) { 654 if (source != null) { 655 wifiSsid = source.wifiSsid; 656 SSID = source.SSID; 657 BSSID = source.BSSID; 658 hessid = source.hessid; 659 anqpDomainId = source.anqpDomainId; 660 informationElements = source.informationElements; 661 anqpElements = source.anqpElements; 662 capabilities = source.capabilities; 663 level = source.level; 664 frequency = source.frequency; 665 channelWidth = source.channelWidth; 666 centerFreq0 = source.centerFreq0; 667 centerFreq1 = source.centerFreq1; 668 timestamp = source.timestamp; 669 distanceCm = source.distanceCm; 670 distanceSdCm = source.distanceSdCm; 671 seen = source.seen; 672 untrusted = source.untrusted; 673 numUsage = source.numUsage; 674 venueName = source.venueName; 675 operatorFriendlyName = source.operatorFriendlyName; 676 flags = source.flags; 677 isCarrierAp = source.isCarrierAp; 678 carrierApEapType = source.carrierApEapType; 679 carrierName = source.carrierName; 680 radioChainInfos = source.radioChainInfos; 681 } 682 } 683 684 /** empty scan result 685 * 686 * {@hide} 687 * */ ScanResult()688 public ScanResult() { 689 } 690 691 @Override toString()692 public String toString() { 693 StringBuffer sb = new StringBuffer(); 694 String none = "<none>"; 695 696 sb.append("SSID: "). 697 append(wifiSsid == null ? WifiSsid.NONE : wifiSsid). 698 append(", BSSID: "). 699 append(BSSID == null ? none : BSSID). 700 append(", capabilities: "). 701 append(capabilities == null ? none : capabilities). 702 append(", level: "). 703 append(level). 704 append(", frequency: "). 705 append(frequency). 706 append(", timestamp: "). 707 append(timestamp); 708 709 sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")). 710 append("(cm)"); 711 sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")). 712 append("(cm)"); 713 714 sb.append(", passpoint: "); 715 sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no"); 716 sb.append(", ChannelBandwidth: ").append(channelWidth); 717 sb.append(", centerFreq0: ").append(centerFreq0); 718 sb.append(", centerFreq1: ").append(centerFreq1); 719 sb.append(", 80211mcResponder: "); 720 sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported"); 721 sb.append(", Carrier AP: ").append(isCarrierAp ? "yes" : "no"); 722 sb.append(", Carrier AP EAP Type: ").append(carrierApEapType); 723 sb.append(", Carrier name: ").append(carrierName); 724 sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos)); 725 return sb.toString(); 726 } 727 728 /** Implement the Parcelable interface {@hide} */ describeContents()729 public int describeContents() { 730 return 0; 731 } 732 733 /** Implement the Parcelable interface {@hide} */ writeToParcel(Parcel dest, int flags)734 public void writeToParcel(Parcel dest, int flags) { 735 if (wifiSsid != null) { 736 dest.writeInt(1); 737 wifiSsid.writeToParcel(dest, flags); 738 } else { 739 dest.writeInt(0); 740 } 741 dest.writeString(SSID); 742 dest.writeString(BSSID); 743 dest.writeLong(hessid); 744 dest.writeInt(anqpDomainId); 745 dest.writeString(capabilities); 746 dest.writeInt(level); 747 dest.writeInt(frequency); 748 dest.writeLong(timestamp); 749 dest.writeInt(distanceCm); 750 dest.writeInt(distanceSdCm); 751 dest.writeInt(channelWidth); 752 dest.writeInt(centerFreq0); 753 dest.writeInt(centerFreq1); 754 dest.writeLong(seen); 755 dest.writeInt(untrusted ? 1 : 0); 756 dest.writeInt(numUsage); 757 dest.writeString((venueName != null) ? venueName.toString() : ""); 758 dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : ""); 759 dest.writeLong(this.flags); 760 761 if (informationElements != null) { 762 dest.writeInt(informationElements.length); 763 for (int i = 0; i < informationElements.length; i++) { 764 dest.writeInt(informationElements[i].id); 765 dest.writeInt(informationElements[i].bytes.length); 766 dest.writeByteArray(informationElements[i].bytes); 767 } 768 } else { 769 dest.writeInt(0); 770 } 771 772 if (anqpLines != null) { 773 dest.writeInt(anqpLines.size()); 774 for (int i = 0; i < anqpLines.size(); i++) { 775 dest.writeString(anqpLines.get(i)); 776 } 777 } 778 else { 779 dest.writeInt(0); 780 } 781 if (anqpElements != null) { 782 dest.writeInt(anqpElements.length); 783 for (AnqpInformationElement element : anqpElements) { 784 dest.writeInt(element.getVendorId()); 785 dest.writeInt(element.getElementId()); 786 dest.writeInt(element.getPayload().length); 787 dest.writeByteArray(element.getPayload()); 788 } 789 } else { 790 dest.writeInt(0); 791 } 792 dest.writeInt(isCarrierAp ? 1 : 0); 793 dest.writeInt(carrierApEapType); 794 dest.writeString(carrierName); 795 796 if (radioChainInfos != null) { 797 dest.writeInt(radioChainInfos.length); 798 for (int i = 0; i < radioChainInfos.length; i++) { 799 dest.writeInt(radioChainInfos[i].id); 800 dest.writeInt(radioChainInfos[i].level); 801 } 802 } else { 803 dest.writeInt(0); 804 } 805 } 806 807 /** Implement the Parcelable interface */ 808 public static final @NonNull Creator<ScanResult> CREATOR = 809 new Creator<ScanResult>() { 810 public ScanResult createFromParcel(Parcel in) { 811 WifiSsid wifiSsid = null; 812 if (in.readInt() == 1) { 813 wifiSsid = WifiSsid.CREATOR.createFromParcel(in); 814 } 815 ScanResult sr = new ScanResult( 816 wifiSsid, 817 in.readString(), /* SSID */ 818 in.readString(), /* BSSID */ 819 in.readLong(), /* HESSID */ 820 in.readInt(), /* ANQP Domain ID */ 821 in.readString(), /* capabilities */ 822 in.readInt(), /* level */ 823 in.readInt(), /* frequency */ 824 in.readLong(), /* timestamp */ 825 in.readInt(), /* distanceCm */ 826 in.readInt(), /* distanceSdCm */ 827 in.readInt(), /* channelWidth */ 828 in.readInt(), /* centerFreq0 */ 829 in.readInt(), /* centerFreq1 */ 830 false /* rtt responder, 831 fixed with flags below */ 832 ); 833 834 sr.seen = in.readLong(); 835 sr.untrusted = in.readInt() != 0; 836 sr.numUsage = in.readInt(); 837 sr.venueName = in.readString(); 838 sr.operatorFriendlyName = in.readString(); 839 sr.flags = in.readLong(); 840 int n = in.readInt(); 841 if (n != 0) { 842 sr.informationElements = new InformationElement[n]; 843 for (int i = 0; i < n; i++) { 844 sr.informationElements[i] = new InformationElement(); 845 sr.informationElements[i].id = in.readInt(); 846 int len = in.readInt(); 847 sr.informationElements[i].bytes = new byte[len]; 848 in.readByteArray(sr.informationElements[i].bytes); 849 } 850 } 851 852 n = in.readInt(); 853 if (n != 0) { 854 sr.anqpLines = new ArrayList<String>(); 855 for (int i = 0; i < n; i++) { 856 sr.anqpLines.add(in.readString()); 857 } 858 } 859 n = in.readInt(); 860 if (n != 0) { 861 sr.anqpElements = new AnqpInformationElement[n]; 862 for (int i = 0; i < n; i++) { 863 int vendorId = in.readInt(); 864 int elementId = in.readInt(); 865 int len = in.readInt(); 866 byte[] payload = new byte[len]; 867 in.readByteArray(payload); 868 sr.anqpElements[i] = 869 new AnqpInformationElement(vendorId, elementId, payload); 870 } 871 } 872 sr.isCarrierAp = in.readInt() != 0; 873 sr.carrierApEapType = in.readInt(); 874 sr.carrierName = in.readString(); 875 n = in.readInt(); 876 if (n != 0) { 877 sr.radioChainInfos = new RadioChainInfo[n]; 878 for (int i = 0; i < n; i++) { 879 sr.radioChainInfos[i] = new RadioChainInfo(); 880 sr.radioChainInfos[i].id = in.readInt(); 881 sr.radioChainInfos[i].level = in.readInt(); 882 } 883 } 884 return sr; 885 } 886 887 public ScanResult[] newArray(int size) { 888 return new ScanResult[size]; 889 } 890 }; 891 } 892