• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.IntDef;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.net.MacAddress;
26 import android.net.wifi.WifiAnnotations.ChannelWidth;
27 import android.net.wifi.WifiAnnotations.WifiStandard;
28 import android.net.wifi.util.ScanResultUtil;
29 import android.os.Build;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 
33 import com.android.modules.utils.build.SdkLevel;
34 
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 import java.nio.ByteBuffer;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.Objects;
43 
44 /**
45  * Describes information about a detected access point. In addition
46  * to the attributes described here, the supplicant keeps track of
47  * {@code quality}, {@code noise}, and {@code maxbitrate} attributes,
48  * but does not currently report them to external clients.
49  */
50 public final class ScanResult implements Parcelable {
51     /**
52      * The network name.
53      *
54      * @deprecated Use {@link #getWifiSsid()} instead.
55      */
56     @Deprecated
57     public String SSID;
58 
59     /**
60      * Ascii encoded SSID. This will replace SSID when we deprecate it. @hide
61      *
62      * @deprecated Use {@link #getWifiSsid()} instead.
63      */
64     @Deprecated
65     // TODO(b/231433398): add maxTargetSdk = Build.VERSION_CODES.S
66     @UnsupportedAppUsage(publicAlternatives = "{@link #getWifiSsid()}")
67     public WifiSsid wifiSsid;
68 
69     /**
70      * Set the SSID of the access point.
71      * @hide
72      */
73     @SystemApi
setWifiSsid(@onNull WifiSsid ssid)74     public void setWifiSsid(@NonNull WifiSsid ssid) {
75         wifiSsid = ssid;
76         CharSequence utf8Text = wifiSsid.getUtf8Text();
77         SSID = utf8Text != null ? utf8Text.toString() : WifiManager.UNKNOWN_SSID;
78     }
79 
80     /**
81      * The SSID of the access point.
82      */
83     @Nullable
getWifiSsid()84     public WifiSsid getWifiSsid() {
85         return wifiSsid;
86     }
87 
88     /**
89      * The address of the access point.
90      */
91     public String BSSID;
92 
93     /**
94      * The Multi-Link Device (MLD) address of the access point.
95      * Only applicable for Wi-Fi 7 access points, null otherwise.
96      */
97     private MacAddress mApMldMacAddress;
98 
99     /**
100      * Return the access point Multi-Link Device (MLD) MAC Address for Wi-Fi 7 access points.
101      * i.e. {@link #getWifiStandard()} returns {@link #WIFI_STANDARD_11BE}.
102      *
103      * @return MLD MAC Address for access point if exists (Wi-Fi 7 access points), null otherwise.
104      */
105     @Nullable
getApMldMacAddress()106     public MacAddress getApMldMacAddress() {
107         return mApMldMacAddress;
108     }
109 
110     /**
111      * Set the access point Multi-Link Device (MLD) MAC Address.
112      * @hide
113      */
setApMldMacAddress(@ullable MacAddress address)114     public void setApMldMacAddress(@Nullable MacAddress address) {
115         mApMldMacAddress = address;
116     }
117 
118     /**
119      * The Multi-Link Operation (MLO) link id for the access point.
120      * Only applicable for Wi-Fi 7 access points.
121      */
122     private int mApMloLinkId = MloLink.INVALID_MLO_LINK_ID;
123 
124     /**
125      * Return the access point Multi-Link Operation (MLO) link-id for Wi-Fi 7 access points.
126      * i.e. when {@link #getWifiStandard()} returns {@link #WIFI_STANDARD_11BE}, otherwise return
127      * {@link MloLink#INVALID_MLO_LINK_ID}.
128      *
129      * Valid values are 0-15 as described in IEEE 802.11be Specification, section 9.4.2.295b.2.
130      *
131      * @return {@link MloLink#INVALID_MLO_LINK_ID} or a valid value (0-15).
132      */
133     @IntRange(from = MloLink.INVALID_MLO_LINK_ID, to = MloLink.MAX_MLO_LINK_ID)
getApMloLinkId()134     public int getApMloLinkId() {
135         return mApMloLinkId;
136     }
137 
138     /**
139      * Sets the access point Multi-Link Operation (MLO) link-id
140      * @hide
141      */
setApMloLinkId(int linkId)142     public void setApMloLinkId(int linkId) {
143         mApMloLinkId = linkId;
144     }
145 
146     /**
147      * The Multi-Link Operation (MLO) affiliated Links.
148      * Only applicable for Wi-Fi 7 access points.
149      * Note: the list of links includes the access point for this ScanResult.
150      */
151     private List<MloLink> mAffiliatedMloLinks = Collections.emptyList();
152 
153     /**
154      * Return the Multi-Link Operation (MLO) affiliated Links for Wi-Fi 7 access points.
155      * i.e. when {@link #getWifiStandard()} returns {@link #WIFI_STANDARD_11BE}.
156      *
157      * @return List of affiliated MLO links, or an empty list if access point is not Wi-Fi 7
158      */
159     @NonNull
getAffiliatedMloLinks()160     public List<MloLink> getAffiliatedMloLinks() {
161         return new ArrayList<MloLink>(mAffiliatedMloLinks);
162     }
163 
164     /**
165      * Set the Multi-Link Operation (MLO) affiliated Links.
166      * Only applicable for Wi-Fi 7 access points.
167      *
168      * @hide
169      */
setAffiliatedMloLinks(@onNull List<MloLink> links)170     public void setAffiliatedMloLinks(@NonNull List<MloLink> links) {
171         mAffiliatedMloLinks = new ArrayList<MloLink>(links);
172     }
173 
174     /**
175      * The HESSID from the beacon.
176      * @hide
177      */
178     @UnsupportedAppUsage
179     public long hessid;
180 
181     /**
182      * The ANQP Domain ID from the Hotspot 2.0 Indication element, if present.
183      * @hide
184      */
185     @UnsupportedAppUsage
186     public int anqpDomainId;
187 
188     /*
189      * This field is equivalent to the |flags|, rather than the |capabilities| field
190      * of the per-BSS scan results returned by WPA supplicant. See the definition of
191      * |struct wpa_bss| in wpa_supplicant/bss.h for more details.
192      */
193     /**
194      * Describes the authentication, key management, and encryption schemes
195      * supported by the access point.
196      */
197     public String capabilities;
198 
199     /**
200      * The interface name on which the scan result was received.
201      * @hide
202      */
203     public String ifaceName;
204 
205     /**
206      * @hide
207      * No security protocol.
208      */
209     @SystemApi
210     public static final int PROTOCOL_NONE = 0;
211     /**
212      * @hide
213      * Security protocol type: WPA version 1.
214      */
215     @SystemApi
216     public static final int PROTOCOL_WPA = 1;
217     /**
218      * @hide
219      * Security protocol type: RSN, for WPA version 2, and version 3.
220      */
221     @SystemApi
222     public static final int PROTOCOL_RSN = 2;
223     /**
224      * @hide
225      * Security protocol type:
226      * OSU Server-only authenticated layer 2 Encryption Network.
227      * Used for Hotspot 2.0.
228      */
229     @SystemApi
230     public static final int PROTOCOL_OSEN = 3;
231 
232     /**
233      * @hide
234      * Security protocol type: WAPI.
235      */
236     @SystemApi
237     public static final int PROTOCOL_WAPI = 4;
238 
239     /**
240      * @hide
241      * No security key management scheme.
242      */
243     @SystemApi
244     public static final int KEY_MGMT_NONE = 0;
245     /**
246      * @hide
247      * Security key management scheme: PSK.
248      */
249     @SystemApi
250     public static final int KEY_MGMT_PSK = 1;
251     /**
252      * @hide
253      * Security key management scheme: EAP.
254      */
255     @SystemApi
256     public static final int KEY_MGMT_EAP = 2;
257     /**
258      * @hide
259      * Security key management scheme: FT_PSK.
260      */
261     @SystemApi
262     public static final int KEY_MGMT_FT_PSK = 3;
263     /**
264      * @hide
265      * Security key management scheme: FT_EAP.
266      */
267     @SystemApi
268     public static final int KEY_MGMT_FT_EAP = 4;
269     /**
270      * @hide
271      * Security key management scheme: PSK_SHA256
272      */
273     @SystemApi
274     public static final int KEY_MGMT_PSK_SHA256 = 5;
275     /**
276      * @hide
277      * Security key management scheme: EAP_SHA256.
278      */
279     @SystemApi
280     public static final int KEY_MGMT_EAP_SHA256 = 6;
281     /**
282      * @hide
283      * Security key management scheme: OSEN.
284      * Used for Hotspot 2.0.
285      */
286     @SystemApi
287     public static final int KEY_MGMT_OSEN = 7;
288      /**
289      * @hide
290      * Security key management scheme: SAE.
291      */
292     @SystemApi
293     public static final int KEY_MGMT_SAE = 8;
294     /**
295      * @hide
296      * Security key management scheme: OWE.
297      */
298     @SystemApi
299     public static final int KEY_MGMT_OWE = 9;
300     /**
301      * @hide
302      * Security key management scheme: SUITE_B_192.
303      */
304     @SystemApi
305     public static final int KEY_MGMT_EAP_SUITE_B_192 = 10;
306     /**
307      * @hide
308      * Security key management scheme: FT_SAE.
309      */
310     @SystemApi
311     public static final int KEY_MGMT_FT_SAE = 11;
312     /**
313      * @hide
314      * Security key management scheme: OWE in transition mode.
315      */
316     @SystemApi
317     public static final int KEY_MGMT_OWE_TRANSITION = 12;
318     /**
319      * @hide
320      * Security key management scheme: WAPI_PSK.
321      */
322     @SystemApi
323     public static final int KEY_MGMT_WAPI_PSK = 13;
324     /**
325      * @hide
326      * Security key management scheme: WAPI_CERT.
327      */
328     @SystemApi
329     public static final int KEY_MGMT_WAPI_CERT = 14;
330 
331     /**
332      * @hide
333      * Security key management scheme: FILS_SHA256.
334      */
335     public static final int KEY_MGMT_FILS_SHA256 = 15;
336     /**
337      * @hide
338      * Security key management scheme: FILS_SHA384.
339      */
340     public static final int KEY_MGMT_FILS_SHA384 = 16;
341     /**
342      * @hide
343      * Security key management scheme: DPP.
344      */
345     public static final int KEY_MGMT_DPP = 17;
346     /**
347      * @hide
348      * Security key management scheme: SAE_EXT_KEY.
349      */
350     public static final int KEY_MGMT_SAE_EXT_KEY = 18;
351     /**
352      * @hide
353      * Security key management scheme: FT_SAE_EXT_KEY.
354      */
355     public static final int KEY_MGMT_FT_SAE_EXT_KEY = 19;
356     /**
357      * @hide
358      * Security key management scheme: any unknown AKM.
359      */
360     public static final int KEY_MGMT_UNKNOWN = 20;
361     /**
362      * @hide
363      * No cipher suite.
364      */
365     @SystemApi
366     public static final int CIPHER_NONE = 0;
367     /**
368      * @hide
369      * No group addressed, only used for group data cipher.
370      */
371     @SystemApi
372     public static final int CIPHER_NO_GROUP_ADDRESSED = 1;
373     /**
374      * @hide
375      * Cipher suite: TKIP
376      */
377     @SystemApi
378     public static final int CIPHER_TKIP = 2;
379     /**
380      * @hide
381      * Cipher suite: CCMP
382      */
383     @SystemApi
384     public static final int CIPHER_CCMP = 3;
385     /**
386      * @hide
387      * Cipher suite: GCMP
388      */
389     @SystemApi
390     public static final int CIPHER_GCMP_256 = 4;
391     /**
392      * @hide
393      * Cipher suite: SMS4
394      */
395     @SystemApi
396     public static final int CIPHER_SMS4 = 5;
397     /**
398      * @hide
399      * Cipher suite: GCMP_128
400      */
401     @SystemApi
402     public static final int CIPHER_GCMP_128 = 6;
403     /**
404      * @hide
405      * Cipher suite: BIP_GMAC_128
406      */
407     @SystemApi
408     public static final int CIPHER_BIP_GMAC_128 = 7;
409     /**
410      * @hide
411      * Cipher suite: BIP_GMAC_256
412      */
413     @SystemApi
414     public static final int CIPHER_BIP_GMAC_256 = 8;
415     /**
416      * @hide
417      * Cipher suite: BIP_CMAC_256
418      */
419     @SystemApi
420     public static final int CIPHER_BIP_CMAC_256 = 9;
421 
422     /**
423      * The detected signal level in dBm, also known as the RSSI.
424      *
425      * <p>Use {@link android.net.wifi.WifiManager#calculateSignalLevel} to convert this number into
426      * an absolute signal level which can be displayed to a user.
427      */
428     public int level;
429 
430     /**
431      * The center frequency of the primary 20 MHz frequency (in MHz) of the channel over which the
432      * client is communicating with the access point.
433      */
434     public int frequency;
435 
436    /**
437     * AP Channel bandwidth is 20 MHZ
438     */
439     public static final int CHANNEL_WIDTH_20MHZ = 0;
440    /**
441     * AP Channel bandwidth is 40 MHZ
442     */
443     public static final int CHANNEL_WIDTH_40MHZ = 1;
444    /**
445     * AP Channel bandwidth is 80 MHZ
446     */
447     public static final int CHANNEL_WIDTH_80MHZ = 2;
448    /**
449     * AP Channel bandwidth is 160 MHZ
450     */
451     public static final int CHANNEL_WIDTH_160MHZ = 3;
452    /**
453     * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
454     */
455     public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
456    /**
457     * AP Channel bandwidth is 320 MHZ
458     */
459     public static final int CHANNEL_WIDTH_320MHZ = 5;
460 
461     /**
462      * Preamble type: Legacy.
463      */
464     public static final int PREAMBLE_LEGACY = 0;
465     /**
466      * Preamble type: HT.
467      */
468     public static final int PREAMBLE_HT = 1;
469     /**
470      * Preamble type: VHT.
471      */
472     public static final int PREAMBLE_VHT = 2;
473     /**
474      * Preamble type: HE.
475      */
476     public static final int PREAMBLE_HE = 3;
477 
478     /**
479      * Preamble type: EHT.
480      */
481     public static final int PREAMBLE_EHT = 4;
482 
483     /**
484      * Wi-Fi unknown standard
485      */
486     public static final int WIFI_STANDARD_UNKNOWN = 0;
487 
488     /**
489      * Wi-Fi 802.11a/b/g
490      */
491     public static final int WIFI_STANDARD_LEGACY = 1;
492 
493     /**
494      * Wi-Fi 802.11n
495      */
496     public static final int WIFI_STANDARD_11N = 4;
497 
498     /**
499      * Wi-Fi 802.11ac
500      */
501     public static final int WIFI_STANDARD_11AC = 5;
502 
503     /**
504      * Wi-Fi 802.11ax
505      */
506     public static final int WIFI_STANDARD_11AX = 6;
507 
508     /**
509      * Wi-Fi 802.11ad
510      */
511     public static final int WIFI_STANDARD_11AD = 7;
512 
513     /**
514      * Wi-Fi 802.11be
515      */
516     public static final int WIFI_STANDARD_11BE = 8;
517 
518     /**
519      * Wi-Fi 2.4 GHz band.
520      */
521     public static final int WIFI_BAND_24_GHZ = WifiScanner.WIFI_BAND_24_GHZ;
522 
523     /**
524      * Wi-Fi 5 GHz band.
525      */
526     public static final int WIFI_BAND_5_GHZ = WifiScanner.WIFI_BAND_5_GHZ;
527 
528     /**
529      * Wi-Fi 6 GHz band.
530      */
531     public static final int WIFI_BAND_6_GHZ = WifiScanner.WIFI_BAND_6_GHZ;
532 
533     /**
534      * Wi-Fi 60 GHz band.
535      */
536     public static final int WIFI_BAND_60_GHZ = WifiScanner.WIFI_BAND_60_GHZ;
537 
538     /**
539      * @hide
540      */
541     @Retention(RetentionPolicy.SOURCE)
542     @IntDef(prefix = {"WIFI_BAND_"}, value = {
543             UNSPECIFIED,
544             WIFI_BAND_24_GHZ,
545             WIFI_BAND_5_GHZ,
546             WIFI_BAND_6_GHZ,
547             WIFI_BAND_60_GHZ})
548     public @interface WifiBand {};
549 
550     /**
551      * AP wifi standard.
552      */
553     private @WifiStandard int mWifiStandard = WIFI_STANDARD_UNKNOWN;
554 
555     /**
556      * return the AP wifi standard.
557      */
getWifiStandard()558     public @WifiStandard int getWifiStandard() {
559         return mWifiStandard;
560     }
561 
562     /**
563      * sets the AP wifi standard.
564      * @hide
565      */
setWifiStandard(@ifiStandard int standard)566     public void setWifiStandard(@WifiStandard int standard) {
567         mWifiStandard = standard;
568     }
569 
570     /**
571      * Convert Wi-Fi standard to string
572      * @hide
573      */
wifiStandardToString(@ifiStandard int standard)574     public static @Nullable String wifiStandardToString(@WifiStandard int standard) {
575         switch(standard) {
576             case WIFI_STANDARD_LEGACY:
577                 return "legacy";
578             case WIFI_STANDARD_11N:
579                 return "11n";
580             case WIFI_STANDARD_11AC:
581                 return "11ac";
582             case WIFI_STANDARD_11AX:
583                 return "11ax";
584             case WIFI_STANDARD_11AD:
585                 return "11ad";
586             case WIFI_STANDARD_11BE:
587                 return "11be";
588             case WIFI_STANDARD_UNKNOWN:
589                 return "unknown";
590         }
591         return null;
592     }
593 
594     /**
595      * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
596      * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}, {@link #CHANNEL_WIDTH_320MHZ},
597      * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}, or {@link #CHANNEL_WIDTH_320MHZ}
598      */
599     public @ChannelWidth int channelWidth;
600 
601     /**
602      * Not used if the AP bandwidth is 20 MHz
603      * If the AP use 40, 80, 160 or 320MHz, this is the center frequency (in MHz)
604      * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz)
605      */
606     public int centerFreq0;
607 
608     /**
609      * Only used if the AP bandwidth is 80 + 80 MHz
610      * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz)
611      */
612     public int centerFreq1;
613 
614     /**
615      * @deprecated use is80211mcResponder() instead
616      * @hide
617      */
618     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
619     public boolean is80211McRTTResponder;
620 
621     /**
622      * timestamp in microseconds (since boot) when
623      * this result was last seen.
624      */
625     public long timestamp;
626 
627     /**
628      * Timestamp representing date when this result was last seen, in milliseconds from 1970
629      * {@hide}
630      */
631     @UnsupportedAppUsage
632     public long seen;
633 
634     /**
635      * On devices with multiple hardware radio chains, this class provides metadata about
636      * each radio chain that was used to receive this scan result (probe response or beacon).
637      * {@hide}
638      */
639     public static class RadioChainInfo {
640         /** Vendor defined id for a radio chain. */
641         public int id;
642         /** Detected signal level in dBm (also known as the RSSI) on this radio chain. */
643         public int level;
644 
645         @Override
toString()646         public String toString() {
647             return "RadioChainInfo: id=" + id + ", level=" + level;
648         }
649 
650         @Override
equals(Object otherObj)651         public boolean equals(Object otherObj) {
652             if (this == otherObj) {
653                 return true;
654             }
655             if (!(otherObj instanceof RadioChainInfo)) {
656                 return false;
657             }
658             RadioChainInfo other = (RadioChainInfo) otherObj;
659             return id == other.id && level == other.level;
660         }
661 
662         @Override
hashCode()663         public int hashCode() {
664             return Objects.hash(id, level);
665         }
666     };
667 
668     /**
669      * Information about the list of the radio chains used to receive this scan result
670      * (probe response or beacon).
671      *
672      * For Example: On devices with 2 hardware radio chains, this list could hold 1 or 2
673      * entries based on whether this scan result was received using one or both the chains.
674      * {@hide}
675      */
676     public RadioChainInfo[] radioChainInfos;
677 
678     /**
679      * Status indicating the scan result does not correspond to a user's saved configuration
680      * @hide
681      * @removed
682      */
683     @SystemApi
684     public boolean untrusted;
685 
686     /**
687      * Number of time autojoin used it
688      * @hide
689      */
690     @UnsupportedAppUsage
691     public int numUsage;
692 
693     /**
694      * The approximate distance to the AP in centimeter, if available.  Else
695      * {@link #UNSPECIFIED}.
696      * {@hide}
697      */
698     @UnsupportedAppUsage
699     public int distanceCm;
700 
701     /**
702      * The standard deviation of the distance to the access point, if available.
703      * Else {@link #UNSPECIFIED}.
704      * {@hide}
705      */
706     @UnsupportedAppUsage
707     public int distanceSdCm;
708 
709     /** {@hide} */
710     public static final long FLAG_PASSPOINT_NETWORK               = 0x0000000000000001;
711 
712     /** {@hide} */
713     public static final long FLAG_80211mc_RESPONDER               = 0x0000000000000002;
714 
715     /*
716      * These flags are specific to the ScanResult class, and are not related to the |flags|
717      * field of the per-BSS scan results from WPA supplicant.
718      */
719     /**
720      * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}.
721      * {@hide}
722      */
723     @UnsupportedAppUsage
724     public long flags;
725 
726     /**
727      * sets a flag in {@link #flags} field
728      * @param flag flag to set
729      * @hide
730      */
setFlag(long flag)731     public void setFlag(long flag) {
732         flags |= flag;
733     }
734 
735     /**
736      * clears a flag in {@link #flags} field
737      * @param flag flag to set
738      * @hide
739      */
clearFlag(long flag)740     public void clearFlag(long flag) {
741         flags &= ~flag;
742     }
743 
is80211mcResponder()744     public boolean is80211mcResponder() {
745         return (flags & FLAG_80211mc_RESPONDER) != 0;
746     }
747 
isPasspointNetwork()748     public boolean isPasspointNetwork() {
749         return (flags & FLAG_PASSPOINT_NETWORK) != 0;
750     }
751 
752     /**
753      * Indicates venue name (such as 'San Francisco Airport') published by access point; only
754      * available on Passpoint network and if published by access point.
755      * @deprecated - This information is not provided
756      */
757     @Deprecated
758     public CharSequence venueName;
759 
760     /**
761      * Indicates Passpoint operator name published by access point.
762      * @deprecated - Use {@link WifiInfo#getPasspointProviderFriendlyName()}
763      */
764     @Deprecated
765     public CharSequence operatorFriendlyName;
766 
767     /**
768      * The unspecified value.
769      */
770     public final static int UNSPECIFIED = -1;
771 
772     /**
773      * 2.4 GHz band first channel number
774      * @hide
775      */
776     public static final int BAND_24_GHZ_FIRST_CH_NUM = 1;
777     /**
778      * 2.4 GHz band last channel number
779      * @hide
780      */
781     public static final int BAND_24_GHZ_LAST_CH_NUM = 14;
782     /**
783      * 2.4 GHz band frequency of first channel in MHz
784      * @hide
785      */
786     public static final int BAND_24_GHZ_START_FREQ_MHZ = 2412;
787     /**
788      * 2.4 GHz band frequency of last channel in MHz
789      * @hide
790      */
791     public static final int BAND_24_GHZ_END_FREQ_MHZ = 2484;
792 
793     /**
794      * 5 GHz band first channel number
795      * @hide
796      */
797     public static final int BAND_5_GHZ_FIRST_CH_NUM = 32;
798     /**
799      * 5 GHz band last channel number
800      * @hide
801      */
802     public static final int BAND_5_GHZ_LAST_CH_NUM = 177;
803     /**
804      * 5 GHz band frequency of first channel in MHz
805      * @hide
806      */
807     public static final int BAND_5_GHZ_START_FREQ_MHZ = 5160;
808     /**
809      * 5 GHz band frequency of last channel in MHz
810      * @hide
811      */
812     public static final int BAND_5_GHZ_END_FREQ_MHZ = 5885;
813 
814     /**
815      * 6 GHz band first channel number
816      * @hide
817      */
818     public static final int BAND_6_GHZ_FIRST_CH_NUM = 1;
819     /**
820      * 6 GHz band last channel number
821      * @hide
822      */
823     public static final int BAND_6_GHZ_LAST_CH_NUM = 233;
824     /**
825      * 6 GHz band frequency of first channel in MHz
826      * @hide
827      */
828     public static final int BAND_6_GHZ_START_FREQ_MHZ = 5955;
829     /**
830      * 6 GHz band frequency of last channel in MHz
831      * @hide
832      */
833     public static final int BAND_6_GHZ_END_FREQ_MHZ = 7115;
834     /**
835      * The center frequency of the first 6Ghz preferred scanning channel, as defined by
836      * IEEE802.11ax draft 7.0 section 26.17.2.3.3.
837      * @hide
838      */
839     public static final int BAND_6_GHZ_PSC_START_MHZ = 5975;
840     /**
841      * The number of MHz to increment in order to get the next 6Ghz preferred scanning channel
842      * as defined by IEEE802.11ax draft 7.0 section 26.17.2.3.3.
843      * @hide
844      */
845     public static final int BAND_6_GHZ_PSC_STEP_SIZE_MHZ = 80;
846 
847     /**
848      * 6 GHz band operating class 136 channel 2 center frequency in MHz
849      * @hide
850      */
851     public static final int BAND_6_GHZ_OP_CLASS_136_CH_2_FREQ_MHZ = 5935;
852 
853     /**
854      * 60 GHz band first channel number
855      * @hide
856      */
857     public static final int BAND_60_GHZ_FIRST_CH_NUM = 1;
858     /**
859      * 60 GHz band last channel number
860      * @hide
861      */
862     public static final int BAND_60_GHZ_LAST_CH_NUM = 6;
863     /**
864      * 60 GHz band frequency of first channel in MHz
865      * @hide
866      */
867     public static final int BAND_60_GHZ_START_FREQ_MHZ = 58320;
868     /**
869      * 60 GHz band frequency of last channel in MHz
870      * @hide
871      */
872     public static final int BAND_60_GHZ_END_FREQ_MHZ = 70200;
873 
874     /**
875      * Utility function to check if a frequency within 2.4 GHz band
876      * @param freqMhz frequency in MHz
877      * @return true if within 2.4GHz, false otherwise
878      *
879      * @hide
880      */
is24GHz(int freqMhz)881     public static boolean is24GHz(int freqMhz) {
882         return freqMhz >= BAND_24_GHZ_START_FREQ_MHZ && freqMhz <= BAND_24_GHZ_END_FREQ_MHZ;
883     }
884 
885     /**
886      * Utility function to check if a frequency within 5 GHz band
887      * @param freqMhz frequency in MHz
888      * @return true if within 5GHz, false otherwise
889      *
890      * @hide
891      */
is5GHz(int freqMhz)892     public static boolean is5GHz(int freqMhz) {
893         return freqMhz >=  BAND_5_GHZ_START_FREQ_MHZ && freqMhz <= BAND_5_GHZ_END_FREQ_MHZ;
894     }
895 
896     /**
897      * Utility function to check if a frequency within 6 GHz band
898      * @param freqMhz
899      * @return true if within 6GHz, false otherwise
900      *
901      * @hide
902      */
is6GHz(int freqMhz)903     public static boolean is6GHz(int freqMhz) {
904         if (freqMhz == BAND_6_GHZ_OP_CLASS_136_CH_2_FREQ_MHZ) {
905             return true;
906         }
907         return (freqMhz >= BAND_6_GHZ_START_FREQ_MHZ && freqMhz <= BAND_6_GHZ_END_FREQ_MHZ);
908     }
909 
910     /**
911      * Utility function to check if a frequency is 6Ghz PSC channel.
912      * @param freqMhz
913      * @return true if the frequency is 6GHz PSC, false otherwise
914      *
915      * @hide
916      */
is6GHzPsc(int freqMhz)917     public static boolean is6GHzPsc(int freqMhz) {
918         if (!ScanResult.is6GHz(freqMhz)) {
919             return false;
920         }
921         return (freqMhz - BAND_6_GHZ_PSC_START_MHZ) % BAND_6_GHZ_PSC_STEP_SIZE_MHZ == 0;
922     }
923 
924     /**
925      * Utility function to check if a frequency within 60 GHz band
926      * @param freqMhz
927      * @return true if within 60GHz, false otherwise
928      *
929      * @hide
930      */
is60GHz(int freqMhz)931     public static boolean is60GHz(int freqMhz) {
932         return freqMhz >= BAND_60_GHZ_START_FREQ_MHZ && freqMhz <= BAND_60_GHZ_END_FREQ_MHZ;
933     }
934 
935     /**
936      * Utility function to convert Wi-Fi channel number to frequency in MHz.
937      *
938      * Reference the Wi-Fi channel numbering and the channelization in IEEE 802.11-2016
939      * specifications, section 17.3.8.4.2, 17.3.8.4.3 and Table 15-6.
940      *
941      * See also {@link #convertFrequencyMhzToChannelIfSupported(int)}.
942      *
943      * @param channel number to convert.
944      * @param band of channel to convert. One of the following bands:
945      *        {@link #WIFI_BAND_24_GHZ},  {@link #WIFI_BAND_5_GHZ},
946      *        {@link #WIFI_BAND_6_GHZ},  {@link #WIFI_BAND_60_GHZ}.
947      * @return center frequency in Mhz of the channel, {@link #UNSPECIFIED} if no match
948      */
convertChannelToFrequencyMhzIfSupported(int channel, @WifiBand int band)949     public static int convertChannelToFrequencyMhzIfSupported(int channel, @WifiBand int band) {
950         if (band == WIFI_BAND_24_GHZ) {
951             // Special case
952             if (channel == 14) {
953                 return 2484;
954             } else if (channel >= BAND_24_GHZ_FIRST_CH_NUM && channel <= BAND_24_GHZ_LAST_CH_NUM) {
955                 return ((channel - BAND_24_GHZ_FIRST_CH_NUM) * 5) + BAND_24_GHZ_START_FREQ_MHZ;
956             } else {
957                 return UNSPECIFIED;
958             }
959         }
960         if (band == WIFI_BAND_5_GHZ) {
961             if (channel >= BAND_5_GHZ_FIRST_CH_NUM && channel <= BAND_5_GHZ_LAST_CH_NUM) {
962                 return ((channel - BAND_5_GHZ_FIRST_CH_NUM) * 5) + BAND_5_GHZ_START_FREQ_MHZ;
963             } else {
964                 return UNSPECIFIED;
965             }
966         }
967         if (band == WIFI_BAND_6_GHZ) {
968             if (channel >= BAND_6_GHZ_FIRST_CH_NUM && channel <= BAND_6_GHZ_LAST_CH_NUM) {
969                 if (channel == 2) {
970                     return BAND_6_GHZ_OP_CLASS_136_CH_2_FREQ_MHZ;
971                 }
972                 return ((channel - BAND_6_GHZ_FIRST_CH_NUM) * 5) + BAND_6_GHZ_START_FREQ_MHZ;
973             } else {
974                 return UNSPECIFIED;
975             }
976         }
977         if (band == WIFI_BAND_60_GHZ) {
978             if (channel >= BAND_60_GHZ_FIRST_CH_NUM && channel <= BAND_60_GHZ_LAST_CH_NUM) {
979                 return ((channel - BAND_60_GHZ_FIRST_CH_NUM) * 2160) + BAND_60_GHZ_START_FREQ_MHZ;
980             } else {
981                 return UNSPECIFIED;
982             }
983         }
984         return UNSPECIFIED;
985     }
986 
987     /**
988      * Utility function to convert Operating Class into a band
989      *
990      * Use 802.11 Specification Table E-4: Global Operating Classes for decoding
991      *
992      * @param opClass operating class
993      * @param channel number
994      *
995      * @return one of {@link WifiScanner.WIFI_BAND_24_GHZ}, {@link WifiScanner.WIFI_BAND_5_GHZ}, or
996      *         {@link WifiScanner.WIFI_BAND_6_GHZ} for a valid opClass, channel pair, otherwise
997      *         {@link WifiScanner.WIFI_BAND_UNSPECIFIED} is returned.
998      *
999      * @hide
1000      */
getBandFromOpClass(int opClass, int channel)1001     public static int getBandFromOpClass(int opClass, int channel) {
1002         if (opClass >= 81 && opClass <= 84) {
1003             if (channel >= BAND_24_GHZ_FIRST_CH_NUM && channel <= BAND_24_GHZ_LAST_CH_NUM) {
1004                 return WifiScanner.WIFI_BAND_24_GHZ;
1005             }
1006         } else if (opClass >= 115 && opClass <= 130) {
1007             if (channel >= BAND_5_GHZ_FIRST_CH_NUM && channel <= BAND_5_GHZ_LAST_CH_NUM) {
1008                 return WifiScanner.WIFI_BAND_5_GHZ;
1009             }
1010         } else if (opClass >= 131 && opClass <= 137) {
1011             if (channel >= BAND_6_GHZ_FIRST_CH_NUM && channel <= BAND_6_GHZ_LAST_CH_NUM) {
1012                 return WifiScanner.WIFI_BAND_6_GHZ;
1013             }
1014         }
1015 
1016         // If none of the above combinations, then return as invalid band
1017         return WifiScanner.WIFI_BAND_UNSPECIFIED;
1018     }
1019 
1020     /**
1021      * Utility function to convert frequency in MHz to channel number.
1022      *
1023      * See also {@link #convertChannelToFrequencyMhzIfSupported(int, int)}.
1024      *
1025      * @param freqMhz frequency in MHz
1026      * @return channel number associated with given frequency, {@link #UNSPECIFIED} if no match
1027      */
convertFrequencyMhzToChannelIfSupported(int freqMhz)1028     public static int convertFrequencyMhzToChannelIfSupported(int freqMhz) {
1029         // Special case
1030         if (freqMhz == 2484) {
1031             return 14;
1032         } else if (is24GHz(freqMhz)) {
1033             return (freqMhz - BAND_24_GHZ_START_FREQ_MHZ) / 5 + BAND_24_GHZ_FIRST_CH_NUM;
1034         } else if (is5GHz(freqMhz)) {
1035             return ((freqMhz - BAND_5_GHZ_START_FREQ_MHZ) / 5) + BAND_5_GHZ_FIRST_CH_NUM;
1036         } else if (is6GHz(freqMhz)) {
1037             if (freqMhz == BAND_6_GHZ_OP_CLASS_136_CH_2_FREQ_MHZ) {
1038                 return 2;
1039             }
1040             return ((freqMhz - BAND_6_GHZ_START_FREQ_MHZ) / 5) + BAND_6_GHZ_FIRST_CH_NUM;
1041         } else if (is60GHz(freqMhz)) {
1042             return ((freqMhz - BAND_60_GHZ_START_FREQ_MHZ) / 2160) + BAND_60_GHZ_FIRST_CH_NUM;
1043         }
1044 
1045         return UNSPECIFIED;
1046     }
1047 
1048     /**
1049      * Returns the band for the ScanResult according to its frequency.
1050      * @hide
1051      */
toBand(int frequency)1052     @WifiBand public static int toBand(int frequency) {
1053         if (ScanResult.is24GHz(frequency)) {
1054             return ScanResult.WIFI_BAND_24_GHZ;
1055         } else if (ScanResult.is5GHz(frequency)) {
1056             return ScanResult.WIFI_BAND_5_GHZ;
1057         } else if (ScanResult.is6GHz(frequency)) {
1058             return ScanResult.WIFI_BAND_6_GHZ;
1059         } else if (ScanResult.is60GHz(frequency)) {
1060             return ScanResult.WIFI_BAND_60_GHZ;
1061         }
1062         return ScanResult.UNSPECIFIED;
1063     }
1064 
1065     /**
1066      * Returns the band for the ScanResult according to its frequency.
1067      * @hide
1068      */
1069     @SystemApi
getBand()1070     @WifiBand public int getBand() {
1071         return ScanResult.toBand(this.frequency);
1072     }
1073 
1074     /**
1075      * @hide
1076      */
is24GHz()1077     public boolean is24GHz() {
1078         return ScanResult.is24GHz(frequency);
1079     }
1080 
1081     /**
1082      * @hide
1083      */
is5GHz()1084     public boolean is5GHz() {
1085         return ScanResult.is5GHz(frequency);
1086     }
1087 
1088     /**
1089      * @hide
1090      */
is6GHz()1091     public boolean is6GHz() {
1092         return ScanResult.is6GHz(frequency);
1093     }
1094 
1095     /**
1096      * @hide
1097      */
is6GhzPsc()1098     public boolean is6GhzPsc() {
1099         return ScanResult.is6GHzPsc(frequency);
1100     }
1101 
1102     /**
1103      * @hide
1104      */
is60GHz()1105     public boolean is60GHz() {
1106         return ScanResult.is60GHz(frequency);
1107     }
1108 
1109     /**
1110      *  @hide
1111      * anqp lines from supplicant BSS response
1112      */
1113     @UnsupportedAppUsage
1114     public List<String> anqpLines;
1115 
1116     /**
1117      * information elements from beacon.
1118      */
1119     public static class InformationElement implements Parcelable {
1120         /** @hide */
1121         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1122         public static final int EID_SSID = 0;
1123         /** @hide */
1124         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1125         public static final int EID_SUPPORTED_RATES = 1;
1126         /** @hide */
1127         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1128         public static final int EID_TIM = 5;
1129         /** @hide */
1130         public static final int EID_COUNTRY = 7;
1131         /** @hide */
1132         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1133         public static final int EID_BSS_LOAD = 11;
1134         /** @hide */
1135         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1136         public static final int EID_ERP = 42;
1137         /** @hide */
1138         public static final int EID_HT_CAPABILITIES = 45;
1139         /** @hide */
1140         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1141         public static final int EID_RSN = 48;
1142         /** @hide */
1143         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1144         public static final int EID_EXTENDED_SUPPORTED_RATES = 50;
1145         /** @hide */
1146         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1147         public static final int EID_HT_OPERATION = 61;
1148         /** @hide */
1149         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1150         public static final int EID_INTERWORKING = 107;
1151         /** @hide */
1152         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1153         public static final int EID_ROAMING_CONSORTIUM = 111;
1154         /** @hide */
1155         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1156         public static final int EID_EXTENDED_CAPS = 127;
1157         /** @hide */
1158         public static final int EID_VHT_CAPABILITIES = 191;
1159         /** @hide */
1160         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1161         public static final int EID_VHT_OPERATION = 192;
1162         /** @hide */
1163         public static final int EID_RNR = 201;
1164         /** @hide */
1165         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
1166         public static final int EID_VSA = 221;
1167         /** @hide */
1168         public static final int EID_EXTENSION_PRESENT = 255;
1169 
1170         // Extension IDs
1171         /** @hide */
1172         public static final int EID_EXT_HE_CAPABILITIES = 35;
1173         /** @hide */
1174         public static final int EID_EXT_HE_OPERATION = 36;
1175         /**
1176          * EHT Operation IE extension id: see IEEE 802.11be Specification section 9.4.2.1
1177          *
1178          * @hide
1179          */
1180         public static final int EID_EXT_EHT_OPERATION = 106;
1181         /**
1182          * Multi-Link IE extension id: see IEEE 802.11be Specification section 9.4.2.1
1183          *
1184          * @hide
1185          */
1186         public static final int EID_EXT_MULTI_LINK = 107;
1187         /**
1188          * EHT Capabilities IE extension id: see IEEE 802.11be Specification section 9.4.2.1
1189          *
1190          * @hide
1191          */
1192         public static final int EID_EXT_EHT_CAPABILITIES = 108;
1193 
1194         /** @hide */
1195         @UnsupportedAppUsage
1196         public int id;
1197         /** @hide */
1198         public int idExt;
1199 
1200         /** @hide */
1201         @UnsupportedAppUsage
1202         public byte[] bytes;
1203 
1204         /** @hide */
InformationElement()1205         public InformationElement() {
1206         }
1207 
1208         /**
1209          * Constructs InformationElements from beacon.
1210          *
1211          * @param id element id
1212          * @param idExt element id extension
1213          * @param bytes the body of the information element, may contain multiple elements
1214          */
InformationElement(int id, int idExt, @NonNull byte[] bytes)1215         public InformationElement(int id, int idExt, @NonNull byte[] bytes) {
1216             this.id = id;
1217             this.idExt = idExt;
1218             this.bytes = bytes.clone();
1219         }
1220 
InformationElement(@onNull InformationElement rhs)1221         public InformationElement(@NonNull InformationElement rhs) {
1222             this.id = rhs.id;
1223             this.idExt = rhs.idExt;
1224             this.bytes = rhs.bytes.clone();
1225         }
1226 
1227         /**
1228          * The element ID of the information element. Defined in the IEEE 802.11-2016 spec
1229          * Table 9-77.
1230          */
getId()1231         public int getId() {
1232             return id;
1233         }
1234 
1235         /**
1236          * The element ID Extension of the information element. Defined in the IEEE 802.11-2016 spec
1237          * Table 9-77.
1238          */
getIdExt()1239         public int getIdExt() {
1240             return idExt;
1241         }
1242 
1243         /**
1244          * Get the specific content of the information element.
1245          */
1246         @NonNull
getBytes()1247         public ByteBuffer getBytes() {
1248             return ByteBuffer.wrap(bytes).asReadOnlyBuffer();
1249         }
1250 
1251         /** Implement the Parcelable interface {@hide} */
describeContents()1252         public int describeContents() {
1253             return 0;
1254         }
1255 
1256         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)1257         public void writeToParcel(Parcel dest, int flags) {
1258             dest.writeInt(id);
1259             dest.writeInt(idExt);
1260             dest.writeByteArray(bytes);
1261         }
1262 
1263         /** Implement the Parcelable interface */
1264         public static final @NonNull Creator<InformationElement> CREATOR =
1265                 new Creator<InformationElement>() {
1266                     public InformationElement createFromParcel(Parcel in) {
1267                         InformationElement informationElement = new InformationElement();
1268                         informationElement.id = in.readInt();
1269                         informationElement.idExt = in.readInt();
1270                         informationElement.bytes = in.createByteArray();
1271                         return informationElement;
1272                     }
1273 
1274                     public InformationElement[] newArray(int size) {
1275                         return new InformationElement[size];
1276                     }
1277                 };
1278 
1279         @Override
equals(Object that)1280         public boolean equals(Object that) {
1281             if (this == that) return true;
1282 
1283             // Potential API behavior change, so don't change behavior on older devices.
1284             if (!SdkLevel.isAtLeastS()) return false;
1285 
1286             if (!(that instanceof InformationElement)) return false;
1287 
1288             InformationElement thatIE = (InformationElement) that;
1289             return id == thatIE.id
1290                     && idExt == thatIE.idExt
1291                     && Arrays.equals(bytes, thatIE.bytes);
1292         }
1293 
1294         @Override
hashCode()1295         public int hashCode() {
1296             // Potential API behavior change, so don't change behavior on older devices.
1297             if (!SdkLevel.isAtLeastS()) return System.identityHashCode(this);
1298 
1299             return Objects.hash(id, idExt, Arrays.hashCode(bytes));
1300         }
1301     }
1302 
1303     /**
1304      * information elements found in the beacon.
1305      * @hide
1306      */
1307     @UnsupportedAppUsage
1308     public InformationElement[] informationElements;
1309     /**
1310      * Get all information elements found in the beacon.
1311      */
1312     @NonNull
getInformationElements()1313     public List<InformationElement> getInformationElements() {
1314         return Collections.unmodifiableList(Arrays.asList(informationElements));
1315     }
1316 
1317     /**
1318      * Get all the security types supported by this ScanResult.
1319      * @return array of {@code WifiInfo#SECURITY_TYPE_*}.
1320      */
1321     @NonNull
getSecurityTypes()1322     public @WifiAnnotations.SecurityType int[] getSecurityTypes() {
1323         List<SecurityParams> params = ScanResultUtil.generateSecurityParamsListFromScanResult(this);
1324         int[] securityTypes = new int[params.size()];
1325         for (int i = 0; i < securityTypes.length; i++) {
1326             securityTypes[i] = WifiInfo.convertWifiConfigurationSecurityType(
1327                     params.get(i).getSecurityType());
1328         }
1329         return securityTypes;
1330     }
1331 
1332     /** ANQP response elements.
1333      * @hide
1334      */
1335     public AnqpInformationElement[] anqpElements;
1336 
1337     /**
1338      * Returns whether a WifiSsid represents a "hidden" SSID of all zero values.
1339      */
isHiddenSsid(@onNull WifiSsid wifiSsid)1340     private boolean isHiddenSsid(@NonNull WifiSsid wifiSsid) {
1341         for (byte b : wifiSsid.getBytes()) {
1342             if (b != 0) {
1343                 return false;
1344             }
1345         }
1346         return true;
1347     }
1348 
1349     /** {@hide} */
ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId, byte[] osuProviders, String caps, int level, int frequency, long tsf)1350     public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId,
1351             byte[] osuProviders, String caps, int level, int frequency, long tsf) {
1352         this.wifiSsid = wifiSsid;
1353         if (wifiSsid != null && isHiddenSsid(wifiSsid)) {
1354             // Retain the legacy behavior of setting SSID to "" if the SSID is all zero values.
1355             this.SSID = "";
1356         } else {
1357             final CharSequence utf8Ssid = (wifiSsid != null) ? wifiSsid.getUtf8Text() : null;
1358             this.SSID = (utf8Ssid != null) ? utf8Ssid.toString() : WifiManager.UNKNOWN_SSID;
1359         }
1360         this.BSSID = BSSID;
1361         this.hessid = hessid;
1362         this.anqpDomainId = anqpDomainId;
1363         if (osuProviders != null) {
1364             this.anqpElements = new AnqpInformationElement[1];
1365             this.anqpElements[0] =
1366                     new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID,
1367                             AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders);
1368         }
1369         this.capabilities = caps;
1370         this.level = level;
1371         this.frequency = frequency;
1372         this.timestamp = tsf;
1373         this.distanceCm = UNSPECIFIED;
1374         this.distanceSdCm = UNSPECIFIED;
1375         this.channelWidth = UNSPECIFIED;
1376         this.centerFreq0 = UNSPECIFIED;
1377         this.centerFreq1 = UNSPECIFIED;
1378         this.flags = 0;
1379         this.radioChainInfos = null;
1380         this.mApMldMacAddress = null;
1381     }
1382 
1383     /** {@hide} */
ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency, long tsf, int distCm, int distSdCm)1384     public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
1385             long tsf, int distCm, int distSdCm) {
1386         this.wifiSsid = wifiSsid;
1387         if (wifiSsid != null && isHiddenSsid(wifiSsid)) {
1388             // Retain the legacy behavior of setting SSID to "" if the SSID is all zero values.
1389             this.SSID = "";
1390         } else {
1391             final CharSequence utf8Ssid = (wifiSsid != null) ? wifiSsid.getUtf8Text() : null;
1392             this.SSID = (utf8Ssid != null) ? utf8Ssid.toString() : WifiManager.UNKNOWN_SSID;
1393         }
1394         this.BSSID = BSSID;
1395         this.capabilities = caps;
1396         this.level = level;
1397         this.frequency = frequency;
1398         this.timestamp = tsf;
1399         this.distanceCm = distCm;
1400         this.distanceSdCm = distSdCm;
1401         this.channelWidth = UNSPECIFIED;
1402         this.centerFreq0 = UNSPECIFIED;
1403         this.centerFreq1 = UNSPECIFIED;
1404         this.flags = 0;
1405         this.radioChainInfos = null;
1406         this.mApMldMacAddress = null;
1407     }
1408 
1409     /** {@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)1410     public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps,
1411             int level, int frequency,
1412             long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
1413             boolean is80211McRTTResponder) {
1414         this.SSID = Ssid;
1415         this.BSSID = BSSID;
1416         this.hessid = hessid;
1417         this.anqpDomainId = anqpDomainId;
1418         this.capabilities = caps;
1419         this.level = level;
1420         this.frequency = frequency;
1421         this.timestamp = tsf;
1422         this.distanceCm = distCm;
1423         this.distanceSdCm = distSdCm;
1424         this.channelWidth = channelWidth;
1425         this.centerFreq0 = centerFreq0;
1426         this.centerFreq1 = centerFreq1;
1427         if (is80211McRTTResponder) {
1428             this.flags = FLAG_80211mc_RESPONDER;
1429         } else {
1430             this.flags = 0;
1431         }
1432         this.radioChainInfos = null;
1433         this.mApMldMacAddress = null;
1434     }
1435 
1436     /** {@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)1437     public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId,
1438                   String caps, int level,
1439                   int frequency, long tsf, int distCm, int distSdCm, int channelWidth,
1440                   int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) {
1441         this(Ssid, BSSID, hessid, anqpDomainId, caps, level, frequency, tsf, distCm,
1442                 distSdCm, channelWidth, centerFreq0, centerFreq1, is80211McRTTResponder);
1443         this.wifiSsid = wifiSsid;
1444     }
1445 
1446     /** copy constructor */
ScanResult(@onNull ScanResult source)1447     public ScanResult(@NonNull ScanResult source) {
1448         if (source != null) {
1449             wifiSsid = source.wifiSsid;
1450             SSID = source.SSID;
1451             BSSID = source.BSSID;
1452             hessid = source.hessid;
1453             anqpDomainId = source.anqpDomainId;
1454             informationElements = source.informationElements;
1455             anqpElements = source.anqpElements;
1456             capabilities = source.capabilities;
1457             level = source.level;
1458             frequency = source.frequency;
1459             channelWidth = source.channelWidth;
1460             centerFreq0 = source.centerFreq0;
1461             centerFreq1 = source.centerFreq1;
1462             timestamp = source.timestamp;
1463             distanceCm = source.distanceCm;
1464             distanceSdCm = source.distanceSdCm;
1465             seen = source.seen;
1466             untrusted = source.untrusted;
1467             numUsage = source.numUsage;
1468             venueName = source.venueName;
1469             operatorFriendlyName = source.operatorFriendlyName;
1470             flags = source.flags;
1471             radioChainInfos = source.radioChainInfos;
1472             this.mWifiStandard = source.mWifiStandard;
1473             this.ifaceName = source.ifaceName;
1474             this.mApMldMacAddress = source.mApMldMacAddress;
1475             this.mApMloLinkId = source.mApMloLinkId;
1476             this.mAffiliatedMloLinks = source.mAffiliatedMloLinks != null
1477                     ? new ArrayList<>(source.mAffiliatedMloLinks) : Collections.emptyList();
1478         }
1479     }
1480 
1481     /** Construct an empty scan result. */
ScanResult()1482     public ScanResult() {
1483     }
1484 
1485     @Override
toString()1486     public String toString() {
1487         StringBuffer sb = new StringBuffer();
1488         String none = "<none>";
1489 
1490         sb.append("SSID: ")
1491                 .append(wifiSsid == null ? WifiManager.UNKNOWN_SSID : wifiSsid)
1492                 .append(", BSSID: ")
1493                 .append(BSSID == null ? none : BSSID)
1494                 .append(", capabilities: ")
1495                 .append(capabilities == null ? none : capabilities)
1496                 .append(", level: ")
1497                 .append(level)
1498                 .append(", frequency: ")
1499                 .append(frequency)
1500                 .append(", timestamp: ")
1501                 .append(timestamp);
1502         sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
1503                 append("(cm)");
1504         sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
1505                 append("(cm)");
1506 
1507         sb.append(", passpoint: ");
1508         sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
1509         sb.append(", ChannelBandwidth: ").append(channelWidth);
1510         sb.append(", centerFreq0: ").append(centerFreq0);
1511         sb.append(", centerFreq1: ").append(centerFreq1);
1512         sb.append(", standard: ").append(wifiStandardToString(mWifiStandard));
1513         sb.append(", 80211mcResponder: ");
1514         sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
1515         sb.append(", Radio Chain Infos: ").append(Arrays.toString(radioChainInfos));
1516         sb.append(", interface name: ").append(ifaceName);
1517 
1518         if (mApMldMacAddress != null) {
1519             sb.append(", MLO Info: ")
1520                     .append(" AP MLD MAC Address: ")
1521                     .append(mApMldMacAddress.toString())
1522                     .append(", AP MLO Link-Id: ")
1523                     .append((mApMloLinkId == MloLink.INVALID_MLO_LINK_ID)
1524                             ? "Unspecified" : mApMloLinkId)
1525                     .append(", AP MLO Affiliated Links: ").append(mAffiliatedMloLinks);
1526         }
1527 
1528         return sb.toString();
1529     }
1530 
1531     /** Implement the Parcelable interface {@hide} */
describeContents()1532     public int describeContents() {
1533         return 0;
1534     }
1535 
1536     /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)1537     public void writeToParcel(Parcel dest, int flags) {
1538         if (wifiSsid != null) {
1539             dest.writeInt(1);
1540             wifiSsid.writeToParcel(dest, flags);
1541         } else {
1542             dest.writeInt(0);
1543         }
1544         dest.writeString(SSID);
1545         dest.writeString(BSSID);
1546         dest.writeLong(hessid);
1547         dest.writeInt(anqpDomainId);
1548         dest.writeString(capabilities);
1549         dest.writeInt(level);
1550         dest.writeInt(frequency);
1551         dest.writeLong(timestamp);
1552         dest.writeInt(distanceCm);
1553         dest.writeInt(distanceSdCm);
1554         dest.writeInt(channelWidth);
1555         dest.writeInt(centerFreq0);
1556         dest.writeInt(centerFreq1);
1557         dest.writeInt(mWifiStandard);
1558         dest.writeLong(seen);
1559         dest.writeInt(untrusted ? 1 : 0);
1560         dest.writeInt(numUsage);
1561         dest.writeString((venueName != null) ? venueName.toString() : "");
1562         dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
1563         dest.writeLong(this.flags);
1564         dest.writeTypedArray(informationElements, flags);
1565 
1566         if (anqpLines != null) {
1567             dest.writeInt(anqpLines.size());
1568             for (int i = 0; i < anqpLines.size(); i++) {
1569                 dest.writeString(anqpLines.get(i));
1570             }
1571         }
1572         else {
1573             dest.writeInt(0);
1574         }
1575         if (anqpElements != null) {
1576             dest.writeInt(anqpElements.length);
1577             for (AnqpInformationElement element : anqpElements) {
1578                 dest.writeInt(element.getVendorId());
1579                 dest.writeInt(element.getElementId());
1580                 dest.writeInt(element.getPayload().length);
1581                 dest.writeByteArray(element.getPayload());
1582             }
1583         } else {
1584             dest.writeInt(0);
1585         }
1586 
1587         if (radioChainInfos != null) {
1588             dest.writeInt(radioChainInfos.length);
1589             for (int i = 0; i < radioChainInfos.length; i++) {
1590                 dest.writeInt(radioChainInfos[i].id);
1591                 dest.writeInt(radioChainInfos[i].level);
1592             }
1593         } else {
1594             dest.writeInt(0);
1595         }
1596         dest.writeString((ifaceName != null) ? ifaceName.toString() : "");
1597 
1598 
1599         // Add MLO related attributes
1600         dest.writeParcelable(mApMldMacAddress, flags);
1601         dest.writeInt(mApMloLinkId);
1602         dest.writeTypedList(mAffiliatedMloLinks);
1603     }
1604 
1605     /** Implement the Parcelable interface */
1606     public static final @NonNull Creator<ScanResult> CREATOR =
1607         new Creator<ScanResult>() {
1608             public ScanResult createFromParcel(Parcel in) {
1609                 WifiSsid wifiSsid = null;
1610                 if (in.readInt() == 1) {
1611                     wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
1612                 }
1613                 ScanResult sr = new ScanResult(
1614                         wifiSsid,
1615                         in.readString(),                    /* SSID  */
1616                         in.readString(),                    /* BSSID */
1617                         in.readLong(),                      /* HESSID */
1618                         in.readInt(),                       /* ANQP Domain ID */
1619                         in.readString(),                    /* capabilities */
1620                         in.readInt(),                       /* level */
1621                         in.readInt(),                       /* frequency */
1622                         in.readLong(),                      /* timestamp */
1623                         in.readInt(),                       /* distanceCm */
1624                         in.readInt(),                       /* distanceSdCm */
1625                         in.readInt(),                       /* channelWidth */
1626                         in.readInt(),                       /* centerFreq0 */
1627                         in.readInt(),                       /* centerFreq1 */
1628                         false                               /* rtt responder,
1629                                                                fixed with flags below */
1630                 );
1631 
1632                 sr.mWifiStandard = in.readInt();
1633                 sr.seen = in.readLong();
1634                 sr.untrusted = in.readInt() != 0;
1635                 sr.numUsage = in.readInt();
1636                 sr.venueName = in.readString();
1637                 sr.operatorFriendlyName = in.readString();
1638                 sr.flags = in.readLong();
1639                 sr.informationElements = in.createTypedArray(InformationElement.CREATOR);
1640 
1641                 int n = in.readInt();
1642                 if (n != 0) {
1643                     sr.anqpLines = new ArrayList<String>();
1644                     for (int i = 0; i < n; i++) {
1645                         sr.anqpLines.add(in.readString());
1646                     }
1647                 }
1648                 n = in.readInt();
1649                 if (n != 0) {
1650                     sr.anqpElements = new AnqpInformationElement[n];
1651                     for (int i = 0; i < n; i++) {
1652                         int vendorId = in.readInt();
1653                         int elementId = in.readInt();
1654                         int len = in.readInt();
1655                         byte[] payload = new byte[len];
1656                         in.readByteArray(payload);
1657                         sr.anqpElements[i] =
1658                                 new AnqpInformationElement(vendorId, elementId, payload);
1659                     }
1660                 }
1661                 n = in.readInt();
1662                 if (n != 0) {
1663                     sr.radioChainInfos = new RadioChainInfo[n];
1664                     for (int i = 0; i < n; i++) {
1665                         sr.radioChainInfos[i] = new RadioChainInfo();
1666                         sr.radioChainInfos[i].id = in.readInt();
1667                         sr.radioChainInfos[i].level = in.readInt();
1668                     }
1669                 }
1670                 sr.ifaceName = in.readString();
1671 
1672 
1673                 // Read MLO related attributes
1674                 sr.mApMldMacAddress = in.readParcelable(MacAddress.class.getClassLoader());
1675                 sr.mApMloLinkId = in.readInt();
1676                 sr.mAffiliatedMloLinks = in.createTypedArrayList(MloLink.CREATOR);
1677 
1678                 return sr;
1679             }
1680 
1681             public ScanResult[] newArray(int size) {
1682                 return new ScanResult[size];
1683             }
1684         };
1685 }
1686