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