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