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.lang.Math;
     26 import java.net.InetAddress;
     27 import java.net.Inet4Address;
     28 import java.net.UnknownHostException;
     29 import java.util.EnumMap;
     30 import java.util.Locale;
     31 
     32 /**
     33  * Describes the state of any Wifi connection that is active or
     34  * is in the process of being set up.
     35  */
     36 public class WifiInfo implements Parcelable {
     37     private static final String TAG = "WifiInfo";
     38     /**
     39      * This is the map described in the Javadoc comment above. The positions
     40      * of the elements of the array must correspond to the ordinal values
     41      * of <code>DetailedState</code>.
     42      */
     43     private static final EnumMap<SupplicantState, DetailedState> stateMap =
     44             new EnumMap<SupplicantState, DetailedState>(SupplicantState.class);
     45 
     46     /**
     47      * Default MAC address reported to a client that does not have the
     48      * android.permission.LOCAL_MAC_ADDRESS permission.
     49      *
     50      * @hide
     51      */
     52     public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
     53 
     54     static {
     55         stateMap.put(SupplicantState.DISCONNECTED, DetailedState.DISCONNECTED);
     56         stateMap.put(SupplicantState.INTERFACE_DISABLED, DetailedState.DISCONNECTED);
     57         stateMap.put(SupplicantState.INACTIVE, DetailedState.IDLE);
     58         stateMap.put(SupplicantState.SCANNING, DetailedState.SCANNING);
     59         stateMap.put(SupplicantState.AUTHENTICATING, DetailedState.CONNECTING);
     60         stateMap.put(SupplicantState.ASSOCIATING, DetailedState.CONNECTING);
     61         stateMap.put(SupplicantState.ASSOCIATED, DetailedState.CONNECTING);
     62         stateMap.put(SupplicantState.FOUR_WAY_HANDSHAKE, DetailedState.AUTHENTICATING);
     63         stateMap.put(SupplicantState.GROUP_HANDSHAKE, DetailedState.AUTHENTICATING);
     64         stateMap.put(SupplicantState.COMPLETED, DetailedState.OBTAINING_IPADDR);
     65         stateMap.put(SupplicantState.DORMANT, DetailedState.DISCONNECTED);
     66         stateMap.put(SupplicantState.UNINITIALIZED, DetailedState.IDLE);
     67         stateMap.put(SupplicantState.INVALID, DetailedState.FAILED);
     68     }
     69 
     70     private SupplicantState mSupplicantState;
     71     private String mBSSID;
     72     private WifiSsid mWifiSsid;
     73     private int mNetworkId;
     74 
     75     /** @hide **/
     76     public static final int INVALID_RSSI = -127;
     77 
     78     /** @hide **/
     79     public static final int MIN_RSSI = -126;
     80 
     81     /** @hide **/
     82     public static final int MAX_RSSI = 200;
     83 
     84 
     85     /**
     86      * Received Signal Strength Indicator
     87      */
     88     private int mRssi;
     89 
     90     /**
     91      * Link speed in Mbps
     92      */
     93     public static final String LINK_SPEED_UNITS = "Mbps";
     94     private int mLinkSpeed;
     95 
     96     /**
     97      * Frequency in MHz
     98      */
     99     public static final String FREQUENCY_UNITS = "MHz";
    100     private int mFrequency;
    101 
    102     private InetAddress mIpAddress;
    103     private String mMacAddress = DEFAULT_MAC_ADDRESS;
    104 
    105     private boolean mEphemeral;
    106 
    107     /**
    108      * Running total count of lost (not ACKed) transmitted unicast data packets.
    109      * @hide
    110      */
    111     public long txBad;
    112     /**
    113      * Running total count of transmitted unicast data retry packets.
    114      * @hide
    115      */
    116     public long txRetries;
    117     /**
    118      * Running total count of successfully transmitted (ACKed) unicast data packets.
    119      * @hide
    120      */
    121     public long txSuccess;
    122     /**
    123      * Running total count of received unicast data packets.
    124      * @hide
    125      */
    126     public long rxSuccess;
    127 
    128     /**
    129      * Average rate of lost transmitted packets, in units of packets per 5 seconds.
    130      * @hide
    131      */
    132     public double txBadRate;
    133     /**
    134      * Average rate of transmitted retry packets, in units of packets per 5 seconds.
    135      * @hide
    136      */
    137     public double txRetriesRate;
    138     /**
    139      * Average rate of successfully transmitted unicast packets, in units of packets per 5 seconds.
    140      * @hide
    141      */
    142     public double txSuccessRate;
    143     /**
    144      * Average rate of received unicast data packets, in units of packets per 5 seconds.
    145      * @hide
    146      */
    147     public double rxSuccessRate;
    148 
    149     private static final long RESET_TIME_STAMP = Long.MIN_VALUE;
    150     private static final long FILTER_TIME_CONSTANT = 3000;
    151     /**
    152      * This factor is used to adjust the rate output under the new algorithm
    153      * such that the result is comparable to the previous algorithm.
    154      * This actually converts from unit 'packets per second' to 'packets per 5 seconds'.
    155      */
    156     private static final long OUTPUT_SCALE_FACTOR = 5;
    157     private long mLastPacketCountUpdateTimeStamp;
    158 
    159     /**
    160      * @hide
    161      */
    162     public int badRssiCount;
    163 
    164     /**
    165      * @hide
    166      */
    167     public int linkStuckCount;
    168 
    169     /**
    170      * @hide
    171      */
    172     public int lowRssiCount;
    173 
    174     /**
    175      * @hide
    176      */
    177     public int score;
    178 
    179     /**
    180      * @hide
    181      */
    182     public void updatePacketRates(WifiLinkLayerStats stats, long timeStamp) {
    183         if (stats != null) {
    184             long txgood = stats.txmpdu_be + stats.txmpdu_bk + stats.txmpdu_vi + stats.txmpdu_vo;
    185             long txretries = stats.retries_be + stats.retries_bk
    186                     + stats.retries_vi + stats.retries_vo;
    187             long rxgood = stats.rxmpdu_be + stats.rxmpdu_bk + stats.rxmpdu_vi + stats.rxmpdu_vo;
    188             long txbad = stats.lostmpdu_be + stats.lostmpdu_bk
    189                     + stats.lostmpdu_vi + stats.lostmpdu_vo;
    190 
    191             if (mLastPacketCountUpdateTimeStamp != RESET_TIME_STAMP
    192                     && mLastPacketCountUpdateTimeStamp < timeStamp
    193                     && txBad <= txbad
    194                     && txSuccess <= txgood
    195                     && rxSuccess <= rxgood
    196                     && txRetries <= txretries) {
    197                     long timeDelta = timeStamp - mLastPacketCountUpdateTimeStamp;
    198                     double lastSampleWeight = Math.exp(-1.0 * timeDelta / FILTER_TIME_CONSTANT);
    199                     double currentSampleWeight = 1.0 - lastSampleWeight;
    200 
    201                     txBadRate = txBadRate * lastSampleWeight
    202                         + (txbad - txBad) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta
    203                         * currentSampleWeight;
    204                     txSuccessRate = txSuccessRate * lastSampleWeight
    205                         + (txgood - txSuccess) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta
    206                         * currentSampleWeight;
    207                     rxSuccessRate = rxSuccessRate * lastSampleWeight
    208                         + (rxgood - rxSuccess) * OUTPUT_SCALE_FACTOR * 1000 / timeDelta
    209                         * currentSampleWeight;
    210                     txRetriesRate = txRetriesRate * lastSampleWeight
    211                         + (txretries - txRetries) * OUTPUT_SCALE_FACTOR * 1000/ timeDelta
    212                         * currentSampleWeight;
    213             } else {
    214                 txBadRate = 0;
    215                 txSuccessRate = 0;
    216                 rxSuccessRate = 0;
    217                 txRetriesRate = 0;
    218             }
    219             txBad = txbad;
    220             txSuccess = txgood;
    221             rxSuccess = rxgood;
    222             txRetries = txretries;
    223             mLastPacketCountUpdateTimeStamp = timeStamp;
    224         } else {
    225             txBad = 0;
    226             txSuccess = 0;
    227             rxSuccess = 0;
    228             txRetries = 0;
    229             txBadRate = 0;
    230             txSuccessRate = 0;
    231             rxSuccessRate = 0;
    232             txRetriesRate = 0;
    233             mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
    234         }
    235     }
    236 
    237 
    238     /**
    239      * This function is less powerful and used if the WifiLinkLayerStats API is not implemented
    240      * at the Wifi HAL
    241      * @hide
    242      */
    243     public void updatePacketRates(long txPackets, long rxPackets) {
    244         //paranoia
    245         txBad = 0;
    246         txRetries = 0;
    247         txBadRate = 0;
    248         txRetriesRate = 0;
    249         if (txSuccess <= txPackets && rxSuccess <= rxPackets) {
    250             txSuccessRate = (txSuccessRate * 0.5)
    251                     + ((double) (txPackets - txSuccess) * 0.5);
    252             rxSuccessRate = (rxSuccessRate * 0.5)
    253                     + ((double) (rxPackets - rxSuccess) * 0.5);
    254         } else {
    255             txBadRate = 0;
    256             txRetriesRate = 0;
    257         }
    258         txSuccess = txPackets;
    259         rxSuccess = rxPackets;
    260     }
    261 
    262         /**
    263          * Flag indicating that AP has hinted that upstream connection is metered,
    264          * and sensitive to heavy data transfers.
    265          */
    266     private boolean mMeteredHint;
    267 
    268     /** @hide */
    269     public WifiInfo() {
    270         mWifiSsid = null;
    271         mBSSID = null;
    272         mNetworkId = -1;
    273         mSupplicantState = SupplicantState.UNINITIALIZED;
    274         mRssi = INVALID_RSSI;
    275         mLinkSpeed = -1;
    276         mFrequency = -1;
    277         mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
    278     }
    279 
    280     /** @hide */
    281     public void reset() {
    282         setInetAddress(null);
    283         setBSSID(null);
    284         setSSID(null);
    285         setNetworkId(-1);
    286         setRssi(INVALID_RSSI);
    287         setLinkSpeed(-1);
    288         setFrequency(-1);
    289         setMeteredHint(false);
    290         setEphemeral(false);
    291         txBad = 0;
    292         txSuccess = 0;
    293         rxSuccess = 0;
    294         txRetries = 0;
    295         txBadRate = 0;
    296         txSuccessRate = 0;
    297         rxSuccessRate = 0;
    298         txRetriesRate = 0;
    299         lowRssiCount = 0;
    300         badRssiCount = 0;
    301         linkStuckCount = 0;
    302         score = 0;
    303         mLastPacketCountUpdateTimeStamp = RESET_TIME_STAMP;
    304     }
    305 
    306     /**
    307      * Copy constructor
    308      * @hide
    309      */
    310     public WifiInfo(WifiInfo source) {
    311         if (source != null) {
    312             mSupplicantState = source.mSupplicantState;
    313             mBSSID = source.mBSSID;
    314             mWifiSsid = source.mWifiSsid;
    315             mNetworkId = source.mNetworkId;
    316             mRssi = source.mRssi;
    317             mLinkSpeed = source.mLinkSpeed;
    318             mFrequency = source.mFrequency;
    319             mIpAddress = source.mIpAddress;
    320             mMacAddress = source.mMacAddress;
    321             mMeteredHint = source.mMeteredHint;
    322             mEphemeral = source.mEphemeral;
    323             txBad = source.txBad;
    324             txRetries = source.txRetries;
    325             txSuccess = source.txSuccess;
    326             rxSuccess = source.rxSuccess;
    327             txBadRate = source.txBadRate;
    328             txRetriesRate = source.txRetriesRate;
    329             txSuccessRate = source.txSuccessRate;
    330             rxSuccessRate = source.rxSuccessRate;
    331             mLastPacketCountUpdateTimeStamp =
    332                 source.mLastPacketCountUpdateTimeStamp;
    333             score = source.score;
    334             badRssiCount = source.badRssiCount;
    335             lowRssiCount = source.lowRssiCount;
    336             linkStuckCount = source.linkStuckCount;
    337         }
    338     }
    339 
    340     /** @hide */
    341     public void setSSID(WifiSsid wifiSsid) {
    342         mWifiSsid = wifiSsid;
    343     }
    344 
    345     /**
    346      * Returns the service set identifier (SSID) of the current 802.11 network.
    347      * If the SSID can be decoded as UTF-8, it will be returned surrounded by double
    348      * quotation marks. Otherwise, it is returned as a string of hex digits. The
    349      * SSID may be &lt;unknown ssid&gt; if there is no network currently connected,
    350      * or if the caller has insufficient permissions to access the SSID.
    351      * @return the SSID
    352      */
    353     public String getSSID() {
    354         if (mWifiSsid != null) {
    355             String unicode = mWifiSsid.toString();
    356             if (!TextUtils.isEmpty(unicode)) {
    357                 return "\"" + unicode + "\"";
    358             } else {
    359                 String hex = mWifiSsid.getHexString();
    360                 return (hex != null) ? hex : WifiSsid.NONE;
    361             }
    362         }
    363         return WifiSsid.NONE;
    364     }
    365 
    366     /** @hide */
    367     public WifiSsid getWifiSsid() {
    368         return mWifiSsid;
    369     }
    370 
    371     /** @hide */
    372     public void setBSSID(String BSSID) {
    373         mBSSID = BSSID;
    374     }
    375 
    376     /**
    377      * Return the basic service set identifier (BSSID) of the current access point.
    378      * The BSSID may be {@code null} if there is no network currently connected.
    379      * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX}
    380      */
    381     public String getBSSID() {
    382         return mBSSID;
    383     }
    384 
    385     /**
    386      * Returns the received signal strength indicator of the current 802.11
    387      * network, in dBm.
    388      *
    389      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
    390      * an absolute signal level which can be displayed to a user.
    391      *
    392      * @return the RSSI.
    393      */
    394     public int getRssi() {
    395         return mRssi;
    396     }
    397 
    398     /** @hide */
    399     public void setRssi(int rssi) {
    400         if (rssi < INVALID_RSSI)
    401             rssi = INVALID_RSSI;
    402         if (rssi > MAX_RSSI)
    403             rssi = MAX_RSSI;
    404         mRssi = rssi;
    405     }
    406 
    407     /**
    408      * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
    409      * @return the link speed.
    410      * @see #LINK_SPEED_UNITS
    411      */
    412     public int getLinkSpeed() {
    413         return mLinkSpeed;
    414     }
    415 
    416     /** @hide */
    417     public void setLinkSpeed(int linkSpeed) {
    418         this.mLinkSpeed = linkSpeed;
    419     }
    420 
    421     /**
    422      * Returns the current frequency in {@link #FREQUENCY_UNITS}.
    423      * @return the frequency.
    424      * @see #FREQUENCY_UNITS
    425      */
    426     public int getFrequency() {
    427         return mFrequency;
    428     }
    429 
    430     /** @hide */
    431     public void setFrequency(int frequency) {
    432         this.mFrequency = frequency;
    433     }
    434 
    435     /**
    436      * @hide
    437      * TODO: makes real freq boundaries
    438      */
    439     public boolean is24GHz() {
    440         return ScanResult.is24GHz(mFrequency);
    441     }
    442 
    443     /**
    444      * @hide
    445      * TODO: makes real freq boundaries
    446      */
    447     public boolean is5GHz() {
    448         return ScanResult.is5GHz(mFrequency);
    449     }
    450 
    451     /**
    452      * @hide
    453      * This returns txSuccessRate in packets per second.
    454      */
    455     public double getTxSuccessRatePps() {
    456         return txSuccessRate / OUTPUT_SCALE_FACTOR;
    457     }
    458 
    459     /**
    460      * @hide
    461      * This returns rxSuccessRate in packets per second.
    462      */
    463     public double getRxSuccessRatePps() {
    464         return rxSuccessRate / OUTPUT_SCALE_FACTOR;
    465     }
    466 
    467     /**
    468      * Record the MAC address of the WLAN interface
    469      * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
    470      * @hide
    471      */
    472     public void setMacAddress(String macAddress) {
    473         this.mMacAddress = macAddress;
    474     }
    475 
    476     public String getMacAddress() {
    477         return mMacAddress;
    478     }
    479 
    480     /**
    481      * @return true if {@link #getMacAddress()} has a real MAC address.
    482      *
    483      * @hide
    484      */
    485     public boolean hasRealMacAddress() {
    486         return mMacAddress != null && !DEFAULT_MAC_ADDRESS.equals(mMacAddress);
    487     }
    488 
    489     /**
    490      * Indicates if we've dynamically detected this active network connection as
    491      * being metered.
    492      *
    493      * @see WifiConfiguration#isMetered(WifiConfiguration, WifiInfo)
    494      * @hide
    495      */
    496     public void setMeteredHint(boolean meteredHint) {
    497         mMeteredHint = meteredHint;
    498     }
    499 
    500     /** {@hide} */
    501     public boolean getMeteredHint() {
    502         return mMeteredHint;
    503     }
    504 
    505     /** {@hide} */
    506     public void setEphemeral(boolean ephemeral) {
    507         mEphemeral = ephemeral;
    508     }
    509 
    510     /** {@hide} */
    511     public boolean isEphemeral() {
    512         return mEphemeral;
    513     }
    514 
    515     /** @hide */
    516     public void setNetworkId(int id) {
    517         mNetworkId = id;
    518     }
    519 
    520     /**
    521      * Each configured network has a unique small integer ID, used to identify
    522      * the network when performing operations on the supplicant. This method
    523      * returns the ID for the currently connected network.
    524      * @return the network ID, or -1 if there is no currently connected network
    525      */
    526     public int getNetworkId() {
    527         return mNetworkId;
    528     }
    529 
    530     /**
    531      * Return the detailed state of the supplicant's negotiation with an
    532      * access point, in the form of a {@link SupplicantState SupplicantState} object.
    533      * @return the current {@link SupplicantState SupplicantState}
    534      */
    535     public SupplicantState getSupplicantState() {
    536         return mSupplicantState;
    537     }
    538 
    539     /** @hide */
    540     public void setSupplicantState(SupplicantState state) {
    541         mSupplicantState = state;
    542     }
    543 
    544     /** @hide */
    545     public void setInetAddress(InetAddress address) {
    546         mIpAddress = address;
    547     }
    548 
    549     public int getIpAddress() {
    550         int result = 0;
    551         if (mIpAddress instanceof Inet4Address) {
    552             result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
    553         }
    554         return result;
    555     }
    556 
    557     /**
    558      * @return {@code true} if this network does not broadcast its SSID, so an
    559      * SSID-specific probe request must be used for scans.
    560      */
    561     public boolean getHiddenSSID() {
    562         if (mWifiSsid == null) return false;
    563         return mWifiSsid.isHidden();
    564     }
    565 
    566    /**
    567      * Map a supplicant state into a fine-grained network connectivity state.
    568      * @param suppState the supplicant state
    569      * @return the corresponding {@link DetailedState}
    570      */
    571     public static DetailedState getDetailedStateOf(SupplicantState suppState) {
    572         return stateMap.get(suppState);
    573     }
    574 
    575     /**
    576      * Set the <code>SupplicantState</code> from the string name
    577      * of the state.
    578      * @param stateName the name of the state, as a <code>String</code> returned
    579      * in an event sent by {@code wpa_supplicant}.
    580      */
    581     void setSupplicantState(String stateName) {
    582         mSupplicantState = valueOf(stateName);
    583     }
    584 
    585     static SupplicantState valueOf(String stateName) {
    586         if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName))
    587             return SupplicantState.FOUR_WAY_HANDSHAKE;
    588         else {
    589             try {
    590                 return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT));
    591             } catch (IllegalArgumentException e) {
    592                 return SupplicantState.INVALID;
    593             }
    594         }
    595     }
    596 
    597     /** {@hide} */
    598     public static String removeDoubleQuotes(String string) {
    599         if (string == null) return null;
    600         final int length = string.length();
    601         if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
    602             return string.substring(1, length - 1);
    603         }
    604         return string;
    605     }
    606 
    607     @Override
    608     public String toString() {
    609         StringBuffer sb = new StringBuffer();
    610         String none = "<none>";
    611 
    612         sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
    613             append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
    614             append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
    615             append(", Supplicant state: ").
    616             append(mSupplicantState == null ? none : mSupplicantState).
    617             append(", RSSI: ").append(mRssi).
    618             append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
    619             append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
    620             append(", Net ID: ").append(mNetworkId).
    621             append(", Metered hint: ").append(mMeteredHint).
    622             append(", score: ").append(Integer.toString(score));
    623         return sb.toString();
    624     }
    625 
    626     /** Implement the Parcelable interface {@hide} */
    627     public int describeContents() {
    628         return 0;
    629     }
    630 
    631     /** Implement the Parcelable interface {@hide} */
    632     public void writeToParcel(Parcel dest, int flags) {
    633         dest.writeInt(mNetworkId);
    634         dest.writeInt(mRssi);
    635         dest.writeInt(mLinkSpeed);
    636         dest.writeInt(mFrequency);
    637         if (mIpAddress != null) {
    638             dest.writeByte((byte)1);
    639             dest.writeByteArray(mIpAddress.getAddress());
    640         } else {
    641             dest.writeByte((byte)0);
    642         }
    643         if (mWifiSsid != null) {
    644             dest.writeInt(1);
    645             mWifiSsid.writeToParcel(dest, flags);
    646         } else {
    647             dest.writeInt(0);
    648         }
    649         dest.writeString(mBSSID);
    650         dest.writeString(mMacAddress);
    651         dest.writeInt(mMeteredHint ? 1 : 0);
    652         dest.writeInt(mEphemeral ? 1 : 0);
    653         dest.writeInt(score);
    654         dest.writeDouble(txSuccessRate);
    655         dest.writeDouble(txRetriesRate);
    656         dest.writeDouble(txBadRate);
    657         dest.writeDouble(rxSuccessRate);
    658         dest.writeInt(badRssiCount);
    659         dest.writeInt(lowRssiCount);
    660         mSupplicantState.writeToParcel(dest, flags);
    661     }
    662 
    663     /** Implement the Parcelable interface {@hide} */
    664     public static final Creator<WifiInfo> CREATOR =
    665         new Creator<WifiInfo>() {
    666             public WifiInfo createFromParcel(Parcel in) {
    667                 WifiInfo info = new WifiInfo();
    668                 info.setNetworkId(in.readInt());
    669                 info.setRssi(in.readInt());
    670                 info.setLinkSpeed(in.readInt());
    671                 info.setFrequency(in.readInt());
    672                 if (in.readByte() == 1) {
    673                     try {
    674                         info.setInetAddress(InetAddress.getByAddress(in.createByteArray()));
    675                     } catch (UnknownHostException e) {}
    676                 }
    677                 if (in.readInt() == 1) {
    678                     info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in);
    679                 }
    680                 info.mBSSID = in.readString();
    681                 info.mMacAddress = in.readString();
    682                 info.mMeteredHint = in.readInt() != 0;
    683                 info.mEphemeral = in.readInt() != 0;
    684                 info.score = in.readInt();
    685                 info.txSuccessRate = in.readDouble();
    686                 info.txRetriesRate = in.readDouble();
    687                 info.txBadRate = in.readDouble();
    688                 info.rxSuccessRate = in.readDouble();
    689                 info.badRssiCount = in.readInt();
    690                 info.lowRssiCount = in.readInt();
    691                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
    692                 return info;
    693             }
    694 
    695             public WifiInfo[] newArray(int size) {
    696                 return new WifiInfo[size];
    697             }
    698         };
    699 }
    700