| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.net.wifi; |
| |
| import android.os.Parcelable; |
| import android.os.Parcel; |
| import android.net.NetworkInfo.DetailedState; |
| import android.net.NetworkUtils; |
| import android.text.TextUtils; |
| |
| import java.net.InetAddress; |
| import java.net.Inet4Address; |
| import java.net.UnknownHostException; |
| import java.util.EnumMap; |
| import java.util.Locale; |
| |
| /** |
| * Describes the state of any Wifi connection that is active or |
| * is in the process of being set up. |
| */ |
| public class WifiInfo implements Parcelable { |
| private static final String TAG = "WifiInfo"; |
| /** |
| * This is the map described in the Javadoc comment above. The positions |
| * of the elements of the array must correspond to the ordinal values |
| * of <code>DetailedState</code>. |
| */ |
| private static final EnumMap<SupplicantState, DetailedState> stateMap = |
| new EnumMap<SupplicantState, DetailedState>(SupplicantState.class); |
| |
| static { |
| stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED); |
| stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED); |
| stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE); |
| stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING); |
| stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING); |
| stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING); |
| stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING); |
| stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING); |
| stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING); |
| stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR); |
| stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED); |
| stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE); |
| stateMap.put(SupplicantState.INVALID, DetailedState.FAILED); |
| } |
| |
| private SupplicantState mSupplicantState; |
| private String mBSSID; |
| private WifiSsid mWifiSsid; |
| private int mNetworkId; |
| |
| /** @hide **/ |
| public static final int INVALID_RSSI = -127; |
| |
| /** @hide **/ |
| public static final int MIN_RSSI = -126; |
| |
| /** @hide **/ |
| public static final int MAX_RSSI = 200; |
| |
| |
| /** |
| * Received Signal Strength Indicator |
| */ |
| private int mRssi; |
| |
| /** |
| * Link speed in Mbps |
| */ |
| public static final String LINK_SPEED_UNITS = "Mbps"; |
| private int mLinkSpeed; |
| |
| /** |
| * Frequency in MHz |
| */ |
| public static final String FREQUENCY_UNITS = "MHz"; |
| private int mFrequency; |
| |
| private InetAddress mIpAddress; |
| private String mMacAddress; |
| |
| /** |
| * @hide |
| */ |
| public long txBad; |
| /** |
| * @hide |
| */ |
| public long txRetries; |
| /** |
| * @hide |
| */ |
| public long txSuccess; |
| /** |
| * @hide |
| */ |
| public long rxSuccess; |
| /** |
| * @hide |
| */ |
| public double txBadRate; |
| /** |
| * @hide |
| */ |
| public double txRetriesRate; |
| /** |
| * @hide |
| */ |
| public double txSuccessRate; |
| /** |
| * @hide |
| */ |
| public double rxSuccessRate; |
| |
| /** |
| * @hide |
| */ |
| public int badRssiCount; |
| |
| /** |
| * @hide |
| */ |
| public int linkStuckCount; |
| |
| /** |
| * @hide |
| */ |
| public int lowRssiCount; |
| |
| /** |
| * @hide |
| */ |
| public int score; |
| |
| /** |
| * TODO: get actual timestamp and calculate true rates |
| * @hide |
| */ |
| public void updatePacketRates(WifiLinkLayerStats stats) { |
| if (stats != null) { |
| long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo; |
| long txretries = stats.retries_be + stats.retries_bk |
| + stats.retries_vi + stats.retries_vo; |
| long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo; |
| long txbad = stats.lostmpdu_be + stats.lostmpdu_bk |
| + stats.lostmpdu_vi + stats.lostmpdu_vo; |
| |
| txBadRate = (txBadRate * 0.5) |
| + ((double) (txbad - txBad) * 0.5); |
| txSuccessRate = (txSuccessRate * 0.5) |
| + ((double) (txgood - txSuccess) * 0.5); |
| rxSuccessRate = (rxSuccessRate * 0.5) |
| + ((double) (rxgood - rxSuccess) * 0.5); |
| txRetriesRate = (txRetriesRate * 0.5) |
| + ((double) (txretries - txRetries) * 0.5); |
| |
| txBad = txbad; |
| txSuccess = txgood; |
| rxSuccess = rxgood; |
| txRetries = txretries; |
| } else { |
| txBad = 0; |
| txSuccess = 0; |
| rxSuccess = 0; |
| txRetries = 0; |
| txBadRate = 0; |
| txSuccessRate = 0; |
| rxSuccessRate = 0; |
| txRetriesRate = 0; |
| } |
| } |
| |
| |
| /** |
| * This function is less powerful and used if the WifiLinkLayerStats API is not implemented |
| * at the Wifi HAL |
| * @hide |
| */ |
| public void updatePacketRates(long txPackets, long rxPackets) { |
| //paranoia |
| txBad = 0; |
| txRetries = 0; |
| txBadRate = 0; |
| txRetriesRate = 0; |
| |
| txSuccessRate = (txSuccessRate * 0.5) |
| + ((double) (txPackets - txSuccess) * 0.5); |
| rxSuccessRate = (rxSuccessRate * 0.5) |
| + ((double) (rxPackets - rxSuccess) * 0.5); |
| txSuccess = txPackets; |
| rxSuccess = rxPackets; |
| } |
| |
| /** |
| * Flag indicating that AP has hinted that upstream connection is metered, |
| * and sensitive to heavy data transfers. |
| */ |
| private boolean mMeteredHint; |
| |
| /** @hide */ |
| public WifiInfo() { |
| mWifiSsid = null; |
| mBSSID = null; |
| mNetworkId = -1; |
| mSupplicantState = SupplicantState.UNINITIALIZED; |
| mRssi = INVALID_RSSI; |
| mLinkSpeed = -1; |
| mFrequency = -1; |
| } |
| |
| /** @hide */ |
| public void reset() { |
| setInetAddress(null); |
| setBSSID(null); |
| setSSID(null); |
| setNetworkId(-1); |
| setRssi(INVALID_RSSI); |
| setLinkSpeed(-1); |
| setFrequency(-1); |
| setMeteredHint(false); |
| txBad = 0; |
| txSuccess = 0; |
| rxSuccess = 0; |
| txRetries = 0; |
| txBadRate = 0; |
| txSuccessRate = 0; |
| rxSuccessRate = 0; |
| txRetriesRate = 0; |
| lowRssiCount = 0; |
| badRssiCount = 0; |
| linkStuckCount = 0; |
| score = 0; |
| } |
| |
| /** |
| * Copy constructor |
| * @hide |
| */ |
| public WifiInfo(WifiInfo source) { |
| if (source != null) { |
| mSupplicantState = source.mSupplicantState; |
| mBSSID = source.mBSSID; |
| mWifiSsid = source.mWifiSsid; |
| mNetworkId = source.mNetworkId; |
| mRssi = source.mRssi; |
| mLinkSpeed = source.mLinkSpeed; |
| mFrequency = source.mFrequency; |
| mIpAddress = source.mIpAddress; |
| mMacAddress = source.mMacAddress; |
| mMeteredHint = source.mMeteredHint; |
| txBad = source.txBad; |
| txRetries = source.txRetries; |
| txSuccess = source.txSuccess; |
| rxSuccess = source.rxSuccess; |
| txBadRate = source.txBadRate; |
| txRetriesRate = source.txRetriesRate; |
| txSuccessRate = source.txSuccessRate; |
| rxSuccessRate = source.rxSuccessRate; |
| score = source.score; |
| badRssiCount = source.badRssiCount; |
| lowRssiCount = source.lowRssiCount; |
| linkStuckCount = source.linkStuckCount; |
| } |
| } |
| |
| /** @hide */ |
| public void setSSID(WifiSsid wifiSsid) { |
| mWifiSsid = wifiSsid; |
| } |
| |
| /** |
| * Returns the service set identifier (SSID) of the current 802.11 network. |
| * If the SSID can be decoded as UTF-8, it will be returned surrounded by double |
| * quotation marks. Otherwise, it is returned as a string of hex digits. The |
| * SSID may be <unknown ssid> if there is no network currently connected. |
| * @return the SSID |
| */ |
| public String getSSID() { |
| if (mWifiSsid != null) { |
| String unicode = mWifiSsid.toString(); |
| if (!TextUtils.isEmpty(unicode)) { |
| return "\"" + unicode + "\""; |
| } else { |
| return mWifiSsid.getHexString(); |
| } |
| } |
| return WifiSsid.NONE; |
| } |
| |
| /** @hide */ |
| public WifiSsid getWifiSsid() { |
| return mWifiSsid; |
| } |
| |
| /** @hide */ |
| public void setBSSID(String BSSID) { |
| mBSSID = BSSID; |
| } |
| |
| /** |
| * Return the basic service set identifier (BSSID) of the current access point. |
| * The BSSID may be {@code null} if there is no network currently connected. |
| * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX} |
| */ |
| public String getBSSID() { |
| return mBSSID; |
| } |
| |
| /** |
| * Returns the received signal strength indicator of the current 802.11 |
| * network, in dBm. |
| * |
| * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into |
| * an absolute signal level which can be displayed to a user. |
| * |
| * @return the RSSI. |
| */ |
| public int getRssi() { |
| return mRssi; |
| } |
| |
| /** @hide */ |
| public void setRssi(int rssi) { |
| if (rssi < INVALID_RSSI) |
| rssi = INVALID_RSSI; |
| if (rssi > MAX_RSSI) |
| rssi = MAX_RSSI; |
| mRssi = rssi; |
| } |
| |
| /** |
| * Returns the current link speed in {@link #LINK_SPEED_UNITS}. |
| * @return the link speed. |
| * @see #LINK_SPEED_UNITS |
| */ |
| public int getLinkSpeed() { |
| return mLinkSpeed; |
| } |
| |
| /** @hide */ |
| public void setLinkSpeed(int linkSpeed) { |
| this.mLinkSpeed = linkSpeed; |
| } |
| |
| /** |
| * Returns the current frequency in {@link #FREQUENCY_UNITS}. |
| * @return the frequency. |
| * @see #FREQUENCY_UNITS |
| */ |
| public int getFrequency() { |
| return mFrequency; |
| } |
| |
| /** @hide */ |
| public void setFrequency(int frequency) { |
| this.mFrequency = frequency; |
| } |
| |
| /** |
| * @hide |
| * TODO: makes real freq boundaries |
| */ |
| public boolean is24GHz() { |
| return ScanResult.is24GHz(mFrequency); |
| } |
| |
| /** |
| * @hide |
| * TODO: makes real freq boundaries |
| */ |
| public boolean is5GHz() { |
| return ScanResult.is5GHz(mFrequency); |
| } |
| |
| /** |
| * Record the MAC address of the WLAN interface |
| * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form |
| * @hide |
| */ |
| public void setMacAddress(String macAddress) { |
| this.mMacAddress = macAddress; |
| } |
| |
| public String getMacAddress() { |
| return mMacAddress; |
| } |
| |
| /** {@hide} */ |
| public void setMeteredHint(boolean meteredHint) { |
| mMeteredHint = meteredHint; |
| } |
| |
| /** {@hide} */ |
| public boolean getMeteredHint() { |
| return mMeteredHint; |
| } |
| |
| /** @hide */ |
| public void setNetworkId(int id) { |
| mNetworkId = id; |
| } |
| |
| /** |
| * Each configured network has a unique small integer ID, used to identify |
| * the network when performing operations on the supplicant. This method |
| * returns the ID for the currently connected network. |
| * @return the network ID, or -1 if there is no currently connected network |
| */ |
| public int getNetworkId() { |
| return mNetworkId; |
| } |
| |
| /** |
| * Return the detailed state of the supplicant's negotiation with an |
| * access point, in the form of a {@link SupplicantState SupplicantState} object. |
| * @return the current {@link SupplicantState SupplicantState} |
| */ |
| public SupplicantState getSupplicantState() { |
| return mSupplicantState; |
| } |
| |
| /** @hide */ |
| public void setSupplicantState(SupplicantState state) { |
| mSupplicantState = state; |
| } |
| |
| /** @hide */ |
| public void setInetAddress(InetAddress address) { |
| mIpAddress = address; |
| } |
| |
| public int getIpAddress() { |
| int result = 0; |
| if (mIpAddress instanceof Inet4Address) { |
| result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress); |
| } |
| return result; |
| } |
| |
| /** |
| * @return {@code true} if this network does not broadcast its SSID, so an |
| * SSID-specific probe request must be used for scans. |
| */ |
| public boolean getHiddenSSID() { |
| if (mWifiSsid == null) return false; |
| return mWifiSsid.isHidden(); |
| } |
| |
| /** |
| * Map a supplicant state into a fine-grained network connectivity state. |
| * @param suppState the supplicant state |
| * @return the corresponding {@link DetailedState} |
| */ |
| public static DetailedState getDetailedStateOf(SupplicantState suppState) { |
| return stateMap.get(suppState); |
| } |
| |
| /** |
| * Set the <code>SupplicantState</code> from the string name |
| * of the state. |
| * @param stateName the name of the state, as a <code>String</code> returned |
| * in an event sent by {@code wpa_supplicant}. |
| */ |
| void setSupplicantState(String stateName) { |
| mSupplicantState = valueOf(stateName); |
| } |
| |
| static SupplicantState valueOf(String stateName) { |
| if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName)) |
| return SupplicantState.FOUR_WAY_HANDSHAKE; |
| else { |
| try { |
| return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT)); |
| } catch (IllegalArgumentException e) { |
| return SupplicantState.INVALID; |
| } |
| } |
| } |
| |
| /** {@hide} */ |
| public static String removeDoubleQuotes(String string) { |
| if (string == null) return null; |
| final int length = string.length(); |
| if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) { |
| return string.substring(1, length - 1); |
| } |
| return string; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuffer sb = new StringBuffer(); |
| String none = "<none>"; |
| |
| sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid). |
| append(", BSSID: ").append(mBSSID == null ? none : mBSSID). |
| append(", MAC: ").append(mMacAddress == null ? none : mMacAddress). |
| append(", Supplicant state: "). |
| append(mSupplicantState == null ? none : mSupplicantState). |
| append(", RSSI: ").append(mRssi). |
| append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS). |
| append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS). |
| append(", Net ID: ").append(mNetworkId). |
| append(", Metered hint: ").append(mMeteredHint). |
| append(", score: ").append(Integer.toString(score)); |
| return sb.toString(); |
| } |
| |
| /** Implement the Parcelable interface {@hide} */ |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** Implement the Parcelable interface {@hide} */ |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeInt(mNetworkId); |
| dest.writeInt(mRssi); |
| dest.writeInt(mLinkSpeed); |
| dest.writeInt(mFrequency); |
| if (mIpAddress != null) { |
| dest.writeByte((byte)1); |
| dest.writeByteArray(mIpAddress.getAddress()); |
| } else { |
| dest.writeByte((byte)0); |
| } |
| if (mWifiSsid != null) { |
| dest.writeInt(1); |
| mWifiSsid.writeToParcel(dest, flags); |
| } else { |
| dest.writeInt(0); |
| } |
| dest.writeString(mBSSID); |
| dest.writeString(mMacAddress); |
| dest.writeInt(mMeteredHint ? 1 : 0); |
| dest.writeInt(score); |
| dest.writeDouble(txSuccessRate); |
| dest.writeDouble(txRetriesRate); |
| dest.writeDouble(txBadRate); |
| dest.writeDouble(rxSuccessRate); |
| dest.writeInt(badRssiCount); |
| dest.writeInt(lowRssiCount); |
| mSupplicantState.writeToParcel(dest, flags); |
| } |
| |
| /** Implement the Parcelable interface {@hide} */ |
| public static final Creator<WifiInfo> CREATOR = |
| new Creator<WifiInfo>() { |
| public WifiInfo createFromParcel(Parcel in) { |
| WifiInfo info = new WifiInfo(); |
| info.setNetworkId(in.readInt()); |
| info.setRssi(in.readInt()); |
| info.setLinkSpeed(in.readInt()); |
| info.setFrequency(in.readInt()); |
| if (in.readByte() == 1) { |
| try { |
| info.setInetAddress(InetAddress.getByAddress(in.createByteArray())); |
| } catch (UnknownHostException e) {} |
| } |
| if (in.readInt() == 1) { |
| info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in); |
| } |
| info.mBSSID = in.readString(); |
| info.mMacAddress = in.readString(); |
| info.mMeteredHint = in.readInt() != 0; |
| info.score = in.readInt(); |
| info.txSuccessRate = in.readDouble(); |
| info.txRetriesRate = in.readDouble(); |
| info.txBadRate = in.readDouble(); |
| info.rxSuccessRate = in.readDouble(); |
| info.badRssiCount = in.readInt(); |
| info.lowRssiCount = in.readInt(); |
| info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); |
| return info; |
| } |
| |
| public WifiInfo[] newArray(int size) { |
| return new WifiInfo[size]; |
| } |
| }; |
| } |