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