ScanResult.java revision 63edd98d2eb744cc78dc3a3f8ec1ce7e6164d69d
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
22/**
23 * Describes information about a detected access point. In addition
24 * to the attributes described here, the supplicant keeps track of
25 * {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
26 * but does not currently report them to external clients.
27 */
28public class ScanResult implements Parcelable {
29    /**
30     * The network name.
31     */
32    public String SSID;
33
34    /**
35     * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide
36     */
37    public WifiSsid wifiSsid;
38
39    /**
40     * The address of the access point.
41     */
42    public String BSSID;
43    /**
44     * Describes the authentication, key management, and encryption schemes
45     * supported by the access point.
46     */
47    public String capabilities;
48    /**
49     * The detected signal level in dBm, also known as the RSSI.
50     *
51     * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
52     * an absolute signal level which can be displayed to a user.
53     */
54    public int level;
55    /**
56     * The frequency in MHz of the channel over which the client is communicating
57     * with the access point.
58     */
59    public int frequency;
60
61    /**
62     * timestamp in microseconds (since boot) when
63     * this result was last seen.
64     */
65    public long timestamp;
66
67    /**
68     * Timestamp representing date when this result was last seen, in milliseconds from 1970
69     * {@hide}
70     */
71    public long seen;
72
73    /**
74     * If the scan result is a valid autojoin candidate
75     * {@hide}
76     */
77    public int isAutoJoinCandidate;
78
79    /**
80     * @hide
81     * Update RSSI of the scan result
82     * @param previousRSSI
83     * @param previousSeen
84     * @param maxAge
85     */
86    public void averageRssi(int previousRssi, long previousSeen, int maxAge) {
87
88        if (seen == 0) {
89            seen = System.currentTimeMillis();
90        }
91        long age = seen - previousSeen;
92
93        if (previousSeen > 0 && age > 0 && age < maxAge/2) {
94            // Average the RSSI with previously seen instances of this scan result
95            double alpha = 0.5 - (double) age / (double) maxAge;
96            level = (int) ((double) level * (1 - alpha) + (double) previousRssi * alpha);
97        }
98    }
99
100    /** @hide */
101    public static final int ENABLED                                          = 0;
102    /** @hide */
103    public static final int AUTO_ROAM_DISABLED                               = 16;
104    /** @hide */
105    public static final int AUTO_JOIN_DISABLED                               = 32;
106    /** @hide */
107    public static final int AUTHENTICATION_ERROR                              = 128;
108
109    /**
110     * Status: indicating join status
111     * @hide
112     */
113    public int autoJoinStatus;
114
115    /**
116     * num IP configuration failures
117     * @hide
118     */
119    public int numIpConfigFailures;
120
121    /**
122     * @hide
123     * Last time we blacklisted the ScanResult
124     */
125    public long blackListTimestamp;
126
127    /** @hide **/
128    public void setAutoJoinStatus(int status) {
129        if (status < 0) status = 0;
130        if (status == 0) {
131            blackListTimestamp = 0;
132        }  else if (status > autoJoinStatus) {
133            blackListTimestamp = System.currentTimeMillis();
134        }
135        autoJoinStatus = status;
136    }
137
138    /**
139     * Status: indicating the scan result is not a result
140     * that is part of user's saved configurations
141     * @hide
142     */
143    public boolean untrusted;
144
145    /**
146     * Number of time we connected to it
147     * @hide
148     */
149    public int numConnection;
150
151    /**
152     * Number of time autojoin used it
153     * @hide
154     */
155    public int numUsage;
156
157    /**
158     * The approximate distance to the AP in centimeter, if available.  Else
159     * {@link UNSPECIFIED}.
160     * {@hide}
161     */
162    public int distanceCm;
163
164    /**
165     * The standard deviation of the distance to the AP, if available.
166     * Else {@link UNSPECIFIED}.
167     * {@hide}
168     */
169    public int distanceSdCm;
170
171    /**
172     * {@hide}
173     */
174    public final static int UNSPECIFIED = -1;
175    /**
176     * @hide
177     */
178    public boolean is24GHz() {
179        return ScanResult.is24GHz(frequency);
180    }
181
182    /**
183     * @hide
184     * TODO: makes real freq boundaries
185     */
186    public static boolean is24GHz(int freq) {
187        return freq > 2400 && freq < 2500;
188    }
189
190    /**
191     * @hide
192     */
193    public boolean is5GHz() {
194        return ScanResult.is5GHz(frequency);
195    }
196
197    /**
198     * @hide
199     * TODO: makes real freq boundaries
200     */
201    public static boolean is5GHz(int freq) {
202        return freq > 4900 && freq < 5900;
203    }
204
205    /** information element from beacon
206     * @hide
207     */
208    public static class InformationElement {
209        public int id;
210        public byte[] bytes;
211
212        public InformationElement() {
213        }
214
215        public InformationElement(InformationElement rhs) {
216            this.id = rhs.id;
217            this.bytes = rhs.bytes.clone();
218        }
219    }
220
221    /** information elements found in the beacon
222     * @hide
223     */
224    public InformationElement informationElements[];
225
226    /** {@hide} */
227    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
228            long tsf) {
229        this.wifiSsid = wifiSsid;
230        this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
231        this.BSSID = BSSID;
232        this.capabilities = caps;
233        this.level = level;
234        this.frequency = frequency;
235        this.timestamp = tsf;
236        this.distanceCm = UNSPECIFIED;
237        this.distanceSdCm = UNSPECIFIED;
238    }
239
240    /** {@hide} */
241    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
242            long tsf, int distCm, int distSdCm) {
243        this.wifiSsid = wifiSsid;
244        this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
245        this.BSSID = BSSID;
246        this.capabilities = caps;
247        this.level = level;
248        this.frequency = frequency;
249        this.timestamp = tsf;
250        this.distanceCm = distCm;
251        this.distanceSdCm = distSdCm;
252    }
253
254    /** copy constructor {@hide} */
255    public ScanResult(ScanResult source) {
256        if (source != null) {
257            wifiSsid = source.wifiSsid;
258            SSID = source.SSID;
259            BSSID = source.BSSID;
260            capabilities = source.capabilities;
261            level = source.level;
262            frequency = source.frequency;
263            timestamp = source.timestamp;
264            distanceCm = source.distanceCm;
265            distanceSdCm = source.distanceSdCm;
266            seen = source.seen;
267            autoJoinStatus = source.autoJoinStatus;
268            untrusted = source.untrusted;
269            numConnection = source.numConnection;
270            numUsage = source.numUsage;
271            numIpConfigFailures = source.numIpConfigFailures;
272            isAutoJoinCandidate = source.isAutoJoinCandidate;
273        }
274    }
275
276    /** empty scan result
277     *
278     * {@hide}
279     * */
280    public ScanResult() {
281    }
282
283    @Override
284    public String toString() {
285        StringBuffer sb = new StringBuffer();
286        String none = "<none>";
287
288        sb.append("SSID: ").
289            append(wifiSsid == null ? WifiSsid.NONE : wifiSsid).
290            append(", BSSID: ").
291            append(BSSID == null ? none : BSSID).
292            append(", capabilities: ").
293            append(capabilities == null ? none : capabilities).
294            append(", level: ").
295            append(level).
296            append(", frequency: ").
297            append(frequency).
298            append(", timestamp: ").
299            append(timestamp);
300
301        sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
302                append("(cm)");
303        sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
304                append("(cm)");
305
306        if (autoJoinStatus != 0) {
307            sb.append(", status: ").append(autoJoinStatus);
308        }
309        return sb.toString();
310    }
311
312    /** Implement the Parcelable interface {@hide} */
313    public int describeContents() {
314        return 0;
315    }
316
317    /** Implement the Parcelable interface {@hide} */
318    public void writeToParcel(Parcel dest, int flags) {
319        if (wifiSsid != null) {
320            dest.writeInt(1);
321            wifiSsid.writeToParcel(dest, flags);
322        } else {
323            dest.writeInt(0);
324        }
325        dest.writeString(BSSID);
326        dest.writeString(capabilities);
327        dest.writeInt(level);
328        dest.writeInt(frequency);
329        dest.writeLong(timestamp);
330        dest.writeInt(distanceCm);
331        dest.writeInt(distanceSdCm);
332        dest.writeLong(seen);
333        dest.writeInt(autoJoinStatus);
334        dest.writeInt(untrusted ? 1 : 0);
335        dest.writeInt(numConnection);
336        dest.writeInt(numUsage);
337        dest.writeInt(numIpConfigFailures);
338        dest.writeInt(isAutoJoinCandidate);
339        if (informationElements != null) {
340            dest.writeInt(informationElements.length);
341            for (int i = 0; i < informationElements.length; i++) {
342                dest.writeInt(informationElements[i].id);
343                dest.writeInt(informationElements[i].bytes.length);
344                dest.writeByteArray(informationElements[i].bytes);
345            }
346        } else {
347            dest.writeInt(0);
348        }
349    }
350
351    /** Implement the Parcelable interface {@hide} */
352    public static final Creator<ScanResult> CREATOR =
353        new Creator<ScanResult>() {
354            public ScanResult createFromParcel(Parcel in) {
355                WifiSsid wifiSsid = null;
356                if (in.readInt() == 1) {
357                    wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
358                }
359                ScanResult sr = new ScanResult(
360                    wifiSsid,
361                    in.readString(),
362                    in.readString(),
363                    in.readInt(),
364                    in.readInt(),
365                    in.readLong(),
366                    in.readInt(),
367                    in.readInt()
368                );
369                sr.seen = in.readLong();
370                sr.autoJoinStatus = in.readInt();
371                sr.untrusted = in.readInt() != 0;
372                sr.numConnection = in.readInt();
373                sr.numUsage = in.readInt();
374                sr.numIpConfigFailures = in.readInt();
375                sr.isAutoJoinCandidate = in.readInt();
376                int n = in.readInt();
377                if (n != 0) {
378                    sr.informationElements = new InformationElement[n];
379                    for (int i = 0; i < n; i++) {
380                        sr.informationElements[i] = new InformationElement();
381                        sr.informationElements[i].id = in.readInt();
382                        int len = in.readInt();
383                        sr.informationElements[i].bytes = new byte[len];
384                        in.readByteArray(sr.informationElements[i].bytes);
385                    }
386                }
387                return sr;
388            }
389
390            public ScanResult[] newArray(int size) {
391                return new ScanResult[size];
392            }
393        };
394}
395