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 30 /** 31 * Describes the state of any Wifi connection that is active or 32 * is in the process of being set up. 33 */ 34 public 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 int result = 0; 235 if (mIpAddress instanceof Inet4Address) { 236 result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress); 237 } 238 return result; 239 } 240 241 /** 242 * @return {@code true} if this network does not broadcast its SSID, so an 243 * SSID-specific probe request must be used for scans. 244 */ 245 public boolean getHiddenSSID() { 246 return mHiddenSSID; 247 } 248 249 /** {@hide} */ 250 public void setHiddenSSID(boolean hiddenSSID) { 251 mHiddenSSID = hiddenSSID; 252 } 253 254 /** 255 * Map a supplicant state into a fine-grained network connectivity state. 256 * @param suppState the supplicant state 257 * @return the corresponding {@link DetailedState} 258 */ 259 public static DetailedState getDetailedStateOf(SupplicantState suppState) { 260 return stateMap.get(suppState); 261 } 262 263 /** 264 * Set the <code>SupplicantState</code> from the string name 265 * of the state. 266 * @param stateName the name of the state, as a <code>String</code> returned 267 * in an event sent by {@code wpa_supplicant}. 268 */ 269 void setSupplicantState(String stateName) { 270 mSupplicantState = valueOf(stateName); 271 } 272 273 static SupplicantState valueOf(String stateName) { 274 if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName)) 275 return SupplicantState.FOUR_WAY_HANDSHAKE; 276 else { 277 try { 278 return SupplicantState.valueOf(stateName.toUpperCase()); 279 } catch (IllegalArgumentException e) { 280 return SupplicantState.INVALID; 281 } 282 } 283 } 284 285 /** {@hide} */ 286 public static String removeDoubleQuotes(String string) { 287 if (string == null) return null; 288 final int length = string.length(); 289 if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { 290 return string.substring(1, length - 1); 291 } 292 return string; 293 } 294 295 @Override 296 public String toString() { 297 StringBuffer sb = new StringBuffer(); 298 String none = "<none>"; 299 300 sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid). 301 append(", BSSID: ").append(mBSSID == null ? none : mBSSID). 302 append(", MAC: ").append(mMacAddress == null ? none : mMacAddress). 303 append(", Supplicant state: "). 304 append(mSupplicantState == null ? none : mSupplicantState). 305 append(", RSSI: ").append(mRssi). 306 append(", Link speed: ").append(mLinkSpeed). 307 append(", Net ID: ").append(mNetworkId). 308 append(", Metered hint: ").append(mMeteredHint); 309 310 return sb.toString(); 311 } 312 313 /** Implement the Parcelable interface {@hide} */ 314 public int describeContents() { 315 return 0; 316 } 317 318 /** Implement the Parcelable interface {@hide} */ 319 public void writeToParcel(Parcel dest, int flags) { 320 dest.writeInt(mNetworkId); 321 dest.writeInt(mRssi); 322 dest.writeInt(mLinkSpeed); 323 if (mIpAddress != null) { 324 dest.writeByte((byte)1); 325 dest.writeByteArray(mIpAddress.getAddress()); 326 } else { 327 dest.writeByte((byte)0); 328 } 329 if (mWifiSsid != null) { 330 dest.writeInt(1); 331 mWifiSsid.writeToParcel(dest, flags); 332 } else { 333 dest.writeInt(0); 334 } 335 dest.writeString(mBSSID); 336 dest.writeString(mMacAddress); 337 dest.writeInt(mMeteredHint ? 1 : 0); 338 mSupplicantState.writeToParcel(dest, flags); 339 } 340 341 /** Implement the Parcelable interface {@hide} */ 342 public static final Creator<WifiInfo> CREATOR = 343 new Creator<WifiInfo>() { 344 public WifiInfo createFromParcel(Parcel in) { 345 WifiInfo info = new WifiInfo(); 346 info.setNetworkId(in.readInt()); 347 info.setRssi(in.readInt()); 348 info.setLinkSpeed(in.readInt()); 349 if (in.readByte() == 1) { 350 try { 351 info.setInetAddress(InetAddress.getByAddress(in.createByteArray())); 352 } catch (UnknownHostException e) {} 353 } 354 if (in.readInt() == 1) { 355 info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in); 356 } 357 info.mBSSID = in.readString(); 358 info.mMacAddress = in.readString(); 359 info.mMeteredHint = in.readInt() != 0; 360 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); 361 return info; 362 } 363 364 public WifiInfo[] newArray(int size) { 365 return new WifiInfo[size]; 366 } 367 }; 368 } 369