Home | History | Annotate | Download | only in wifi
      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 
     66     /** @hide **/
     67     public static final int INVALID_RSSI = -127;
     68 
     69     /** @hide **/
     70     public static final int MIN_RSSI = -126;
     71 
     72     /** @hide **/
     73     public static final int MAX_RSSI = 200;
     74 
     75 
     76     /**
     77      * Received Signal Strength Indicator
     78      */
     79     private int mRssi;
     80 
     81     /**
     82      * Link speed in Mbps
     83      */
     84     public static final String LINK_SPEED_UNITS = "Mbps";
     85     private int mLinkSpeed;
     86 
     87     /**
     88      * Frequency in MHz
     89      */
     90     public static final String FREQUENCY_UNITS = "MHz";
     91     private int mFrequency;
     92 
     93     private InetAddress mIpAddress;
     94     private String mMacAddress;
     95 
     96     /**
     97      * @hide
     98      */
     99     public long txBad;
    100     /**
    101      * @hide
    102      */
    103     public long txRetries;
    104     /**
    105      * @hide
    106      */
    107     public long txSuccess;
    108     /**
    109      * @hide
    110      */
    111     public long rxSuccess;
    112     /**
    113      * @hide
    114      */
    115     public double txBadRate;
    116     /**
    117      * @hide
    118      */
    119     public double txRetriesRate;
    120     /**
    121      * @hide
    122      */
    123     public double txSuccessRate;
    124     /**
    125      * @hide
    126      */
    127     public double rxSuccessRate;
    128 
    129     /**
    130      * @hide
    131      */
    132     public int badRssiCount;
    133 
    134     /**
    135      * @hide
    136      */
    137     public int linkStuckCount;
    138 
    139     /**
    140      * @hide
    141      */
    142     public int lowRssiCount;
    143 
    144     /**
    145      * @hide
    146      */
    147     public int score;
    148 
    149     /**
    150      * TODO: get actual timestamp and calculate true rates
    151      * @hide
    152      */
    153     public void updatePacketRates(WifiLinkLayerStats stats) {
    154         if (stats != null) {
    155             long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
    156             long txretries = stats.retries_be + stats.retries_bk
    157                     + stats.retries_vi + stats.retries_vo;
    158             long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo;
    159             long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
    160                     + stats.lostmpdu_vi + stats.lostmpdu_vo;
    161 
    162             txBadRate = (txBadRate * 0.5)
    163                 + ((double) (txbad - txBad) * 0.5);
    164             txSuccessRate = (txSuccessRate * 0.5)
    165                 + ((double) (txgood - txSuccess) * 0.5);
    166             rxSuccessRate = (rxSuccessRate * 0.5)
    167                 + ((double) (rxgood - rxSuccess) * 0.5);
    168             txRetriesRate = (txRetriesRate * 0.5)
    169                 + ((double) (txretries - txRetries) * 0.5);
    170 
    171             txBad = txbad;
    172             txSuccess = txgood;
    173             rxSuccess = rxgood;
    174             txRetries = txretries;
    175         } else {
    176             txBad = 0;
    177             txSuccess = 0;
    178             rxSuccess = 0;
    179             txRetries = 0;
    180             txBadRate = 0;
    181             txSuccessRate = 0;
    182             rxSuccessRate = 0;
    183             txRetriesRate = 0;
    184         }
    185     }
    186 
    187 
    188     /**
    189      * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
    190      * at the Wifi HAL
    191      * @hide
    192      */
    193     public void updatePacketRates(long txPackets, long rxPackets) {
    194         //paranoia
    195         txBad = 0;
    196         txRetries = 0;
    197         txBadRate = 0;
    198         txRetriesRate = 0;
    199 
    200         txSuccessRate = (txSuccessRate * 0.5)
    201                 + ((double) (txPackets - txSuccess) * 0.5);
    202         rxSuccessRate = (rxSuccessRate * 0.5)
    203                 + ((double) (rxPackets - rxSuccess) * 0.5);
    204         txSuccess = txPackets;
    205         rxSuccess = rxPackets;
    206     }
    207 
    208         /**
    209          * Flag indicating that AP has hinted that upstream connection is metered,
    210          * and sensitive to heavy data transfers.
    211          */
    212     private boolean mMeteredHint;
    213 
    214     /** @hide */
    215     public WifiInfo() {
    216         mWifiSsid = null;
    217         mBSSID = null;
    218         mNetworkId = -1;
    219         mSupplicantState = SupplicantState.UNINITIALIZED;
    220         mRssi = INVALID_RSSI;
    221         mLinkSpeed = -1;
    222         mFrequency = -1;
    223     }
    224 
    225     /** @hide */
    226     public void reset() {
    227         setInetAddress(null);
    228         setBSSID(null);
    229         setSSID(null);
    230         setNetworkId(-1);
    231         setRssi(INVALID_RSSI);
    232         setLinkSpeed(-1);
    233         setFrequency(-1);
    234         setMeteredHint(false);
    235         txBad = 0;
    236         txSuccess = 0;
    237         rxSuccess = 0;
    238         txRetries = 0;
    239         txBadRate = 0;
    240         txSuccessRate = 0;
    241         rxSuccessRate = 0;
    242         txRetriesRate = 0;
    243         lowRssiCount = 0;
    244         badRssiCount = 0;
    245         linkStuckCount = 0;
    246         score = 0;
    247     }
    248 
    249     /**
    250      * Copy constructor
    251      * @hide
    252      */
    253     public WifiInfo(WifiInfo source) {
    254         if (source != null) {
    255             mSupplicantState = source.mSupplicantState;
    256             mBSSID = source.mBSSID;
    257             mWifiSsid = source.mWifiSsid;
    258             mNetworkId = source.mNetworkId;
    259             mRssi = source.mRssi;
    260             mLinkSpeed = source.mLinkSpeed;
    261             mFrequency = source.mFrequency;
    262             mIpAddress = source.mIpAddress;
    263             mMacAddress = source.mMacAddress;
    264             mMeteredHint = source.mMeteredHint;
    265             txBad = source.txBad;
    266             txRetries = source.txRetries;
    267             txSuccess = source.txSuccess;
    268             rxSuccess = source.rxSuccess;
    269             txBadRate = source.txBadRate;
    270             txRetriesRate = source.txRetriesRate;
    271             txSuccessRate = source.txSuccessRate;
    272             rxSuccessRate = source.rxSuccessRate;
    273             score = source.score;
    274             badRssiCount = source.badRssiCount;
    275             lowRssiCount = source.lowRssiCount;
    276             linkStuckCount = source.linkStuckCount;
    277         }
    278     }
    279 
    280     /** @hide */
    281     public void setSSID(WifiSsid wifiSsid) {
    282         mWifiSsid = wifiSsid;
    283     }
    284 
    285     /**
    286      * Returns the service set identifier (SSID) of the current 802.11 network.
    287      * If the SSID can be decoded as UTF-8, it will be returned surrounded by double
    288      * quotation marks. Otherwise, it is returned as a string of hex digits. The
    289      * SSID may be &lt;unknown ssid&gt; if there is no network currently connected.
    290      * @return the SSID
    291      */
    292     public String getSSID() {
    293         if (mWifiSsid != null) {
    294             String unicode = mWifiSsid.toString();
    295             if (!TextUtils.isEmpty(unicode)) {
    296                 return "\"" + unicode + "\"";
    297             } else {
    298                 return mWifiSsid.getHexString();
    299             }
    300         }
    301         return WifiSsid.NONE;
    302     }
    303 
    304     /** @hide */
    305     public WifiSsid getWifiSsid() {
    306         return mWifiSsid;
    307     }
    308 
    309     /** @hide */
    310     public void setBSSID(String BSSID) {
    311         mBSSID = BSSID;
    312     }
    313 
    314     /**
    315      * Return the basic service set identifier (BSSID) of the current access point.
    316      * The BSSID may be {@code null} if there is no network currently connected.
    317      * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX}
    318      */
    319     public String getBSSID() {
    320         return mBSSID;
    321     }
    322 
    323     /**
    324      * Returns the received signal strength indicator of the current 802.11
    325      * network, in dBm.
    326      *
    327      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
    328      * an absolute signal level which can be displayed to a user.
    329      *
    330      * @return the RSSI.
    331      */
    332     public int getRssi() {
    333         return mRssi;
    334     }
    335 
    336     /** @hide */
    337     public void setRssi(int rssi) {
    338         if (rssi < INVALID_RSSI)
    339             rssi = INVALID_RSSI;
    340         if (rssi > MAX_RSSI)
    341             rssi = MAX_RSSI;
    342         mRssi = rssi;
    343     }
    344 
    345     /**
    346      * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
    347      * @return the link speed.
    348      * @see #LINK_SPEED_UNITS
    349      */
    350     public int getLinkSpeed() {
    351         return mLinkSpeed;
    352     }
    353 
    354     /** @hide */
    355     public void setLinkSpeed(int linkSpeed) {
    356         this.mLinkSpeed = linkSpeed;
    357     }
    358 
    359     /**
    360      * Returns the current frequency in {@link #FREQUENCY_UNITS}.
    361      * @return the frequency.
    362      * @see #FREQUENCY_UNITS
    363      */
    364     public int getFrequency() {
    365         return mFrequency;
    366     }
    367 
    368     /** @hide */
    369     public void setFrequency(int frequency) {
    370         this.mFrequency = frequency;
    371     }
    372 
    373     /**
    374      * @hide
    375      * TODO: makes real freq boundaries
    376      */
    377     public boolean is24GHz() {
    378         return ScanResult.is24GHz(mFrequency);
    379     }
    380 
    381     /**
    382      * @hide
    383      * TODO: makes real freq boundaries
    384      */
    385     public boolean is5GHz() {
    386         return ScanResult.is5GHz(mFrequency);
    387     }
    388 
    389     /**
    390      * Record the MAC address of the WLAN interface
    391      * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
    392      * @hide
    393      */
    394     public void setMacAddress(String macAddress) {
    395         this.mMacAddress = macAddress;
    396     }
    397 
    398     public String getMacAddress() {
    399         return mMacAddress;
    400     }
    401 
    402     /** {@hide} */
    403     public void setMeteredHint(boolean meteredHint) {
    404         mMeteredHint = meteredHint;
    405     }
    406 
    407     /** {@hide} */
    408     public boolean getMeteredHint() {
    409         return mMeteredHint;
    410     }
    411 
    412     /** @hide */
    413     public void setNetworkId(int id) {
    414         mNetworkId = id;
    415     }
    416 
    417     /**
    418      * Each configured network has a unique small integer ID, used to identify
    419      * the network when performing operations on the supplicant. This method
    420      * returns the ID for the currently connected network.
    421      * @return the network ID, or -1 if there is no currently connected network
    422      */
    423     public int getNetworkId() {
    424         return mNetworkId;
    425     }
    426 
    427     /**
    428      * Return the detailed state of the supplicant's negotiation with an
    429      * access point, in the form of a {@link SupplicantState SupplicantState} object.
    430      * @return the current {@link SupplicantState SupplicantState}
    431      */
    432     public SupplicantState getSupplicantState() {
    433         return mSupplicantState;
    434     }
    435 
    436     /** @hide */
    437     public void setSupplicantState(SupplicantState state) {
    438         mSupplicantState = state;
    439     }
    440 
    441     /** @hide */
    442     public void setInetAddress(InetAddress address) {
    443         mIpAddress = address;
    444     }
    445 
    446     public int getIpAddress() {
    447         int result = 0;
    448         if (mIpAddress instanceof Inet4Address) {
    449             result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
    450         }
    451         return result;
    452     }
    453 
    454     /**
    455      * @return {@code true} if this network does not broadcast its SSID, so an
    456      * SSID-specific probe request must be used for scans.
    457      */
    458     public boolean getHiddenSSID() {
    459         if (mWifiSsid == null) return false;
    460         return mWifiSsid.isHidden();
    461     }
    462 
    463    /**
    464      * Map a supplicant state into a fine-grained network connectivity state.
    465      * @param suppState the supplicant state
    466      * @return the corresponding {@link DetailedState}
    467      */
    468     public static DetailedState getDetailedStateOf(SupplicantState suppState) {
    469         return stateMap.get(suppState);
    470     }
    471 
    472     /**
    473      * Set the <code>SupplicantState</code> from the string name
    474      * of the state.
    475      * @param stateName the name of the state, as a <code>String</code> returned
    476      * in an event sent by {@code wpa_supplicant}.
    477      */
    478     void setSupplicantState(String stateName) {
    479         mSupplicantState = valueOf(stateName);
    480     }
    481 
    482     static SupplicantState valueOf(String stateName) {
    483         if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName))
    484             return SupplicantState.FOUR_WAY_HANDSHAKE;
    485         else {
    486             try {
    487                 return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT));
    488             } catch (IllegalArgumentException e) {
    489                 return SupplicantState.INVALID;
    490             }
    491         }
    492     }
    493 
    494     /** {@hide} */
    495     public static String removeDoubleQuotes(String string) {
    496         if (string == null) return null;
    497         final int length = string.length();
    498         if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
    499             return string.substring(1, length - 1);
    500         }
    501         return string;
    502     }
    503 
    504     @Override
    505     public String toString() {
    506         StringBuffer sb = new StringBuffer();
    507         String none = "<none>";
    508 
    509         sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
    510             append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
    511             append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
    512             append(", Supplicant state: ").
    513             append(mSupplicantState == null ? none : mSupplicantState).
    514             append(", RSSI: ").append(mRssi).
    515             append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
    516             append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
    517             append(", Net ID: ").append(mNetworkId).
    518             append(", Metered hint: ").append(mMeteredHint).
    519             append(", score: ").append(Integer.toString(score));
    520         return sb.toString();
    521     }
    522 
    523     /** Implement the Parcelable interface {@hide} */
    524     public int describeContents() {
    525         return 0;
    526     }
    527 
    528     /** Implement the Parcelable interface {@hide} */
    529     public void writeToParcel(Parcel dest, int flags) {
    530         dest.writeInt(mNetworkId);
    531         dest.writeInt(mRssi);
    532         dest.writeInt(mLinkSpeed);
    533         dest.writeInt(mFrequency);
    534         if (mIpAddress != null) {
    535             dest.writeByte((byte)1);
    536             dest.writeByteArray(mIpAddress.getAddress());
    537         } else {
    538             dest.writeByte((byte)0);
    539         }
    540         if (mWifiSsid != null) {
    541             dest.writeInt(1);
    542             mWifiSsid.writeToParcel(dest, flags);
    543         } else {
    544             dest.writeInt(0);
    545         }
    546         dest.writeString(mBSSID);
    547         dest.writeString(mMacAddress);
    548         dest.writeInt(mMeteredHint ? 1 : 0);
    549         dest.writeInt(score);
    550         dest.writeDouble(txSuccessRate);
    551         dest.writeDouble(txRetriesRate);
    552         dest.writeDouble(txBadRate);
    553         dest.writeDouble(rxSuccessRate);
    554         dest.writeInt(badRssiCount);
    555         dest.writeInt(lowRssiCount);
    556         mSupplicantState.writeToParcel(dest, flags);
    557     }
    558 
    559     /** Implement the Parcelable interface {@hide} */
    560     public static final Creator<WifiInfo> CREATOR =
    561         new Creator<WifiInfo>() {
    562             public WifiInfo createFromParcel(Parcel in) {
    563                 WifiInfo info = new WifiInfo();
    564                 info.setNetworkId(in.readInt());
    565                 info.setRssi(in.readInt());
    566                 info.setLinkSpeed(in.readInt());
    567                 info.setFrequency(in.readInt());
    568                 if (in.readByte() == 1) {
    569                     try {
    570                         info.setInetAddress(InetAddress.getByAddress(in.createByteArray()));
    571                     } catch (UnknownHostException e) {}
    572                 }
    573                 if (in.readInt() == 1) {
    574                     info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in);
    575                 }
    576                 info.mBSSID = in.readString();
    577                 info.mMacAddress = in.readString();
    578                 info.mMeteredHint = in.readInt() != 0;
    579                 info.score = in.readInt();
    580                 info.txSuccessRate = in.readDouble();
    581                 info.txRetriesRate = in.readDouble();
    582                 info.txBadRate = in.readDouble();
    583                 info.rxSuccessRate = in.readDouble();
    584                 info.badRssiCount = in.readInt();
    585                 info.lowRssiCount = in.readInt();
    586                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
    587                 return info;
    588             }
    589 
    590             public WifiInfo[] newArray(int size) {
    591                 return new WifiInfo[size];
    592             }
    593         };
    594 }
    595