ScanResult.java revision c0e86b2e90d46cfa51519e8e3d91aad18ffcdb09
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.Parcel;
20import android.os.Parcelable;
21
22import java.util.ArrayList;
23import java.util.List;
24
25/**
26 * Describes information about a detected access point. In addition
27 * to the attributes described here, the supplicant keeps track of
28 * {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
29 * but does not currently report them to external clients.
30 */
31public class ScanResult implements Parcelable {
32    /**
33     * The network name.
34     */
35    public String SSID;
36
37    /**
38     * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide
39     */
40    public WifiSsid wifiSsid;
41
42    /**
43     * The address of the access point.
44     */
45    public String BSSID;
46    /**
47     * Describes the authentication, key management, and encryption schemes
48     * supported by the access point.
49     */
50    public String capabilities;
51    /**
52     * The detected signal level in dBm, also known as the RSSI.
53     *
54     * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
55     * an absolute signal level which can be displayed to a user.
56     */
57    public int level;
58    /**
59     * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating
60     * with the access point.
61     */
62    public int frequency;
63
64   /**
65    * AP Channel bandwidth is 20 MHZ
66    */
67    public static final int CHANNEL_WIDTH_20MHZ = 0;
68   /**
69    * AP Channel bandwidth is 40 MHZ
70    */
71    public static final int CHANNEL_WIDTH_40MHZ = 1;
72   /**
73    * AP Channel bandwidth is 80 MHZ
74    */
75    public static final int CHANNEL_WIDTH_80MHZ = 2;
76   /**
77    * AP Channel bandwidth is 160 MHZ
78    */
79    public static final int CHANNEL_WIDTH_160MHZ = 3;
80   /**
81    * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
82    */
83    public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
84
85   /**
86    * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
87    * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
88    * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
89    */
90    public int channelWidth;
91
92    /**
93     * Not used if the AP bandwidth is 20 MHz
94     * If the AP use 40, 80 or 160 MHz, this is the center frequency (in MHz)
95     * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz)
96     */
97    public int centerFreq0;
98
99    /**
100     * Only used if the AP bandwidth is 80 + 80 MHz
101     * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz)
102     */
103    public int centerFreq1;
104
105    /**
106     * @deprecated use is80211mcResponder() instead
107     * @hide
108     */
109    public boolean is80211McRTTResponder;
110
111    /**
112     * timestamp in microseconds (since boot) when
113     * this result was last seen.
114     */
115    public long timestamp;
116
117    /**
118     * Timestamp representing date when this result was last seen, in milliseconds from 1970
119     * {@hide}
120     */
121    public long seen;
122
123    /**
124     * If the scan result is a valid autojoin candidate
125     * {@hide}
126     */
127    public int isAutoJoinCandidate;
128
129    /**
130     * @hide
131     * Update RSSI of the scan result
132     * @param previousRssi
133     * @param previousSeen
134     * @param maxAge
135     */
136    public void averageRssi(int previousRssi, long previousSeen, int maxAge) {
137
138        if (seen == 0) {
139            seen = System.currentTimeMillis();
140        }
141        long age = seen - previousSeen;
142
143        if (previousSeen > 0 && age > 0 && age < maxAge/2) {
144            // Average the RSSI with previously seen instances of this scan result
145            double alpha = 0.5 - (double) age / (double) maxAge;
146            level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha);
147        }
148    }
149
150    /** @hide */
151    public static final int ENABLED                                          = 0;
152    /** @hide */
153    public static final int AUTO_ROAM_DISABLED                               = 16;
154    /** @hide */
155    public static final int AUTO_JOIN_DISABLED                               = 32;
156    /** @hide */
157    public static final int AUTHENTICATION_ERROR                              = 128;
158
159    /**
160     * Status: indicating join status
161     * @hide
162     */
163    public int autoJoinStatus;
164
165    /**
166     * num IP configuration failures
167     * @hide
168     */
169    public int numIpConfigFailures;
170
171    /**
172     * @hide
173     * Last time we blacklisted the ScanResult
174     */
175    public long blackListTimestamp;
176
177    /** @hide **/
178    public void setAutoJoinStatus(int status) {
179        if (status < 0) status = 0;
180        if (status == 0) {
181            blackListTimestamp = 0;
182        }  else if (status > autoJoinStatus) {
183            blackListTimestamp = System.currentTimeMillis();
184        }
185        autoJoinStatus = status;
186    }
187
188    /**
189     * Status: indicating the scan result is not a result
190     * that is part of user's saved configurations
191     * @hide
192     */
193    public boolean untrusted;
194
195    /**
196     * Number of time we connected to it
197     * @hide
198     */
199    public int numConnection;
200
201    /**
202     * Number of time autojoin used it
203     * @hide
204     */
205    public int numUsage;
206
207    /**
208     * The approximate distance to the AP in centimeter, if available.  Else
209     * {@link UNSPECIFIED}.
210     * {@hide}
211     */
212    public int distanceCm;
213
214    /**
215     * The standard deviation of the distance to the access point, if available.
216     * Else {@link UNSPECIFIED}.
217     * {@hide}
218     */
219    public int distanceSdCm;
220
221    /** {@hide} */
222    public static final long FLAG_PASSPOINT_NETWORK               = 0x0000000000000001;
223
224    /** {@hide} */
225    public static final long FLAG_80211mc_RESPONDER               = 0x0000000000000002;
226
227    /**
228     * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}.
229     * {@hide}
230     */
231    public long flags;
232
233    /**
234     * sets a flag in {@link #flags} field
235     * @param flag flag to set
236     * @hide
237     */
238    public void setFlag(long flag) {
239        flags |= flag;
240    }
241
242    /**
243     * clears a flag in {@link #flags} field
244     * @param flag flag to set
245     * @hide
246     */
247    public void clearFlag(long flag) {
248        flags &= ~flag;
249    }
250
251    public boolean is80211mcResponder() {
252        return (flags & FLAG_80211mc_RESPONDER) != 0;
253    }
254
255    public boolean isPasspointNetwork() {
256        return (flags & FLAG_PASSPOINT_NETWORK) != 0;
257    }
258
259    /**
260     * Indicates venue name (such as 'San Francisco Airport') published by access point; only
261     * available on passpoint network and if published by access point.
262     */
263    public CharSequence venueName;
264
265    /**
266     * Indicates passpoint operator name published by access point.
267     */
268    public CharSequence operatorFriendlyName;
269
270    /**
271     * {@hide}
272     */
273    public final static int UNSPECIFIED = -1;
274    /**
275     * @hide
276     */
277    public boolean is24GHz() {
278        return ScanResult.is24GHz(frequency);
279    }
280
281    /**
282     * @hide
283     * TODO: makes real freq boundaries
284     */
285    public static boolean is24GHz(int freq) {
286        return freq > 2400 && freq < 2500;
287    }
288
289    /**
290     * @hide
291     */
292    public boolean is5GHz() {
293        return ScanResult.is5GHz(frequency);
294    }
295
296    /**
297     * @hide
298     * TODO: makes real freq boundaries
299     */
300    public static boolean is5GHz(int freq) {
301        return freq > 4900 && freq < 5900;
302    }
303
304    /**
305     *  @hide
306     * anqp lines from supplicant BSS response
307     */
308    public List<String> anqpLines;
309
310    /**
311     *  @hide
312     * storing the raw bytes of full result IEs
313     **/
314    public byte[] bytes;
315
316    /** information elements from beacon
317     * @hide
318     */
319    public static class InformationElement {
320        public static final int EID_SSID = 0;
321        public static final int EID_BSS_LOAD = 11;
322        public static final int EID_RSN = 48;
323        public static final int EID_HT_OPERATION = 61;
324        public static final int EID_INTERWORKING = 107;
325        public static final int EID_ROAMING_CONSORTIUM = 111;
326        public static final int EID_EXTENDED_CAPS = 127;
327        public static final int EID_VHT_OPERATION = 192;
328        public static final int EID_VSA = 221;
329
330        public int id;
331        public byte[] bytes;
332
333        public InformationElement() {
334        }
335
336        public InformationElement(InformationElement rhs) {
337            this.id = rhs.id;
338            this.bytes = rhs.bytes.clone();
339        }
340    }
341
342    /** information elements found in the beacon
343     * @hide
344     */
345    public InformationElement informationElements[];
346
347    /** {@hide} */
348    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
349            long tsf) {
350        this.wifiSsid = wifiSsid;
351        this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
352        this.BSSID = BSSID;
353        this.capabilities = caps;
354        this.level = level;
355        this.frequency = frequency;
356        this.timestamp = tsf;
357        this.distanceCm = UNSPECIFIED;
358        this.distanceSdCm = UNSPECIFIED;
359        this.channelWidth = UNSPECIFIED;
360        this.centerFreq0 = UNSPECIFIED;
361        this.centerFreq1 = UNSPECIFIED;
362        this.flags = 0;
363    }
364
365    /** {@hide} */
366    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
367            long tsf, int distCm, int distSdCm) {
368        this.wifiSsid = wifiSsid;
369        this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
370        this.BSSID = BSSID;
371        this.capabilities = caps;
372        this.level = level;
373        this.frequency = frequency;
374        this.timestamp = tsf;
375        this.distanceCm = distCm;
376        this.distanceSdCm = distSdCm;
377        this.channelWidth = UNSPECIFIED;
378        this.centerFreq0 = UNSPECIFIED;
379        this.centerFreq1 = UNSPECIFIED;
380        this.flags = 0;
381    }
382
383    /** {@hide} */
384    public ScanResult(String Ssid, String BSSID, String caps, int level, int frequency,
385            long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
386            boolean is80211McRTTResponder) {
387        this.SSID = Ssid;
388        this.BSSID = BSSID;
389        this.capabilities = caps;
390        this.level = level;
391        this.frequency = frequency;
392        this.timestamp = tsf;
393        this.distanceCm = distCm;
394        this.distanceSdCm = distSdCm;
395        this.channelWidth = channelWidth;
396        this.centerFreq0 = centerFreq0;
397        this.centerFreq1 = centerFreq1;
398        if (is80211McRTTResponder) {
399            this.flags = FLAG_80211mc_RESPONDER;
400        } else {
401            this.flags = 0;
402        }
403    }
404
405    /** {@hide} */
406    public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, String caps, int level,
407                  int frequency, long tsf, int distCm, int distSdCm, int channelWidth,
408                  int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) {
409        this(Ssid, BSSID, caps,level, frequency, tsf, distCm, distSdCm, channelWidth, centerFreq0,
410                centerFreq1, is80211McRTTResponder);
411        this.wifiSsid = wifiSsid;
412    }
413
414    /** copy constructor {@hide} */
415    public ScanResult(ScanResult source) {
416        if (source != null) {
417            wifiSsid = source.wifiSsid;
418            SSID = source.SSID;
419            BSSID = source.BSSID;
420            capabilities = source.capabilities;
421            level = source.level;
422            frequency = source.frequency;
423            channelWidth = source.channelWidth;
424            centerFreq0 = source.centerFreq0;
425            centerFreq1 = source.centerFreq1;
426            timestamp = source.timestamp;
427            distanceCm = source.distanceCm;
428            distanceSdCm = source.distanceSdCm;
429            seen = source.seen;
430            autoJoinStatus = source.autoJoinStatus;
431            untrusted = source.untrusted;
432            numConnection = source.numConnection;
433            numUsage = source.numUsage;
434            numIpConfigFailures = source.numIpConfigFailures;
435            isAutoJoinCandidate = source.isAutoJoinCandidate;
436            venueName = source.venueName;
437            operatorFriendlyName = source.operatorFriendlyName;
438            flags = source.flags;
439        }
440    }
441
442    /** empty scan result
443     *
444     * {@hide}
445     * */
446    public ScanResult() {
447    }
448
449    @Override
450    public String toString() {
451        StringBuffer sb = new StringBuffer();
452        String none = "<none>";
453
454        sb.append("SSID: ").
455            append(wifiSsid == null ? WifiSsid.NONE : wifiSsid).
456            append(", BSSID: ").
457            append(BSSID == null ? none : BSSID).
458            append(", capabilities: ").
459            append(capabilities == null ? none : capabilities).
460            append(", level: ").
461            append(level).
462            append(", frequency: ").
463            append(frequency).
464            append(", timestamp: ").
465            append(timestamp);
466
467        sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
468                append("(cm)");
469        sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
470                append("(cm)");
471
472        sb.append(", passpoint: ");
473        sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
474        if (autoJoinStatus != 0) {
475            sb.append(", status: ").append(autoJoinStatus);
476        }
477        sb.append(", ChannelBandwidth: ").append(channelWidth);
478        sb.append(", centerFreq0: ").append(centerFreq0);
479        sb.append(", centerFreq1: ").append(centerFreq1);
480        sb.append(", 80211mcResponder: ");
481        sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
482        return sb.toString();
483    }
484
485    /** Implement the Parcelable interface {@hide} */
486    public int describeContents() {
487        return 0;
488    }
489
490    /** Implement the Parcelable interface {@hide} */
491    public void writeToParcel(Parcel dest, int flags) {
492        if (wifiSsid != null) {
493            dest.writeInt(1);
494            wifiSsid.writeToParcel(dest, flags);
495        } else {
496            dest.writeInt(0);
497        }
498        dest.writeString(SSID);
499        dest.writeString(BSSID);
500        dest.writeString(capabilities);
501        dest.writeInt(level);
502        dest.writeInt(frequency);
503        dest.writeLong(timestamp);
504        dest.writeInt(distanceCm);
505        dest.writeInt(distanceSdCm);
506        dest.writeInt(channelWidth);
507        dest.writeInt(centerFreq0);
508        dest.writeInt(centerFreq1);
509        dest.writeLong(seen);
510        dest.writeInt(autoJoinStatus);
511        dest.writeInt(untrusted ? 1 : 0);
512        dest.writeInt(numConnection);
513        dest.writeInt(numUsage);
514        dest.writeInt(numIpConfigFailures);
515        dest.writeInt(isAutoJoinCandidate);
516        dest.writeString((venueName != null) ? venueName.toString() : "");
517        dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
518        dest.writeLong(this.flags);
519
520        if (informationElements != null) {
521            dest.writeInt(informationElements.length);
522            for (int i = 0; i < informationElements.length; i++) {
523                dest.writeInt(informationElements[i].id);
524                dest.writeInt(informationElements[i].bytes.length);
525                dest.writeByteArray(informationElements[i].bytes);
526            }
527        } else {
528            dest.writeInt(0);
529        }
530
531        if (anqpLines != null) {
532            dest.writeInt(anqpLines.size());
533            for (int i = 0; i < anqpLines.size(); i++) {
534                dest.writeString(anqpLines.get(i));
535            }
536        } else {
537            dest.writeInt(0);
538        }
539    }
540
541    /** Implement the Parcelable interface {@hide} */
542    public static final Creator<ScanResult> CREATOR =
543        new Creator<ScanResult>() {
544            public ScanResult createFromParcel(Parcel in) {
545                WifiSsid wifiSsid = null;
546                if (in.readInt() == 1) {
547                    wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
548                }
549                ScanResult sr = new ScanResult(
550                    wifiSsid,
551                    in.readString(),                    /* SSID  */
552                    in.readString(),                    /* BSSID */
553                    in.readString(),                    /* capabilities */
554                    in.readInt(),                       /* level */
555                    in.readInt(),                       /* frequency */
556                    in.readLong(),                      /* timestamp */
557                    in.readInt(),                       /* distanceCm */
558                    in.readInt(),                       /* distanceSdCm */
559                    in.readInt(),                       /* channelWidth */
560                    in.readInt(),                       /* centerFreq0 */
561                    in.readInt(),                       /* centerFreq1 */
562                    false                               /* rtt responder, fixed with flags below */
563                );
564
565                sr.seen = in.readLong();
566                sr.autoJoinStatus = in.readInt();
567                sr.untrusted = in.readInt() != 0;
568                sr.numConnection = in.readInt();
569                sr.numUsage = in.readInt();
570                sr.numIpConfigFailures = in.readInt();
571                sr.isAutoJoinCandidate = in.readInt();
572                sr.venueName = in.readString();
573                sr.operatorFriendlyName = in.readString();
574                sr.flags = in.readLong();
575                int n = in.readInt();
576                if (n != 0) {
577                    sr.informationElements = new InformationElement[n];
578                    for (int i = 0; i < n; i++) {
579                        sr.informationElements[i] = new InformationElement();
580                        sr.informationElements[i].id = in.readInt();
581                        int len = in.readInt();
582                        sr.informationElements[i].bytes = new byte[len];
583                        in.readByteArray(sr.informationElements[i].bytes);
584                    }
585                }
586
587                n = in.readInt();
588                if (n != 0) {
589                    sr.anqpLines = new ArrayList<String>();
590                    for (int i = 0; i < n; i++) {
591                        sr.anqpLines.add(in.readString());
592                    }
593                }
594                return sr;
595            }
596
597            public ScanResult[] newArray(int size) {
598                return new ScanResult[size];
599            }
600        };
601}
602