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 */ averageRssi(int previousRssi, long previousSeen, int maxAge)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 **/ setAutoJoinStatus(int status)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 */ setFlag(long flag)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 */ clearFlag(long flag)245 public void clearFlag(long flag) { 246 flags &= ~flag; 247 } 248 is80211mcResponder()249 public boolean is80211mcResponder() { 250 return (flags & FLAG_80211mc_RESPONDER) != 0; 251 } 252 isPasspointNetwork()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 */ is24GHz()275 public boolean is24GHz() { 276 return ScanResult.is24GHz(frequency); 277 } 278 279 /** 280 * @hide 281 * TODO: makes real freq boundaries 282 */ is24GHz(int freq)283 public static boolean is24GHz(int freq) { 284 return freq > 2400 && freq < 2500; 285 } 286 287 /** 288 * @hide 289 */ is5GHz()290 public boolean is5GHz() { 291 return ScanResult.is5GHz(frequency); 292 } 293 294 /** 295 * @hide 296 * TODO: makes real freq boundaries 297 */ is5GHz(int freq)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 InformationElement()315 public InformationElement() { 316 } 317 InformationElement(InformationElement rhs)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} */ ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, long tsf)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} */ ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, long tsf, int distCm, int distSdCm)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} */ ScanResult(String Ssid, String BSSID, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder)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} */ ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder)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} */ ScanResult(ScanResult source)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 * */ ScanResult()428 public ScanResult() { 429 } 430 431 @Override toString()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} */ describeContents()468 public int describeContents() { 469 return 0; 470 } 471 472 /** Implement the Parcelable interface {@hide} */ writeToParcel(Parcel dest, int flags)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