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