ScanResult.java revision c0e86b2e90d46cfa51519e8e3d91aad18ffcdb09
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 17package android.net.wifi; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21 22import java.util.ArrayList; 23import java.util.List; 24 25/** 26 * Describes information about a detected access point. In addition 27 * to the attributes described here, the supplicant keeps track of 28 * {@code quality}, {@code noise}, and {@code maxbitrate} attributes, 29 * but does not currently report them to external clients. 30 */ 31public class ScanResult implements Parcelable { 32 /** 33 * The network name. 34 */ 35 public String SSID; 36 37 /** 38 * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide 39 */ 40 public WifiSsid wifiSsid; 41 42 /** 43 * The address of the access point. 44 */ 45 public String BSSID; 46 /** 47 * Describes the authentication, key management, and encryption schemes 48 * supported by the access point. 49 */ 50 public String capabilities; 51 /** 52 * The detected signal level in dBm, also known as the RSSI. 53 * 54 * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into 55 * an absolute signal level which can be displayed to a user. 56 */ 57 public int level; 58 /** 59 * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating 60 * with the access point. 61 */ 62 public int frequency; 63 64 /** 65 * AP Channel bandwidth is 20 MHZ 66 */ 67 public static final int CHANNEL_WIDTH_20MHZ = 0; 68 /** 69 * AP Channel bandwidth is 40 MHZ 70 */ 71 public static final int CHANNEL_WIDTH_40MHZ = 1; 72 /** 73 * AP Channel bandwidth is 80 MHZ 74 */ 75 public static final int CHANNEL_WIDTH_80MHZ = 2; 76 /** 77 * AP Channel bandwidth is 160 MHZ 78 */ 79 public static final int CHANNEL_WIDTH_160MHZ = 3; 80 /** 81 * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ 82 */ 83 public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; 84 85 /** 86 * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ}, 87 * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ} 88 * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}. 89 */ 90 public int channelWidth; 91 92 /** 93 * Not used if the AP bandwidth is 20 MHz 94 * If the AP use 40, 80 or 160 MHz, this is the center frequency (in MHz) 95 * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz) 96 */ 97 public int centerFreq0; 98 99 /** 100 * Only used if the AP bandwidth is 80 + 80 MHz 101 * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz) 102 */ 103 public int centerFreq1; 104 105 /** 106 * @deprecated use is80211mcResponder() instead 107 * @hide 108 */ 109 public boolean is80211McRTTResponder; 110 111 /** 112 * timestamp in microseconds (since boot) when 113 * this result was last seen. 114 */ 115 public long timestamp; 116 117 /** 118 * Timestamp representing date when this result was last seen, in milliseconds from 1970 119 * {@hide} 120 */ 121 public long seen; 122 123 /** 124 * If the scan result is a valid autojoin candidate 125 * {@hide} 126 */ 127 public int isAutoJoinCandidate; 128 129 /** 130 * @hide 131 * Update RSSI of the scan result 132 * @param previousRssi 133 * @param previousSeen 134 * @param maxAge 135 */ 136 public void averageRssi(int previousRssi, long previousSeen, int maxAge) { 137 138 if (seen == 0) { 139 seen = System.currentTimeMillis(); 140 } 141 long age = seen - previousSeen; 142 143 if (previousSeen > 0 && age > 0 && age < maxAge/2) { 144 // Average the RSSI with previously seen instances of this scan result 145 double alpha = 0.5 - (double) age / (double) maxAge; 146 level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha); 147 } 148 } 149 150 /** @hide */ 151 public static final int ENABLED = 0; 152 /** @hide */ 153 public static final int AUTO_ROAM_DISABLED = 16; 154 /** @hide */ 155 public static final int AUTO_JOIN_DISABLED = 32; 156 /** @hide */ 157 public static final int AUTHENTICATION_ERROR = 128; 158 159 /** 160 * Status: indicating join status 161 * @hide 162 */ 163 public int autoJoinStatus; 164 165 /** 166 * num IP configuration failures 167 * @hide 168 */ 169 public int numIpConfigFailures; 170 171 /** 172 * @hide 173 * Last time we blacklisted the ScanResult 174 */ 175 public long blackListTimestamp; 176 177 /** @hide **/ 178 public void setAutoJoinStatus(int status) { 179 if (status < 0) status = 0; 180 if (status == 0) { 181 blackListTimestamp = 0; 182 } else if (status > autoJoinStatus) { 183 blackListTimestamp = System.currentTimeMillis(); 184 } 185 autoJoinStatus = status; 186 } 187 188 /** 189 * Status: indicating the scan result is not a result 190 * that is part of user's saved configurations 191 * @hide 192 */ 193 public boolean untrusted; 194 195 /** 196 * Number of time we connected to it 197 * @hide 198 */ 199 public int numConnection; 200 201 /** 202 * Number of time autojoin used it 203 * @hide 204 */ 205 public int numUsage; 206 207 /** 208 * The approximate distance to the AP in centimeter, if available. Else 209 * {@link UNSPECIFIED}. 210 * {@hide} 211 */ 212 public int distanceCm; 213 214 /** 215 * The standard deviation of the distance to the access point, if available. 216 * Else {@link UNSPECIFIED}. 217 * {@hide} 218 */ 219 public int distanceSdCm; 220 221 /** {@hide} */ 222 public static final long FLAG_PASSPOINT_NETWORK = 0x0000000000000001; 223 224 /** {@hide} */ 225 public static final long FLAG_80211mc_RESPONDER = 0x0000000000000002; 226 227 /** 228 * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}. 229 * {@hide} 230 */ 231 public long flags; 232 233 /** 234 * sets a flag in {@link #flags} field 235 * @param flag flag to set 236 * @hide 237 */ 238 public void setFlag(long flag) { 239 flags |= flag; 240 } 241 242 /** 243 * clears a flag in {@link #flags} field 244 * @param flag flag to set 245 * @hide 246 */ 247 public void clearFlag(long flag) { 248 flags &= ~flag; 249 } 250 251 public boolean is80211mcResponder() { 252 return (flags & FLAG_80211mc_RESPONDER) != 0; 253 } 254 255 public boolean isPasspointNetwork() { 256 return (flags & FLAG_PASSPOINT_NETWORK) != 0; 257 } 258 259 /** 260 * Indicates venue name (such as 'San Francisco Airport') published by access point; only 261 * available on passpoint network and if published by access point. 262 */ 263 public CharSequence venueName; 264 265 /** 266 * Indicates passpoint operator name published by access point. 267 */ 268 public CharSequence operatorFriendlyName; 269 270 /** 271 * {@hide} 272 */ 273 public final static int UNSPECIFIED = -1; 274 /** 275 * @hide 276 */ 277 public boolean is24GHz() { 278 return ScanResult.is24GHz(frequency); 279 } 280 281 /** 282 * @hide 283 * TODO: makes real freq boundaries 284 */ 285 public static boolean is24GHz(int freq) { 286 return freq > 2400 && freq < 2500; 287 } 288 289 /** 290 * @hide 291 */ 292 public boolean is5GHz() { 293 return ScanResult.is5GHz(frequency); 294 } 295 296 /** 297 * @hide 298 * TODO: makes real freq boundaries 299 */ 300 public static boolean is5GHz(int freq) { 301 return freq > 4900 && freq < 5900; 302 } 303 304 /** 305 * @hide 306 * anqp lines from supplicant BSS response 307 */ 308 public List<String> anqpLines; 309 310 /** 311 * @hide 312 * storing the raw bytes of full result IEs 313 **/ 314 public byte[] bytes; 315 316 /** information elements from beacon 317 * @hide 318 */ 319 public static class InformationElement { 320 public static final int EID_SSID = 0; 321 public static final int EID_BSS_LOAD = 11; 322 public static final int EID_RSN = 48; 323 public static final int EID_HT_OPERATION = 61; 324 public static final int EID_INTERWORKING = 107; 325 public static final int EID_ROAMING_CONSORTIUM = 111; 326 public static final int EID_EXTENDED_CAPS = 127; 327 public static final int EID_VHT_OPERATION = 192; 328 public static final int EID_VSA = 221; 329 330 public int id; 331 public byte[] bytes; 332 333 public InformationElement() { 334 } 335 336 public InformationElement(InformationElement rhs) { 337 this.id = rhs.id; 338 this.bytes = rhs.bytes.clone(); 339 } 340 } 341 342 /** information elements found in the beacon 343 * @hide 344 */ 345 public InformationElement informationElements[]; 346 347 /** {@hide} */ 348 public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, 349 long tsf) { 350 this.wifiSsid = wifiSsid; 351 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 352 this.BSSID = BSSID; 353 this.capabilities = caps; 354 this.level = level; 355 this.frequency = frequency; 356 this.timestamp = tsf; 357 this.distanceCm = UNSPECIFIED; 358 this.distanceSdCm = UNSPECIFIED; 359 this.channelWidth = UNSPECIFIED; 360 this.centerFreq0 = UNSPECIFIED; 361 this.centerFreq1 = UNSPECIFIED; 362 this.flags = 0; 363 } 364 365 /** {@hide} */ 366 public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, 367 long tsf, int distCm, int distSdCm) { 368 this.wifiSsid = wifiSsid; 369 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 370 this.BSSID = BSSID; 371 this.capabilities = caps; 372 this.level = level; 373 this.frequency = frequency; 374 this.timestamp = tsf; 375 this.distanceCm = distCm; 376 this.distanceSdCm = distSdCm; 377 this.channelWidth = UNSPECIFIED; 378 this.centerFreq0 = UNSPECIFIED; 379 this.centerFreq1 = UNSPECIFIED; 380 this.flags = 0; 381 } 382 383 /** {@hide} */ 384 public ScanResult(String Ssid, String BSSID, String caps, int level, int frequency, 385 long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, 386 boolean is80211McRTTResponder) { 387 this.SSID = Ssid; 388 this.BSSID = BSSID; 389 this.capabilities = caps; 390 this.level = level; 391 this.frequency = frequency; 392 this.timestamp = tsf; 393 this.distanceCm = distCm; 394 this.distanceSdCm = distSdCm; 395 this.channelWidth = channelWidth; 396 this.centerFreq0 = centerFreq0; 397 this.centerFreq1 = centerFreq1; 398 if (is80211McRTTResponder) { 399 this.flags = FLAG_80211mc_RESPONDER; 400 } else { 401 this.flags = 0; 402 } 403 } 404 405 /** {@hide} */ 406 public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, String caps, int level, 407 int frequency, long tsf, int distCm, int distSdCm, int channelWidth, 408 int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) { 409 this(Ssid, BSSID, caps,level, frequency, tsf, distCm, distSdCm, channelWidth, centerFreq0, 410 centerFreq1, is80211McRTTResponder); 411 this.wifiSsid = wifiSsid; 412 } 413 414 /** copy constructor {@hide} */ 415 public ScanResult(ScanResult source) { 416 if (source != null) { 417 wifiSsid = source.wifiSsid; 418 SSID = source.SSID; 419 BSSID = source.BSSID; 420 capabilities = source.capabilities; 421 level = source.level; 422 frequency = source.frequency; 423 channelWidth = source.channelWidth; 424 centerFreq0 = source.centerFreq0; 425 centerFreq1 = source.centerFreq1; 426 timestamp = source.timestamp; 427 distanceCm = source.distanceCm; 428 distanceSdCm = source.distanceSdCm; 429 seen = source.seen; 430 autoJoinStatus = source.autoJoinStatus; 431 untrusted = source.untrusted; 432 numConnection = source.numConnection; 433 numUsage = source.numUsage; 434 numIpConfigFailures = source.numIpConfigFailures; 435 isAutoJoinCandidate = source.isAutoJoinCandidate; 436 venueName = source.venueName; 437 operatorFriendlyName = source.operatorFriendlyName; 438 flags = source.flags; 439 } 440 } 441 442 /** empty scan result 443 * 444 * {@hide} 445 * */ 446 public ScanResult() { 447 } 448 449 @Override 450 public String toString() { 451 StringBuffer sb = new StringBuffer(); 452 String none = "<none>"; 453 454 sb.append("SSID: "). 455 append(wifiSsid == null ? WifiSsid.NONE : wifiSsid). 456 append(", BSSID: "). 457 append(BSSID == null ? none : BSSID). 458 append(", capabilities: "). 459 append(capabilities == null ? none : capabilities). 460 append(", level: "). 461 append(level). 462 append(", frequency: "). 463 append(frequency). 464 append(", timestamp: "). 465 append(timestamp); 466 467 sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")). 468 append("(cm)"); 469 sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")). 470 append("(cm)"); 471 472 sb.append(", passpoint: "); 473 sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no"); 474 if (autoJoinStatus != 0) { 475 sb.append(", status: ").append(autoJoinStatus); 476 } 477 sb.append(", ChannelBandwidth: ").append(channelWidth); 478 sb.append(", centerFreq0: ").append(centerFreq0); 479 sb.append(", centerFreq1: ").append(centerFreq1); 480 sb.append(", 80211mcResponder: "); 481 sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported"); 482 return sb.toString(); 483 } 484 485 /** Implement the Parcelable interface {@hide} */ 486 public int describeContents() { 487 return 0; 488 } 489 490 /** Implement the Parcelable interface {@hide} */ 491 public void writeToParcel(Parcel dest, int flags) { 492 if (wifiSsid != null) { 493 dest.writeInt(1); 494 wifiSsid.writeToParcel(dest, flags); 495 } else { 496 dest.writeInt(0); 497 } 498 dest.writeString(SSID); 499 dest.writeString(BSSID); 500 dest.writeString(capabilities); 501 dest.writeInt(level); 502 dest.writeInt(frequency); 503 dest.writeLong(timestamp); 504 dest.writeInt(distanceCm); 505 dest.writeInt(distanceSdCm); 506 dest.writeInt(channelWidth); 507 dest.writeInt(centerFreq0); 508 dest.writeInt(centerFreq1); 509 dest.writeLong(seen); 510 dest.writeInt(autoJoinStatus); 511 dest.writeInt(untrusted ? 1 : 0); 512 dest.writeInt(numConnection); 513 dest.writeInt(numUsage); 514 dest.writeInt(numIpConfigFailures); 515 dest.writeInt(isAutoJoinCandidate); 516 dest.writeString((venueName != null) ? venueName.toString() : ""); 517 dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : ""); 518 dest.writeLong(this.flags); 519 520 if (informationElements != null) { 521 dest.writeInt(informationElements.length); 522 for (int i = 0; i < informationElements.length; i++) { 523 dest.writeInt(informationElements[i].id); 524 dest.writeInt(informationElements[i].bytes.length); 525 dest.writeByteArray(informationElements[i].bytes); 526 } 527 } else { 528 dest.writeInt(0); 529 } 530 531 if (anqpLines != null) { 532 dest.writeInt(anqpLines.size()); 533 for (int i = 0; i < anqpLines.size(); i++) { 534 dest.writeString(anqpLines.get(i)); 535 } 536 } else { 537 dest.writeInt(0); 538 } 539 } 540 541 /** Implement the Parcelable interface {@hide} */ 542 public static final Creator<ScanResult> CREATOR = 543 new Creator<ScanResult>() { 544 public ScanResult createFromParcel(Parcel in) { 545 WifiSsid wifiSsid = null; 546 if (in.readInt() == 1) { 547 wifiSsid = WifiSsid.CREATOR.createFromParcel(in); 548 } 549 ScanResult sr = new ScanResult( 550 wifiSsid, 551 in.readString(), /* SSID */ 552 in.readString(), /* BSSID */ 553 in.readString(), /* capabilities */ 554 in.readInt(), /* level */ 555 in.readInt(), /* frequency */ 556 in.readLong(), /* timestamp */ 557 in.readInt(), /* distanceCm */ 558 in.readInt(), /* distanceSdCm */ 559 in.readInt(), /* channelWidth */ 560 in.readInt(), /* centerFreq0 */ 561 in.readInt(), /* centerFreq1 */ 562 false /* rtt responder, fixed with flags below */ 563 ); 564 565 sr.seen = in.readLong(); 566 sr.autoJoinStatus = in.readInt(); 567 sr.untrusted = in.readInt() != 0; 568 sr.numConnection = in.readInt(); 569 sr.numUsage = in.readInt(); 570 sr.numIpConfigFailures = in.readInt(); 571 sr.isAutoJoinCandidate = in.readInt(); 572 sr.venueName = in.readString(); 573 sr.operatorFriendlyName = in.readString(); 574 sr.flags = in.readLong(); 575 int n = in.readInt(); 576 if (n != 0) { 577 sr.informationElements = new InformationElement[n]; 578 for (int i = 0; i < n; i++) { 579 sr.informationElements[i] = new InformationElement(); 580 sr.informationElements[i].id = in.readInt(); 581 int len = in.readInt(); 582 sr.informationElements[i].bytes = new byte[len]; 583 in.readByteArray(sr.informationElements[i].bytes); 584 } 585 } 586 587 n = in.readInt(); 588 if (n != 0) { 589 sr.anqpLines = new ArrayList<String>(); 590 for (int i = 0; i < n; i++) { 591 sr.anqpLines.add(in.readString()); 592 } 593 } 594 return sr; 595 } 596 597 public ScanResult[] newArray(int size) { 598 return new ScanResult[size]; 599 } 600 }; 601} 602