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