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.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.content.pm.PackageManager;
25 import android.net.IpConfiguration;
26 import android.net.IpConfiguration.ProxySettings;
27 import android.net.MacAddress;
28 import android.net.NetworkSpecifier;
29 import android.net.ProxyInfo;
30 import android.net.StaticIpConfiguration;
31 import android.net.Uri;
32 import android.net.util.MacAddressUtils;
33 import android.os.Build;
34 import android.os.Parcel;
35 import android.os.Parcelable;
36 import android.os.SystemClock;
37 import android.os.UserHandle;
38 import android.telephony.TelephonyManager;
39 import android.text.TextUtils;
40 import android.util.Log;
41 import android.util.SparseArray;
42 
43 import com.android.internal.annotations.VisibleForTesting;
44 
45 import java.lang.annotation.Retention;
46 import java.lang.annotation.RetentionPolicy;
47 import java.util.Arrays;
48 import java.util.BitSet;
49 import java.util.Calendar;
50 import java.util.HashMap;
51 
52 /**
53  * A class representing a configured Wi-Fi network, including the
54  * security configuration.
55  *
56  * @deprecated Use {@link WifiNetworkSpecifier.Builder} to create {@link NetworkSpecifier} and
57  * {@link WifiNetworkSuggestion.Builder} to create {@link WifiNetworkSuggestion}. This will become a
58  * system use only object in the future.
59  */
60 @Deprecated
61 public class WifiConfiguration implements Parcelable {
62     private static final String TAG = "WifiConfiguration";
63     /**
64      * Current Version of the Backup Serializer.
65     */
66     private static final int BACKUP_VERSION = 3;
67     /** {@hide} */
68     public static final String ssidVarName = "ssid";
69     /** {@hide} */
70     public static final String bssidVarName = "bssid";
71     /** {@hide} */
72     public static final String pskVarName = "psk";
73     /** {@hide} */
74     @Deprecated
75     @UnsupportedAppUsage
76     public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" };
77     /** {@hide} */
78     @Deprecated
79     public static final String wepTxKeyIdxVarName = "wep_tx_keyidx";
80     /** {@hide} */
81     public static final String priorityVarName = "priority";
82     /** {@hide} */
83     public static final String hiddenSSIDVarName = "scan_ssid";
84     /** {@hide} */
85     public static final String pmfVarName = "ieee80211w";
86     /** {@hide} */
87     public static final String updateIdentiferVarName = "update_identifier";
88     /**
89      * The network ID for an invalid network.
90      *
91      * @hide
92      */
93     @SystemApi
94     public static final int INVALID_NETWORK_ID = -1;
95     /** {@hide} */
96     public static final int LOCAL_ONLY_NETWORK_ID = -2;
97 
98     /** {@hide} */
99     private String mPasspointManagementObjectTree;
100     /** {@hide} */
101     private static final int MAXIMUM_RANDOM_MAC_GENERATION_RETRY = 3;
102 
103     /**
104      * Recognized key management schemes.
105      */
106     public static class KeyMgmt {
KeyMgmt()107         private KeyMgmt() { }
108 
109         /** @hide */
110         @Retention(RetentionPolicy.SOURCE)
111         @IntDef(value = {
112                 NONE,
113                 WPA_PSK,
114                 WPA_EAP,
115                 IEEE8021X,
116                 WPA2_PSK,
117                 OSEN,
118                 FT_PSK,
119                 FT_EAP,
120                 SAE,
121                 OWE,
122                 SUITE_B_192,
123                 WPA_PSK_SHA256,
124                 WPA_EAP_SHA256,
125                 WAPI_PSK,
126                 WAPI_CERT,
127                 FILS_SHA256,
128                 FILS_SHA384})
129         public @interface KeyMgmtScheme {}
130 
131         /** WPA is not used; plaintext or static WEP could be used. */
132         public static final int NONE = 0;
133         /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
134         public static final int WPA_PSK = 1;
135         /** WPA using EAP authentication. Generally used with an external authentication server. */
136         public static final int WPA_EAP = 2;
137         /**
138          * IEEE 802.1X using EAP authentication and (optionally) dynamically
139          * generated WEP keys.
140          */
141         public static final int IEEE8021X = 3;
142 
143         /**
144          * WPA2 pre-shared key for use with soft access point
145          * (requires {@code preSharedKey} to be specified).
146          * @hide
147          */
148         @SystemApi
149         public static final int WPA2_PSK = 4;
150         /**
151          * Hotspot 2.0 r2 OSEN:
152          * @hide
153          */
154         public static final int OSEN = 5;
155 
156         /**
157          * IEEE 802.11r Fast BSS Transition with PSK authentication.
158          * @hide
159          */
160         public static final int FT_PSK = 6;
161 
162         /**
163          * IEEE 802.11r Fast BSS Transition with EAP authentication.
164          * @hide
165          */
166         public static final int FT_EAP = 7;
167 
168         /**
169          * Simultaneous Authentication of Equals
170          */
171         public static final int SAE = 8;
172 
173         /**
174          * Opportunististic Wireless Encryption
175          */
176         public static final int OWE = 9;
177 
178         /**
179          * SUITE_B_192 192 bit level
180          */
181         public static final int SUITE_B_192 = 10;
182 
183         /**
184          * WPA pre-shared key with stronger SHA256-based algorithms.
185          * @hide
186          */
187         public static final int WPA_PSK_SHA256 = 11;
188 
189         /**
190          * WPA using EAP authentication with stronger SHA256-based algorithms.
191          * @hide
192          */
193         public static final int WPA_EAP_SHA256 = 12;
194 
195         /**
196          * WAPI pre-shared key (requires {@code preSharedKey} to be specified).
197          * @hide
198          */
199         @SystemApi
200         public static final int WAPI_PSK = 13;
201 
202         /**
203          * WAPI certificate to be specified.
204          * @hide
205          */
206         @SystemApi
207         public static final int WAPI_CERT = 14;
208 
209         /**
210         * IEEE 802.11ai FILS SK with SHA256
211          * @hide
212         */
213         public static final int FILS_SHA256 = 15;
214         /**
215          * IEEE 802.11ai FILS SK with SHA384:
216          * @hide
217          */
218         public static final int FILS_SHA384 = 16;
219 
220         public static final String varName = "key_mgmt";
221 
222         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
223                 "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP",
224                 "SAE", "OWE", "SUITE_B_192", "WPA_PSK_SHA256", "WPA_EAP_SHA256",
225                 "WAPI_PSK", "WAPI_CERT", "FILS_SHA256", "FILS_SHA384" };
226     }
227 
228     /**
229      * Recognized security protocols.
230      */
231     public static class Protocol {
Protocol()232         private Protocol() { }
233 
234         /** WPA/IEEE 802.11i/D3.0
235          * @deprecated Due to security and performance limitations, use of WPA-1 networks
236          * is discouraged. WPA-2 (RSN) should be used instead. */
237         @Deprecated
238         public static final int WPA = 0;
239         /** RSN WPA2/WPA3/IEEE 802.11i */
240         public static final int RSN = 1;
241         /** HS2.0 r2 OSEN
242          * @hide
243          */
244         public static final int OSEN = 2;
245 
246         /**
247          * WAPI Protocol
248          */
249         public static final int WAPI = 3;
250 
251         public static final String varName = "proto";
252 
253         public static final String[] strings = { "WPA", "RSN", "OSEN", "WAPI" };
254     }
255 
256     /**
257      * Recognized IEEE 802.11 authentication algorithms.
258      */
259     public static class AuthAlgorithm {
AuthAlgorithm()260         private AuthAlgorithm() { }
261 
262         /** Open System authentication (required for WPA/WPA2) */
263         public static final int OPEN = 0;
264         /** Shared Key authentication (requires static WEP keys)
265          * @deprecated Due to security and performance limitations, use of WEP networks
266          * is discouraged. */
267         @Deprecated
268         public static final int SHARED = 1;
269         /** LEAP/Network EAP (only used with LEAP) */
270         public static final int LEAP = 2;
271 
272         /** SAE (Used only for WPA3-Personal) */
273         public static final int SAE = 3;
274 
275         public static final String varName = "auth_alg";
276 
277         public static final String[] strings = { "OPEN", "SHARED", "LEAP", "SAE" };
278     }
279 
280     /**
281      * Recognized pairwise ciphers for WPA.
282      */
283     public static class PairwiseCipher {
PairwiseCipher()284         private PairwiseCipher() { }
285 
286         /** Use only Group keys (deprecated) */
287         public static final int NONE = 0;
288         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
289          * @deprecated Due to security and performance limitations, use of WPA-1 networks
290          * is discouraged. WPA-2 (RSN) should be used instead. */
291         @Deprecated
292         public static final int TKIP = 1;
293         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
294         public static final int CCMP = 2;
295         /**
296          * AES in Galois/Counter Mode
297          */
298         public static final int GCMP_256 = 3;
299         /**
300          * SMS4 cipher for WAPI
301          */
302         public static final int SMS4 = 4;
303 
304         public static final String varName = "pairwise";
305 
306         public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256", "SMS4" };
307     }
308 
309     /**
310      * Recognized group ciphers.
311      * <pre>
312      * CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
313      * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
314      * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
315      * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
316      * GCMP_256 = AES in Galois/Counter Mode
317      * </pre>
318      */
319     public static class GroupCipher {
GroupCipher()320         private GroupCipher() { }
321 
322         /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
323          * @deprecated Due to security and performance limitations, use of WEP networks
324          * is discouraged. */
325         @Deprecated
326         public static final int WEP40 = 0;
327         /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
328          * @deprecated Due to security and performance limitations, use of WEP networks
329          * is discouraged. */
330         @Deprecated
331         public static final int WEP104 = 1;
332         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
333         public static final int TKIP = 2;
334         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
335         public static final int CCMP = 3;
336         /** Hotspot 2.0 r2 OSEN
337          * @hide
338          */
339         public static final int GTK_NOT_USED = 4;
340         /**
341          * AES in Galois/Counter Mode
342          */
343         public static final int GCMP_256 = 5;
344         /**
345          * SMS4 cipher for WAPI
346          */
347         public static final int SMS4 = 6;
348 
349         public static final String varName = "group";
350 
351         public static final String[] strings =
352                 { /* deprecated */ "WEP40", /* deprecated */ "WEP104",
353                         "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256",
354                         "SMS4" };
355     }
356 
357     /**
358      * Recognized group management ciphers.
359      * <pre>
360      * BIP_CMAC_256 = Cipher-based Message Authentication Code 256 bits
361      * BIP_GMAC_128 = Galois Message Authentication Code 128 bits
362      * BIP_GMAC_256 = Galois Message Authentication Code 256 bits
363      * </pre>
364      */
365     public static class GroupMgmtCipher {
GroupMgmtCipher()366         private GroupMgmtCipher() { }
367 
368         /** CMAC-256 = Cipher-based Message Authentication Code */
369         public static final int BIP_CMAC_256 = 0;
370 
371         /** GMAC-128 = Galois Message Authentication Code */
372         public static final int BIP_GMAC_128 = 1;
373 
374         /** GMAC-256 = Galois Message Authentication Code */
375         public static final int BIP_GMAC_256 = 2;
376 
377         private static final String varName = "groupMgmt";
378 
379         private static final String[] strings = { "BIP_CMAC_256",
380                 "BIP_GMAC_128", "BIP_GMAC_256"};
381     }
382 
383     /**
384      * Recognized suiteB ciphers.
385      * <pre>
386      * ECDHE_ECDSA
387      * ECDHE_RSA
388      * </pre>
389      * @hide
390      */
391     public static class SuiteBCipher {
SuiteBCipher()392         private SuiteBCipher() { }
393 
394         /** Diffie-Hellman with Elliptic Curve_ECDSA signature */
395         public static final int ECDHE_ECDSA = 0;
396 
397         /** Diffie-Hellman with_RSA signature */
398         public static final int ECDHE_RSA = 1;
399 
400         private static final String varName = "SuiteB";
401 
402         private static final String[] strings = { "ECDHE_ECDSA", "ECDHE_RSA" };
403     }
404 
405     /** Possible status of a network configuration. */
406     public static class Status {
Status()407         private Status() { }
408 
409         /** this is the network we are currently connected to */
410         public static final int CURRENT = 0;
411         /** supplicant will not attempt to use this network */
412         public static final int DISABLED = 1;
413         /** supplicant will consider this network available for association */
414         public static final int ENABLED = 2;
415 
416         public static final String[] strings = { "current", "disabled", "enabled" };
417     }
418 
419     /** Security type for an open network. */
420     public static final int SECURITY_TYPE_OPEN = 0;
421     /** Security type for a WEP network. */
422     public static final int SECURITY_TYPE_WEP = 1;
423     /** Security type for a PSK network. */
424     public static final int SECURITY_TYPE_PSK = 2;
425     /** Security type for an EAP network. */
426     public static final int SECURITY_TYPE_EAP = 3;
427     /** Security type for an SAE network. */
428     public static final int SECURITY_TYPE_SAE = 4;
429     /** Security type for an EAP Suite B network. */
430     public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
431     /** Security type for an OWE network. */
432     public static final int SECURITY_TYPE_OWE = 6;
433     /** Security type for a WAPI PSK network. */
434     public static final int SECURITY_TYPE_WAPI_PSK = 7;
435     /** Security type for a WAPI Certificate network. */
436     public static final int SECURITY_TYPE_WAPI_CERT = 8;
437 
438     /**
439      * Security types we support.
440      * @hide
441      */
442     @Retention(RetentionPolicy.SOURCE)
443     @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
444             SECURITY_TYPE_OPEN,
445             SECURITY_TYPE_WEP,
446             SECURITY_TYPE_PSK,
447             SECURITY_TYPE_EAP,
448             SECURITY_TYPE_SAE,
449             SECURITY_TYPE_EAP_SUITE_B,
450             SECURITY_TYPE_OWE,
451             SECURITY_TYPE_WAPI_PSK,
452             SECURITY_TYPE_WAPI_CERT
453     })
454     public @interface SecurityType {}
455 
456     /**
457      * Set the various security params to correspond to the provided security type.
458      * This is accomplished by setting the various BitSets exposed in WifiConfiguration.
459      *
460      * @param securityType One of the following security types:
461      * {@link #SECURITY_TYPE_OPEN},
462      * {@link #SECURITY_TYPE_WEP},
463      * {@link #SECURITY_TYPE_PSK},
464      * {@link #SECURITY_TYPE_EAP},
465      * {@link #SECURITY_TYPE_SAE},
466      * {@link #SECURITY_TYPE_EAP_SUITE_B},
467      * {@link #SECURITY_TYPE_OWE},
468      * {@link #SECURITY_TYPE_WAPI_PSK}, or
469      * {@link #SECURITY_TYPE_WAPI_CERT}
470      */
setSecurityParams(@ecurityType int securityType)471     public void setSecurityParams(@SecurityType int securityType) {
472         // Clear all the bitsets.
473         allowedKeyManagement.clear();
474         allowedProtocols.clear();
475         allowedAuthAlgorithms.clear();
476         allowedPairwiseCiphers.clear();
477         allowedGroupCiphers.clear();
478         allowedGroupManagementCiphers.clear();
479         allowedSuiteBCiphers.clear();
480 
481         switch (securityType) {
482             case SECURITY_TYPE_OPEN:
483                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
484                 break;
485             case SECURITY_TYPE_WEP:
486                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
487                 allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
488                 allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
489                 break;
490             case SECURITY_TYPE_PSK:
491                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
492                 break;
493             case SECURITY_TYPE_EAP:
494                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
495                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
496                 break;
497             case SECURITY_TYPE_SAE:
498                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
499                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
500                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
501                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
502                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
503                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
504                 requirePmf = true;
505                 break;
506             case SECURITY_TYPE_EAP_SUITE_B:
507                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
508                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
509                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
510                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
511                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
512                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
513                 allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
514                 // Note: allowedSuiteBCiphers bitset will be set by the service once the
515                 // certificates are attached to this profile
516                 requirePmf = true;
517                 break;
518             case SECURITY_TYPE_OWE:
519                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
520                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
521                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
522                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
523                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
524                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
525                 requirePmf = true;
526                 break;
527             case SECURITY_TYPE_WAPI_PSK:
528                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_PSK);
529                 allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
530                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
531                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
532                 break;
533             case SECURITY_TYPE_WAPI_CERT:
534                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WAPI_CERT);
535                 allowedProtocols.set(WifiConfiguration.Protocol.WAPI);
536                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
537                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
538                 break;
539             default:
540                 throw new IllegalArgumentException("unknown security type " + securityType);
541         }
542     }
543 
544     /** @hide */
545     public static final int UNKNOWN_UID = -1;
546 
547     /**
548      * The ID number that the supplicant uses to identify this
549      * network configuration entry. This must be passed as an argument
550      * to most calls into the supplicant.
551      */
552     public int networkId;
553 
554     // Fixme We need remove this field to use only Quality network selection status only
555     /**
556      * The current status of this network configuration entry.
557      * @see Status
558      */
559     public int status;
560 
561     /**
562      * The network's SSID. Can either be a UTF-8 string,
563      * which must be enclosed in double quotation marks
564      * (e.g., {@code "MyNetwork"}), or a string of
565      * hex digits, which are not enclosed in quotes
566      * (e.g., {@code 01a243f405}).
567      */
568     public String SSID;
569 
570     /**
571      * When set, this network configuration entry should only be used when
572      * associating with the AP having the specified BSSID. The value is
573      * a string in the format of an Ethernet MAC address, e.g.,
574      * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
575      */
576     public String BSSID;
577 
578     /** @hide */
579     @Retention(RetentionPolicy.SOURCE)
580     @IntDef(prefix = {"AP_BAND_"}, value = {
581             AP_BAND_2GHZ,
582             AP_BAND_5GHZ,
583             AP_BAND_ANY})
584     public @interface ApBand {}
585 
586     /**
587      * 2GHz band.
588      * @hide
589      */
590     public static final int AP_BAND_2GHZ = 0;
591 
592     /**
593      * 5GHz band.
594      * @hide
595      */
596     public static final int AP_BAND_5GHZ = 1;
597 
598     /**
599      * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
600      * operating country code and current radio conditions.
601      * @hide
602      */
603     public static final int AP_BAND_ANY = -1;
604 
605     /**
606      * The band which the AP resides on.
607      * One of {@link #AP_BAND_2GHZ}, {@link #AP_BAND_5GHZ}, or {@link #AP_BAND_ANY}.
608      * By default, {@link #AP_BAND_2GHZ} is chosen.
609      *
610      * @hide
611      */
612     @UnsupportedAppUsage
613     @ApBand
614     public int apBand = AP_BAND_2GHZ;
615 
616     /**
617      * The channel which AP resides on,currently, US only
618      * 2G  1-11
619      * 5G  36,40,44,48,149,153,157,161,165
620      * 0 - find a random available channel according to the apBand
621      * @hide
622      */
623     @UnsupportedAppUsage
624     public int apChannel = 0;
625 
626     /**
627      * Pre-shared key for use with WPA-PSK. Either an ASCII string enclosed in
628      * double quotation marks (e.g., {@code "abcdefghij"} for PSK passphrase or
629      * a string of 64 hex digits for raw PSK.
630      * <p/>
631      * When the value of this key is read, the actual key is
632      * not returned, just a "*" if the key has a value, or the null
633      * string otherwise.
634      */
635     public String preSharedKey;
636 
637     /**
638      * Four WEP keys. For each of the four values, provide either an ASCII
639      * string enclosed in double quotation marks (e.g., {@code "abcdef"}),
640      * a string of hex digits (e.g., {@code 0102030405}), or an empty string
641      * (e.g., {@code ""}).
642      * <p/>
643      * When the value of one of these keys is read, the actual key is
644      * not returned, just a "*" if the key has a value, or the null
645      * string otherwise.
646      * @deprecated Due to security and performance limitations, use of WEP networks
647      * is discouraged.
648      */
649     @Deprecated
650     public String[] wepKeys;
651 
652     /** Default WEP key index, ranging from 0 to 3.
653      * @deprecated Due to security and performance limitations, use of WEP networks
654      * is discouraged. */
655     @Deprecated
656     public int wepTxKeyIndex;
657 
658     /**
659      * Priority determines the preference given to a network by {@code wpa_supplicant}
660      * when choosing an access point with which to associate.
661      * @deprecated This field does not exist anymore.
662      */
663     @Deprecated
664     public int priority;
665 
666     /**
667      * This is a network that does not broadcast its SSID, so an
668      * SSID-specific probe request must be used for scans.
669      */
670     public boolean hiddenSSID;
671 
672     /**
673      * True if the network requires Protected Management Frames (PMF), false otherwise.
674      * @hide
675      */
676     @SystemApi
677     public boolean requirePmf;
678 
679     /**
680      * Update identifier, for Passpoint network.
681      * @hide
682      */
683     public String updateIdentifier;
684 
685     /**
686      * The set of key management protocols supported by this configuration.
687      * See {@link KeyMgmt} for descriptions of the values.
688      * Defaults to WPA-PSK WPA-EAP.
689      */
690     @NonNull
691     public BitSet allowedKeyManagement;
692     /**
693      * The set of security protocols supported by this configuration.
694      * See {@link Protocol} for descriptions of the values.
695      * Defaults to WPA RSN.
696      */
697     @NonNull
698     public BitSet allowedProtocols;
699     /**
700      * The set of authentication protocols supported by this configuration.
701      * See {@link AuthAlgorithm} for descriptions of the values.
702      * Defaults to automatic selection.
703      */
704     @NonNull
705     public BitSet allowedAuthAlgorithms;
706     /**
707      * The set of pairwise ciphers for WPA supported by this configuration.
708      * See {@link PairwiseCipher} for descriptions of the values.
709      * Defaults to CCMP TKIP.
710      */
711     @NonNull
712     public BitSet allowedPairwiseCiphers;
713     /**
714      * The set of group ciphers supported by this configuration.
715      * See {@link GroupCipher} for descriptions of the values.
716      * Defaults to CCMP TKIP WEP104 WEP40.
717      */
718     @NonNull
719     public BitSet allowedGroupCiphers;
720     /**
721      * The set of group management ciphers supported by this configuration.
722      * See {@link GroupMgmtCipher} for descriptions of the values.
723      */
724     @NonNull
725     public BitSet allowedGroupManagementCiphers;
726     /**
727      * The set of SuiteB ciphers supported by this configuration.
728      * To be used for WPA3-Enterprise mode. Set automatically by the framework based on the
729      * certificate type that is used in this configuration.
730      */
731     @NonNull
732     public BitSet allowedSuiteBCiphers;
733     /**
734      * The enterprise configuration details specifying the EAP method,
735      * certificates and other settings associated with the EAP.
736      */
737     public WifiEnterpriseConfig enterpriseConfig;
738 
739     /**
740      * Fully qualified domain name of a Passpoint configuration
741      */
742     public String FQDN;
743 
744     /**
745      * Name of Passpoint credential provider
746      */
747     public String providerFriendlyName;
748 
749     /**
750      * Flag indicating if this network is provided by a home Passpoint provider or a roaming
751      * Passpoint provider.  This flag will be {@code true} if this network is provided by
752      * a home Passpoint provider and {@code false} if is provided by a roaming Passpoint provider
753      * or is a non-Passpoint network.
754      */
755     public boolean isHomeProviderNetwork;
756 
757     /**
758      * Roaming Consortium Id list for Passpoint credential; identifies a set of networks where
759      * Passpoint credential will be considered valid
760      */
761     public long[] roamingConsortiumIds;
762 
763     /**
764      * True if this network configuration is visible to and usable by other users on the
765      * same device, false otherwise.
766      *
767      * @hide
768      */
769     @SystemApi
770     public boolean shared;
771 
772     /**
773      * @hide
774      */
775     @NonNull
776     @UnsupportedAppUsage
777     private IpConfiguration mIpConfiguration;
778 
779     /**
780      * @hide
781      * dhcp server MAC address if known
782      */
783     public String dhcpServer;
784 
785     /**
786      * @hide
787      * default Gateway MAC address if known
788      */
789     @UnsupportedAppUsage
790     public String defaultGwMacAddress;
791 
792     /**
793      * @hide
794      * last time we connected, this configuration had validated internet access
795      */
796     @UnsupportedAppUsage
797     public boolean validatedInternetAccess;
798 
799     /**
800      * @hide
801      * The number of beacon intervals between Delivery Traffic Indication Maps (DTIM)
802      * This value is populated from scan results that contain Beacon Frames, which are infrequent.
803      * The value is not guaranteed to be set or current (Although it SHOULDNT change once set)
804      * Valid values are from 1 - 255. Initialized here as 0, use this to check if set.
805      */
806     public int dtimInterval = 0;
807 
808     /**
809      * Flag indicating if this configuration represents a legacy Passpoint configuration
810      * (Release N or older).  This is used for migrating Passpoint configuration from N to O.
811      * This will no longer be needed after O.
812      * @hide
813      */
814     public boolean isLegacyPasspointConfig = false;
815     /**
816      * @hide
817      * Uid of app creating the configuration
818      */
819     @SystemApi
820     public int creatorUid;
821 
822     /**
823      * @hide
824      * Uid of last app issuing a connection related command
825      */
826     @UnsupportedAppUsage
827     public int lastConnectUid;
828 
829     /**
830      * @hide
831      * Uid of last app modifying the configuration
832      */
833     @SystemApi
834     public int lastUpdateUid;
835 
836     /**
837      * @hide
838      * Universal name for app creating the configuration
839      *    see {@link PackageManager#getNameForUid(int)}
840      */
841     @SystemApi
842     public String creatorName;
843 
844     /**
845      * @hide
846      * Universal name for app updating the configuration
847      *    see {@link PackageManager#getNameForUid(int)}
848      */
849     @SystemApi
850     public String lastUpdateName;
851 
852     /**
853      * The carrier ID identifies the operator who provides this network configuration.
854      *    see {@link TelephonyManager#getSimCarrierId()}
855      * @hide
856      */
857     @SystemApi
858     public int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
859 
860     /**
861      * @hide
862      * Auto-join is allowed by user for this network.
863      * Default true.
864      */
865     @SystemApi
866     public boolean allowAutojoin = true;
867 
868     /** @hide **/
869     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
870     public static int INVALID_RSSI = -127;
871 
872     /**
873      * @hide
874      * Number of reports indicating no Internet Access
875      */
876     @UnsupportedAppUsage
877     public int numNoInternetAccessReports;
878 
879     /**
880      * @hide
881      * The WiFi configuration is considered to have no internet access for purpose of autojoining
882      * if there has been a report of it having no internet access, and, it never have had
883      * internet access in the past.
884      */
885     @SystemApi
hasNoInternetAccess()886     public boolean hasNoInternetAccess() {
887         return numNoInternetAccessReports > 0 && !validatedInternetAccess;
888     }
889 
890     /**
891      * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
892      * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
893      * this configuration and selects "don't ask again".
894      * @hide
895      */
896     @UnsupportedAppUsage
897     public boolean noInternetAccessExpected;
898 
899     /**
900      * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
901      * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
902      * this configuration and selects "don't ask again".
903      * @hide
904      */
905     @SystemApi
isNoInternetAccessExpected()906     public boolean isNoInternetAccessExpected() {
907         return noInternetAccessExpected;
908     }
909 
910     /**
911      * This Wifi configuration is expected for OSU(Online Sign Up) of Passpoint Release 2.
912      * @hide
913      */
914     public boolean osu;
915 
916     /**
917      * @hide
918      * Last time the system was connected to this configuration.
919      */
920     public long lastConnected;
921 
922     /**
923      * @hide
924      * Last time the system was disconnected to this configuration.
925      */
926     public long lastDisconnected;
927 
928     /**
929      * Set if the configuration was self added by the framework
930      * This boolean is cleared if we get a connect/save/ update or
931      * any wifiManager command that indicate the user interacted with the configuration
932      * since we will now consider that the configuration belong to him.
933      * @deprecated only kept for @UnsupportedAppUsage
934      * @hide
935      */
936     @UnsupportedAppUsage
937     public boolean selfAdded;
938 
939     /**
940      * Peer WifiConfiguration this WifiConfiguration was added for
941      * @hide
942      */
943     public String peerWifiConfiguration;
944 
945     /**
946      * @hide
947      * Indicate that a WifiConfiguration is temporary and should not be saved
948      * nor considered by AutoJoin.
949      */
950     public boolean ephemeral;
951 
952     /**
953      * @hide
954      * Indicate that a WifiConfiguration is temporary and should not be saved
955      * nor considered by AutoJoin.
956      */
957     @SystemApi
isEphemeral()958     public boolean isEphemeral() {
959       return ephemeral;
960     }
961 
962     /**
963      * Indicate whether the network is trusted or not. Networks are considered trusted
964      * if the user explicitly allowed this network connection.
965      * This bit can be used by suggestion network, see
966      * {@link WifiNetworkSuggestion.Builder#setUntrusted(boolean)}
967      * @hide
968      */
969     public boolean trusted;
970 
971     /**
972      * True if this Wifi configuration is created from a {@link WifiNetworkSuggestion},
973      * false otherwise.
974      *
975      * @hide
976      */
977     @SystemApi
978     public boolean fromWifiNetworkSuggestion;
979 
980     /**
981      * True if this Wifi configuration is created from a {@link WifiNetworkSpecifier},
982      * false otherwise.
983      *
984      * @hide
985      */
986     @SystemApi
987     public boolean fromWifiNetworkSpecifier;
988 
989     /**
990      * True if the creator of this configuration has expressed that it
991      * should be considered metered, false otherwise.
992      *
993      * @see #isMetered(WifiConfiguration, WifiInfo)
994      *
995      * @hide
996      */
997     @SystemApi
998     public boolean meteredHint;
999 
1000     /** @hide */
1001     @Retention(RetentionPolicy.SOURCE)
1002     @IntDef(prefix = {"METERED_OVERRIDE_"}, value = {
1003             METERED_OVERRIDE_NONE,
1004             METERED_OVERRIDE_METERED,
1005             METERED_OVERRIDE_NOT_METERED})
1006     public @interface MeteredOverride {}
1007 
1008     /**
1009      * No metered override.
1010      * @hide
1011      */
1012     @SystemApi
1013     public static final int METERED_OVERRIDE_NONE = 0;
1014     /**
1015      * Override network to be metered.
1016      * @hide
1017      */
1018     @SystemApi
1019     public static final int METERED_OVERRIDE_METERED = 1;
1020     /**
1021      * Override network to be unmetered.
1022      * @hide
1023      */
1024     @SystemApi
1025     public static final int METERED_OVERRIDE_NOT_METERED = 2;
1026 
1027     /**
1028      * Indicates if the end user has expressed an explicit opinion about the
1029      * meteredness of this network, such as through the Settings app.
1030      * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED},
1031      * or {@link #METERED_OVERRIDE_NOT_METERED}.
1032      * <p>
1033      * This should always override any values from {@link #meteredHint} or
1034      * {@link WifiInfo#getMeteredHint()}.
1035      *
1036      * By default this field is set to {@link #METERED_OVERRIDE_NONE}.
1037      *
1038      * @see #isMetered(WifiConfiguration, WifiInfo)
1039      * @hide
1040      */
1041     @SystemApi
1042     @MeteredOverride
1043     public int meteredOverride = METERED_OVERRIDE_NONE;
1044 
1045     /**
1046      * Blend together all the various opinions to decide if the given network
1047      * should be considered metered or not.
1048      *
1049      * @hide
1050      */
1051     @SystemApi
isMetered(@ullable WifiConfiguration config, @Nullable WifiInfo info)1052     public static boolean isMetered(@Nullable WifiConfiguration config, @Nullable WifiInfo info) {
1053         boolean metered = false;
1054         if (info != null && info.getMeteredHint()) {
1055             metered = true;
1056         }
1057         if (config != null && config.meteredHint) {
1058             metered = true;
1059         }
1060         if (config != null
1061                 && config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED) {
1062             metered = true;
1063         }
1064         if (config != null
1065                 && config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_NOT_METERED) {
1066             metered = false;
1067         }
1068         return metered;
1069     }
1070 
1071     /**
1072      * @hide
1073      * Returns true if this WiFi config is for an open network.
1074      */
isOpenNetwork()1075     public boolean isOpenNetwork() {
1076         final int cardinality = allowedKeyManagement.cardinality();
1077         final boolean hasNoKeyMgmt = cardinality == 0
1078                 || (cardinality == 1 && (allowedKeyManagement.get(KeyMgmt.NONE)
1079                 || allowedKeyManagement.get(KeyMgmt.OWE)));
1080 
1081         boolean hasNoWepKeys = true;
1082         if (wepKeys != null) {
1083             for (int i = 0; i < wepKeys.length; i++) {
1084                 if (wepKeys[i] != null) {
1085                     hasNoWepKeys = false;
1086                     break;
1087                 }
1088             }
1089         }
1090 
1091         return hasNoKeyMgmt && hasNoWepKeys;
1092     }
1093 
1094     /**
1095      * @hide
1096      * Setting this value will force scan results associated with this configuration to
1097      * be included in the bucket of networks that are externally scored.
1098      * If not set, associated scan results will be treated as legacy saved networks and
1099      * will take precedence over networks in the scored category.
1100      */
1101     @SystemApi
1102     public boolean useExternalScores;
1103 
1104     /**
1105      * @hide
1106      * Number of time the scorer overrode a the priority based choice, when comparing two
1107      * WifiConfigurations, note that since comparing WifiConfiguration happens very often
1108      * potentially at every scan, this number might become very large, even on an idle
1109      * system.
1110      */
1111     @SystemApi
1112     public int numScorerOverride;
1113 
1114     /**
1115      * @hide
1116      * Number of time the scorer overrode a the priority based choice, and the comparison
1117      * triggered a network switch
1118      */
1119     @SystemApi
1120     public int numScorerOverrideAndSwitchedNetwork;
1121 
1122     /**
1123      * @hide
1124      * Number of time we associated to this configuration.
1125      */
1126     @SystemApi
1127     public int numAssociation;
1128 
1129     /** @hide */
1130     @Retention(RetentionPolicy.SOURCE)
1131     @IntDef(prefix = {"RANDOMIZATION_"}, value = {
1132             RANDOMIZATION_NONE,
1133             RANDOMIZATION_PERSISTENT})
1134     public @interface MacRandomizationSetting {}
1135 
1136     /**
1137      * Use factory MAC when connecting to this network
1138      * @hide
1139      */
1140     @SystemApi
1141     public static final int RANDOMIZATION_NONE = 0;
1142     /**
1143      * Generate a randomized MAC once and reuse it for all connections to this network
1144      * @hide
1145      */
1146     @SystemApi
1147     public static final int RANDOMIZATION_PERSISTENT = 1;
1148 
1149     /**
1150      * Level of MAC randomization for this network.
1151      * One of {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}.
1152      * By default this field is set to {@link #RANDOMIZATION_PERSISTENT}.
1153      * @hide
1154      */
1155     @SystemApi
1156     @MacRandomizationSetting
1157     public int macRandomizationSetting = RANDOMIZATION_PERSISTENT;
1158 
1159     /**
1160      * @hide
1161      * Randomized MAC address to use with this particular network
1162      */
1163     @NonNull
1164     private MacAddress mRandomizedMacAddress;
1165 
1166     /**
1167      * @hide
1168      * The wall clock time of when |mRandomizedMacAddress| should be re-randomized in aggressive
1169      * randomization mode.
1170      */
1171     public long randomizedMacExpirationTimeMs = 0;
1172 
1173     /**
1174      * @hide
1175      * Checks if the given MAC address can be used for Connected Mac Randomization
1176      * by verifying that it is non-null, unicast, locally assigned, and not default mac.
1177      * @param mac MacAddress to check
1178      * @return true if mac is good to use
1179      */
isValidMacAddressForRandomization(MacAddress mac)1180     public static boolean isValidMacAddressForRandomization(MacAddress mac) {
1181         return mac != null && !MacAddressUtils.isMulticastAddress(mac) && mac.isLocallyAssigned()
1182                 && !MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS).equals(mac);
1183     }
1184 
1185     /**
1186      * Returns MAC address set to be the local randomized MAC address.
1187      * Depending on user preference, the device may or may not use the returned MAC address for
1188      * connections to this network.
1189      * <p>
1190      * Information is restricted to Device Owner, Profile Owner, and Carrier apps
1191      * (which will only obtain addresses for configurations which they create). Other callers
1192      * will receive a default "02:00:00:00:00:00" MAC address.
1193      */
getRandomizedMacAddress()1194     public @NonNull MacAddress getRandomizedMacAddress() {
1195         return mRandomizedMacAddress;
1196     }
1197 
1198     /**
1199      * @hide
1200      * @param mac MacAddress to change into
1201      */
setRandomizedMacAddress(@onNull MacAddress mac)1202     public void setRandomizedMacAddress(@NonNull MacAddress mac) {
1203         if (mac == null) {
1204             Log.e(TAG, "setRandomizedMacAddress received null MacAddress.");
1205             return;
1206         }
1207         mRandomizedMacAddress = mac;
1208     }
1209 
1210     /** @hide
1211      * Boost given to RSSI on a home network for the purpose of calculating the score
1212      * This adds stickiness to home networks, as defined by:
1213      * - less than 4 known BSSIDs
1214      * - PSK only
1215      * - TODO: add a test to verify that all BSSIDs are behind same gateway
1216      ***/
1217     public static final int HOME_NETWORK_RSSI_BOOST = 5;
1218 
1219     /**
1220      * This class is used to contain all the information and API used for quality network selection.
1221      * @hide
1222      */
1223     @SystemApi
1224     public static class NetworkSelectionStatus {
1225         /** @hide */
1226         @Retention(RetentionPolicy.SOURCE)
1227         @IntDef(prefix = "NETWORK_SELECTION_",
1228                 value = {
1229                 NETWORK_SELECTION_ENABLED,
1230                 NETWORK_SELECTION_TEMPORARY_DISABLED,
1231                 NETWORK_SELECTION_PERMANENTLY_DISABLED})
1232         public @interface NetworkEnabledStatus {}
1233         /**
1234          * This network will be considered as a potential candidate to connect to during network
1235          * selection.
1236          */
1237         public static final int NETWORK_SELECTION_ENABLED = 0;
1238         /**
1239          * This network was temporary disabled. May be re-enabled after a time out.
1240          */
1241         public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1;
1242         /**
1243          * This network was permanently disabled.
1244          */
1245         public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2;
1246         /**
1247          * Maximum Network selection status
1248          * @hide
1249          */
1250         public static final int NETWORK_SELECTION_STATUS_MAX = 3;
1251 
1252         /**
1253          * Quality network selection status String (for debug purpose). Use Quality network
1254          * selection status value as index to extec the corresponding debug string
1255          * @hide
1256          */
1257         public static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
1258                 "NETWORK_SELECTION_ENABLED",
1259                 "NETWORK_SELECTION_TEMPORARY_DISABLED",
1260                 "NETWORK_SELECTION_PERMANENTLY_DISABLED"};
1261 
1262         /** @hide */
1263         @Retention(RetentionPolicy.SOURCE)
1264         @IntDef(prefix = "DISABLED_", value = {
1265                 DISABLED_NONE,
1266                 DISABLED_ASSOCIATION_REJECTION,
1267                 DISABLED_AUTHENTICATION_FAILURE,
1268                 DISABLED_DHCP_FAILURE,
1269                 DISABLED_NO_INTERNET_TEMPORARY,
1270                 DISABLED_AUTHENTICATION_NO_CREDENTIALS,
1271                 DISABLED_NO_INTERNET_PERMANENT,
1272                 DISABLED_BY_WIFI_MANAGER,
1273                 DISABLED_BY_WRONG_PASSWORD,
1274                 DISABLED_AUTHENTICATION_NO_SUBSCRIPTION})
1275         public @interface NetworkSelectionDisableReason {}
1276 
1277         // Quality Network disabled reasons
1278         /** Default value. Means not disabled. */
1279         public static final int DISABLED_NONE = 0;
1280         /**
1281          * The starting index for network selection disabled reasons.
1282          * @hide
1283          */
1284         public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
1285         /**
1286          * The starting index for network selection temporarily disabled reasons.
1287          * @hide
1288          */
1289         public static final int TEMPORARILY_DISABLED_STARTING_INDEX = 1;
1290         /** This network is disabled because of multiple association rejections. */
1291         public static final int DISABLED_ASSOCIATION_REJECTION = 1;
1292         /** This network is disabled because of multiple authentication failure. */
1293         public static final int DISABLED_AUTHENTICATION_FAILURE = 2;
1294         /** This network is disabled because of multiple DHCP failure. */
1295         public static final int DISABLED_DHCP_FAILURE = 3;
1296         /** This network is temporarily disabled because it has no Internet access. */
1297         public static final int DISABLED_NO_INTERNET_TEMPORARY = 4;
1298         /**
1299          * The starting index for network selection permanently disabled reasons.
1300          * @hide
1301          */
1302         public static final int PERMANENTLY_DISABLED_STARTING_INDEX = 5;
1303         /** This network is disabled due to absence of user credentials */
1304         public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5;
1305         /**
1306          * This network is permanently disabled because it has no Internet access and the user does
1307          * not want to stay connected.
1308          */
1309         public static final int DISABLED_NO_INTERNET_PERMANENT = 6;
1310         /** This network is disabled due to WifiManager disabling it explicitly. */
1311         public static final int DISABLED_BY_WIFI_MANAGER = 7;
1312         /** This network is disabled due to wrong password. */
1313         public static final int DISABLED_BY_WRONG_PASSWORD = 8;
1314         /** This network is disabled because service is not subscribed. */
1315         public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9;
1316         /**
1317          * All other disable reasons should be strictly less than this value.
1318          * @hide
1319          */
1320         public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
1321 
1322         /**
1323          * Get an integer that is equal to the maximum integer value of all the
1324          * DISABLED_* reasons
1325          * e.g. {@link #DISABLED_NONE}, {@link #DISABLED_ASSOCIATION_REJECTION}, etc.
1326          *
1327          * All DISABLED_* constants will be contiguous in the range
1328          * 0, 1, 2, 3, ..., getMaxNetworkSelectionDisableReasons()
1329          *
1330          * <br />
1331          * For example, this can be used to iterate through all the network selection
1332          * disable reasons like so:
1333          * <pre>{@code
1334          * for (int reason = 0; reason <= getMaxNetworkSelectionDisableReasons(); reason++) {
1335          *     ...
1336          * }
1337          * }</pre>
1338          */
getMaxNetworkSelectionDisableReason()1339         public static int getMaxNetworkSelectionDisableReason() {
1340             return NETWORK_SELECTION_DISABLED_MAX - 1;
1341         }
1342 
1343         /**
1344          * Contains info about disable reasons.
1345          * @hide
1346          */
1347         public static final class DisableReasonInfo {
1348             /**
1349              * String representation for the disable reason.
1350              * Note that these strings are persisted in
1351              * {@link
1352              * com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml},
1353              * so do not change the string values to maintain backwards compatibility.
1354              */
1355             public final String mReasonStr;
1356             /**
1357              * Network Selection disable reason threshold, used to debounce network failures before
1358              * we disable them.
1359              */
1360             public final int mDisableThreshold;
1361             /**
1362              * Network Selection disable timeout for the error. After the timeout milliseconds,
1363              * enable the network again.
1364              */
1365             public final int mDisableTimeoutMillis;
1366 
1367             /**
1368              * Constructor
1369              * @param reasonStr string representation of the error
1370              * @param disableThreshold number of failures before we disable the network
1371              * @param disableTimeoutMillis the timeout, in milliseconds, before we re-enable the
1372              *                             network after disabling it
1373              */
DisableReasonInfo(String reasonStr, int disableThreshold, int disableTimeoutMillis)1374             public DisableReasonInfo(String reasonStr, int disableThreshold,
1375                     int disableTimeoutMillis) {
1376                 mReasonStr = reasonStr;
1377                 mDisableThreshold = disableThreshold;
1378                 mDisableTimeoutMillis = disableTimeoutMillis;
1379             }
1380         }
1381 
1382         /**
1383          * Quality network selection disable reason infos.
1384          * @hide
1385          */
1386         public static final SparseArray<DisableReasonInfo> DISABLE_REASON_INFOS =
1387                 buildDisableReasonInfos();
1388 
buildDisableReasonInfos()1389         private static SparseArray<DisableReasonInfo> buildDisableReasonInfos() {
1390             SparseArray<DisableReasonInfo> reasons = new SparseArray<>();
1391 
1392             reasons.append(DISABLED_NONE,
1393                     new DisableReasonInfo(
1394                             // Note that these strings are persisted in
1395                             // XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml,
1396                             // so do not change the string values to maintain backwards
1397                             // compatibility.
1398                             "NETWORK_SELECTION_ENABLE",
1399                             -1,
1400                             Integer.MAX_VALUE));
1401 
1402             reasons.append(DISABLED_ASSOCIATION_REJECTION,
1403                     new DisableReasonInfo(
1404                             // Note that there is a space at the end of this string. Cannot fix
1405                             // since this string is persisted.
1406                             "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
1407                             5,
1408                             5 * 60 * 1000));
1409 
1410             reasons.append(DISABLED_AUTHENTICATION_FAILURE,
1411                     new DisableReasonInfo(
1412                             "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
1413                             5,
1414                             5 * 60 * 1000));
1415 
1416             reasons.append(DISABLED_DHCP_FAILURE,
1417                     new DisableReasonInfo(
1418                             "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
1419                             5,
1420                             5 * 60 * 1000));
1421 
1422             reasons.append(DISABLED_NO_INTERNET_TEMPORARY,
1423                     new DisableReasonInfo(
1424                             "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY",
1425                             1,
1426                             10 * 60 * 1000));
1427 
1428             reasons.append(DISABLED_AUTHENTICATION_NO_CREDENTIALS,
1429                     new DisableReasonInfo(
1430                             "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
1431                             1,
1432                             Integer.MAX_VALUE));
1433 
1434             reasons.append(DISABLED_NO_INTERNET_PERMANENT,
1435                     new DisableReasonInfo(
1436                             "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
1437                             1,
1438                             Integer.MAX_VALUE));
1439 
1440             reasons.append(DISABLED_BY_WIFI_MANAGER,
1441                     new DisableReasonInfo(
1442                             "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
1443                             1,
1444                             Integer.MAX_VALUE));
1445 
1446             reasons.append(DISABLED_BY_WRONG_PASSWORD,
1447                     new DisableReasonInfo(
1448                             "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD",
1449                             1,
1450                             Integer.MAX_VALUE));
1451 
1452             reasons.append(DISABLED_AUTHENTICATION_NO_SUBSCRIPTION,
1453                     new DisableReasonInfo(
1454                             "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION",
1455                             1,
1456                             Integer.MAX_VALUE));
1457 
1458             return reasons;
1459         }
1460 
1461         /**
1462          * Get the {@link NetworkSelectionDisableReason} int code by its string value.
1463          * @return the NetworkSelectionDisableReason int code corresponding to the reason string,
1464          * or -1 if the reason string is unrecognized.
1465          * @hide
1466          */
1467         @NetworkSelectionDisableReason
getDisableReasonByString(@onNull String reasonString)1468         public static int getDisableReasonByString(@NonNull String reasonString) {
1469             for (int i = 0; i < DISABLE_REASON_INFOS.size(); i++) {
1470                 int key = DISABLE_REASON_INFOS.keyAt(i);
1471                 DisableReasonInfo value = DISABLE_REASON_INFOS.valueAt(i);
1472                 if (value != null && TextUtils.equals(reasonString, value.mReasonStr)) {
1473                     return key;
1474                 }
1475             }
1476             Log.e(TAG, "Unrecognized network disable reason: " + reasonString);
1477             return -1;
1478         }
1479 
1480         /**
1481          * Invalid time stamp for network selection disable
1482          * @hide
1483          */
1484         public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
1485 
1486         /**
1487          * This constant indicates the current configuration has connect choice set
1488          */
1489         private static final int CONNECT_CHOICE_EXISTS = 1;
1490 
1491         /**
1492          * This constant indicates the current configuration does not have connect choice set
1493          */
1494         private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
1495 
1496         // fields for QualityNetwork Selection
1497         /**
1498          * Network selection status, should be in one of three status: enable, temporaily disabled
1499          * or permanently disabled
1500          */
1501         @NetworkEnabledStatus
1502         private int mStatus;
1503 
1504         /**
1505          * Reason for disable this network
1506          */
1507         @NetworkSelectionDisableReason
1508         private int mNetworkSelectionDisableReason;
1509 
1510         /**
1511          * Last time we temporarily disabled the configuration
1512          */
1513         private long mTemporarilyDisabledTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
1514 
1515         /**
1516          * counter for each Network selection disable reason
1517          */
1518         private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
1519 
1520         /**
1521          * Connect Choice over this configuration
1522          *
1523          * When current wifi configuration is visible to the user but user explicitly choose to
1524          * connect to another network X, the another networks X's configure key will be stored here.
1525          * We will consider user has a preference of X over this network. And in the future,
1526          * network selection will always give X a higher preference over this configuration.
1527          * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
1528          */
1529         private String mConnectChoice;
1530 
1531         /**
1532          * Used to cache the temporary candidate during the network selection procedure. It will be
1533          * kept updating once a new scan result has a higher score than current one
1534          */
1535         private ScanResult mCandidate;
1536 
1537         /**
1538          * Used to cache the score of the current temporary candidate during the network
1539          * selection procedure.
1540          */
1541         private int mCandidateScore;
1542 
1543         /**
1544          * Indicate whether this network is visible in latest Qualified Network Selection. This
1545          * means there is scan result found related to this Configuration and meet the minimum
1546          * requirement. The saved network need not join latest Qualified Network Selection. For
1547          * example, it is disabled. True means network is visible in latest Qualified Network
1548          * Selection and false means network is invisible
1549          */
1550         private boolean mSeenInLastQualifiedNetworkSelection;
1551 
1552         /**
1553          * Boolean indicating if we have ever successfully connected to this network.
1554          *
1555          * This value will be set to true upon a successful connection.
1556          * This value will be set to false if a previous value was not stored in the config or if
1557          * the credentials are updated (ex. a password change).
1558          */
1559         private boolean mHasEverConnected;
1560 
1561         /**
1562          * set whether this network is visible in latest Qualified Network Selection
1563          * @param seen value set to candidate
1564          * @hide
1565          */
setSeenInLastQualifiedNetworkSelection(boolean seen)1566         public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
1567             mSeenInLastQualifiedNetworkSelection =  seen;
1568         }
1569 
1570         /**
1571          * get whether this network is visible in latest Qualified Network Selection
1572          * @return returns true -- network is visible in latest Qualified Network Selection
1573          *         false -- network is invisible in latest Qualified Network Selection
1574          * @hide
1575          */
getSeenInLastQualifiedNetworkSelection()1576         public boolean getSeenInLastQualifiedNetworkSelection() {
1577             return mSeenInLastQualifiedNetworkSelection;
1578         }
1579         /**
1580          * set the temporary candidate of current network selection procedure
1581          * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
1582          * @hide
1583          */
setCandidate(ScanResult scanCandidate)1584         public void setCandidate(ScanResult scanCandidate) {
1585             mCandidate = scanCandidate;
1586         }
1587 
1588         /**
1589          * get the temporary candidate of current network selection procedure
1590          * @return  returns {@link ScanResult} temporary candidate of current network selection
1591          * procedure
1592          * @hide
1593          */
getCandidate()1594         public ScanResult getCandidate() {
1595             return mCandidate;
1596         }
1597 
1598         /**
1599          * set the score of the temporary candidate of current network selection procedure
1600          * @param score value set to mCandidateScore
1601          * @hide
1602          */
setCandidateScore(int score)1603         public void setCandidateScore(int score) {
1604             mCandidateScore = score;
1605         }
1606 
1607         /**
1608          * get the score of the temporary candidate of current network selection procedure
1609          * @return returns score of the temporary candidate of current network selection procedure
1610          * @hide
1611          */
getCandidateScore()1612         public int getCandidateScore() {
1613             return mCandidateScore;
1614         }
1615 
1616         /**
1617          * get user preferred choice over this configuration
1618          * @return returns configKey of user preferred choice over this configuration
1619          * @hide
1620          */
getConnectChoice()1621         public String getConnectChoice() {
1622             return mConnectChoice;
1623         }
1624 
1625         /**
1626          * set user preferred choice over this configuration
1627          * @param newConnectChoice, the configKey of user preferred choice over this configuration
1628          * @hide
1629          */
setConnectChoice(String newConnectChoice)1630         public void setConnectChoice(String newConnectChoice) {
1631             mConnectChoice = newConnectChoice;
1632         }
1633 
1634         /** Get the current Quality network selection status as a String (for debugging). */
1635         @NonNull
getNetworkStatusString()1636         public String getNetworkStatusString() {
1637             return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
1638         }
1639 
1640         /** @hide */
setHasEverConnected(boolean value)1641         public void setHasEverConnected(boolean value) {
1642             mHasEverConnected = value;
1643         }
1644 
1645         /** True if the device has ever connected to this network, false otherwise. */
hasEverConnected()1646         public boolean hasEverConnected() {
1647             return mHasEverConnected;
1648         }
1649 
1650         /** @hide */
NetworkSelectionStatus()1651         public NetworkSelectionStatus() {
1652             // previously stored configs will not have this parameter, so we default to false.
1653             mHasEverConnected = false;
1654         }
1655 
1656         /**
1657          * NetworkSelectionStatus exports an immutable public API.
1658          * However, test code has a need to construct a NetworkSelectionStatus in a specific state.
1659          * (Note that mocking using Mockito does not work if the object needs to be parceled and
1660          * unparceled.)
1661          * Export a @SystemApi Builder to allow tests to construct a NetworkSelectionStatus object
1662          * in the desired state, without sacrificing NetworkSelectionStatus's immutability.
1663          */
1664         @VisibleForTesting
1665         public static final class Builder {
1666             private final NetworkSelectionStatus mNetworkSelectionStatus =
1667                     new NetworkSelectionStatus();
1668 
1669             /**
1670              * Set the current network selection status.
1671              * One of:
1672              * {@link #NETWORK_SELECTION_ENABLED},
1673              * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED},
1674              * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED}
1675              * @see NetworkSelectionStatus#getNetworkSelectionStatus()
1676              */
1677             @NonNull
setNetworkSelectionStatus(@etworkEnabledStatus int status)1678             public Builder setNetworkSelectionStatus(@NetworkEnabledStatus int status) {
1679                 mNetworkSelectionStatus.setNetworkSelectionStatus(status);
1680                 return this;
1681             }
1682 
1683             /**
1684              *
1685              * Set the current network's disable reason.
1686              * One of the {@link #DISABLED_NONE} or DISABLED_* constants.
1687              * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
1688              * @see NetworkSelectionStatus#getNetworkSelectionDisableReason()
1689              */
1690             @NonNull
setNetworkSelectionDisableReason( @etworkSelectionDisableReason int reason)1691             public Builder setNetworkSelectionDisableReason(
1692                     @NetworkSelectionDisableReason int reason) {
1693                 mNetworkSelectionStatus.setNetworkSelectionDisableReason(reason);
1694                 return this;
1695             }
1696 
1697             /**
1698              * Build a NetworkSelectionStatus object.
1699              */
1700             @NonNull
build()1701             public NetworkSelectionStatus build() {
1702                 NetworkSelectionStatus status = new NetworkSelectionStatus();
1703                 status.copy(mNetworkSelectionStatus);
1704                 return status;
1705             }
1706         }
1707 
1708         /**
1709          * Get the network disable reason string for a reason code (for debugging).
1710          * @param reason specific error reason. One of the {@link #DISABLED_NONE} or
1711          *               DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
1712          * @return network disable reason string, or null if the reason is invalid.
1713          */
1714         @Nullable
getNetworkSelectionDisableReasonString( @etworkSelectionDisableReason int reason)1715         public static String getNetworkSelectionDisableReasonString(
1716                 @NetworkSelectionDisableReason int reason) {
1717             DisableReasonInfo info = DISABLE_REASON_INFOS.get(reason);
1718             if (info == null) {
1719                 return null;
1720             } else {
1721                 return info.mReasonStr;
1722             }
1723         }
1724         /**
1725          * get current network disable reason
1726          * @return current network disable reason in String (for debug purpose)
1727          * @hide
1728          */
getNetworkSelectionDisableReasonString()1729         public String getNetworkSelectionDisableReasonString() {
1730             return getNetworkSelectionDisableReasonString(mNetworkSelectionDisableReason);
1731         }
1732 
1733         /**
1734          * Get the current network network selection status.
1735          * One of:
1736          * {@link #NETWORK_SELECTION_ENABLED},
1737          * {@link #NETWORK_SELECTION_TEMPORARY_DISABLED},
1738          * {@link #NETWORK_SELECTION_PERMANENTLY_DISABLED}
1739          */
1740         @NetworkEnabledStatus
getNetworkSelectionStatus()1741         public int getNetworkSelectionStatus() {
1742             return mStatus;
1743         }
1744 
1745         /**
1746          * True if the current network is enabled to join network selection, false otherwise.
1747          * @hide
1748          */
isNetworkEnabled()1749         public boolean isNetworkEnabled() {
1750             return mStatus == NETWORK_SELECTION_ENABLED;
1751         }
1752 
1753         /**
1754          * @return whether current network is temporary disabled
1755          * @hide
1756          */
isNetworkTemporaryDisabled()1757         public boolean isNetworkTemporaryDisabled() {
1758             return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
1759         }
1760 
1761         /**
1762          * True if the current network is permanently disabled, false otherwise.
1763          * @hide
1764          */
isNetworkPermanentlyDisabled()1765         public boolean isNetworkPermanentlyDisabled() {
1766             return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
1767         }
1768 
1769         /**
1770          * set current network selection status
1771          * @param status network selection status to set
1772          * @hide
1773          */
setNetworkSelectionStatus(int status)1774         public void setNetworkSelectionStatus(int status) {
1775             if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) {
1776                 mStatus = status;
1777             }
1778         }
1779 
1780         /**
1781          * Returns the current network's disable reason.
1782          * One of the {@link #DISABLED_NONE} or DISABLED_* constants
1783          * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
1784          */
1785         @NetworkSelectionDisableReason
getNetworkSelectionDisableReason()1786         public int getNetworkSelectionDisableReason() {
1787             return mNetworkSelectionDisableReason;
1788         }
1789 
1790         /**
1791          * set Network disable reason
1792          * @param reason Network disable reason
1793          * @hide
1794          */
setNetworkSelectionDisableReason(@etworkSelectionDisableReason int reason)1795         public void setNetworkSelectionDisableReason(@NetworkSelectionDisableReason int reason) {
1796             if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) {
1797                 mNetworkSelectionDisableReason = reason;
1798             } else {
1799                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1800             }
1801         }
1802 
1803         /**
1804          * @param timeStamp Set when current network is disabled in millisecond since January 1,
1805          * 1970 00:00:00.0 UTC
1806          * @hide
1807          */
setDisableTime(long timeStamp)1808         public void setDisableTime(long timeStamp) {
1809             mTemporarilyDisabledTimestamp = timeStamp;
1810         }
1811 
1812         /**
1813          * Returns when the current network was disabled, in milliseconds since January 1,
1814          * 1970 00:00:00.0 UTC.
1815          */
getDisableTime()1816         public long getDisableTime() {
1817             return mTemporarilyDisabledTimestamp;
1818         }
1819 
1820         /**
1821          * Get the disable counter of a specific reason.
1822          * @param reason specific failure reason. One of the {@link #DISABLED_NONE} or
1823          *              DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}.
1824          * @exception IllegalArgumentException for invalid reason
1825          * @return counter number for specific error reason.
1826          */
getDisableReasonCounter(@etworkSelectionDisableReason int reason)1827         public int getDisableReasonCounter(@NetworkSelectionDisableReason int reason) {
1828             if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1829                 return mNetworkSeclectionDisableCounter[reason];
1830             } else {
1831                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1832             }
1833         }
1834 
1835         /**
1836          * set the counter of a specific failure reason
1837          * @param reason reason for disable error
1838          * @param value the counter value for this specific reason
1839          * @exception throw IllegalArgumentException for illegal input
1840          * @hide
1841          */
setDisableReasonCounter(int reason, int value)1842         public void setDisableReasonCounter(int reason, int value) {
1843             if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1844                 mNetworkSeclectionDisableCounter[reason] = value;
1845             } else {
1846                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1847             }
1848         }
1849 
1850         /**
1851          * increment the counter of a specific failure reason
1852          * @param reason a specific failure reason
1853          * @exception throw IllegalArgumentException for illegal input
1854          * @hide
1855          */
incrementDisableReasonCounter(int reason)1856         public void incrementDisableReasonCounter(int reason) {
1857             if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1858                 mNetworkSeclectionDisableCounter[reason]++;
1859             } else {
1860                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1861             }
1862         }
1863 
1864         /**
1865          * clear the counter of a specific failure reason
1866          * @param reason a specific failure reason
1867          * @exception throw IllegalArgumentException for illegal input
1868          * @hide
1869          */
clearDisableReasonCounter(int reason)1870         public void clearDisableReasonCounter(int reason) {
1871             if (reason >= DISABLED_NONE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1872                 mNetworkSeclectionDisableCounter[reason] = DISABLED_NONE;
1873             } else {
1874                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1875             }
1876         }
1877 
1878         /**
1879          * clear all the failure reason counters
1880          * @hide
1881          */
clearDisableReasonCounter()1882         public void clearDisableReasonCounter() {
1883             Arrays.fill(mNetworkSeclectionDisableCounter, DISABLED_NONE);
1884         }
1885 
1886         /**
1887          * BSSID for connection to this network (through network selection procedure)
1888          */
1889         private String mNetworkSelectionBSSID;
1890 
1891         /**
1892          * get current network Selection BSSID
1893          * @return current network Selection BSSID
1894          * @hide
1895          */
getNetworkSelectionBSSID()1896         public String getNetworkSelectionBSSID() {
1897             return mNetworkSelectionBSSID;
1898         }
1899 
1900         /**
1901          * set network Selection BSSID
1902          * @param bssid The target BSSID for assocaition
1903          * @hide
1904          */
setNetworkSelectionBSSID(String bssid)1905         public void setNetworkSelectionBSSID(String bssid) {
1906             mNetworkSelectionBSSID = bssid;
1907         }
1908 
1909         /** @hide */
copy(NetworkSelectionStatus source)1910         public void copy(NetworkSelectionStatus source) {
1911             mStatus = source.mStatus;
1912             mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason;
1913             for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX;
1914                     index++) {
1915                 mNetworkSeclectionDisableCounter[index] =
1916                         source.mNetworkSeclectionDisableCounter[index];
1917             }
1918             mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
1919             mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
1920             setSeenInLastQualifiedNetworkSelection(source.getSeenInLastQualifiedNetworkSelection());
1921             setCandidate(source.getCandidate());
1922             setCandidateScore(source.getCandidateScore());
1923             setConnectChoice(source.getConnectChoice());
1924             setHasEverConnected(source.hasEverConnected());
1925         }
1926 
1927         /** @hide */
writeToParcel(Parcel dest)1928         public void writeToParcel(Parcel dest) {
1929             dest.writeInt(getNetworkSelectionStatus());
1930             dest.writeInt(getNetworkSelectionDisableReason());
1931             for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX;
1932                     index++) {
1933                 dest.writeInt(getDisableReasonCounter(index));
1934             }
1935             dest.writeLong(getDisableTime());
1936             dest.writeString(getNetworkSelectionBSSID());
1937             if (getConnectChoice() != null) {
1938                 dest.writeInt(CONNECT_CHOICE_EXISTS);
1939                 dest.writeString(getConnectChoice());
1940             } else {
1941                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
1942             }
1943             dest.writeInt(hasEverConnected() ? 1 : 0);
1944         }
1945 
1946         /** @hide */
readFromParcel(Parcel in)1947         public void readFromParcel(Parcel in) {
1948             setNetworkSelectionStatus(in.readInt());
1949             setNetworkSelectionDisableReason(in.readInt());
1950             for (int index = DISABLED_NONE; index < NETWORK_SELECTION_DISABLED_MAX;
1951                     index++) {
1952                 setDisableReasonCounter(index, in.readInt());
1953             }
1954             setDisableTime(in.readLong());
1955             setNetworkSelectionBSSID(in.readString());
1956             if (in.readInt() == CONNECT_CHOICE_EXISTS) {
1957                 setConnectChoice(in.readString());
1958             } else {
1959                 setConnectChoice(null);
1960             }
1961             setHasEverConnected(in.readInt() != 0);
1962         }
1963     }
1964 
1965     /**
1966      * @hide
1967      * network selection related member
1968      */
1969     private NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
1970 
1971     /**
1972      * This class is intended to store extra failure reason information for the most recent
1973      * connection attempt, so that it may be surfaced to the settings UI
1974      * @hide
1975      */
1976     // TODO(b/148626966): called by SUW via reflection, remove once SUW is updated
1977     public static class RecentFailure {
1978 
RecentFailure()1979         private RecentFailure() {}
1980 
1981         /**
1982          * Association Rejection Status code (NONE for success/non-association-rejection-fail)
1983          */
1984         @RecentFailureReason
1985         private int mAssociationStatus = RECENT_FAILURE_NONE;
1986 
1987         /**
1988          * @param status the association status code for the recent failure
1989          */
setAssociationStatus(@ecentFailureReason int status)1990         public void setAssociationStatus(@RecentFailureReason int status) {
1991             mAssociationStatus = status;
1992         }
1993         /**
1994          * Sets the RecentFailure to NONE
1995          */
clear()1996         public void clear() {
1997             mAssociationStatus = RECENT_FAILURE_NONE;
1998         }
1999         /**
2000          * Get the recent failure code. One of {@link #RECENT_FAILURE_NONE} or
2001          * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}.
2002          */
2003         @RecentFailureReason
getAssociationStatus()2004         public int getAssociationStatus() {
2005             return mAssociationStatus;
2006         }
2007     }
2008 
2009     /**
2010      * RecentFailure member
2011      * @hide
2012      */
2013     // TODO(b/148626966): called by SUW via reflection, once SUW is updated, make private and
2014     //  rename to mRecentFailure
2015     @NonNull
2016     public final RecentFailure recentFailure = new RecentFailure();
2017 
2018     /** @hide */
2019     @Retention(RetentionPolicy.SOURCE)
2020     @IntDef(prefix = "RECENT_FAILURE_", value = {
2021             RECENT_FAILURE_NONE,
2022             RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA})
2023     public @interface RecentFailureReason {}
2024 
2025     /**
2026      * No recent failure, or no specific reason given for the recent connection failure
2027      * @hide
2028      */
2029     @SystemApi
2030     public static final int RECENT_FAILURE_NONE = 0;
2031     /**
2032      * Connection to this network recently failed due to Association Rejection Status 17
2033      * (AP is full)
2034      * @hide
2035      */
2036     @SystemApi
2037     public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
2038 
2039     /**
2040      * Get the failure reason for the most recent connection attempt, or
2041      * {@link #RECENT_FAILURE_NONE} if there was no failure.
2042      *
2043      * Failure reasons include:
2044      * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}
2045      *
2046      * @hide
2047      */
2048     @RecentFailureReason
2049     @SystemApi
getRecentFailureReason()2050     public int getRecentFailureReason() {
2051         return recentFailure.getAssociationStatus();
2052     }
2053 
2054     /**
2055      * Get the network selection status.
2056      * @hide
2057      */
2058     @NonNull
2059     @SystemApi
getNetworkSelectionStatus()2060     public NetworkSelectionStatus getNetworkSelectionStatus() {
2061         return mNetworkSelectionStatus;
2062     }
2063 
2064     /**
2065      * Set the network selection status.
2066      * @hide
2067      */
2068     @SystemApi
setNetworkSelectionStatus(@onNull NetworkSelectionStatus status)2069     public void setNetworkSelectionStatus(@NonNull NetworkSelectionStatus status) {
2070         mNetworkSelectionStatus = status;
2071     }
2072 
2073     /**
2074      * @hide
2075      * Linked Configurations: represent the set of Wificonfigurations that are equivalent
2076      * regarding roaming and auto-joining.
2077      * The linked configuration may or may not have same SSID, and may or may not have same
2078      * credentials.
2079      * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
2080      */
2081     public HashMap<String, Integer>  linkedConfigurations;
2082 
WifiConfiguration()2083     public WifiConfiguration() {
2084         networkId = INVALID_NETWORK_ID;
2085         SSID = null;
2086         BSSID = null;
2087         FQDN = null;
2088         roamingConsortiumIds = new long[0];
2089         priority = 0;
2090         hiddenSSID = false;
2091         allowedKeyManagement = new BitSet();
2092         allowedProtocols = new BitSet();
2093         allowedAuthAlgorithms = new BitSet();
2094         allowedPairwiseCiphers = new BitSet();
2095         allowedGroupCiphers = new BitSet();
2096         allowedGroupManagementCiphers = new BitSet();
2097         allowedSuiteBCiphers = new BitSet();
2098         wepKeys = new String[4];
2099         for (int i = 0; i < wepKeys.length; i++) {
2100             wepKeys[i] = null;
2101         }
2102         enterpriseConfig = new WifiEnterpriseConfig();
2103         ephemeral = false;
2104         osu = false;
2105         trusted = true; // Networks are considered trusted by default.
2106         fromWifiNetworkSuggestion = false;
2107         fromWifiNetworkSpecifier = false;
2108         meteredHint = false;
2109         meteredOverride = METERED_OVERRIDE_NONE;
2110         useExternalScores = false;
2111         validatedInternetAccess = false;
2112         mIpConfiguration = new IpConfiguration();
2113         lastUpdateUid = -1;
2114         creatorUid = -1;
2115         shared = true;
2116         dtimInterval = 0;
2117         mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
2118     }
2119 
2120     /**
2121      * Identify if this configuration represents a Passpoint network
2122      */
isPasspoint()2123     public boolean isPasspoint() {
2124         return !TextUtils.isEmpty(FQDN)
2125                 && !TextUtils.isEmpty(providerFriendlyName)
2126                 && enterpriseConfig != null
2127                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE
2128                 && !TextUtils.isEmpty(mPasspointUniqueId);
2129     }
2130 
2131     /**
2132      * Helper function, identify if a configuration is linked
2133      * @hide
2134      */
isLinked(WifiConfiguration config)2135     public boolean isLinked(WifiConfiguration config) {
2136         if (config != null) {
2137             if (config.linkedConfigurations != null && linkedConfigurations != null) {
2138                 if (config.linkedConfigurations.get(getKey()) != null
2139                         && linkedConfigurations.get(config.getKey()) != null) {
2140                     return true;
2141                 }
2142             }
2143         }
2144         return  false;
2145     }
2146 
2147     /**
2148      * Helper function, idenfity if a configuration should be treated as an enterprise network
2149      * @hide
2150      */
2151     @UnsupportedAppUsage
isEnterprise()2152     public boolean isEnterprise() {
2153         return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
2154                 || allowedKeyManagement.get(KeyMgmt.IEEE8021X)
2155                 || allowedKeyManagement.get(KeyMgmt.SUITE_B_192)
2156                 || allowedKeyManagement.get(KeyMgmt.WAPI_CERT))
2157                 && enterpriseConfig != null
2158                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
2159     }
2160 
logTimeOfDay(long millis)2161     private static String logTimeOfDay(long millis) {
2162         Calendar c = Calendar.getInstance();
2163         if (millis >= 0) {
2164             c.setTimeInMillis(millis);
2165             return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
2166         } else {
2167             return Long.toString(millis);
2168         }
2169     }
2170 
2171     @Override
toString()2172     public String toString() {
2173         StringBuilder sbuf = new StringBuilder();
2174         if (this.status == WifiConfiguration.Status.CURRENT) {
2175             sbuf.append("* ");
2176         } else if (this.status == WifiConfiguration.Status.DISABLED) {
2177             sbuf.append("- DSBLE ");
2178         }
2179         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
2180                 append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
2181                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
2182                 .append(" HOME-PROVIDER-NETWORK: ").append(this.isHomeProviderNetwork)
2183                 .append(" PRIO: ").append(this.priority)
2184                 .append(" HIDDEN: ").append(this.hiddenSSID)
2185                 .append(" PMF: ").append(this.requirePmf)
2186                 .append("CarrierId: ").append(this.carrierId)
2187                 .append('\n');
2188 
2189 
2190         sbuf.append(" NetworkSelectionStatus ")
2191                 .append(mNetworkSelectionStatus.getNetworkStatusString())
2192                 .append("\n");
2193         if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) {
2194             sbuf.append(" mNetworkSelectionDisableReason ")
2195                     .append(mNetworkSelectionStatus.getNetworkSelectionDisableReasonString())
2196                     .append("\n");
2197 
2198             for (int index = NetworkSelectionStatus.DISABLED_NONE;
2199                     index < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
2200                 if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) {
2201                     sbuf.append(
2202                             NetworkSelectionStatus.getNetworkSelectionDisableReasonString(index))
2203                             .append(" counter:")
2204                             .append(mNetworkSelectionStatus.getDisableReasonCounter(index))
2205                             .append("\n");
2206                 }
2207             }
2208         }
2209         if (mNetworkSelectionStatus.getConnectChoice() != null) {
2210             sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
2211         }
2212         sbuf.append(" hasEverConnected: ")
2213                 .append(mNetworkSelectionStatus.hasEverConnected()).append("\n");
2214 
2215         if (this.numAssociation > 0) {
2216             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
2217         }
2218         if (this.numNoInternetAccessReports > 0) {
2219             sbuf.append(" numNoInternetAccessReports ");
2220             sbuf.append(this.numNoInternetAccessReports).append("\n");
2221         }
2222         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
2223         if (this.ephemeral) sbuf.append(" ephemeral");
2224         if (this.osu) sbuf.append(" osu");
2225         if (this.trusted) sbuf.append(" trusted");
2226         if (this.fromWifiNetworkSuggestion) sbuf.append(" fromWifiNetworkSuggestion");
2227         if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier");
2228         if (this.meteredHint) sbuf.append(" meteredHint");
2229         if (this.useExternalScores) sbuf.append(" useExternalScores");
2230         if (this.validatedInternetAccess || this.ephemeral || this.trusted
2231                 || this.fromWifiNetworkSuggestion || this.fromWifiNetworkSpecifier
2232                 || this.meteredHint || this.useExternalScores) {
2233             sbuf.append("\n");
2234         }
2235         if (this.meteredOverride != METERED_OVERRIDE_NONE) {
2236             sbuf.append(" meteredOverride ").append(meteredOverride).append("\n");
2237         }
2238         sbuf.append(" macRandomizationSetting: ").append(macRandomizationSetting).append("\n");
2239         sbuf.append(" mRandomizedMacAddress: ").append(mRandomizedMacAddress).append("\n");
2240         sbuf.append(" randomizedMacExpirationTimeMs: ")
2241                 .append(randomizedMacExpirationTimeMs == 0 ? "<none>"
2242                         : logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
2243         sbuf.append(" KeyMgmt:");
2244         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
2245             if (this.allowedKeyManagement.get(k)) {
2246                 sbuf.append(" ");
2247                 if (k < KeyMgmt.strings.length) {
2248                     sbuf.append(KeyMgmt.strings[k]);
2249                 } else {
2250                     sbuf.append("??");
2251                 }
2252             }
2253         }
2254         sbuf.append(" Protocols:");
2255         for (int p = 0; p < this.allowedProtocols.size(); p++) {
2256             if (this.allowedProtocols.get(p)) {
2257                 sbuf.append(" ");
2258                 if (p < Protocol.strings.length) {
2259                     sbuf.append(Protocol.strings[p]);
2260                 } else {
2261                     sbuf.append("??");
2262                 }
2263             }
2264         }
2265         sbuf.append('\n');
2266         sbuf.append(" AuthAlgorithms:");
2267         for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) {
2268             if (this.allowedAuthAlgorithms.get(a)) {
2269                 sbuf.append(" ");
2270                 if (a < AuthAlgorithm.strings.length) {
2271                     sbuf.append(AuthAlgorithm.strings[a]);
2272                 } else {
2273                     sbuf.append("??");
2274                 }
2275             }
2276         }
2277         sbuf.append('\n');
2278         sbuf.append(" PairwiseCiphers:");
2279         for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) {
2280             if (this.allowedPairwiseCiphers.get(pc)) {
2281                 sbuf.append(" ");
2282                 if (pc < PairwiseCipher.strings.length) {
2283                     sbuf.append(PairwiseCipher.strings[pc]);
2284                 } else {
2285                     sbuf.append("??");
2286                 }
2287             }
2288         }
2289         sbuf.append('\n');
2290         sbuf.append(" GroupCiphers:");
2291         for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) {
2292             if (this.allowedGroupCiphers.get(gc)) {
2293                 sbuf.append(" ");
2294                 if (gc < GroupCipher.strings.length) {
2295                     sbuf.append(GroupCipher.strings[gc]);
2296                 } else {
2297                     sbuf.append("??");
2298                 }
2299             }
2300         }
2301         sbuf.append('\n');
2302         sbuf.append(" GroupMgmtCiphers:");
2303         for (int gmc = 0; gmc < this.allowedGroupManagementCiphers.size(); gmc++) {
2304             if (this.allowedGroupManagementCiphers.get(gmc)) {
2305                 sbuf.append(" ");
2306                 if (gmc < GroupMgmtCipher.strings.length) {
2307                     sbuf.append(GroupMgmtCipher.strings[gmc]);
2308                 } else {
2309                     sbuf.append("??");
2310                 }
2311             }
2312         }
2313         sbuf.append('\n');
2314         sbuf.append(" SuiteBCiphers:");
2315         for (int sbc = 0; sbc < this.allowedSuiteBCiphers.size(); sbc++) {
2316             if (this.allowedSuiteBCiphers.get(sbc)) {
2317                 sbuf.append(" ");
2318                 if (sbc < SuiteBCipher.strings.length) {
2319                     sbuf.append(SuiteBCipher.strings[sbc]);
2320                 } else {
2321                     sbuf.append("??");
2322                 }
2323             }
2324         }
2325         sbuf.append('\n').append(" PSK/SAE: ");
2326         if (this.preSharedKey != null) {
2327             sbuf.append('*');
2328         }
2329 
2330         sbuf.append("\nEnterprise config:\n");
2331         sbuf.append(enterpriseConfig);
2332 
2333         sbuf.append("IP config:\n");
2334         sbuf.append(mIpConfiguration.toString());
2335 
2336         if (mNetworkSelectionStatus.getNetworkSelectionBSSID() != null) {
2337             sbuf.append(" networkSelectionBSSID="
2338                     + mNetworkSelectionStatus.getNetworkSelectionBSSID());
2339         }
2340         long now_ms = SystemClock.elapsedRealtime();
2341         if (mNetworkSelectionStatus.getDisableTime() != NetworkSelectionStatus
2342                 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP) {
2343             sbuf.append('\n');
2344             long diff = now_ms - mNetworkSelectionStatus.getDisableTime();
2345             if (diff <= 0) {
2346                 sbuf.append(" blackListed since <incorrect>");
2347             } else {
2348                 sbuf.append(" blackListed: ").append(Long.toString(diff / 1000)).append("sec ");
2349             }
2350         }
2351         if (creatorUid != 0) sbuf.append(" cuid=" + creatorUid);
2352         if (creatorName != null) sbuf.append(" cname=" + creatorName);
2353         if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
2354         if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
2355         if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier);
2356         sbuf.append(" lcuid=" + lastConnectUid);
2357         sbuf.append(" allowAutojoin=" + allowAutojoin);
2358         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
2359         sbuf.append(" mostRecentlyConnected=" + isMostRecentlyConnected);
2360 
2361         sbuf.append(" ");
2362 
2363         if (this.lastConnected != 0) {
2364             sbuf.append('\n');
2365             sbuf.append("lastConnected: ").append(logTimeOfDay(this.lastConnected));
2366             sbuf.append(" ");
2367         }
2368         sbuf.append('\n');
2369         if (this.linkedConfigurations != null) {
2370             for (String key : this.linkedConfigurations.keySet()) {
2371                 sbuf.append(" linked: ").append(key);
2372                 sbuf.append('\n');
2373             }
2374         }
2375         sbuf.append("recentFailure: ").append("Association Rejection code: ")
2376                 .append(recentFailure.getAssociationStatus()).append("\n");
2377         return sbuf.toString();
2378     }
2379 
2380     /**
2381      * Get the SSID in a human-readable format, with all additional formatting removed
2382      * e.g. quotation marks around the SSID, "P" prefix
2383      * @hide
2384      */
2385     @NonNull
2386     @SystemApi
getPrintableSsid()2387     public String getPrintableSsid() {
2388         if (SSID == null) return "";
2389         final int length = SSID.length();
2390         if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
2391             return SSID.substring(1, length - 1);
2392         }
2393 
2394         /* The ascii-encoded string format is P"<ascii-encoded-string>"
2395          * The decoding is implemented in the supplicant for a newly configured
2396          * network.
2397          */
2398         if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
2399                 (SSID.charAt(length-1) == '"')) {
2400             WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
2401                     SSID.substring(2, length - 1));
2402             return wifiSsid.toString();
2403         }
2404         return SSID;
2405     }
2406 
2407     /**
2408      * Get an identifier for associating credentials with this config
2409      * @param current configuration contains values for additional fields
2410      *                that are not part of this configuration. Used
2411      *                when a config with some fields is passed by an application.
2412      * @throws IllegalStateException if config is invalid for key id generation
2413      * @hide
2414      */
getKeyIdForCredentials(WifiConfiguration current)2415     public String getKeyIdForCredentials(WifiConfiguration current) {
2416         String keyMgmt = "";
2417 
2418         try {
2419             // Get current config details for fields that are not initialized
2420             if (TextUtils.isEmpty(SSID)) SSID = current.SSID;
2421             if (allowedKeyManagement.cardinality() == 0) {
2422                 allowedKeyManagement = current.allowedKeyManagement;
2423             }
2424             if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
2425                 keyMgmt += KeyMgmt.strings[KeyMgmt.WPA_EAP];
2426             }
2427             if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
2428                 keyMgmt += KeyMgmt.strings[KeyMgmt.OSEN];
2429             }
2430             if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
2431                 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
2432             }
2433             if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
2434                 keyMgmt += KeyMgmt.strings[KeyMgmt.SUITE_B_192];
2435             }
2436             if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
2437                 keyMgmt += KeyMgmt.strings[KeyMgmt.WAPI_CERT];
2438             }
2439 
2440             if (TextUtils.isEmpty(keyMgmt)) {
2441                 throw new IllegalStateException("Not an EAP network");
2442             }
2443             String keyId = trimStringForKeyId(SSID) + "_" + keyMgmt + "_"
2444                     + trimStringForKeyId(enterpriseConfig.getKeyId(current != null
2445                     ? current.enterpriseConfig : null));
2446 
2447             if (!fromWifiNetworkSuggestion) {
2448                 return keyId;
2449             }
2450             return keyId + "_" + trimStringForKeyId(BSSID) + "_" + trimStringForKeyId(creatorName);
2451         } catch (NullPointerException e) {
2452             throw new IllegalStateException("Invalid config details");
2453         }
2454     }
2455 
trimStringForKeyId(String string)2456     private String trimStringForKeyId(String string) {
2457         if (string == null) {
2458             return "";
2459         }
2460         // Remove quotes and spaces
2461         return string.replace("\"", "").replace(" ", "");
2462     }
2463 
readBitSet(Parcel src)2464     private static BitSet readBitSet(Parcel src) {
2465         int cardinality = src.readInt();
2466 
2467         BitSet set = new BitSet();
2468         for (int i = 0; i < cardinality; i++) {
2469             set.set(src.readInt());
2470         }
2471 
2472         return set;
2473     }
2474 
writeBitSet(Parcel dest, BitSet set)2475     private static void writeBitSet(Parcel dest, BitSet set) {
2476         int nextSetBit = -1;
2477 
2478         dest.writeInt(set.cardinality());
2479 
2480         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
2481             dest.writeInt(nextSetBit);
2482         }
2483     }
2484 
2485     /**
2486      * Get the authentication type of the network.
2487      * @return One of the {@link KeyMgmt} constants. e.g. {@link KeyMgmt#WPA2_PSK}.
2488      * @hide
2489      */
2490     @SystemApi
2491     @KeyMgmt.KeyMgmtScheme
getAuthType()2492     public int getAuthType() {
2493         if (allowedKeyManagement.cardinality() > 1) {
2494             throw new IllegalStateException("More than one auth type set");
2495         }
2496         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
2497             return KeyMgmt.WPA_PSK;
2498         } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
2499             return KeyMgmt.WPA2_PSK;
2500         } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
2501             return KeyMgmt.WPA_EAP;
2502         } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
2503             return KeyMgmt.IEEE8021X;
2504         } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
2505             return KeyMgmt.SAE;
2506         } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
2507             return KeyMgmt.OWE;
2508         } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
2509             return KeyMgmt.SUITE_B_192;
2510         } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
2511             return KeyMgmt.WAPI_PSK;
2512         } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
2513             return KeyMgmt.WAPI_CERT;
2514         }
2515         return KeyMgmt.NONE;
2516     }
2517 
2518     /**
2519      * Return a String that can be used to uniquely identify this WifiConfiguration.
2520      * <br />
2521      * Note: Do not persist this value! This value is not guaranteed to remain backwards compatible.
2522      */
2523     @NonNull
getKey()2524     public String getKey() {
2525         // Passpoint ephemeral networks have their unique identifier set. Return it as is to be
2526         // able to match internally.
2527         if (mPasspointUniqueId != null) {
2528             return mPasspointUniqueId;
2529         }
2530 
2531         String key = getSsidAndSecurityTypeString();
2532         if (!shared) {
2533             key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
2534         }
2535 
2536         return key;
2537     }
2538 
2539     /** @hide
2540      *  return the SSID + security type in String format.
2541      */
getSsidAndSecurityTypeString()2542     public String getSsidAndSecurityTypeString() {
2543         String key;
2544         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
2545             key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
2546         } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
2547                 || allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
2548             key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
2549         } else if (wepTxKeyIndex >= 0 && wepTxKeyIndex < wepKeys.length
2550                 && wepKeys[wepTxKeyIndex] != null) {
2551             key = SSID + "WEP";
2552         } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
2553             key = SSID + KeyMgmt.strings[KeyMgmt.OWE];
2554         } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
2555             key = SSID + KeyMgmt.strings[KeyMgmt.SAE];
2556         } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
2557             key = SSID + KeyMgmt.strings[KeyMgmt.SUITE_B_192];
2558         } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
2559             key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_PSK];
2560         } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
2561             key = SSID + KeyMgmt.strings[KeyMgmt.WAPI_CERT];
2562         } else if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
2563             key = SSID + KeyMgmt.strings[KeyMgmt.OSEN];
2564         } else {
2565             key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
2566         }
2567         return key;
2568     }
2569 
2570     /**
2571      * Get the IpConfiguration object associated with this WifiConfiguration.
2572      * @hide
2573      */
2574     @NonNull
2575     @SystemApi
getIpConfiguration()2576     public IpConfiguration getIpConfiguration() {
2577         return new IpConfiguration(mIpConfiguration);
2578     }
2579 
2580     /**
2581      * Set the {@link IpConfiguration} for this network.
2582      * @param ipConfiguration the {@link IpConfiguration} to set, or null to use the default
2583      *                        constructor {@link IpConfiguration#IpConfiguration()}.
2584      * @hide
2585      */
2586     @SystemApi
setIpConfiguration(@ullable IpConfiguration ipConfiguration)2587     public void setIpConfiguration(@Nullable IpConfiguration ipConfiguration) {
2588         if (ipConfiguration == null) ipConfiguration = new IpConfiguration();
2589         mIpConfiguration = ipConfiguration;
2590     }
2591 
2592     /**
2593      * Get the {@link StaticIpConfiguration} for this network.
2594      * @return the {@link StaticIpConfiguration}, or null if unset.
2595      * @hide
2596      */
2597     @Nullable
2598     @UnsupportedAppUsage
getStaticIpConfiguration()2599     public StaticIpConfiguration getStaticIpConfiguration() {
2600         return mIpConfiguration.getStaticIpConfiguration();
2601     }
2602 
2603     /** @hide */
2604     @UnsupportedAppUsage
setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration)2605     public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
2606         mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration);
2607     }
2608 
2609     /**
2610      * Get the {@link IpConfiguration.IpAssignment} for this network.
2611      * @hide
2612      */
2613     @NonNull
2614     @UnsupportedAppUsage
getIpAssignment()2615     public IpConfiguration.IpAssignment getIpAssignment() {
2616         return mIpConfiguration.getIpAssignment();
2617     }
2618 
2619     /** @hide */
2620     @UnsupportedAppUsage
setIpAssignment(IpConfiguration.IpAssignment ipAssignment)2621     public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
2622         mIpConfiguration.setIpAssignment(ipAssignment);
2623     }
2624 
2625     /**
2626      * Get the {@link IpConfiguration.ProxySettings} for this network.
2627      * @hide
2628      */
2629     @NonNull
2630     @UnsupportedAppUsage
getProxySettings()2631     public IpConfiguration.ProxySettings getProxySettings() {
2632         return mIpConfiguration.getProxySettings();
2633     }
2634 
2635     /** @hide */
2636     @UnsupportedAppUsage
setProxySettings(IpConfiguration.ProxySettings proxySettings)2637     public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
2638         mIpConfiguration.setProxySettings(proxySettings);
2639     }
2640 
2641     /**
2642      * Returns the HTTP proxy used by this object.
2643      * @return a {@link ProxyInfo httpProxy} representing the proxy specified by this
2644      *                  WifiConfiguration, or {@code null} if no proxy is specified.
2645      */
getHttpProxy()2646     public ProxyInfo getHttpProxy() {
2647         if (mIpConfiguration.getProxySettings() == IpConfiguration.ProxySettings.NONE) {
2648             return null;
2649         }
2650         return new ProxyInfo(mIpConfiguration.getHttpProxy());
2651     }
2652 
2653     /**
2654      * Set the {@link ProxyInfo} for this WifiConfiguration. This method should only be used by a
2655      * device owner or profile owner. When other apps attempt to save a {@link WifiConfiguration}
2656      * with modified proxy settings, the methods {@link WifiManager#addNetwork} and
2657      * {@link WifiManager#updateNetwork} fail and return {@code -1}.
2658      *
2659      * @param httpProxy {@link ProxyInfo} representing the httpProxy to be used by this
2660      *                  WifiConfiguration. Setting this to {@code null} will explicitly set no
2661      *                  proxy, removing any proxy that was previously set.
2662      * @exception IllegalArgumentException for invalid httpProxy
2663      */
setHttpProxy(ProxyInfo httpProxy)2664     public void setHttpProxy(ProxyInfo httpProxy) {
2665         if (httpProxy == null) {
2666             mIpConfiguration.setProxySettings(IpConfiguration.ProxySettings.NONE);
2667             mIpConfiguration.setHttpProxy(null);
2668             return;
2669         }
2670         ProxyInfo httpProxyCopy;
2671         ProxySettings proxySettingCopy;
2672         if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
2673             proxySettingCopy = IpConfiguration.ProxySettings.PAC;
2674             // Construct a new PAC URL Proxy
2675             httpProxyCopy = ProxyInfo.buildPacProxy(httpProxy.getPacFileUrl(), httpProxy.getPort());
2676         } else {
2677             proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
2678             // Construct a new HTTP Proxy
2679             httpProxyCopy = ProxyInfo.buildDirectProxy(httpProxy.getHost(), httpProxy.getPort(),
2680                     Arrays.asList(httpProxy.getExclusionList()));
2681         }
2682         if (!httpProxyCopy.isValid()) {
2683             throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
2684         }
2685         mIpConfiguration.setProxySettings(proxySettingCopy);
2686         mIpConfiguration.setHttpProxy(httpProxyCopy);
2687     }
2688 
2689     /**
2690      * Set the {@link ProxySettings} and {@link ProxyInfo} for this network.
2691      * @hide
2692      */
2693     @UnsupportedAppUsage
setProxy(@onNull ProxySettings settings, @NonNull ProxyInfo proxy)2694     public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) {
2695         mIpConfiguration.setProxySettings(settings);
2696         mIpConfiguration.setHttpProxy(proxy);
2697     }
2698 
2699     /** Implement the Parcelable interface {@hide} */
describeContents()2700     public int describeContents() {
2701         return 0;
2702     }
2703 
2704     /** @hide */
setPasspointManagementObjectTree(String passpointManagementObjectTree)2705     public void setPasspointManagementObjectTree(String passpointManagementObjectTree) {
2706         mPasspointManagementObjectTree = passpointManagementObjectTree;
2707     }
2708 
2709     /** @hide */
getMoTree()2710     public String getMoTree() {
2711         return mPasspointManagementObjectTree;
2712     }
2713 
2714     /** Copy constructor */
WifiConfiguration(@onNull WifiConfiguration source)2715     public WifiConfiguration(@NonNull WifiConfiguration source) {
2716         if (source != null) {
2717             networkId = source.networkId;
2718             status = source.status;
2719             SSID = source.SSID;
2720             BSSID = source.BSSID;
2721             FQDN = source.FQDN;
2722             roamingConsortiumIds = source.roamingConsortiumIds.clone();
2723             providerFriendlyName = source.providerFriendlyName;
2724             isHomeProviderNetwork = source.isHomeProviderNetwork;
2725             preSharedKey = source.preSharedKey;
2726 
2727             mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
2728             apBand = source.apBand;
2729             apChannel = source.apChannel;
2730 
2731             wepKeys = new String[4];
2732             for (int i = 0; i < wepKeys.length; i++) {
2733                 wepKeys[i] = source.wepKeys[i];
2734             }
2735 
2736             wepTxKeyIndex = source.wepTxKeyIndex;
2737             priority = source.priority;
2738             hiddenSSID = source.hiddenSSID;
2739             allowedKeyManagement   = (BitSet) source.allowedKeyManagement.clone();
2740             allowedProtocols       = (BitSet) source.allowedProtocols.clone();
2741             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
2742             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
2743             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
2744             allowedGroupManagementCiphers = (BitSet) source.allowedGroupManagementCiphers.clone();
2745             allowedSuiteBCiphers    = (BitSet) source.allowedSuiteBCiphers.clone();
2746             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
2747 
2748             defaultGwMacAddress = source.defaultGwMacAddress;
2749 
2750             mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
2751 
2752             if ((source.linkedConfigurations != null)
2753                     && (source.linkedConfigurations.size() > 0)) {
2754                 linkedConfigurations = new HashMap<String, Integer>();
2755                 linkedConfigurations.putAll(source.linkedConfigurations);
2756             }
2757             validatedInternetAccess = source.validatedInternetAccess;
2758             isLegacyPasspointConfig = source.isLegacyPasspointConfig;
2759             ephemeral = source.ephemeral;
2760             osu = source.osu;
2761             trusted = source.trusted;
2762             fromWifiNetworkSuggestion = source.fromWifiNetworkSuggestion;
2763             fromWifiNetworkSpecifier = source.fromWifiNetworkSpecifier;
2764             meteredHint = source.meteredHint;
2765             meteredOverride = source.meteredOverride;
2766             useExternalScores = source.useExternalScores;
2767 
2768             lastConnectUid = source.lastConnectUid;
2769             lastUpdateUid = source.lastUpdateUid;
2770             creatorUid = source.creatorUid;
2771             creatorName = source.creatorName;
2772             lastUpdateName = source.lastUpdateName;
2773             peerWifiConfiguration = source.peerWifiConfiguration;
2774 
2775             lastConnected = source.lastConnected;
2776             lastDisconnected = source.lastDisconnected;
2777             numScorerOverride = source.numScorerOverride;
2778             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
2779             numAssociation = source.numAssociation;
2780             allowAutojoin = source.allowAutojoin;
2781             numNoInternetAccessReports = source.numNoInternetAccessReports;
2782             noInternetAccessExpected = source.noInternetAccessExpected;
2783             shared = source.shared;
2784             recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus());
2785             mRandomizedMacAddress = source.mRandomizedMacAddress;
2786             macRandomizationSetting = source.macRandomizationSetting;
2787             randomizedMacExpirationTimeMs = source.randomizedMacExpirationTimeMs;
2788             requirePmf = source.requirePmf;
2789             updateIdentifier = source.updateIdentifier;
2790             carrierId = source.carrierId;
2791             mPasspointUniqueId = source.mPasspointUniqueId;
2792         }
2793     }
2794 
2795     /** Implement the Parcelable interface {@hide} */
2796     @Override
writeToParcel(Parcel dest, int flags)2797     public void writeToParcel(Parcel dest, int flags) {
2798         dest.writeInt(networkId);
2799         dest.writeInt(status);
2800         mNetworkSelectionStatus.writeToParcel(dest);
2801         dest.writeString(SSID);
2802         dest.writeString(BSSID);
2803         dest.writeInt(apBand);
2804         dest.writeInt(apChannel);
2805         dest.writeString(FQDN);
2806         dest.writeString(providerFriendlyName);
2807         dest.writeInt(isHomeProviderNetwork ? 1 : 0);
2808         dest.writeInt(roamingConsortiumIds.length);
2809         for (long roamingConsortiumId : roamingConsortiumIds) {
2810             dest.writeLong(roamingConsortiumId);
2811         }
2812         dest.writeString(preSharedKey);
2813         for (String wepKey : wepKeys) {
2814             dest.writeString(wepKey);
2815         }
2816         dest.writeInt(wepTxKeyIndex);
2817         dest.writeInt(priority);
2818         dest.writeInt(hiddenSSID ? 1 : 0);
2819         dest.writeInt(requirePmf ? 1 : 0);
2820         dest.writeString(updateIdentifier);
2821 
2822         writeBitSet(dest, allowedKeyManagement);
2823         writeBitSet(dest, allowedProtocols);
2824         writeBitSet(dest, allowedAuthAlgorithms);
2825         writeBitSet(dest, allowedPairwiseCiphers);
2826         writeBitSet(dest, allowedGroupCiphers);
2827         writeBitSet(dest, allowedGroupManagementCiphers);
2828         writeBitSet(dest, allowedSuiteBCiphers);
2829 
2830         dest.writeParcelable(enterpriseConfig, flags);
2831 
2832         dest.writeParcelable(mIpConfiguration, flags);
2833         dest.writeString(dhcpServer);
2834         dest.writeString(defaultGwMacAddress);
2835         dest.writeInt(validatedInternetAccess ? 1 : 0);
2836         dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
2837         dest.writeInt(ephemeral ? 1 : 0);
2838         dest.writeInt(trusted ? 1 : 0);
2839         dest.writeInt(fromWifiNetworkSuggestion ? 1 : 0);
2840         dest.writeInt(fromWifiNetworkSpecifier ? 1 : 0);
2841         dest.writeInt(meteredHint ? 1 : 0);
2842         dest.writeInt(meteredOverride);
2843         dest.writeInt(useExternalScores ? 1 : 0);
2844         dest.writeInt(creatorUid);
2845         dest.writeInt(lastConnectUid);
2846         dest.writeInt(lastUpdateUid);
2847         dest.writeString(creatorName);
2848         dest.writeString(lastUpdateName);
2849         dest.writeInt(numScorerOverride);
2850         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
2851         dest.writeInt(numAssociation);
2852         dest.writeBoolean(allowAutojoin);
2853         dest.writeInt(numNoInternetAccessReports);
2854         dest.writeInt(noInternetAccessExpected ? 1 : 0);
2855         dest.writeInt(shared ? 1 : 0);
2856         dest.writeString(mPasspointManagementObjectTree);
2857         dest.writeInt(recentFailure.getAssociationStatus());
2858         dest.writeParcelable(mRandomizedMacAddress, flags);
2859         dest.writeInt(macRandomizationSetting);
2860         dest.writeInt(osu ? 1 : 0);
2861         dest.writeLong(randomizedMacExpirationTimeMs);
2862         dest.writeInt(carrierId);
2863         dest.writeString(mPasspointUniqueId);
2864     }
2865 
2866     /** Implement the Parcelable interface {@hide} */
2867     @UnsupportedAppUsage
2868     public static final @android.annotation.NonNull Creator<WifiConfiguration> CREATOR =
2869         new Creator<WifiConfiguration>() {
2870             public WifiConfiguration createFromParcel(Parcel in) {
2871                 WifiConfiguration config = new WifiConfiguration();
2872                 config.networkId = in.readInt();
2873                 config.status = in.readInt();
2874                 config.mNetworkSelectionStatus.readFromParcel(in);
2875                 config.SSID = in.readString();
2876                 config.BSSID = in.readString();
2877                 config.apBand = in.readInt();
2878                 config.apChannel = in.readInt();
2879                 config.FQDN = in.readString();
2880                 config.providerFriendlyName = in.readString();
2881                 config.isHomeProviderNetwork = in.readInt() != 0;
2882                 int numRoamingConsortiumIds = in.readInt();
2883                 config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
2884                 for (int i = 0; i < numRoamingConsortiumIds; i++) {
2885                     config.roamingConsortiumIds[i] = in.readLong();
2886                 }
2887                 config.preSharedKey = in.readString();
2888                 for (int i = 0; i < config.wepKeys.length; i++) {
2889                     config.wepKeys[i] = in.readString();
2890                 }
2891                 config.wepTxKeyIndex = in.readInt();
2892                 config.priority = in.readInt();
2893                 config.hiddenSSID = in.readInt() != 0;
2894                 config.requirePmf = in.readInt() != 0;
2895                 config.updateIdentifier = in.readString();
2896 
2897                 config.allowedKeyManagement   = readBitSet(in);
2898                 config.allowedProtocols       = readBitSet(in);
2899                 config.allowedAuthAlgorithms  = readBitSet(in);
2900                 config.allowedPairwiseCiphers = readBitSet(in);
2901                 config.allowedGroupCiphers    = readBitSet(in);
2902                 config.allowedGroupManagementCiphers = readBitSet(in);
2903                 config.allowedSuiteBCiphers   = readBitSet(in);
2904 
2905                 config.enterpriseConfig = in.readParcelable(null);
2906                 config.setIpConfiguration(in.readParcelable(null));
2907                 config.dhcpServer = in.readString();
2908                 config.defaultGwMacAddress = in.readString();
2909                 config.validatedInternetAccess = in.readInt() != 0;
2910                 config.isLegacyPasspointConfig = in.readInt() != 0;
2911                 config.ephemeral = in.readInt() != 0;
2912                 config.trusted = in.readInt() != 0;
2913                 config.fromWifiNetworkSuggestion =  in.readInt() != 0;
2914                 config.fromWifiNetworkSpecifier =  in.readInt() != 0;
2915                 config.meteredHint = in.readInt() != 0;
2916                 config.meteredOverride = in.readInt();
2917                 config.useExternalScores = in.readInt() != 0;
2918                 config.creatorUid = in.readInt();
2919                 config.lastConnectUid = in.readInt();
2920                 config.lastUpdateUid = in.readInt();
2921                 config.creatorName = in.readString();
2922                 config.lastUpdateName = in.readString();
2923                 config.numScorerOverride = in.readInt();
2924                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
2925                 config.numAssociation = in.readInt();
2926                 config.allowAutojoin = in.readBoolean();
2927                 config.numNoInternetAccessReports = in.readInt();
2928                 config.noInternetAccessExpected = in.readInt() != 0;
2929                 config.shared = in.readInt() != 0;
2930                 config.mPasspointManagementObjectTree = in.readString();
2931                 config.recentFailure.setAssociationStatus(in.readInt());
2932                 config.mRandomizedMacAddress = in.readParcelable(null);
2933                 config.macRandomizationSetting = in.readInt();
2934                 config.osu = in.readInt() != 0;
2935                 config.randomizedMacExpirationTimeMs = in.readLong();
2936                 config.carrierId = in.readInt();
2937                 config.mPasspointUniqueId = in.readString();
2938                 return config;
2939             }
2940 
2941             public WifiConfiguration[] newArray(int size) {
2942                 return new WifiConfiguration[size];
2943             }
2944         };
2945 
2946     /**
2947      * Passpoint Unique identifier
2948      * @hide
2949      */
2950     private String mPasspointUniqueId = null;
2951 
2952     /**
2953      * Set the Passpoint unique identifier
2954      * @param uniqueId Passpoint unique identifier to be set
2955      * @hide
2956      */
setPasspointUniqueId(String uniqueId)2957     public void setPasspointUniqueId(String uniqueId) {
2958         mPasspointUniqueId = uniqueId;
2959     }
2960 
2961     /**
2962      * Set the Passpoint unique identifier
2963      * @hide
2964      */
getPasspointUniqueId()2965     public String getPasspointUniqueId() {
2966         return mPasspointUniqueId;
2967     }
2968 
2969     /**
2970      * If network is one of the most recently connected.
2971      * For framework internal use only. Do not parcel.
2972      * @hide
2973      */
2974     public boolean isMostRecentlyConnected = false;
2975 
2976     /**
2977      * Whether the key mgmt indicates if the WifiConfiguration needs a preSharedKey or not.
2978      * @return true if preSharedKey is needed, false otherwise.
2979      * @hide
2980      */
needsPreSharedKey()2981     public boolean needsPreSharedKey() {
2982         return allowedKeyManagement.get(KeyMgmt.WPA_PSK)
2983                 || allowedKeyManagement.get(KeyMgmt.SAE)
2984                 || allowedKeyManagement.get(KeyMgmt.WAPI_PSK);
2985     }
2986 
2987 }
2988