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