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.Parcelable; 20 import android.os.Parcel; 21 import android.net.NetworkInfo.DetailedState; 22 import android.net.NetworkUtils; 23 import android.text.TextUtils; 24 25 import java.net.InetAddress; 26 import java.net.Inet4Address; 27 import java.net.UnknownHostException; 28 import java.util.EnumMap; 29 import java.util.Locale; 30 31 /** 32 * Describes the state of any Wifi connection that is active or 33 * is in the process of being set up. 34 */ 35 public class WifiInfo implements Parcelable { 36 private static final String TAG = "WifiInfo"; 37 /** 38 * This is the map described in the Javadoc comment above. The positions 39 * of the elements of the array must correspond to the ordinal values 40 * of <code>DetailedState</code>. 41 */ 42 private static final EnumMap<SupplicantState, DetailedState> stateMap = 43 new EnumMap<SupplicantState, DetailedState>(SupplicantState.class); 44 45 /** 46 * Default MAC address reported to a client that does not have the 47 * android.permission.LOCAL_MAC_ADDRESS permission. 48 * 49 * @hide 50 */ 51 public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; 52 53 static { stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED)54 stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED); stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED)55 stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED); stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE)56 stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE); stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING)57 stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING); stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING)58 stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING); stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING)59 stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING); stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING)60 stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING); stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING)61 stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING); stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING)62 stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING); stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR)63 stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR); stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED)64 stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED); stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE)65 stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE); stateMap.put(SupplicantState.INVALID, DetailedState.FAILED)66 stateMap.put(SupplicantState.INVALID, DetailedState.FAILED); 67 } 68 69 private SupplicantState mSupplicantState; 70 private String mBSSID; 71 private WifiSsid mWifiSsid; 72 private int mNetworkId; 73 74 /** @hide **/ 75 public static final int INVALID_RSSI = -127; 76 77 /** @hide **/ 78 public static final int MIN_RSSI = -126; 79 80 /** @hide **/ 81 public static final int MAX_RSSI = 200; 82 83 84 /** 85 * Received Signal Strength Indicator 86 */ 87 private int mRssi; 88 89 /** 90 * Link speed in Mbps 91 */ 92 public static final String LINK_SPEED_UNITS = "Mbps"; 93 private int mLinkSpeed; 94 95 /** 96 * Frequency in MHz 97 */ 98 public static final String FREQUENCY_UNITS = "MHz"; 99 private int mFrequency; 100 101 private InetAddress mIpAddress; 102 private String mMacAddress = DEFAULT_MAC_ADDRESS; 103 104 private boolean mEphemeral; 105 106 /** 107 * Running total count of lost (not ACKed) transmitted unicast data packets. 108 * @hide 109 */ 110 public long txBad; 111 /** 112 * Running total count of transmitted unicast data retry packets. 113 * @hide 114 */ 115 public long txRetries; 116 /** 117 * Running total count of successfully transmitted (ACKed) unicast data packets. 118 * @hide 119 */ 120 public long txSuccess; 121 /** 122 * Running total count of received unicast data packets. 123 * @hide 124 */ 125 public long rxSuccess; 126 127 /** 128 * Average rate of lost transmitted packets, in units of packets per second. 129 * @hide 130 */ 131 public double txBadRate; 132 /** 133 * Average rate of transmitted retry packets, in units of packets per second. 134 * @hide 135 */ 136 public double txRetriesRate; 137 /** 138 * Average rate of successfully transmitted unicast packets, in units of packets per second. 139 * @hide 140 */ 141 public double txSuccessRate; 142 /** 143 * Average rate of received unicast data packets, in units of packets per second. 144 * @hide 145 */ 146 public double rxSuccessRate; 147 148 /** 149 * @hide 150 */ 151 public int score; 152 153 /** 154 * Flag indicating that AP has hinted that upstream connection is metered, 155 * and sensitive to heavy data transfers. 156 */ 157 private boolean mMeteredHint; 158 159 /** @hide */ WifiInfo()160 public WifiInfo() { 161 mWifiSsid = null; 162 mBSSID = null; 163 mNetworkId = -1; 164 mSupplicantState = SupplicantState.UNINITIALIZED; 165 mRssi = INVALID_RSSI; 166 mLinkSpeed = -1; 167 mFrequency = -1; 168 } 169 170 /** @hide */ reset()171 public void reset() { 172 setInetAddress(null); 173 setBSSID(null); 174 setSSID(null); 175 setNetworkId(-1); 176 setRssi(INVALID_RSSI); 177 setLinkSpeed(-1); 178 setFrequency(-1); 179 setMeteredHint(false); 180 setEphemeral(false); 181 txBad = 0; 182 txSuccess = 0; 183 rxSuccess = 0; 184 txRetries = 0; 185 txBadRate = 0; 186 txSuccessRate = 0; 187 rxSuccessRate = 0; 188 txRetriesRate = 0; 189 score = 0; 190 } 191 192 /** 193 * Copy constructor 194 * @hide 195 */ WifiInfo(WifiInfo source)196 public WifiInfo(WifiInfo source) { 197 if (source != null) { 198 mSupplicantState = source.mSupplicantState; 199 mBSSID = source.mBSSID; 200 mWifiSsid = source.mWifiSsid; 201 mNetworkId = source.mNetworkId; 202 mRssi = source.mRssi; 203 mLinkSpeed = source.mLinkSpeed; 204 mFrequency = source.mFrequency; 205 mIpAddress = source.mIpAddress; 206 mMacAddress = source.mMacAddress; 207 mMeteredHint = source.mMeteredHint; 208 mEphemeral = source.mEphemeral; 209 txBad = source.txBad; 210 txRetries = source.txRetries; 211 txSuccess = source.txSuccess; 212 rxSuccess = source.rxSuccess; 213 txBadRate = source.txBadRate; 214 txRetriesRate = source.txRetriesRate; 215 txSuccessRate = source.txSuccessRate; 216 rxSuccessRate = source.rxSuccessRate; 217 score = source.score; 218 } 219 } 220 221 /** @hide */ setSSID(WifiSsid wifiSsid)222 public void setSSID(WifiSsid wifiSsid) { 223 mWifiSsid = wifiSsid; 224 } 225 226 /** 227 * Returns the service set identifier (SSID) of the current 802.11 network. 228 * If the SSID can be decoded as UTF-8, it will be returned surrounded by double 229 * quotation marks. Otherwise, it is returned as a string of hex digits. The 230 * SSID may be <unknown ssid> if there is no network currently connected, 231 * or if the caller has insufficient permissions to access the SSID. 232 * 233 * Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method 234 * always returned the SSID with no quotes around it. 235 * @return the SSID 236 */ getSSID()237 public String getSSID() { 238 if (mWifiSsid != null) { 239 String unicode = mWifiSsid.toString(); 240 if (!TextUtils.isEmpty(unicode)) { 241 return "\"" + unicode + "\""; 242 } else { 243 String hex = mWifiSsid.getHexString(); 244 return (hex != null) ? hex : WifiSsid.NONE; 245 } 246 } 247 return WifiSsid.NONE; 248 } 249 250 /** @hide */ getWifiSsid()251 public WifiSsid getWifiSsid() { 252 return mWifiSsid; 253 } 254 255 /** @hide */ setBSSID(String BSSID)256 public void setBSSID(String BSSID) { 257 mBSSID = BSSID; 258 } 259 260 /** 261 * Return the basic service set identifier (BSSID) of the current access point. 262 * The BSSID may be {@code null} if there is no network currently connected. 263 * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX} 264 */ getBSSID()265 public String getBSSID() { 266 return mBSSID; 267 } 268 269 /** 270 * Returns the received signal strength indicator of the current 802.11 271 * network, in dBm. 272 * 273 * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into 274 * an absolute signal level which can be displayed to a user. 275 * 276 * @return the RSSI. 277 */ getRssi()278 public int getRssi() { 279 return mRssi; 280 } 281 282 /** @hide */ setRssi(int rssi)283 public void setRssi(int rssi) { 284 if (rssi < INVALID_RSSI) 285 rssi = INVALID_RSSI; 286 if (rssi > MAX_RSSI) 287 rssi = MAX_RSSI; 288 mRssi = rssi; 289 } 290 291 /** 292 * Returns the current link speed in {@link #LINK_SPEED_UNITS}. 293 * @return the link speed. 294 * @see #LINK_SPEED_UNITS 295 */ getLinkSpeed()296 public int getLinkSpeed() { 297 return mLinkSpeed; 298 } 299 300 /** @hide */ setLinkSpeed(int linkSpeed)301 public void setLinkSpeed(int linkSpeed) { 302 this.mLinkSpeed = linkSpeed; 303 } 304 305 /** 306 * Returns the current frequency in {@link #FREQUENCY_UNITS}. 307 * @return the frequency. 308 * @see #FREQUENCY_UNITS 309 */ getFrequency()310 public int getFrequency() { 311 return mFrequency; 312 } 313 314 /** @hide */ setFrequency(int frequency)315 public void setFrequency(int frequency) { 316 this.mFrequency = frequency; 317 } 318 319 /** 320 * @hide 321 * TODO: makes real freq boundaries 322 */ is24GHz()323 public boolean is24GHz() { 324 return ScanResult.is24GHz(mFrequency); 325 } 326 327 /** 328 * @hide 329 * TODO: makes real freq boundaries 330 */ is5GHz()331 public boolean is5GHz() { 332 return ScanResult.is5GHz(mFrequency); 333 } 334 335 /** 336 * Record the MAC address of the WLAN interface 337 * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form 338 * @hide 339 */ setMacAddress(String macAddress)340 public void setMacAddress(String macAddress) { 341 this.mMacAddress = macAddress; 342 } 343 getMacAddress()344 public String getMacAddress() { 345 return mMacAddress; 346 } 347 348 /** 349 * @return true if {@link #getMacAddress()} has a real MAC address. 350 * 351 * @hide 352 */ hasRealMacAddress()353 public boolean hasRealMacAddress() { 354 return mMacAddress != null && !DEFAULT_MAC_ADDRESS.equals(mMacAddress); 355 } 356 357 /** 358 * Indicates if we've dynamically detected this active network connection as 359 * being metered. 360 * 361 * @see WifiConfiguration#isMetered(WifiConfiguration, WifiInfo) 362 * @hide 363 */ setMeteredHint(boolean meteredHint)364 public void setMeteredHint(boolean meteredHint) { 365 mMeteredHint = meteredHint; 366 } 367 368 /** {@hide} */ getMeteredHint()369 public boolean getMeteredHint() { 370 return mMeteredHint; 371 } 372 373 /** {@hide} */ setEphemeral(boolean ephemeral)374 public void setEphemeral(boolean ephemeral) { 375 mEphemeral = ephemeral; 376 } 377 378 /** {@hide} */ isEphemeral()379 public boolean isEphemeral() { 380 return mEphemeral; 381 } 382 383 /** @hide */ setNetworkId(int id)384 public void setNetworkId(int id) { 385 mNetworkId = id; 386 } 387 388 /** 389 * Each configured network has a unique small integer ID, used to identify 390 * the network when performing operations on the supplicant. This method 391 * returns the ID for the currently connected network. 392 * @return the network ID, or -1 if there is no currently connected network 393 */ getNetworkId()394 public int getNetworkId() { 395 return mNetworkId; 396 } 397 398 /** 399 * Return the detailed state of the supplicant's negotiation with an 400 * access point, in the form of a {@link SupplicantState SupplicantState} object. 401 * @return the current {@link SupplicantState SupplicantState} 402 */ getSupplicantState()403 public SupplicantState getSupplicantState() { 404 return mSupplicantState; 405 } 406 407 /** @hide */ setSupplicantState(SupplicantState state)408 public void setSupplicantState(SupplicantState state) { 409 mSupplicantState = state; 410 } 411 412 /** @hide */ setInetAddress(InetAddress address)413 public void setInetAddress(InetAddress address) { 414 mIpAddress = address; 415 } 416 getIpAddress()417 public int getIpAddress() { 418 int result = 0; 419 if (mIpAddress instanceof Inet4Address) { 420 result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress); 421 } 422 return result; 423 } 424 425 /** 426 * @return {@code true} if this network does not broadcast its SSID, so an 427 * SSID-specific probe request must be used for scans. 428 */ getHiddenSSID()429 public boolean getHiddenSSID() { 430 if (mWifiSsid == null) return false; 431 return mWifiSsid.isHidden(); 432 } 433 434 /** 435 * Map a supplicant state into a fine-grained network connectivity state. 436 * @param suppState the supplicant state 437 * @return the corresponding {@link DetailedState} 438 */ getDetailedStateOf(SupplicantState suppState)439 public static DetailedState getDetailedStateOf(SupplicantState suppState) { 440 return stateMap.get(suppState); 441 } 442 443 /** 444 * Set the <code>SupplicantState</code> from the string name 445 * of the state. 446 * @param stateName the name of the state, as a <code>String</code> returned 447 * in an event sent by {@code wpa_supplicant}. 448 */ setSupplicantState(String stateName)449 void setSupplicantState(String stateName) { 450 mSupplicantState = valueOf(stateName); 451 } 452 valueOf(String stateName)453 static SupplicantState valueOf(String stateName) { 454 if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName)) 455 return SupplicantState.FOUR_WAY_HANDSHAKE; 456 else { 457 try { 458 return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT)); 459 } catch (IllegalArgumentException e) { 460 return SupplicantState.INVALID; 461 } 462 } 463 } 464 465 /** {@hide} */ removeDoubleQuotes(String string)466 public static String removeDoubleQuotes(String string) { 467 if (string == null) return null; 468 final int length = string.length(); 469 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { 470 return string.substring(1, length - 1); 471 } 472 return string; 473 } 474 475 @Override toString()476 public String toString() { 477 StringBuffer sb = new StringBuffer(); 478 String none = "<none>"; 479 480 sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid). 481 append(", BSSID: ").append(mBSSID == null ? none : mBSSID). 482 append(", MAC: ").append(mMacAddress == null ? none : mMacAddress). 483 append(", Supplicant state: "). 484 append(mSupplicantState == null ? none : mSupplicantState). 485 append(", RSSI: ").append(mRssi). 486 append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS). 487 append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS). 488 append(", Net ID: ").append(mNetworkId). 489 append(", Metered hint: ").append(mMeteredHint). 490 append(", score: ").append(Integer.toString(score)); 491 return sb.toString(); 492 } 493 494 /** Implement the Parcelable interface {@hide} */ describeContents()495 public int describeContents() { 496 return 0; 497 } 498 499 /** Implement the Parcelable interface {@hide} */ writeToParcel(Parcel dest, int flags)500 public void writeToParcel(Parcel dest, int flags) { 501 dest.writeInt(mNetworkId); 502 dest.writeInt(mRssi); 503 dest.writeInt(mLinkSpeed); 504 dest.writeInt(mFrequency); 505 if (mIpAddress != null) { 506 dest.writeByte((byte)1); 507 dest.writeByteArray(mIpAddress.getAddress()); 508 } else { 509 dest.writeByte((byte)0); 510 } 511 if (mWifiSsid != null) { 512 dest.writeInt(1); 513 mWifiSsid.writeToParcel(dest, flags); 514 } else { 515 dest.writeInt(0); 516 } 517 dest.writeString(mBSSID); 518 dest.writeString(mMacAddress); 519 dest.writeInt(mMeteredHint ? 1 : 0); 520 dest.writeInt(mEphemeral ? 1 : 0); 521 dest.writeInt(score); 522 dest.writeDouble(txSuccessRate); 523 dest.writeDouble(txRetriesRate); 524 dest.writeDouble(txBadRate); 525 dest.writeDouble(rxSuccessRate); 526 mSupplicantState.writeToParcel(dest, flags); 527 } 528 529 /** Implement the Parcelable interface {@hide} */ 530 public static final Creator<WifiInfo> CREATOR = 531 new Creator<WifiInfo>() { 532 public WifiInfo createFromParcel(Parcel in) { 533 WifiInfo info = new WifiInfo(); 534 info.setNetworkId(in.readInt()); 535 info.setRssi(in.readInt()); 536 info.setLinkSpeed(in.readInt()); 537 info.setFrequency(in.readInt()); 538 if (in.readByte() == 1) { 539 try { 540 info.setInetAddress(InetAddress.getByAddress(in.createByteArray())); 541 } catch (UnknownHostException e) {} 542 } 543 if (in.readInt() == 1) { 544 info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in); 545 } 546 info.mBSSID = in.readString(); 547 info.mMacAddress = in.readString(); 548 info.mMeteredHint = in.readInt() != 0; 549 info.mEphemeral = in.readInt() != 0; 550 info.score = in.readInt(); 551 info.txSuccessRate = in.readDouble(); 552 info.txRetriesRate = in.readDouble(); 553 info.txBadRate = in.readDouble(); 554 info.rxSuccessRate = in.readDouble(); 555 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); 556 return info; 557 } 558 559 public WifiInfo[] newArray(int size) { 560 return new WifiInfo[size]; 561 } 562 }; 563 } 564