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.annotation.SystemApi;
     20 import android.os.Parcel;
     21 import android.os.Parcelable;
     22 
     23 import java.util.ArrayList;
     24 import java.util.Arrays;
     25 import java.util.List;
     26 import java.util.Objects;
     27 
     28 /**
     29  * Describes information about a detected access point. In addition
     30  * to the attributes described here, the supplicant keeps track of
     31  * {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
     32  * but does not currently report them to external clients.
     33  */
     34 public class ScanResult implements Parcelable {
     35     /**
     36      * The network name.
     37      */
     38     public String SSID;
     39 
     40     /**
     41      * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide
     42      */
     43     public WifiSsid wifiSsid;
     44 
     45     /**
     46      * The address of the access point.
     47      */
     48     public String BSSID;
     49 
     50     /**
     51      * The HESSID from the beacon.
     52      * @hide
     53      */
     54     public long hessid;
     55 
     56     /**
     57      * The ANQP Domain ID from the Hotspot 2.0 Indication element, if present.
     58      * @hide
     59      */
     60     public int anqpDomainId;
     61 
     62     /*
     63      * This field is equivalent to the |flags|, rather than the |capabilities| field
     64      * of the per-BSS scan results returned by WPA supplicant. See the definition of
     65      * |struct wpa_bss| in wpa_supplicant/bss.h for more details.
     66      */
     67     /**
     68      * Describes the authentication, key management, and encryption schemes
     69      * supported by the access point.
     70      */
     71     public String capabilities;
     72 
     73     /**
     74      * @hide
     75      * No security protocol.
     76      */
     77     public static final int PROTOCOL_NONE = 0;
     78     /**
     79      * @hide
     80      * Security protocol type: WPA version 1.
     81      */
     82     public static final int PROTOCOL_WPA = 1;
     83     /**
     84      * @hide
     85      * Security protocol type: WPA version 2, also called RSN.
     86      */
     87     public static final int PROTOCOL_WPA2 = 2;
     88     /**
     89      * @hide
     90      * Security protocol type:
     91      * OSU Server-only authenticated layer 2 Encryption Network.
     92      * Used for Hotspot 2.0.
     93      */
     94     public static final int PROTOCOL_OSEN = 3;
     95 
     96     /**
     97      * @hide
     98      * No security key management scheme.
     99      */
    100     public static final int KEY_MGMT_NONE = 0;
    101     /**
    102      * @hide
    103      * Security key management scheme: PSK.
    104      */
    105     public static final int KEY_MGMT_PSK = 1;
    106     /**
    107      * @hide
    108      * Security key management scheme: EAP.
    109      */
    110     public static final int KEY_MGMT_EAP = 2;
    111     /**
    112      * @hide
    113      * Security key management scheme: FT_PSK.
    114      */
    115     public static final int KEY_MGMT_FT_PSK = 3;
    116     /**
    117      * @hide
    118      * Security key management scheme: FT_EAP.
    119      */
    120     public static final int KEY_MGMT_FT_EAP = 4;
    121     /**
    122      * @hide
    123      * Security key management scheme: PSK_SHA256
    124      */
    125     public static final int KEY_MGMT_PSK_SHA256 = 5;
    126     /**
    127      * @hide
    128      * Security key management scheme: EAP_SHA256.
    129      */
    130     public static final int KEY_MGMT_EAP_SHA256 = 6;
    131     /**
    132      * @hide
    133      * Security key management scheme: OSEN.
    134      * Used for Hotspot 2.0.
    135      */
    136     public static final int KEY_MGMT_OSEN = 7;
    137 
    138     /**
    139      * @hide
    140      * No cipher suite.
    141      */
    142     public static final int CIPHER_NONE = 0;
    143     /**
    144      * @hide
    145      * No group addressed, only used for group data cipher.
    146      */
    147     public static final int CIPHER_NO_GROUP_ADDRESSED = 1;
    148     /**
    149      * @hide
    150      * Cipher suite: TKIP
    151      */
    152     public static final int CIPHER_TKIP = 2;
    153     /**
    154      * @hide
    155      * Cipher suite: CCMP
    156      */
    157     public static final int CIPHER_CCMP = 3;
    158 
    159     /**
    160      * The detected signal level in dBm, also known as the RSSI.
    161      *
    162      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
    163      * an absolute signal level which can be displayed to a user.
    164      */
    165     public int level;
    166     /**
    167      * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating
    168      * with the access point.
    169      */
    170     public int frequency;
    171 
    172    /**
    173     * AP Channel bandwidth is 20 MHZ
    174     */
    175     public static final int CHANNEL_WIDTH_20MHZ = 0;
    176    /**
    177     * AP Channel bandwidth is 40 MHZ
    178     */
    179     public static final int CHANNEL_WIDTH_40MHZ = 1;
    180    /**
    181     * AP Channel bandwidth is 80 MHZ
    182     */
    183     public static final int CHANNEL_WIDTH_80MHZ = 2;
    184    /**
    185     * AP Channel bandwidth is 160 MHZ
    186     */
    187     public static final int CHANNEL_WIDTH_160MHZ = 3;
    188    /**
    189     * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
    190     */
    191     public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
    192 
    193    /**
    194     * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
    195     * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
    196     * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
    197     */
    198     public int channelWidth;
    199 
    200     /**
    201      * Not used if the AP bandwidth is 20 MHz
    202      * If the AP use 40, 80 or 160 MHz, this is the center frequency (in MHz)
    203      * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz)
    204      */
    205     public int centerFreq0;
    206 
    207     /**
    208      * Only used if the AP bandwidth is 80 + 80 MHz
    209      * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz)
    210      */
    211     public int centerFreq1;
    212 
    213     /**
    214      * @deprecated use is80211mcResponder() instead
    215      * @hide
    216      */
    217     public boolean is80211McRTTResponder;
    218 
    219     /**
    220      * timestamp in microseconds (since boot) when
    221      * this result was last seen.
    222      */
    223     public long timestamp;
    224 
    225     /**
    226      * Timestamp representing date when this result was last seen, in milliseconds from 1970
    227      * {@hide}
    228      */
    229     public long seen;
    230 
    231     /**
    232      * On devices with multiple hardware radio chains, this class provides metadata about
    233      * each radio chain that was used to receive this scan result (probe response or beacon).
    234      * {@hide}
    235      */
    236     public static class RadioChainInfo {
    237         /** Vendor defined id for a radio chain. */
    238         public int id;
    239         /** Detected signal level in dBm (also known as the RSSI) on this radio chain. */
    240         public int level;
    241 
    242         @Override
    243         public String toString() {
    244             return "RadioChainInfo: id=" + id + ", level=" + level;
    245         }
    246 
    247         @Override
    248         public boolean equals(Object otherObj) {
    249             if (this == otherObj) {
    250                 return true;
    251             }
    252             if (!(otherObj instanceof RadioChainInfo)) {
    253                 return false;
    254             }
    255             RadioChainInfo other = (RadioChainInfo) otherObj;
    256             return id == other.id && level == other.level;
    257         }
    258 
    259         @Override
    260         public int hashCode() {
    261             return Objects.hash(id, level);
    262         }
    263     };
    264 
    265     /**
    266      * Information about the list of the radio chains used to receive this scan result
    267      * (probe response or beacon).
    268      *
    269      * For Example: On devices with 2 hardware radio chains, this list could hold 1 or 2
    270      * entries based on whether this scan result was received using one or both the chains.
    271      * {@hide}
    272      */
    273     public RadioChainInfo[] radioChainInfos;
    274 
    275     /**
    276      * Status indicating the scan result does not correspond to a user's saved configuration
    277      * @hide
    278      * @removed
    279      */
    280     @SystemApi
    281     public boolean untrusted;
    282 
    283     /**
    284      * Number of time autojoin used it
    285      * @hide
    286      */
    287     public int numUsage;
    288 
    289     /**
    290      * The approximate distance to the AP in centimeter, if available.  Else
    291      * {@link UNSPECIFIED}.
    292      * {@hide}
    293      */
    294     public int distanceCm;
    295 
    296     /**
    297      * The standard deviation of the distance to the access point, if available.
    298      * Else {@link UNSPECIFIED}.
    299      * {@hide}
    300      */
    301     public int distanceSdCm;
    302 
    303     /** {@hide} */
    304     public static final long FLAG_PASSPOINT_NETWORK               = 0x0000000000000001;
    305 
    306     /** {@hide} */
    307     public static final long FLAG_80211mc_RESPONDER               = 0x0000000000000002;
    308 
    309     /*
    310      * These flags are specific to the ScanResult class, and are not related to the |flags|
    311      * field of the per-BSS scan results from WPA supplicant.
    312      */
    313     /**
    314      * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}.
    315      * {@hide}
    316      */
    317     public long flags;
    318 
    319     /**
    320      * sets a flag in {@link #flags} field
    321      * @param flag flag to set
    322      * @hide
    323      */
    324     public void setFlag(long flag) {
    325         flags |= flag;
    326     }
    327 
    328     /**
    329      * clears a flag in {@link #flags} field
    330      * @param flag flag to set
    331      * @hide
    332      */
    333     public void clearFlag(long flag) {
    334         flags &= ~flag;
    335     }
    336 
    337     public boolean is80211mcResponder() {
    338         return (flags & FLAG_80211mc_RESPONDER) != 0;
    339     }
    340 
    341     public boolean isPasspointNetwork() {
    342         return (flags & FLAG_PASSPOINT_NETWORK) != 0;
    343     }
    344 
    345     /**
    346      * Indicates venue name (such as 'San Francisco Airport') published by access point; only
    347      * available on Passpoint network and if published by access point.
    348      */
    349     public CharSequence venueName;
    350 
    351     /**
    352      * Indicates Passpoint operator name published by access point.
    353      */
    354     public CharSequence operatorFriendlyName;
    355 
    356     /**
    357      * {@hide}
    358      */
    359     public final static int UNSPECIFIED = -1;
    360     /**
    361      * @hide
    362      */
    363     public boolean is24GHz() {
    364         return ScanResult.is24GHz(frequency);
    365     }
    366 
    367     /**
    368      * @hide
    369      * TODO: makes real freq boundaries
    370      */
    371     public static boolean is24GHz(int freq) {
    372         return freq > 2400 && freq < 2500;
    373     }
    374 
    375     /**
    376      * @hide
    377      */
    378     public boolean is5GHz() {
    379         return ScanResult.is5GHz(frequency);
    380     }
    381 
    382     /**
    383      * @hide
    384      * TODO: makes real freq boundaries
    385      */
    386     public static boolean is5GHz(int freq) {
    387         return freq > 4900 && freq < 5900;
    388     }
    389 
    390     /**
    391      *  @hide
    392      * anqp lines from supplicant BSS response
    393      */
    394     public List<String> anqpLines;
    395 
    396     /** information elements from beacon
    397      * @hide
    398      */
    399     public static class InformationElement {
    400         public static final int EID_SSID = 0;
    401         public static final int EID_SUPPORTED_RATES = 1;
    402         public static final int EID_TIM = 5;
    403         public static final int EID_BSS_LOAD = 11;
    404         public static final int EID_ERP = 42;
    405         public static final int EID_HT_CAPABILITIES = 45;
    406         public static final int EID_RSN = 48;
    407         public static final int EID_EXTENDED_SUPPORTED_RATES = 50;
    408         public static final int EID_HT_OPERATION = 61;
    409         public static final int EID_INTERWORKING = 107;
    410         public static final int EID_ROAMING_CONSORTIUM = 111;
    411         public static final int EID_EXTENDED_CAPS = 127;
    412         public static final int EID_VHT_CAPABILITIES = 191;
    413         public static final int EID_VHT_OPERATION = 192;
    414         public static final int EID_VSA = 221;
    415 
    416         public int id;
    417         public byte[] bytes;
    418 
    419         public InformationElement() {
    420         }
    421 
    422         public InformationElement(InformationElement rhs) {
    423             this.id = rhs.id;
    424             this.bytes = rhs.bytes.clone();
    425         }
    426     }
    427 
    428     /** information elements found in the beacon
    429      * @hide
    430      */
    431     public InformationElement[] informationElements;
    432 
    433     /** ANQP response elements.
    434      * @hide
    435      */
    436     public AnqpInformationElement[] anqpElements;
    437 
    438     /**
    439      * Flag indicating if this AP is a carrier AP. The determination is based
    440      * on the AP's SSID and if AP is using EAP security.
    441      *
    442      * @hide
    443      */
    444     public boolean isCarrierAp;
    445 
    446     /**
    447      * The EAP type {@link WifiEnterpriseConfig.Eap} associated with this AP if it is a carrier AP.
    448      *
    449      * @hide
    450      */
    451     public int carrierApEapType;
    452 
    453     /**
    454      * The name of the carrier that's associated with this AP if it is a carrier AP.
    455      *
    456      * @hide
    457      */
    458     public String carrierName;
    459 
    460     /** {@hide} */
    461     public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId,
    462             byte[] osuProviders, String caps, int level, int frequency, long tsf) {
    463         this.wifiSsid = wifiSsid;
    464         this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
    465         this.BSSID = BSSID;
    466         this.hessid = hessid;
    467         this.anqpDomainId = anqpDomainId;
    468         if (osuProviders != null) {
    469             this.anqpElements = new AnqpInformationElement[1];
    470             this.anqpElements[0] =
    471                     new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID,
    472                             AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders);
    473         }
    474         this.capabilities = caps;
    475         this.level = level;
    476         this.frequency = frequency;
    477         this.timestamp = tsf;
    478         this.distanceCm = UNSPECIFIED;
    479         this.distanceSdCm = UNSPECIFIED;
    480         this.channelWidth = UNSPECIFIED;
    481         this.centerFreq0 = UNSPECIFIED;
    482         this.centerFreq1 = UNSPECIFIED;
    483         this.flags = 0;
    484         this.isCarrierAp = false;
    485         this.carrierApEapType = UNSPECIFIED;
    486         this.carrierName = null;
    487         this.radioChainInfos = null;
    488     }
    489 
    490     /** {@hide} */
    491     public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
    492             long tsf, int distCm, int distSdCm) {
    493         this.wifiSsid = wifiSsid;
    494         this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
    495         this.BSSID = BSSID;
    496         this.capabilities = caps;
    497         this.level = level;
    498         this.frequency = frequency;
    499         this.timestamp = tsf;
    500         this.distanceCm = distCm;
    501         this.distanceSdCm = distSdCm;
    502         this.channelWidth = UNSPECIFIED;
    503         this.centerFreq0 = UNSPECIFIED;
    504         this.centerFreq1 = UNSPECIFIED;
    505         this.flags = 0;
    506         this.isCarrierAp = false;
    507         this.carrierApEapType = UNSPECIFIED;
    508         this.carrierName = null;
    509         this.radioChainInfos = null;
    510     }
    511 
    512     /** {@hide} */
    513     public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps,
    514             int level, int frequency,
    515             long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
    516             boolean is80211McRTTResponder) {
    517         this.SSID = Ssid;
    518         this.BSSID = BSSID;
    519         this.hessid = hessid;
    520         this.anqpDomainId = anqpDomainId;
    521         this.capabilities = caps;
    522         this.level = level;
    523         this.frequency = frequency;
    524         this.timestamp = tsf;
    525         this.distanceCm = distCm;
    526         this.distanceSdCm = distSdCm;
    527         this.channelWidth = channelWidth;
    528         this.centerFreq0 = centerFreq0;
    529         this.centerFreq1 = centerFreq1;
    530         if (is80211McRTTResponder) {
    531             this.flags = FLAG_80211mc_RESPONDER;
    532         } else {
    533             this.flags = 0;
    534         }
    535         this.isCarrierAp = false;
    536         this.carrierApEapType = UNSPECIFIED;
    537         this.carrierName = null;
    538         this.radioChainInfos = null;
    539     }
    540 
    541     /** {@hide} */
    542     public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId,
    543                   String caps, int level,
    544                   int frequency, long tsf, int distCm, int distSdCm, int channelWidth,
    545                   int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) {
    546         this(Ssid, BSSID, hessid, anqpDomainId, caps, level, frequency, tsf, distCm,
    547                 distSdCm, channelWidth, centerFreq0, centerFreq1, is80211McRTTResponder);
    548         this.wifiSsid = wifiSsid;
    549     }
    550 
    551     /** copy constructor {@hide} */
    552     public ScanResult(ScanResult source) {
    553         if (source != null) {
    554             wifiSsid = source.wifiSsid;
    555             SSID = source.SSID;
    556             BSSID = source.BSSID;
    557             hessid = source.hessid;
    558             anqpDomainId = source.anqpDomainId;
    559             informationElements = source.informationElements;
    560             anqpElements = source.anqpElements;
    561             capabilities = source.capabilities;
    562             level = source.level;
    563             frequency = source.frequency;
    564             channelWidth = source.channelWidth;
    565             centerFreq0 = source.centerFreq0;
    566             centerFreq1 = source.centerFreq1;
    567             timestamp = source.timestamp;
    568             distanceCm = source.distanceCm;
    569             distanceSdCm = source.distanceSdCm;
    570             seen = source.seen;
    571             untrusted = source.untrusted;
    572             numUsage = source.numUsage;
    573             venueName = source.venueName;
    574             operatorFriendlyName = source.operatorFriendlyName;
    575             flags = source.flags;
    576             isCarrierAp = source.isCarrierAp;
    577             carrierApEapType = source.carrierApEapType;
    578             carrierName = source.carrierName;
    579             radioChainInfos = source.radioChainInfos;
    580         }
    581     }
    582 
    583     /** empty scan result
    584      *
    585      * {@hide}
    586      * */
    587     public ScanResult() {
    588     }
    589 
    590     @Override
    591     public String toString() {
    592         StringBuffer sb = new StringBuffer();
    593         String none = "<none>";
    594 
    595         sb.append("SSID: ").
    596             append(wifiSsid == null ? WifiSsid.NONE : wifiSsid).
    597             append(", BSSID: ").
    598             append(BSSID == null ? none : BSSID).
    599             append(", capabilities: ").
    600             append(capabilities == null ? none : capabilities).
    601             append(", level: ").
    602             append(level).
    603             append(", frequency: ").
    604             append(frequency).
    605             append(", timestamp: ").
    606             append(timestamp);
    607 
    608         sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
    609                 append("(cm)");
    610         sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
    611                 append("(cm)");
    612 
    613         sb.append(", passpoint: ");
    614         sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
    615         sb.append(", ChannelBandwidth: ").append(channelWidth);
    616         sb.append(", centerFreq0: ").append(centerFreq0);
    617         sb.append(", centerFreq1: ").append(centerFreq1);
    618         sb.append(", 80211mcResponder: ");
    619         sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
    620         sb.append(", Carrier AP: ").append(isCarrierAp ? "yes" : "no");
    621         sb.append(", Carrier AP EAP Type: ").append(carrierApEapType);
    622         sb.append(", Carrier name: ").append(carrierName);
    623         sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos));
    624         return sb.toString();
    625     }
    626 
    627     /** Implement the Parcelable interface {@hide} */
    628     public int describeContents() {
    629         return 0;
    630     }
    631 
    632     /** Implement the Parcelable interface {@hide} */
    633     public void writeToParcel(Parcel dest, int flags) {
    634         if (wifiSsid != null) {
    635             dest.writeInt(1);
    636             wifiSsid.writeToParcel(dest, flags);
    637         } else {
    638             dest.writeInt(0);
    639         }
    640         dest.writeString(SSID);
    641         dest.writeString(BSSID);
    642         dest.writeLong(hessid);
    643         dest.writeInt(anqpDomainId);
    644         dest.writeString(capabilities);
    645         dest.writeInt(level);
    646         dest.writeInt(frequency);
    647         dest.writeLong(timestamp);
    648         dest.writeInt(distanceCm);
    649         dest.writeInt(distanceSdCm);
    650         dest.writeInt(channelWidth);
    651         dest.writeInt(centerFreq0);
    652         dest.writeInt(centerFreq1);
    653         dest.writeLong(seen);
    654         dest.writeInt(untrusted ? 1 : 0);
    655         dest.writeInt(numUsage);
    656         dest.writeString((venueName != null) ? venueName.toString() : "");
    657         dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
    658         dest.writeLong(this.flags);
    659 
    660         if (informationElements != null) {
    661             dest.writeInt(informationElements.length);
    662             for (int i = 0; i < informationElements.length; i++) {
    663                 dest.writeInt(informationElements[i].id);
    664                 dest.writeInt(informationElements[i].bytes.length);
    665                 dest.writeByteArray(informationElements[i].bytes);
    666             }
    667         } else {
    668             dest.writeInt(0);
    669         }
    670 
    671         if (anqpLines != null) {
    672             dest.writeInt(anqpLines.size());
    673             for (int i = 0; i < anqpLines.size(); i++) {
    674                 dest.writeString(anqpLines.get(i));
    675             }
    676         }
    677         else {
    678             dest.writeInt(0);
    679         }
    680         if (anqpElements != null) {
    681             dest.writeInt(anqpElements.length);
    682             for (AnqpInformationElement element : anqpElements) {
    683                 dest.writeInt(element.getVendorId());
    684                 dest.writeInt(element.getElementId());
    685                 dest.writeInt(element.getPayload().length);
    686                 dest.writeByteArray(element.getPayload());
    687             }
    688         } else {
    689             dest.writeInt(0);
    690         }
    691         dest.writeInt(isCarrierAp ? 1 : 0);
    692         dest.writeInt(carrierApEapType);
    693         dest.writeString(carrierName);
    694 
    695         if (radioChainInfos != null) {
    696             dest.writeInt(radioChainInfos.length);
    697             for (int i = 0; i < radioChainInfos.length; i++) {
    698                 dest.writeInt(radioChainInfos[i].id);
    699                 dest.writeInt(radioChainInfos[i].level);
    700             }
    701         } else {
    702             dest.writeInt(0);
    703         }
    704     }
    705 
    706     /** Implement the Parcelable interface {@hide} */
    707     public static final Creator<ScanResult> CREATOR =
    708         new Creator<ScanResult>() {
    709             public ScanResult createFromParcel(Parcel in) {
    710                 WifiSsid wifiSsid = null;
    711                 if (in.readInt() == 1) {
    712                     wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
    713                 }
    714                 ScanResult sr = new ScanResult(
    715                         wifiSsid,
    716                         in.readString(),                    /* SSID  */
    717                         in.readString(),                    /* BSSID */
    718                         in.readLong(),                      /* HESSID */
    719                         in.readInt(),                       /* ANQP Domain ID */
    720                         in.readString(),                    /* capabilities */
    721                         in.readInt(),                       /* level */
    722                         in.readInt(),                       /* frequency */
    723                         in.readLong(),                      /* timestamp */
    724                         in.readInt(),                       /* distanceCm */
    725                         in.readInt(),                       /* distanceSdCm */
    726                         in.readInt(),                       /* channelWidth */
    727                         in.readInt(),                       /* centerFreq0 */
    728                         in.readInt(),                       /* centerFreq1 */
    729                         false                               /* rtt responder,
    730                                                                fixed with flags below */
    731                 );
    732 
    733                 sr.seen = in.readLong();
    734                 sr.untrusted = in.readInt() != 0;
    735                 sr.numUsage = in.readInt();
    736                 sr.venueName = in.readString();
    737                 sr.operatorFriendlyName = in.readString();
    738                 sr.flags = in.readLong();
    739                 int n = in.readInt();
    740                 if (n != 0) {
    741                     sr.informationElements = new InformationElement[n];
    742                     for (int i = 0; i < n; i++) {
    743                         sr.informationElements[i] = new InformationElement();
    744                         sr.informationElements[i].id = in.readInt();
    745                         int len = in.readInt();
    746                         sr.informationElements[i].bytes = new byte[len];
    747                         in.readByteArray(sr.informationElements[i].bytes);
    748                     }
    749                 }
    750 
    751                 n = in.readInt();
    752                 if (n != 0) {
    753                     sr.anqpLines = new ArrayList<String>();
    754                     for (int i = 0; i < n; i++) {
    755                         sr.anqpLines.add(in.readString());
    756                     }
    757                 }
    758                 n = in.readInt();
    759                 if (n != 0) {
    760                     sr.anqpElements = new AnqpInformationElement[n];
    761                     for (int i = 0; i < n; i++) {
    762                         int vendorId = in.readInt();
    763                         int elementId = in.readInt();
    764                         int len = in.readInt();
    765                         byte[] payload = new byte[len];
    766                         in.readByteArray(payload);
    767                         sr.anqpElements[i] =
    768                                 new AnqpInformationElement(vendorId, elementId, payload);
    769                     }
    770                 }
    771                 sr.isCarrierAp = in.readInt() != 0;
    772                 sr.carrierApEapType = in.readInt();
    773                 sr.carrierName = in.readString();
    774                 n = in.readInt();
    775                 if (n != 0) {
    776                     sr.radioChainInfos = new RadioChainInfo[n];
    777                     for (int i = 0; i < n; i++) {
    778                         sr.radioChainInfos[i] = new RadioChainInfo();
    779                         sr.radioChainInfos[i].id = in.readInt();
    780                         sr.radioChainInfos[i].level = in.readInt();
    781                     }
    782                 }
    783                 return sr;
    784             }
    785 
    786             public ScanResult[] newArray(int size) {
    787                 return new ScanResult[size];
    788             }
    789         };
    790 }
    791