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