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.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.net.wifi.WifiAnnotations.ChannelWidth;
24 import android.net.wifi.WifiAnnotations.WifiStandard;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import java.nio.ByteBuffer;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.Objects;
34 
35 /**
36  * Describes information about a detected access point. In addition
37  * to the attributes described here, the supplicant keeps track of
38  * {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
39  * but does not currently report them to external clients.
40  */
41 public final class ScanResult implements Parcelable {
42     /**
43      * The network name.
44      */
45     public String SSID;
46 
47     /**
48      * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide
49      */
50     @UnsupportedAppUsage
51     public WifiSsid wifiSsid;
52 
53     /**
54      * The address of the access point.
55      */
56     public String BSSID;
57 
58     /**
59      * The HESSID from the beacon.
60      * @hide
61      */
62     @UnsupportedAppUsage
63     public long hessid;
64 
65     /**
66      * The ANQP Domain ID from the Hotspot 2.0 Indication element, if present.
67      * @hide
68      */
69     @UnsupportedAppUsage
70     public int anqpDomainId;
71 
72     /*
73      * This field is equivalent to the |flags|, rather than the |capabilities| field
74      * of the per-BSS scan results returned by WPA supplicant. See the definition of
75      * |struct wpa_bss| in wpa_supplicant/bss.h for more details.
76      */
77     /**
78      * Describes the authentication, key management, and encryption schemes
79      * supported by the access point.
80      */
81     public String capabilities;
82 
83     /**
84      * @hide
85      * No security protocol.
86      */
87     @SystemApi
88     public static final int PROTOCOL_NONE = 0;
89     /**
90      * @hide
91      * Security protocol type: WPA version 1.
92      */
93     @SystemApi
94     public static final int PROTOCOL_WPA = 1;
95     /**
96      * @hide
97      * Security protocol type: RSN, for WPA version 2, and version 3.
98      */
99     @SystemApi
100     public static final int PROTOCOL_RSN = 2;
101     /**
102      * @hide
103      * Security protocol type:
104      * OSU Server-only authenticated layer 2 Encryption Network.
105      * Used for Hotspot 2.0.
106      */
107     @SystemApi
108     public static final int PROTOCOL_OSEN = 3;
109 
110     /**
111      * @hide
112      * Security protocol type: WAPI.
113      */
114     @SystemApi
115     public static final int PROTOCOL_WAPI = 4;
116 
117     /**
118      * @hide
119      * No security key management scheme.
120      */
121     @SystemApi
122     public static final int KEY_MGMT_NONE = 0;
123     /**
124      * @hide
125      * Security key management scheme: PSK.
126      */
127     @SystemApi
128     public static final int KEY_MGMT_PSK = 1;
129     /**
130      * @hide
131      * Security key management scheme: EAP.
132      */
133     @SystemApi
134     public static final int KEY_MGMT_EAP = 2;
135     /**
136      * @hide
137      * Security key management scheme: FT_PSK.
138      */
139     @SystemApi
140     public static final int KEY_MGMT_FT_PSK = 3;
141     /**
142      * @hide
143      * Security key management scheme: FT_EAP.
144      */
145     @SystemApi
146     public static final int KEY_MGMT_FT_EAP = 4;
147     /**
148      * @hide
149      * Security key management scheme: PSK_SHA256
150      */
151     @SystemApi
152     public static final int KEY_MGMT_PSK_SHA256 = 5;
153     /**
154      * @hide
155      * Security key management scheme: EAP_SHA256.
156      */
157     @SystemApi
158     public static final int KEY_MGMT_EAP_SHA256 = 6;
159     /**
160      * @hide
161      * Security key management scheme: OSEN.
162      * Used for Hotspot 2.0.
163      */
164     @SystemApi
165     public static final int KEY_MGMT_OSEN = 7;
166      /**
167      * @hide
168      * Security key management scheme: SAE.
169      */
170     @SystemApi
171     public static final int KEY_MGMT_SAE = 8;
172     /**
173      * @hide
174      * Security key management scheme: OWE.
175      */
176     @SystemApi
177     public static final int KEY_MGMT_OWE = 9;
178     /**
179      * @hide
180      * Security key management scheme: SUITE_B_192.
181      */
182     @SystemApi
183     public static final int KEY_MGMT_EAP_SUITE_B_192 = 10;
184     /**
185      * @hide
186      * Security key management scheme: FT_SAE.
187      */
188     @SystemApi
189     public static final int KEY_MGMT_FT_SAE = 11;
190     /**
191      * @hide
192      * Security key management scheme: OWE in transition mode.
193      */
194     @SystemApi
195     public static final int KEY_MGMT_OWE_TRANSITION = 12;
196     /**
197      * @hide
198      * Security key management scheme: WAPI_PSK.
199      */
200     @SystemApi
201     public static final int KEY_MGMT_WAPI_PSK = 13;
202     /**
203      * @hide
204      * Security key management scheme: WAPI_CERT.
205      */
206     @SystemApi
207     public static final int KEY_MGMT_WAPI_CERT = 14;
208 
209     /**
210      * @hide
211      * Security key management scheme: FILS_SHA256.
212      */
213     public static final int KEY_MGMT_FILS_SHA256 = 15;
214     /**
215      * @hide
216      * Security key management scheme: FILS_SHA384.
217      */
218     public static final int KEY_MGMT_FILS_SHA384 = 16;
219     /**
220      * @hide
221      * No cipher suite.
222      */
223     @SystemApi
224     public static final int CIPHER_NONE = 0;
225     /**
226      * @hide
227      * No group addressed, only used for group data cipher.
228      */
229     @SystemApi
230     public static final int CIPHER_NO_GROUP_ADDRESSED = 1;
231     /**
232      * @hide
233      * Cipher suite: TKIP
234      */
235     @SystemApi
236     public static final int CIPHER_TKIP = 2;
237     /**
238      * @hide
239      * Cipher suite: CCMP
240      */
241     @SystemApi
242     public static final int CIPHER_CCMP = 3;
243     /**
244      * @hide
245      * Cipher suite: GCMP
246      */
247     @SystemApi
248     public static final int CIPHER_GCMP_256 = 4;
249     /**
250      * @hide
251      * Cipher suite: SMS4
252      */
253     @SystemApi
254     public static final int CIPHER_SMS4 = 5;
255 
256     /**
257      * The detected signal level in dBm, also known as the RSSI.
258      *
259      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
260      * an absolute signal level which can be displayed to a user.
261      */
262     public int level;
263     /**
264      * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating
265      * with the access point.
266      */
267     public int frequency;
268 
269    /**
270     * AP Channel bandwidth is 20 MHZ
271     */
272     public static final int CHANNEL_WIDTH_20MHZ = 0;
273    /**
274     * AP Channel bandwidth is 40 MHZ
275     */
276     public static final int CHANNEL_WIDTH_40MHZ = 1;
277    /**
278     * AP Channel bandwidth is 80 MHZ
279     */
280     public static final int CHANNEL_WIDTH_80MHZ = 2;
281    /**
282     * AP Channel bandwidth is 160 MHZ
283     */
284     public static final int CHANNEL_WIDTH_160MHZ = 3;
285    /**
286     * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
287     */
288     public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
289 
290     /**
291      * Wi-Fi unknown standard
292      */
293     public static final int WIFI_STANDARD_UNKNOWN = 0;
294 
295     /**
296      * Wi-Fi 802.11a/b/g
297      */
298     public static final int WIFI_STANDARD_LEGACY = 1;
299 
300     /**
301      * Wi-Fi 802.11n
302      */
303     public static final int WIFI_STANDARD_11N = 4;
304 
305     /**
306      * Wi-Fi 802.11ac
307      */
308     public static final int WIFI_STANDARD_11AC = 5;
309 
310     /**
311      * Wi-Fi 802.11ax
312      */
313     public static final int WIFI_STANDARD_11AX = 6;
314 
315     /**
316      * AP wifi standard.
317      */
318     private @WifiStandard int mWifiStandard;
319 
320     /**
321      * return the AP wifi standard.
322      */
getWifiStandard()323     public @WifiStandard int getWifiStandard() {
324         return mWifiStandard;
325     }
326 
327     /**
328      * sets the AP wifi standard.
329      * @hide
330      */
setWifiStandard(@ifiStandard int standard)331     public void setWifiStandard(@WifiStandard int standard) {
332         mWifiStandard = standard;
333     }
334 
335     /**
336      * Convert Wi-Fi standard to string
337      */
wifiStandardToString(@ifiStandard int standard)338     private static @Nullable String wifiStandardToString(@WifiStandard int standard) {
339         switch(standard) {
340             case WIFI_STANDARD_LEGACY:
341                 return "legacy";
342             case WIFI_STANDARD_11N:
343                 return "11n";
344             case WIFI_STANDARD_11AC:
345                 return "11ac";
346             case WIFI_STANDARD_11AX:
347                 return "11ax";
348             case WIFI_STANDARD_UNKNOWN:
349                 return "unknown";
350         }
351         return null;
352     }
353 
354     /**
355      * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
356      * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
357      * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
358      */
359     public @ChannelWidth int channelWidth;
360 
361     /**
362      * Not used if the AP bandwidth is 20 MHz
363      * If the AP use 40, 80 or 160 MHz, this is the center frequency (in MHz)
364      * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz)
365      */
366     public int centerFreq0;
367 
368     /**
369      * Only used if the AP bandwidth is 80 + 80 MHz
370      * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz)
371      */
372     public int centerFreq1;
373 
374     /**
375      * @deprecated use is80211mcResponder() instead
376      * @hide
377      */
378     @UnsupportedAppUsage
379     public boolean is80211McRTTResponder;
380 
381     /**
382      * timestamp in microseconds (since boot) when
383      * this result was last seen.
384      */
385     public long timestamp;
386 
387     /**
388      * Timestamp representing date when this result was last seen, in milliseconds from 1970
389      * {@hide}
390      */
391     @UnsupportedAppUsage
392     public long seen;
393 
394     /**
395      * On devices with multiple hardware radio chains, this class provides metadata about
396      * each radio chain that was used to receive this scan result (probe response or beacon).
397      * {@hide}
398      */
399     public static class RadioChainInfo {
400         /** Vendor defined id for a radio chain. */
401         public int id;
402         /** Detected signal level in dBm (also known as the RSSI) on this radio chain. */
403         public int level;
404 
405         @Override
toString()406         public String toString() {
407             return "RadioChainInfo: id=" + id + ", level=" + level;
408         }
409 
410         @Override
equals(Object otherObj)411         public boolean equals(Object otherObj) {
412             if (this == otherObj) {
413                 return true;
414             }
415             if (!(otherObj instanceof RadioChainInfo)) {
416                 return false;
417             }
418             RadioChainInfo other = (RadioChainInfo) otherObj;
419             return id == other.id && level == other.level;
420         }
421 
422         @Override
hashCode()423         public int hashCode() {
424             return Objects.hash(id, level);
425         }
426     };
427 
428     /**
429      * Information about the list of the radio chains used to receive this scan result
430      * (probe response or beacon).
431      *
432      * For Example: On devices with 2 hardware radio chains, this list could hold 1 or 2
433      * entries based on whether this scan result was received using one or both the chains.
434      * {@hide}
435      */
436     public RadioChainInfo[] radioChainInfos;
437 
438     /**
439      * Status indicating the scan result does not correspond to a user's saved configuration
440      * @hide
441      * @removed
442      */
443     @SystemApi
444     public boolean untrusted;
445 
446     /**
447      * Number of time autojoin used it
448      * @hide
449      */
450     @UnsupportedAppUsage
451     public int numUsage;
452 
453     /**
454      * The approximate distance to the AP in centimeter, if available.  Else
455      * {@link UNSPECIFIED}.
456      * {@hide}
457      */
458     @UnsupportedAppUsage
459     public int distanceCm;
460 
461     /**
462      * The standard deviation of the distance to the access point, if available.
463      * Else {@link UNSPECIFIED}.
464      * {@hide}
465      */
466     @UnsupportedAppUsage
467     public int distanceSdCm;
468 
469     /** {@hide} */
470     public static final long FLAG_PASSPOINT_NETWORK               = 0x0000000000000001;
471 
472     /** {@hide} */
473     public static final long FLAG_80211mc_RESPONDER               = 0x0000000000000002;
474 
475     /*
476      * These flags are specific to the ScanResult class, and are not related to the |flags|
477      * field of the per-BSS scan results from WPA supplicant.
478      */
479     /**
480      * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}.
481      * {@hide}
482      */
483     @UnsupportedAppUsage
484     public long flags;
485 
486     /**
487      * sets a flag in {@link #flags} field
488      * @param flag flag to set
489      * @hide
490      */
setFlag(long flag)491     public void setFlag(long flag) {
492         flags |= flag;
493     }
494 
495     /**
496      * clears a flag in {@link #flags} field
497      * @param flag flag to set
498      * @hide
499      */
clearFlag(long flag)500     public void clearFlag(long flag) {
501         flags &= ~flag;
502     }
503 
is80211mcResponder()504     public boolean is80211mcResponder() {
505         return (flags & FLAG_80211mc_RESPONDER) != 0;
506     }
507 
isPasspointNetwork()508     public boolean isPasspointNetwork() {
509         return (flags & FLAG_PASSPOINT_NETWORK) != 0;
510     }
511 
512     /**
513      * Indicates venue name (such as 'San Francisco Airport') published by access point; only
514      * available on Passpoint network and if published by access point.
515      */
516     public CharSequence venueName;
517 
518     /**
519      * Indicates Passpoint operator name published by access point.
520      */
521     public CharSequence operatorFriendlyName;
522 
523     /**
524      * {@hide}
525      */
526     public final static int UNSPECIFIED = -1;
527 
528     /**
529      * 2.4 GHz band first channel number
530      * @hide
531      */
532     public static final int BAND_24_GHZ_FIRST_CH_NUM = 1;
533     /**
534      * 2.4 GHz band last channel number
535      * @hide
536      */
537     public static final int BAND_24_GHZ_LAST_CH_NUM = 14;
538     /**
539      * 2.4 GHz band frequency of first channel in MHz
540      * @hide
541      */
542     public static final int BAND_24_GHZ_START_FREQ_MHZ = 2412;
543     /**
544      * 2.4 GHz band frequency of last channel in MHz
545      * @hide
546      */
547     public static final int BAND_24_GHZ_END_FREQ_MHZ = 2484;
548 
549     /**
550      * 5 GHz band first channel number
551      * @hide
552      */
553     public static final int BAND_5_GHZ_FIRST_CH_NUM = 32;
554     /**
555      * 5 GHz band last channel number
556      * @hide
557      */
558     public static final int BAND_5_GHZ_LAST_CH_NUM = 173;
559     /**
560      * 5 GHz band frequency of first channel in MHz
561      * @hide
562      */
563     public static final int BAND_5_GHZ_START_FREQ_MHZ = 5160;
564     /**
565      * 5 GHz band frequency of last channel in MHz
566      * @hide
567      */
568     public static final int BAND_5_GHZ_END_FREQ_MHZ = 5865;
569 
570     /**
571      * 6 GHz band first channel number
572      * @hide
573      */
574     public static final int BAND_6_GHZ_FIRST_CH_NUM = 1;
575     /**
576      * 6 GHz band last channel number
577      * @hide
578      */
579     public static final int BAND_6_GHZ_LAST_CH_NUM = 233;
580     /**
581      * 6 GHz band frequency of first channel in MHz
582      * @hide
583      */
584     public static final int BAND_6_GHZ_START_FREQ_MHZ = 5945;
585     /**
586      * 6 GHz band frequency of last channel in MHz
587      * @hide
588      */
589     public static final int BAND_6_GHZ_END_FREQ_MHZ = 7105;
590 
591     /**
592      * Utility function to check if a frequency within 2.4 GHz band
593      * @param freqMhz frequency in MHz
594      * @return true if within 2.4GHz, false otherwise
595      *
596      * @hide
597      */
is24GHz(int freqMhz)598     public static boolean is24GHz(int freqMhz) {
599         return freqMhz >= BAND_24_GHZ_START_FREQ_MHZ && freqMhz <= BAND_24_GHZ_END_FREQ_MHZ;
600     }
601 
602     /**
603      * Utility function to check if a frequency within 5 GHz band
604      * @param freqMhz frequency in MHz
605      * @return true if within 5GHz, false otherwise
606      *
607      * @hide
608      */
is5GHz(int freqMhz)609     public static boolean is5GHz(int freqMhz) {
610         return freqMhz >=  BAND_5_GHZ_START_FREQ_MHZ && freqMhz <= BAND_5_GHZ_END_FREQ_MHZ;
611     }
612 
613     /**
614      * Utility function to check if a frequency within 6 GHz band
615      * @param freqMhz
616      * @return true if within 6GHz, false otherwise
617      *
618      * @hide
619      */
is6GHz(int freqMhz)620     public static boolean is6GHz(int freqMhz) {
621         return freqMhz >= BAND_6_GHZ_START_FREQ_MHZ && freqMhz <= BAND_6_GHZ_END_FREQ_MHZ;
622     }
623 
624     /**
625      * Utility function to convert channel number/band to frequency in MHz
626      * @param channel number to convert
627      * @param band of channel to convert
628      * @return center frequency in Mhz of the channel, {@link UNSPECIFIED} if no match
629      *
630      * @hide
631      */
convertChannelToFrequencyMhz(int channel, @WifiScanner.WifiBand int band)632     public static int convertChannelToFrequencyMhz(int channel, @WifiScanner.WifiBand int band) {
633         if (band == WifiScanner.WIFI_BAND_24_GHZ) {
634             // Special case
635             if (channel == 14) {
636                 return 2484;
637             } else if (channel >= BAND_24_GHZ_FIRST_CH_NUM && channel <= BAND_24_GHZ_LAST_CH_NUM) {
638                 return ((channel - BAND_24_GHZ_FIRST_CH_NUM) * 5) + BAND_24_GHZ_START_FREQ_MHZ;
639             } else {
640                 return UNSPECIFIED;
641             }
642         }
643         if (band == WifiScanner.WIFI_BAND_5_GHZ) {
644             if (channel >= BAND_5_GHZ_FIRST_CH_NUM && channel <= BAND_5_GHZ_LAST_CH_NUM) {
645                 return ((channel - BAND_5_GHZ_FIRST_CH_NUM) * 5) + BAND_5_GHZ_START_FREQ_MHZ;
646             } else {
647                 return UNSPECIFIED;
648             }
649         }
650         if (band == WifiScanner.WIFI_BAND_6_GHZ) {
651             if (channel >= BAND_6_GHZ_FIRST_CH_NUM && channel <= BAND_6_GHZ_LAST_CH_NUM) {
652                 return ((channel - BAND_6_GHZ_FIRST_CH_NUM) * 5) + BAND_6_GHZ_START_FREQ_MHZ;
653             } else {
654                 return UNSPECIFIED;
655             }
656         }
657         return UNSPECIFIED;
658     }
659 
660     /**
661      * Utility function to convert frequency in MHz to channel number
662      * @param freqMhz frequency in MHz
663      * @return channel number associated with given frequency, {@link UNSPECIFIED} if no match
664      *
665      * @hide
666      */
convertFrequencyMhzToChannel(int freqMhz)667     public static int convertFrequencyMhzToChannel(int freqMhz) {
668         // Special case
669         if (freqMhz == 2484) {
670             return 14;
671         } else if (is24GHz(freqMhz)) {
672             return (freqMhz - BAND_24_GHZ_START_FREQ_MHZ) / 5 + BAND_24_GHZ_FIRST_CH_NUM;
673         } else if (is5GHz(freqMhz)) {
674             return ((freqMhz - BAND_5_GHZ_START_FREQ_MHZ) / 5) + BAND_5_GHZ_FIRST_CH_NUM;
675         } else if (is6GHz(freqMhz)) {
676             return ((freqMhz - BAND_6_GHZ_START_FREQ_MHZ) / 5) + BAND_6_GHZ_FIRST_CH_NUM;
677         }
678 
679         return UNSPECIFIED;
680     }
681 
682     /**
683      * @hide
684      */
is24GHz()685     public boolean is24GHz() {
686         return ScanResult.is24GHz(frequency);
687     }
688 
689     /**
690      * @hide
691      */
is5GHz()692     public boolean is5GHz() {
693         return ScanResult.is5GHz(frequency);
694     }
695 
696     /**
697      * @hide
698      */
is6GHz()699     public boolean is6GHz() {
700         return ScanResult.is6GHz(frequency);
701     }
702 
703     /**
704      *  @hide
705      * anqp lines from supplicant BSS response
706      */
707     @UnsupportedAppUsage
708     public List<String> anqpLines;
709 
710     /**
711      * information elements from beacon.
712      */
713     public static class InformationElement {
714         /** @hide */
715         @UnsupportedAppUsage
716         public static final int EID_SSID = 0;
717         /** @hide */
718         @UnsupportedAppUsage
719         public static final int EID_SUPPORTED_RATES = 1;
720         /** @hide */
721         @UnsupportedAppUsage
722         public static final int EID_TIM = 5;
723         /** @hide */
724         @UnsupportedAppUsage
725         public static final int EID_BSS_LOAD = 11;
726         /** @hide */
727         @UnsupportedAppUsage
728         public static final int EID_ERP = 42;
729         /** @hide */
730         public static final int EID_HT_CAPABILITIES = 45;
731         /** @hide */
732         @UnsupportedAppUsage
733         public static final int EID_RSN = 48;
734         /** @hide */
735         @UnsupportedAppUsage
736         public static final int EID_EXTENDED_SUPPORTED_RATES = 50;
737         /** @hide */
738         @UnsupportedAppUsage
739         public static final int EID_HT_OPERATION = 61;
740         /** @hide */
741         @UnsupportedAppUsage
742         public static final int EID_INTERWORKING = 107;
743         /** @hide */
744         @UnsupportedAppUsage
745         public static final int EID_ROAMING_CONSORTIUM = 111;
746         /** @hide */
747         @UnsupportedAppUsage
748         public static final int EID_EXTENDED_CAPS = 127;
749         /** @hide */
750         public static final int EID_VHT_CAPABILITIES = 191;
751         /** @hide */
752         @UnsupportedAppUsage
753         public static final int EID_VHT_OPERATION = 192;
754         /** @hide */
755         @UnsupportedAppUsage
756         public static final int EID_VSA = 221;
757         /** @hide */
758         public static final int EID_EXTENSION_PRESENT = 255;
759 
760         // Extension IDs
761         /** @hide */
762         public static final int EID_EXT_HE_CAPABILITIES = 35;
763         /** @hide */
764         public static final int EID_EXT_HE_OPERATION = 36;
765 
766         /** @hide */
767         @UnsupportedAppUsage
768         public int id;
769         /** @hide */
770         public int idExt;
771 
772         /** @hide */
773         @UnsupportedAppUsage
774         public byte[] bytes;
775 
776         /** @hide */
InformationElement()777         public InformationElement() {
778         }
779 
InformationElement(@onNull InformationElement rhs)780         public InformationElement(@NonNull InformationElement rhs) {
781             this.id = rhs.id;
782             this.idExt = rhs.idExt;
783             this.bytes = rhs.bytes.clone();
784         }
785 
786         /**
787          * The element ID of the information element. Defined in the IEEE 802.11-2016 spec
788          * Table 9-77.
789          */
getId()790         public int getId() {
791             return id;
792         }
793 
794         /**
795          * The element ID Extension of the information element. Defined in the IEEE 802.11-2016 spec
796          * Table 9-77.
797          */
getIdExt()798         public int getIdExt() {
799             return idExt;
800         }
801 
802         /**
803          * Get the specific content of the information element.
804          */
805         @NonNull
getBytes()806         public ByteBuffer getBytes() {
807             return ByteBuffer.wrap(bytes).asReadOnlyBuffer();
808         }
809     }
810 
811     /**
812      * information elements found in the beacon.
813      * @hide
814      */
815     @UnsupportedAppUsage
816     public InformationElement[] informationElements;
817     /**
818      * Get all information elements found in the beacon.
819      */
820     @NonNull
getInformationElements()821     public List<InformationElement> getInformationElements() {
822         return Collections.unmodifiableList(Arrays.asList(informationElements));
823     }
824 
825     /** ANQP response elements.
826      * @hide
827      */
828     public AnqpInformationElement[] anqpElements;
829 
830     /** {@hide} */
ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId, byte[] osuProviders, String caps, int level, int frequency, long tsf)831     public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId,
832             byte[] osuProviders, String caps, int level, int frequency, long tsf) {
833         this.wifiSsid = wifiSsid;
834         this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiManager.UNKNOWN_SSID;
835         this.BSSID = BSSID;
836         this.hessid = hessid;
837         this.anqpDomainId = anqpDomainId;
838         if (osuProviders != null) {
839             this.anqpElements = new AnqpInformationElement[1];
840             this.anqpElements[0] =
841                     new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID,
842                             AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders);
843         }
844         this.capabilities = caps;
845         this.level = level;
846         this.frequency = frequency;
847         this.timestamp = tsf;
848         this.distanceCm = UNSPECIFIED;
849         this.distanceSdCm = UNSPECIFIED;
850         this.channelWidth = UNSPECIFIED;
851         this.centerFreq0 = UNSPECIFIED;
852         this.centerFreq1 = UNSPECIFIED;
853         this.flags = 0;
854         this.radioChainInfos = null;
855         this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
856     }
857 
858     /** {@hide} */
ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, long tsf, int distCm, int distSdCm)859     public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
860             long tsf, int distCm, int distSdCm) {
861         this.wifiSsid = wifiSsid;
862         this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiManager.UNKNOWN_SSID;
863         this.BSSID = BSSID;
864         this.capabilities = caps;
865         this.level = level;
866         this.frequency = frequency;
867         this.timestamp = tsf;
868         this.distanceCm = distCm;
869         this.distanceSdCm = distSdCm;
870         this.channelWidth = UNSPECIFIED;
871         this.centerFreq0 = UNSPECIFIED;
872         this.centerFreq1 = UNSPECIFIED;
873         this.flags = 0;
874         this.radioChainInfos = null;
875         this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
876     }
877 
878     /** {@hide} */
ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder)879     public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps,
880             int level, int frequency,
881             long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
882             boolean is80211McRTTResponder) {
883         this.SSID = Ssid;
884         this.BSSID = BSSID;
885         this.hessid = hessid;
886         this.anqpDomainId = anqpDomainId;
887         this.capabilities = caps;
888         this.level = level;
889         this.frequency = frequency;
890         this.timestamp = tsf;
891         this.distanceCm = distCm;
892         this.distanceSdCm = distSdCm;
893         this.channelWidth = channelWidth;
894         this.centerFreq0 = centerFreq0;
895         this.centerFreq1 = centerFreq1;
896         if (is80211McRTTResponder) {
897             this.flags = FLAG_80211mc_RESPONDER;
898         } else {
899             this.flags = 0;
900         }
901         this.radioChainInfos = null;
902         this.mWifiStandard = WIFI_STANDARD_UNKNOWN;
903     }
904 
905     /** {@hide} */
ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId, String caps, int level, int frequency, long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1, boolean is80211McRTTResponder)906     public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId,
907                   String caps, int level,
908                   int frequency, long tsf, int distCm, int distSdCm, int channelWidth,
909                   int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) {
910         this(Ssid, BSSID, hessid, anqpDomainId, caps, level, frequency, tsf, distCm,
911                 distSdCm, channelWidth, centerFreq0, centerFreq1, is80211McRTTResponder);
912         this.wifiSsid = wifiSsid;
913     }
914 
915     /** copy constructor */
ScanResult(@onNull ScanResult source)916     public ScanResult(@NonNull ScanResult source) {
917         if (source != null) {
918             wifiSsid = source.wifiSsid;
919             SSID = source.SSID;
920             BSSID = source.BSSID;
921             hessid = source.hessid;
922             anqpDomainId = source.anqpDomainId;
923             informationElements = source.informationElements;
924             anqpElements = source.anqpElements;
925             capabilities = source.capabilities;
926             level = source.level;
927             frequency = source.frequency;
928             channelWidth = source.channelWidth;
929             centerFreq0 = source.centerFreq0;
930             centerFreq1 = source.centerFreq1;
931             timestamp = source.timestamp;
932             distanceCm = source.distanceCm;
933             distanceSdCm = source.distanceSdCm;
934             seen = source.seen;
935             untrusted = source.untrusted;
936             numUsage = source.numUsage;
937             venueName = source.venueName;
938             operatorFriendlyName = source.operatorFriendlyName;
939             flags = source.flags;
940             radioChainInfos = source.radioChainInfos;
941             this.mWifiStandard = source.mWifiStandard;
942         }
943     }
944 
945     /** Construct an empty scan result. */
ScanResult()946     public ScanResult() {
947     }
948 
949     @Override
toString()950     public String toString() {
951         StringBuffer sb = new StringBuffer();
952         String none = "<none>";
953 
954         sb.append("SSID: ")
955                 .append(wifiSsid == null ? WifiManager.UNKNOWN_SSID : wifiSsid)
956                 .append(", BSSID: ")
957                 .append(BSSID == null ? none : BSSID)
958                 .append(", capabilities: ")
959                 .append(capabilities == null ? none : capabilities)
960                 .append(", level: ")
961                 .append(level)
962                 .append(", frequency: ")
963                 .append(frequency)
964                 .append(", timestamp: ")
965                 .append(timestamp);
966         sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
967                 append("(cm)");
968         sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
969                 append("(cm)");
970 
971         sb.append(", passpoint: ");
972         sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
973         sb.append(", ChannelBandwidth: ").append(channelWidth);
974         sb.append(", centerFreq0: ").append(centerFreq0);
975         sb.append(", centerFreq1: ").append(centerFreq1);
976         sb.append(", standard: ").append(wifiStandardToString(mWifiStandard));
977         sb.append(", 80211mcResponder: ");
978         sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
979         sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos));
980         return sb.toString();
981     }
982 
983     /** Implement the Parcelable interface {@hide} */
describeContents()984     public int describeContents() {
985         return 0;
986     }
987 
988     /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)989     public void writeToParcel(Parcel dest, int flags) {
990         if (wifiSsid != null) {
991             dest.writeInt(1);
992             wifiSsid.writeToParcel(dest, flags);
993         } else {
994             dest.writeInt(0);
995         }
996         dest.writeString(SSID);
997         dest.writeString(BSSID);
998         dest.writeLong(hessid);
999         dest.writeInt(anqpDomainId);
1000         dest.writeString(capabilities);
1001         dest.writeInt(level);
1002         dest.writeInt(frequency);
1003         dest.writeLong(timestamp);
1004         dest.writeInt(distanceCm);
1005         dest.writeInt(distanceSdCm);
1006         dest.writeInt(channelWidth);
1007         dest.writeInt(centerFreq0);
1008         dest.writeInt(centerFreq1);
1009         dest.writeInt(mWifiStandard);
1010         dest.writeLong(seen);
1011         dest.writeInt(untrusted ? 1 : 0);
1012         dest.writeInt(numUsage);
1013         dest.writeString((venueName != null) ? venueName.toString() : "");
1014         dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
1015         dest.writeLong(this.flags);
1016 
1017         if (informationElements != null) {
1018             dest.writeInt(informationElements.length);
1019             for (int i = 0; i < informationElements.length; i++) {
1020                 dest.writeInt(informationElements[i].id);
1021                 dest.writeInt(informationElements[i].idExt);
1022                 dest.writeInt(informationElements[i].bytes.length);
1023                 dest.writeByteArray(informationElements[i].bytes);
1024             }
1025         } else {
1026             dest.writeInt(0);
1027         }
1028 
1029         if (anqpLines != null) {
1030             dest.writeInt(anqpLines.size());
1031             for (int i = 0; i < anqpLines.size(); i++) {
1032                 dest.writeString(anqpLines.get(i));
1033             }
1034         }
1035         else {
1036             dest.writeInt(0);
1037         }
1038         if (anqpElements != null) {
1039             dest.writeInt(anqpElements.length);
1040             for (AnqpInformationElement element : anqpElements) {
1041                 dest.writeInt(element.getVendorId());
1042                 dest.writeInt(element.getElementId());
1043                 dest.writeInt(element.getPayload().length);
1044                 dest.writeByteArray(element.getPayload());
1045             }
1046         } else {
1047             dest.writeInt(0);
1048         }
1049 
1050         if (radioChainInfos != null) {
1051             dest.writeInt(radioChainInfos.length);
1052             for (int i = 0; i < radioChainInfos.length; i++) {
1053                 dest.writeInt(radioChainInfos[i].id);
1054                 dest.writeInt(radioChainInfos[i].level);
1055             }
1056         } else {
1057             dest.writeInt(0);
1058         }
1059     }
1060 
1061     /** Implement the Parcelable interface */
1062     public static final @NonNull Creator<ScanResult> CREATOR =
1063         new Creator<ScanResult>() {
1064             public ScanResult createFromParcel(Parcel in) {
1065                 WifiSsid wifiSsid = null;
1066                 if (in.readInt() == 1) {
1067                     wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
1068                 }
1069                 ScanResult sr = new ScanResult(
1070                         wifiSsid,
1071                         in.readString(),                    /* SSID  */
1072                         in.readString(),                    /* BSSID */
1073                         in.readLong(),                      /* HESSID */
1074                         in.readInt(),                       /* ANQP Domain ID */
1075                         in.readString(),                    /* capabilities */
1076                         in.readInt(),                       /* level */
1077                         in.readInt(),                       /* frequency */
1078                         in.readLong(),                      /* timestamp */
1079                         in.readInt(),                       /* distanceCm */
1080                         in.readInt(),                       /* distanceSdCm */
1081                         in.readInt(),                       /* channelWidth */
1082                         in.readInt(),                       /* centerFreq0 */
1083                         in.readInt(),                       /* centerFreq1 */
1084                         false                               /* rtt responder,
1085                                                                fixed with flags below */
1086                 );
1087 
1088                 sr.mWifiStandard = in.readInt();
1089                 sr.seen = in.readLong();
1090                 sr.untrusted = in.readInt() != 0;
1091                 sr.numUsage = in.readInt();
1092                 sr.venueName = in.readString();
1093                 sr.operatorFriendlyName = in.readString();
1094                 sr.flags = in.readLong();
1095                 int n = in.readInt();
1096                 if (n != 0) {
1097                     sr.informationElements = new InformationElement[n];
1098                     for (int i = 0; i < n; i++) {
1099                         sr.informationElements[i] = new InformationElement();
1100                         sr.informationElements[i].id = in.readInt();
1101                         sr.informationElements[i].idExt = in.readInt();
1102                         int len = in.readInt();
1103                         sr.informationElements[i].bytes = new byte[len];
1104                         in.readByteArray(sr.informationElements[i].bytes);
1105                     }
1106                 }
1107 
1108                 n = in.readInt();
1109                 if (n != 0) {
1110                     sr.anqpLines = new ArrayList<String>();
1111                     for (int i = 0; i < n; i++) {
1112                         sr.anqpLines.add(in.readString());
1113                     }
1114                 }
1115                 n = in.readInt();
1116                 if (n != 0) {
1117                     sr.anqpElements = new AnqpInformationElement[n];
1118                     for (int i = 0; i < n; i++) {
1119                         int vendorId = in.readInt();
1120                         int elementId = in.readInt();
1121                         int len = in.readInt();
1122                         byte[] payload = new byte[len];
1123                         in.readByteArray(payload);
1124                         sr.anqpElements[i] =
1125                                 new AnqpInformationElement(vendorId, elementId, payload);
1126                     }
1127                 }
1128                 n = in.readInt();
1129                 if (n != 0) {
1130                     sr.radioChainInfos = new RadioChainInfo[n];
1131                     for (int i = 0; i < n; i++) {
1132                         sr.radioChainInfos[i] = new RadioChainInfo();
1133                         sr.radioChainInfos[i].id = in.readInt();
1134                         sr.radioChainInfos[i].level = in.readInt();
1135                     }
1136                 }
1137                 return sr;
1138             }
1139 
1140             public ScanResult[] newArray(int size) {
1141                 return new ScanResult[size];
1142             }
1143         };
1144 }
1145