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.Parcelable; 20import android.os.Parcel; 21import android.net.NetworkInfo.DetailedState; 22import android.net.NetworkUtils; 23import android.text.TextUtils; 24 25import java.net.InetAddress; 26import java.net.Inet6Address; 27import java.net.UnknownHostException; 28import java.util.EnumMap; 29 30/** 31 * Describes the state of any Wifi connection that is active or 32 * is in the process of being set up. 33 */ 34public class WifiInfo implements Parcelable { 35 private static final String TAG = "WifiInfo"; 36 /** 37 * This is the map described in the Javadoc comment above. The positions 38 * of the elements of the array must correspond to the ordinal values 39 * of <code>DetailedState</code>. 40 */ 41 private static final EnumMap<SupplicantState, DetailedState> stateMap = 42 new EnumMap<SupplicantState, DetailedState>(SupplicantState.class); 43 44 static { 45 stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED); 46 stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED); 47 stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE); 48 stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING); 49 stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING); 50 stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING); 51 stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING); 52 stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING); 53 stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING); 54 stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR); 55 stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED); 56 stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE); 57 stateMap.put(SupplicantState.INVALID, DetailedState.FAILED); 58 } 59 60 private SupplicantState mSupplicantState; 61 private String mBSSID; 62 private WifiSsid mWifiSsid; 63 private int mNetworkId; 64 private boolean mHiddenSSID; 65 /** Received Signal Strength Indicator */ 66 private int mRssi; 67 68 /** Link speed in Mbps */ 69 public static final String LINK_SPEED_UNITS = "Mbps"; 70 private int mLinkSpeed; 71 72 private InetAddress mIpAddress; 73 private String mMacAddress; 74 75 /** 76 * Flag indicating that AP has hinted that upstream connection is metered, 77 * and sensitive to heavy data transfers. 78 */ 79 private boolean mMeteredHint; 80 81 WifiInfo() { 82 mWifiSsid = null; 83 mBSSID = null; 84 mNetworkId = -1; 85 mSupplicantState = SupplicantState.UNINITIALIZED; 86 mRssi = -9999; 87 mLinkSpeed = -1; 88 mHiddenSSID = false; 89 } 90 91 /** 92 * Copy constructor 93 * @hide 94 */ 95 public WifiInfo(WifiInfo source) { 96 if (source != null) { 97 mSupplicantState = source.mSupplicantState; 98 mBSSID = source.mBSSID; 99 mWifiSsid = source.mWifiSsid; 100 mNetworkId = source.mNetworkId; 101 mHiddenSSID = source.mHiddenSSID; 102 mRssi = source.mRssi; 103 mLinkSpeed = source.mLinkSpeed; 104 mIpAddress = source.mIpAddress; 105 mMacAddress = source.mMacAddress; 106 mMeteredHint = source.mMeteredHint; 107 } 108 } 109 110 void setSSID(WifiSsid wifiSsid) { 111 mWifiSsid = wifiSsid; 112 // network is considered not hidden by default 113 mHiddenSSID = false; 114 } 115 116 /** 117 * Returns the service set identifier (SSID) of the current 802.11 network. 118 * If the SSID can be decoded as UTF-8, it will be returned surrounded by double 119 * quotation marks. Otherwise, it is returned as a string of hex digits. The 120 * SSID may be {@code null} if there is no network currently connected. 121 * @return the SSID 122 */ 123 public String getSSID() { 124 if (mWifiSsid != null) { 125 String unicode = mWifiSsid.toString(); 126 if (!TextUtils.isEmpty(unicode)) { 127 return "\"" + unicode + "\""; 128 } else { 129 return mWifiSsid.getHexString(); 130 } 131 } 132 return WifiSsid.NONE; 133 } 134 135 /** @hide */ 136 public WifiSsid getWifiSsid() { 137 return mWifiSsid; 138 } 139 140 void setBSSID(String BSSID) { 141 mBSSID = BSSID; 142 } 143 144 /** 145 * Return the basic service set identifier (BSSID) of the current access point. 146 * The BSSID may be {@code null} if there is no network currently connected. 147 * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX} 148 */ 149 public String getBSSID() { 150 return mBSSID; 151 } 152 153 /** 154 * Returns the received signal strength indicator of the current 802.11 155 * network. 156 * <p><strong>This is not normalized, but should be!</strong></p> 157 * @return the RSSI, in the range ??? to ??? 158 */ 159 public int getRssi() { 160 return mRssi; 161 } 162 163 void setRssi(int rssi) { 164 mRssi = rssi; 165 } 166 167 /** 168 * Returns the current link speed in {@link #LINK_SPEED_UNITS}. 169 * @return the link speed. 170 * @see #LINK_SPEED_UNITS 171 */ 172 public int getLinkSpeed() { 173 return mLinkSpeed; 174 } 175 176 void setLinkSpeed(int linkSpeed) { 177 this.mLinkSpeed = linkSpeed; 178 } 179 180 /** 181 * Record the MAC address of the WLAN interface 182 * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form 183 */ 184 void setMacAddress(String macAddress) { 185 this.mMacAddress = macAddress; 186 } 187 188 public String getMacAddress() { 189 return mMacAddress; 190 } 191 192 /** {@hide} */ 193 public void setMeteredHint(boolean meteredHint) { 194 mMeteredHint = meteredHint; 195 } 196 197 /** {@hide} */ 198 public boolean getMeteredHint() { 199 return mMeteredHint; 200 } 201 202 void setNetworkId(int id) { 203 mNetworkId = id; 204 } 205 206 /** 207 * Each configured network has a unique small integer ID, used to identify 208 * the network when performing operations on the supplicant. This method 209 * returns the ID for the currently connected network. 210 * @return the network ID, or -1 if there is no currently connected network 211 */ 212 public int getNetworkId() { 213 return mNetworkId; 214 } 215 216 /** 217 * Return the detailed state of the supplicant's negotiation with an 218 * access point, in the form of a {@link SupplicantState SupplicantState} object. 219 * @return the current {@link SupplicantState SupplicantState} 220 */ 221 public SupplicantState getSupplicantState() { 222 return mSupplicantState; 223 } 224 225 void setSupplicantState(SupplicantState state) { 226 mSupplicantState = state; 227 } 228 229 void setInetAddress(InetAddress address) { 230 mIpAddress = address; 231 } 232 233 public int getIpAddress() { 234 if (mIpAddress == null || mIpAddress instanceof Inet6Address) return 0; 235 return NetworkUtils.inetAddressToInt(mIpAddress); 236 } 237 238 /** 239 * @return {@code true} if this network does not broadcast its SSID, so an 240 * SSID-specific probe request must be used for scans. 241 */ 242 public boolean getHiddenSSID() { 243 return mHiddenSSID; 244 } 245 246 /** {@hide} */ 247 public void setHiddenSSID(boolean hiddenSSID) { 248 mHiddenSSID = hiddenSSID; 249 } 250 251 /** 252 * Map a supplicant state into a fine-grained network connectivity state. 253 * @param suppState the supplicant state 254 * @return the corresponding {@link DetailedState} 255 */ 256 public static DetailedState getDetailedStateOf(SupplicantState suppState) { 257 return stateMap.get(suppState); 258 } 259 260 /** 261 * Set the <code>SupplicantState</code> from the string name 262 * of the state. 263 * @param stateName the name of the state, as a <code>String</code> returned 264 * in an event sent by {@code wpa_supplicant}. 265 */ 266 void setSupplicantState(String stateName) { 267 mSupplicantState = valueOf(stateName); 268 } 269 270 static SupplicantState valueOf(String stateName) { 271 if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName)) 272 return SupplicantState.FOUR_WAY_HANDSHAKE; 273 else { 274 try { 275 return SupplicantState.valueOf(stateName.toUpperCase()); 276 } catch (IllegalArgumentException e) { 277 return SupplicantState.INVALID; 278 } 279 } 280 } 281 282 /** {@hide} */ 283 public static String removeDoubleQuotes(String string) { 284 if (string == null) return null; 285 final int length = string.length(); 286 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { 287 return string.substring(1, length - 1); 288 } 289 return string; 290 } 291 292 @Override 293 public String toString() { 294 StringBuffer sb = new StringBuffer(); 295 String none = "<none>"; 296 297 sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid). 298 append(", BSSID: ").append(mBSSID == null ? none : mBSSID). 299 append(", MAC: ").append(mMacAddress == null ? none : mMacAddress). 300 append(", Supplicant state: "). 301 append(mSupplicantState == null ? none : mSupplicantState). 302 append(", RSSI: ").append(mRssi). 303 append(", Link speed: ").append(mLinkSpeed). 304 append(", Net ID: ").append(mNetworkId). 305 append(", Metered hint: ").append(mMeteredHint); 306 307 return sb.toString(); 308 } 309 310 /** Implement the Parcelable interface {@hide} */ 311 public int describeContents() { 312 return 0; 313 } 314 315 /** Implement the Parcelable interface {@hide} */ 316 public void writeToParcel(Parcel dest, int flags) { 317 dest.writeInt(mNetworkId); 318 dest.writeInt(mRssi); 319 dest.writeInt(mLinkSpeed); 320 if (mIpAddress != null) { 321 dest.writeByte((byte)1); 322 dest.writeByteArray(mIpAddress.getAddress()); 323 } else { 324 dest.writeByte((byte)0); 325 } 326 if (mWifiSsid != null) { 327 dest.writeInt(1); 328 mWifiSsid.writeToParcel(dest, flags); 329 } else { 330 dest.writeInt(0); 331 } 332 dest.writeString(mBSSID); 333 dest.writeString(mMacAddress); 334 dest.writeInt(mMeteredHint ? 1 : 0); 335 mSupplicantState.writeToParcel(dest, flags); 336 } 337 338 /** Implement the Parcelable interface {@hide} */ 339 public static final Creator<WifiInfo> CREATOR = 340 new Creator<WifiInfo>() { 341 public WifiInfo createFromParcel(Parcel in) { 342 WifiInfo info = new WifiInfo(); 343 info.setNetworkId(in.readInt()); 344 info.setRssi(in.readInt()); 345 info.setLinkSpeed(in.readInt()); 346 if (in.readByte() == 1) { 347 try { 348 info.setInetAddress(InetAddress.getByAddress(in.createByteArray())); 349 } catch (UnknownHostException e) {} 350 } 351 if (in.readInt() == 1) { 352 info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in); 353 } 354 info.mBSSID = in.readString(); 355 info.mMacAddress = in.readString(); 356 info.mMeteredHint = in.readInt() != 0; 357 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); 358 return info; 359 } 360 361 public WifiInfo[] newArray(int size) { 362 return new WifiInfo[size]; 363 } 364 }; 365} 366