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 22 /** 23 * Describes information about a detected access point. In addition 24 * to the attributes described here, the supplicant keeps track of 25 * {@code quality}, {@code noise}, and {@code maxbitrate} attributes, 26 * but does not currently report them to external clients. 27 */ 28 public class ScanResult implements Parcelable { 29 /** 30 * The network name. 31 */ 32 public String SSID; 33 34 /** 35 * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide 36 */ 37 public WifiSsid wifiSsid; 38 39 /** 40 * The address of the access point. 41 */ 42 public String BSSID; 43 /** 44 * Describes the authentication, key management, and encryption schemes 45 * supported by the access point. 46 */ 47 public String capabilities; 48 /** 49 * The detected signal level in dBm, also known as the RSSI. 50 * 51 * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into 52 * an absolute signal level which can be displayed to a user. 53 */ 54 public int level; 55 /** 56 * The frequency in MHz of the channel over which the client is communicating 57 * with the access point. 58 */ 59 public int frequency; 60 61 /** 62 * timestamp in microseconds (since boot) when 63 * this result was last seen. 64 */ 65 public long timestamp; 66 67 /** 68 * Timestamp representing date when this result was last seen, in milliseconds from 1970 69 * {@hide} 70 */ 71 public long seen; 72 73 /** 74 * If the scan result is a valid autojoin candidate 75 * {@hide} 76 */ 77 public int isAutoJoinCandidate; 78 79 /** 80 * @hide 81 * Update RSSI of the scan result 82 * @param previousRSSI 83 * @param previousSeen 84 * @param maxAge 85 */ 86 public void averageRssi(int previousRssi, long previousSeen, int maxAge) { 87 88 if (seen == 0) { 89 seen = System.currentTimeMillis(); 90 } 91 long age = seen - previousSeen; 92 93 if (previousSeen > 0 && age > 0 && age < maxAge/2) { 94 // Average the RSSI with previously seen instances of this scan result 95 double alpha = 0.5 - (double) age / (double) maxAge; 96 level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha); 97 } 98 } 99 100 /** @hide */ 101 public static final int ENABLED = 0; 102 /** @hide */ 103 public static final int AUTO_ROAM_DISABLED = 16; 104 /** @hide */ 105 public static final int AUTO_JOIN_DISABLED = 32; 106 /** @hide */ 107 public static final int AUTHENTICATION_ERROR = 128; 108 109 /** 110 * Status: indicating join status 111 * @hide 112 */ 113 public int autoJoinStatus; 114 115 /** 116 * num IP configuration failures 117 * @hide 118 */ 119 public int numIpConfigFailures; 120 121 /** 122 * @hide 123 * Last time we blacklisted the ScanResult 124 */ 125 public long blackListTimestamp; 126 127 /** @hide **/ 128 public void setAutoJoinStatus(int status) { 129 if (status < 0) status = 0; 130 if (status == 0) { 131 blackListTimestamp = 0; 132 } else if (status > autoJoinStatus) { 133 blackListTimestamp = System.currentTimeMillis(); 134 } 135 autoJoinStatus = status; 136 } 137 138 /** 139 * Status: indicating the scan result is not a result 140 * that is part of user's saved configurations 141 * @hide 142 */ 143 public boolean untrusted; 144 145 /** 146 * Number of time we connected to it 147 * @hide 148 */ 149 public int numConnection; 150 151 /** 152 * Number of time autojoin used it 153 * @hide 154 */ 155 public int numUsage; 156 157 /** 158 * The approximate distance to the AP in centimeter, if available. Else 159 * {@link UNSPECIFIED}. 160 * {@hide} 161 */ 162 public int distanceCm; 163 164 /** 165 * The standard deviation of the distance to the AP, if available. 166 * Else {@link UNSPECIFIED}. 167 * {@hide} 168 */ 169 public int distanceSdCm; 170 171 /** 172 * {@hide} 173 */ 174 public final static int UNSPECIFIED = -1; 175 /** 176 * @hide 177 */ 178 public boolean is24GHz() { 179 return ScanResult.is24GHz(frequency); 180 } 181 182 /** 183 * @hide 184 * TODO: makes real freq boundaries 185 */ 186 public static boolean is24GHz(int freq) { 187 return freq > 2400 && freq < 2500; 188 } 189 190 /** 191 * @hide 192 */ 193 public boolean is5GHz() { 194 return ScanResult.is5GHz(frequency); 195 } 196 197 /** 198 * @hide 199 * TODO: makes real freq boundaries 200 */ 201 public static boolean is5GHz(int freq) { 202 return freq > 4900 && freq < 5900; 203 } 204 205 /** information element from beacon 206 * @hide 207 */ 208 public static class InformationElement { 209 public int id; 210 public byte[] bytes; 211 212 public InformationElement() { 213 } 214 215 public InformationElement(InformationElement rhs) { 216 this.id = rhs.id; 217 this.bytes = rhs.bytes.clone(); 218 } 219 } 220 221 /** information elements found in the beacon 222 * @hide 223 */ 224 public InformationElement informationElements[]; 225 226 /** {@hide} */ 227 public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, 228 long tsf) { 229 this.wifiSsid = wifiSsid; 230 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 231 this.BSSID = BSSID; 232 this.capabilities = caps; 233 this.level = level; 234 this.frequency = frequency; 235 this.timestamp = tsf; 236 this.distanceCm = UNSPECIFIED; 237 this.distanceSdCm = UNSPECIFIED; 238 } 239 240 /** {@hide} */ 241 public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, 242 long tsf, int distCm, int distSdCm) { 243 this.wifiSsid = wifiSsid; 244 this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE; 245 this.BSSID = BSSID; 246 this.capabilities = caps; 247 this.level = level; 248 this.frequency = frequency; 249 this.timestamp = tsf; 250 this.distanceCm = distCm; 251 this.distanceSdCm = distSdCm; 252 } 253 254 /** copy constructor {@hide} */ 255 public ScanResult(ScanResult source) { 256 if (source != null) { 257 wifiSsid = source.wifiSsid; 258 SSID = source.SSID; 259 BSSID = source.BSSID; 260 capabilities = source.capabilities; 261 level = source.level; 262 frequency = source.frequency; 263 timestamp = source.timestamp; 264 distanceCm = source.distanceCm; 265 distanceSdCm = source.distanceSdCm; 266 seen = source.seen; 267 autoJoinStatus = source.autoJoinStatus; 268 untrusted = source.untrusted; 269 numConnection = source.numConnection; 270 numUsage = source.numUsage; 271 numIpConfigFailures = source.numIpConfigFailures; 272 isAutoJoinCandidate = source.isAutoJoinCandidate; 273 } 274 } 275 276 /** empty scan result 277 * 278 * {@hide} 279 * */ 280 public ScanResult() { 281 } 282 283 @Override 284 public String toString() { 285 StringBuffer sb = new StringBuffer(); 286 String none = "<none>"; 287 288 sb.append("SSID: "). 289 append(wifiSsid == null ? WifiSsid.NONE : wifiSsid). 290 append(", BSSID: "). 291 append(BSSID == null ? none : BSSID). 292 append(", capabilities: "). 293 append(capabilities == null ? none : capabilities). 294 append(", level: "). 295 append(level). 296 append(", frequency: "). 297 append(frequency). 298 append(", timestamp: "). 299 append(timestamp); 300 301 sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")). 302 append("(cm)"); 303 sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")). 304 append("(cm)"); 305 306 if (autoJoinStatus != 0) { 307 sb.append(", status: ").append(autoJoinStatus); 308 } 309 return sb.toString(); 310 } 311 312 /** Implement the Parcelable interface {@hide} */ 313 public int describeContents() { 314 return 0; 315 } 316 317 /** Implement the Parcelable interface {@hide} */ 318 public void writeToParcel(Parcel dest, int flags) { 319 if (wifiSsid != null) { 320 dest.writeInt(1); 321 wifiSsid.writeToParcel(dest, flags); 322 } else { 323 dest.writeInt(0); 324 } 325 dest.writeString(BSSID); 326 dest.writeString(capabilities); 327 dest.writeInt(level); 328 dest.writeInt(frequency); 329 dest.writeLong(timestamp); 330 dest.writeInt(distanceCm); 331 dest.writeInt(distanceSdCm); 332 dest.writeLong(seen); 333 dest.writeInt(autoJoinStatus); 334 dest.writeInt(untrusted ? 1 : 0); 335 dest.writeInt(numConnection); 336 dest.writeInt(numUsage); 337 dest.writeInt(numIpConfigFailures); 338 dest.writeInt(isAutoJoinCandidate); 339 if (informationElements != null) { 340 dest.writeInt(informationElements.length); 341 for (int i = 0; i < informationElements.length; i++) { 342 dest.writeInt(informationElements[i].id); 343 dest.writeInt(informationElements[i].bytes.length); 344 dest.writeByteArray(informationElements[i].bytes); 345 } 346 } else { 347 dest.writeInt(0); 348 } 349 } 350 351 /** Implement the Parcelable interface {@hide} */ 352 public static final Creator<ScanResult> CREATOR = 353 new Creator<ScanResult>() { 354 public ScanResult createFromParcel(Parcel in) { 355 WifiSsid wifiSsid = null; 356 if (in.readInt() == 1) { 357 wifiSsid = WifiSsid.CREATOR.createFromParcel(in); 358 } 359 ScanResult sr = new ScanResult( 360 wifiSsid, 361 in.readString(), 362 in.readString(), 363 in.readInt(), 364 in.readInt(), 365 in.readLong(), 366 in.readInt(), 367 in.readInt() 368 ); 369 sr.seen = in.readLong(); 370 sr.autoJoinStatus = in.readInt(); 371 sr.untrusted = in.readInt() != 0; 372 sr.numConnection = in.readInt(); 373 sr.numUsage = in.readInt(); 374 sr.numIpConfigFailures = in.readInt(); 375 sr.isAutoJoinCandidate = in.readInt(); 376 int n = in.readInt(); 377 if (n != 0) { 378 sr.informationElements = new InformationElement[n]; 379 for (int i = 0; i < n; i++) { 380 sr.informationElements[i] = new InformationElement(); 381 sr.informationElements[i].id = in.readInt(); 382 int len = in.readInt(); 383 sr.informationElements[i].bytes = new byte[len]; 384 in.readByteArray(sr.informationElements[i].bytes); 385 } 386 } 387 return sr; 388 } 389 390 public ScanResult[] newArray(int size) { 391 return new ScanResult[size]; 392 } 393 }; 394 } 395