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