WifiInfo.java revision 4eeecb25509f91ac7a6e2cde76dac782fbec5360
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
17package android.net.wifi;
18
19import android.os.Parcelable;
20import android.os.Parcel;
21import android.net.NetworkInfo.DetailedState;
22import android.net.NetworkUtils;
23import android.text.TextUtils;
24
25import java.net.InetAddress;
26import java.net.Inet4Address;
27import java.net.UnknownHostException;
28import java.util.EnumMap;
29import 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 */
35public 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 {@code null} 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     * @return the RSSI, in the range -127 to 200
327     */
328    public int getRssi() {
329        return mRssi;
330    }
331
332    /** @hide */
333    public void setRssi(int rssi) {
334        if (rssi < INVALID_RSSI)
335            rssi = INVALID_RSSI;
336        if (rssi > MAX_RSSI)
337            rssi = MAX_RSSI;
338        mRssi = rssi;
339    }
340
341    /**
342     * Returns the current link speed in {@link #LINK_SPEED_UNITS}.
343     * @return the link speed.
344     * @see #LINK_SPEED_UNITS
345     */
346    public int getLinkSpeed() {
347        return mLinkSpeed;
348    }
349
350    /** @hide */
351    public void setLinkSpeed(int linkSpeed) {
352        this.mLinkSpeed = linkSpeed;
353    }
354
355    /**
356     * Returns the current frequency in {@link #FREQUENCY_UNITS}.
357     * @return the frequency.
358     * @see #FREQUENCY_UNITS
359     */
360    public int getFrequency() {
361        return mFrequency;
362    }
363
364    /** @hide */
365    public void setFrequency(int frequency) {
366        this.mFrequency = frequency;
367    }
368
369    /**
370     * @hide
371     * TODO: makes real freq boundaries
372     */
373    public boolean is24GHz() {
374        return ScanResult.is24GHz(mFrequency);
375    }
376
377    /**
378     * @hide
379     * TODO: makes real freq boundaries
380     */
381    public boolean is5GHz() {
382        return ScanResult.is5GHz(mFrequency);
383    }
384
385    /**
386     * Record the MAC address of the WLAN interface
387     * @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
388     * @hide
389     */
390    public void setMacAddress(String macAddress) {
391        this.mMacAddress = macAddress;
392    }
393
394    public String getMacAddress() {
395        return mMacAddress;
396    }
397
398    /** {@hide} */
399    public void setMeteredHint(boolean meteredHint) {
400        mMeteredHint = meteredHint;
401    }
402
403    /** {@hide} */
404    public boolean getMeteredHint() {
405        return mMeteredHint;
406    }
407
408    /** @hide */
409    public void setNetworkId(int id) {
410        mNetworkId = id;
411    }
412
413    /**
414     * Each configured network has a unique small integer ID, used to identify
415     * the network when performing operations on the supplicant. This method
416     * returns the ID for the currently connected network.
417     * @return the network ID, or -1 if there is no currently connected network
418     */
419    public int getNetworkId() {
420        return mNetworkId;
421    }
422
423    /**
424     * Return the detailed state of the supplicant's negotiation with an
425     * access point, in the form of a {@link SupplicantState SupplicantState} object.
426     * @return the current {@link SupplicantState SupplicantState}
427     */
428    public SupplicantState getSupplicantState() {
429        return mSupplicantState;
430    }
431
432    /** @hide */
433    public void setSupplicantState(SupplicantState state) {
434        mSupplicantState = state;
435    }
436
437    /** @hide */
438    public void setInetAddress(InetAddress address) {
439        mIpAddress = address;
440    }
441
442    public int getIpAddress() {
443        int result = 0;
444        if (mIpAddress instanceof Inet4Address) {
445            result = NetworkUtils.inetAddressToInt((Inet4Address)mIpAddress);
446        }
447        return result;
448    }
449
450    /**
451     * @return {@code true} if this network does not broadcast its SSID, so an
452     * SSID-specific probe request must be used for scans.
453     */
454    public boolean getHiddenSSID() {
455        return mWifiSsid.isHidden();
456    }
457
458   /**
459     * Map a supplicant state into a fine-grained network connectivity state.
460     * @param suppState the supplicant state
461     * @return the corresponding {@link DetailedState}
462     */
463    public static DetailedState getDetailedStateOf(SupplicantState suppState) {
464        return stateMap.get(suppState);
465    }
466
467    /**
468     * Set the <code>SupplicantState</code> from the string name
469     * of the state.
470     * @param stateName the name of the state, as a <code>String</code> returned
471     * in an event sent by {@code wpa_supplicant}.
472     */
473    void setSupplicantState(String stateName) {
474        mSupplicantState = valueOf(stateName);
475    }
476
477    static SupplicantState valueOf(String stateName) {
478        if ("4WAY_HANDSHAKE".equalsIgnoreCase(stateName))
479            return SupplicantState.FOUR_WAY_HANDSHAKE;
480        else {
481            try {
482                return SupplicantState.valueOf(stateName.toUpperCase(Locale.ROOT));
483            } catch (IllegalArgumentException e) {
484                return SupplicantState.INVALID;
485            }
486        }
487    }
488
489    /** {@hide} */
490    public static String removeDoubleQuotes(String string) {
491        if (string == null) return null;
492        final int length = string.length();
493        if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
494            return string.substring(1, length - 1);
495        }
496        return string;
497    }
498
499    @Override
500    public String toString() {
501        StringBuffer sb = new StringBuffer();
502        String none = "<none>";
503
504        sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
505            append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
506            append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
507            append(", Supplicant state: ").
508            append(mSupplicantState == null ? none : mSupplicantState).
509            append(", RSSI: ").append(mRssi).
510            append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
511            append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
512            append(", Net ID: ").append(mNetworkId).
513            append(", Metered hint: ").append(mMeteredHint).
514            append(", score: ").append(Integer.toString(score));
515        return sb.toString();
516    }
517
518    /** Implement the Parcelable interface {@hide} */
519    public int describeContents() {
520        return 0;
521    }
522
523    /** Implement the Parcelable interface {@hide} */
524    public void writeToParcel(Parcel dest, int flags) {
525        dest.writeInt(mNetworkId);
526        dest.writeInt(mRssi);
527        dest.writeInt(mLinkSpeed);
528        dest.writeInt(mFrequency);
529        if (mIpAddress != null) {
530            dest.writeByte((byte)1);
531            dest.writeByteArray(mIpAddress.getAddress());
532        } else {
533            dest.writeByte((byte)0);
534        }
535        if (mWifiSsid != null) {
536            dest.writeInt(1);
537            mWifiSsid.writeToParcel(dest, flags);
538        } else {
539            dest.writeInt(0);
540        }
541        dest.writeString(mBSSID);
542        dest.writeString(mMacAddress);
543        dest.writeInt(mMeteredHint ? 1 : 0);
544        dest.writeInt(score);
545        dest.writeDouble(txSuccessRate);
546        dest.writeDouble(txRetriesRate);
547        dest.writeDouble(txBadRate);
548        dest.writeDouble(rxSuccessRate);
549        dest.writeInt(badRssiCount);
550        dest.writeInt(lowRssiCount);
551        mSupplicantState.writeToParcel(dest, flags);
552    }
553
554    /** Implement the Parcelable interface {@hide} */
555    public static final Creator<WifiInfo> CREATOR =
556        new Creator<WifiInfo>() {
557            public WifiInfo createFromParcel(Parcel in) {
558                WifiInfo info = new WifiInfo();
559                info.setNetworkId(in.readInt());
560                info.setRssi(in.readInt());
561                info.setLinkSpeed(in.readInt());
562                info.setFrequency(in.readInt());
563                if (in.readByte() == 1) {
564                    try {
565                        info.setInetAddress(InetAddress.getByAddress(in.createByteArray()));
566                    } catch (UnknownHostException e) {}
567                }
568                if (in.readInt() == 1) {
569                    info.mWifiSsid = WifiSsid.CREATOR.createFromParcel(in);
570                }
571                info.mBSSID = in.readString();
572                info.mMacAddress = in.readString();
573                info.mMeteredHint = in.readInt() != 0;
574                info.score = in.readInt();
575                info.txSuccessRate = in.readDouble();
576                info.txRetriesRate = in.readDouble();
577                info.txBadRate = in.readDouble();
578                info.rxSuccessRate = in.readDouble();
579                info.badRssiCount = in.readInt();
580                info.lowRssiCount = in.readInt();
581                info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
582                return info;
583            }
584
585            public WifiInfo[] newArray(int size) {
586                return new WifiInfo[size];
587            }
588        };
589}
590