1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.wifi;
18 
19 import android.annotation.SystemApi;
20 import android.content.pm.PackageManager;
21 import android.net.IpConfiguration;
22 import android.net.IpConfiguration.ProxySettings;
23 import android.net.ProxyInfo;
24 import android.net.StaticIpConfiguration;
25 import android.net.Uri;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.os.UserHandle;
29 import android.text.TextUtils;
30 import android.util.BackupUtils;
31 
32 import java.io.ByteArrayOutputStream;
33 import java.io.DataInputStream;
34 import java.io.DataOutputStream;
35 import java.io.IOException;
36 import java.util.Arrays;
37 import java.util.BitSet;
38 import java.util.HashMap;
39 
40 /**
41  * A class representing a configured Wi-Fi network, including the
42  * security configuration.
43  */
44 public class WifiConfiguration implements Parcelable {
45     private static final String TAG = "WifiConfiguration";
46     /**
47      * Current Version of the Backup Serializer.
48     */
49     private static final int BACKUP_VERSION = 2;
50     /** {@hide} */
51     public static final String ssidVarName = "ssid";
52     /** {@hide} */
53     public static final String bssidVarName = "bssid";
54     /** {@hide} */
55     public static final String pskVarName = "psk";
56     /** {@hide} */
57     public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" };
58     /** {@hide} */
59     public static final String wepTxKeyIdxVarName = "wep_tx_keyidx";
60     /** {@hide} */
61     public static final String priorityVarName = "priority";
62     /** {@hide} */
63     public static final String hiddenSSIDVarName = "scan_ssid";
64     /** {@hide} */
65     public static final String pmfVarName = "ieee80211w";
66     /** {@hide} */
67     public static final String updateIdentiferVarName = "update_identifier";
68     /** {@hide} */
69     public static final int INVALID_NETWORK_ID = -1;
70     /** {@hide} */
71     public static final int LOCAL_ONLY_NETWORK_ID = -2;
72 
73     /** {@hide} */
74     private String mPasspointManagementObjectTree;
75 
76     /**
77      * Recognized key management schemes.
78      */
79     public static class KeyMgmt {
KeyMgmt()80         private KeyMgmt() { }
81 
82         /** WPA is not used; plaintext or static WEP could be used. */
83         public static final int NONE = 0;
84         /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
85         public static final int WPA_PSK = 1;
86         /** WPA using EAP authentication. Generally used with an external authentication server. */
87         public static final int WPA_EAP = 2;
88         /** IEEE 802.1X using EAP authentication and (optionally) dynamically
89          * generated WEP keys. */
90         public static final int IEEE8021X = 3;
91 
92         /** WPA2 pre-shared key for use with soft access point
93           * (requires {@code preSharedKey} to be specified).
94           * @hide
95           */
96         @SystemApi
97         public static final int WPA2_PSK = 4;
98         /**
99          * Hotspot 2.0 r2 OSEN:
100          * @hide
101          */
102         public static final int OSEN = 5;
103 
104         /**
105          * IEEE 802.11r Fast BSS Transition with PSK authentication.
106          * @hide
107          */
108         public static final int FT_PSK = 6;
109 
110         /**
111          * IEEE 802.11r Fast BSS Transition with EAP authentication.
112          * @hide
113          */
114         public static final int FT_EAP = 7;
115 
116         public static final String varName = "key_mgmt";
117 
118         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X",
119                 "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" };
120     }
121 
122     /**
123      * Recognized security protocols.
124      */
125     public static class Protocol {
Protocol()126         private Protocol() { }
127 
128         /** WPA/IEEE 802.11i/D3.0 */
129         public static final int WPA = 0;
130         /** WPA2/IEEE 802.11i */
131         public static final int RSN = 1;
132         /** HS2.0 r2 OSEN
133          * @hide
134          */
135         public static final int OSEN = 2;
136 
137         public static final String varName = "proto";
138 
139         public static final String[] strings = { "WPA", "RSN", "OSEN" };
140     }
141 
142     /**
143      * Recognized IEEE 802.11 authentication algorithms.
144      */
145     public static class AuthAlgorithm {
AuthAlgorithm()146         private AuthAlgorithm() { }
147 
148         /** Open System authentication (required for WPA/WPA2) */
149         public static final int OPEN = 0;
150         /** Shared Key authentication (requires static WEP keys) */
151         public static final int SHARED = 1;
152         /** LEAP/Network EAP (only used with LEAP) */
153         public static final int LEAP = 2;
154 
155         public static final String varName = "auth_alg";
156 
157         public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
158     }
159 
160     /**
161      * Recognized pairwise ciphers for WPA.
162      */
163     public static class PairwiseCipher {
PairwiseCipher()164         private PairwiseCipher() { }
165 
166         /** Use only Group keys (deprecated) */
167         public static final int NONE = 0;
168         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
169         public static final int TKIP = 1;
170         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
171         public static final int CCMP = 2;
172 
173         public static final String varName = "pairwise";
174 
175         public static final String[] strings = { "NONE", "TKIP", "CCMP" };
176     }
177 
178     /**
179      * Recognized group ciphers.
180      * <pre>
181      * CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
182      * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
183      * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
184      * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
185      * </pre>
186      */
187     public static class GroupCipher {
GroupCipher()188         private GroupCipher() { }
189 
190         /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) */
191         public static final int WEP40 = 0;
192         /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key */
193         public static final int WEP104 = 1;
194         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
195         public static final int TKIP = 2;
196         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
197         public static final int CCMP = 3;
198         /** Hotspot 2.0 r2 OSEN
199          * @hide
200          */
201         public static final int GTK_NOT_USED = 4;
202 
203         public static final String varName = "group";
204 
205         public static final String[] strings =
206                 { "WEP40", "WEP104", "TKIP", "CCMP", "GTK_NOT_USED" };
207     }
208 
209     /** Possible status of a network configuration. */
210     public static class Status {
Status()211         private Status() { }
212 
213         /** this is the network we are currently connected to */
214         public static final int CURRENT = 0;
215         /** supplicant will not attempt to use this network */
216         public static final int DISABLED = 1;
217         /** supplicant will consider this network available for association */
218         public static final int ENABLED = 2;
219 
220         public static final String[] strings = { "current", "disabled", "enabled" };
221     }
222 
223     /** @hide */
224     public static final int UNKNOWN_UID = -1;
225 
226     /**
227      * The ID number that the supplicant uses to identify this
228      * network configuration entry. This must be passed as an argument
229      * to most calls into the supplicant.
230      */
231     public int networkId;
232 
233     // Fixme We need remove this field to use only Quality network selection status only
234     /**
235      * The current status of this network configuration entry.
236      * @see Status
237      */
238     public int status;
239 
240     /**
241      * The network's SSID. Can either be an ASCII string,
242      * which must be enclosed in double quotation marks
243      * (e.g., {@code "MyNetwork"}), or a string of
244      * hex digits, which are not enclosed in quotes
245      * (e.g., {@code 01a243f405}).
246      */
247     public String SSID;
248     /**
249      * When set, this network configuration entry should only be used when
250      * associating with the AP having the specified BSSID. The value is
251      * a string in the format of an Ethernet MAC address, e.g.,
252      * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
253      */
254     public String BSSID;
255 
256     /**
257      * 2GHz band.
258      * @hide
259      */
260     public static final int AP_BAND_2GHZ = 0;
261 
262     /**
263      * 5GHz band.
264      * @hide
265      */
266     public static final int AP_BAND_5GHZ = 1;
267 
268     /**
269      * The band which AP resides on
270      * 0-2G  1-5G
271      * By default, 2G is chosen
272      * @hide
273      */
274     public int apBand = AP_BAND_2GHZ;
275 
276     /**
277      * The channel which AP resides on,currently, US only
278      * 2G  1-11
279      * 5G  36,40,44,48,149,153,157,161,165
280      * 0 - find a random available channel according to the apBand
281      * @hide
282      */
283     public int apChannel = 0;
284 
285     /**
286      * Pre-shared key for use with WPA-PSK. Either an ASCII string enclosed in
287      * double quotation marks (e.g., {@code "abcdefghij"} for PSK passphrase or
288      * a string of 64 hex digits for raw PSK.
289      * <p/>
290      * When the value of this key is read, the actual key is
291      * not returned, just a "*" if the key has a value, or the null
292      * string otherwise.
293      */
294     public String preSharedKey;
295 
296     /**
297      * Up to four WEP keys. Either an ASCII string enclosed in double
298      * quotation marks (e.g., {@code "abcdef"}) or a string
299      * of hex digits (e.g., {@code 0102030405}).
300      * <p/>
301      * When the value of one of these keys is read, the actual key is
302      * not returned, just a "*" if the key has a value, or the null
303      * string otherwise.
304      */
305     public String[] wepKeys;
306 
307     /** Default WEP key index, ranging from 0 to 3. */
308     public int wepTxKeyIndex;
309 
310     /**
311      * Priority determines the preference given to a network by {@code wpa_supplicant}
312      * when choosing an access point with which to associate.
313      * @deprecated This field does not exist anymore.
314      */
315     @Deprecated
316     public int priority;
317 
318     /**
319      * This is a network that does not broadcast its SSID, so an
320      * SSID-specific probe request must be used for scans.
321      */
322     public boolean hiddenSSID;
323 
324     /**
325      * This is a network that requries Protected Management Frames (PMF).
326      * @hide
327      */
328     public boolean requirePMF;
329 
330     /**
331      * Update identifier, for Passpoint network.
332      * @hide
333      */
334     public String updateIdentifier;
335 
336     /**
337      * The set of key management protocols supported by this configuration.
338      * See {@link KeyMgmt} for descriptions of the values.
339      * Defaults to WPA-PSK WPA-EAP.
340      */
341     public BitSet allowedKeyManagement;
342     /**
343      * The set of security protocols supported by this configuration.
344      * See {@link Protocol} for descriptions of the values.
345      * Defaults to WPA RSN.
346      */
347     public BitSet allowedProtocols;
348     /**
349      * The set of authentication protocols supported by this configuration.
350      * See {@link AuthAlgorithm} for descriptions of the values.
351      * Defaults to automatic selection.
352      */
353     public BitSet allowedAuthAlgorithms;
354     /**
355      * The set of pairwise ciphers for WPA supported by this configuration.
356      * See {@link PairwiseCipher} for descriptions of the values.
357      * Defaults to CCMP TKIP.
358      */
359     public BitSet allowedPairwiseCiphers;
360     /**
361      * The set of group ciphers supported by this configuration.
362      * See {@link GroupCipher} for descriptions of the values.
363      * Defaults to CCMP TKIP WEP104 WEP40.
364      */
365     public BitSet allowedGroupCiphers;
366     /**
367      * The enterprise configuration details specifying the EAP method,
368      * certificates and other settings associated with the EAP.
369      */
370     public WifiEnterpriseConfig enterpriseConfig;
371 
372     /**
373      * Fully qualified domain name of a Passpoint configuration
374      */
375     public String FQDN;
376 
377     /**
378      * Name of Passpoint credential provider
379      */
380     public String providerFriendlyName;
381 
382     /**
383      * Flag indicating if this network is provided by a home Passpoint provider or a roaming
384      * Passpoint provider.  This flag will be {@code true} if this network is provided by
385      * a home Passpoint provider and {@code false} if is provided by a roaming Passpoint provider
386      * or is a non-Passpoint network.
387      */
388     public boolean isHomeProviderNetwork;
389 
390     /**
391      * Roaming Consortium Id list for Passpoint credential; identifies a set of networks where
392      * Passpoint credential will be considered valid
393      */
394     public long[] roamingConsortiumIds;
395 
396     /**
397      * @hide
398      * This network configuration is visible to and usable by other users on the
399      * same device.
400      */
401     public boolean shared;
402 
403     /**
404      * @hide
405      */
406     private IpConfiguration mIpConfiguration;
407 
408     /**
409      * @hide
410      * dhcp server MAC address if known
411      */
412     public String dhcpServer;
413 
414     /**
415      * @hide
416      * default Gateway MAC address if known
417      */
418     public String defaultGwMacAddress;
419 
420     /**
421      * @hide
422      * last failure
423      */
424     public String lastFailure;
425 
426     /**
427      * @hide
428      * last time we connected, this configuration had validated internet access
429      */
430     public boolean validatedInternetAccess;
431 
432     /**
433      * @hide
434      * The number of beacon intervals between Delivery Traffic Indication Maps (DTIM)
435      * This value is populated from scan results that contain Beacon Frames, which are infrequent.
436      * The value is not guaranteed to be set or current (Although it SHOULDNT change once set)
437      * Valid values are from 1 - 255. Initialized here as 0, use this to check if set.
438      */
439     public int dtimInterval = 0;
440 
441     /**
442      * Flag indicating if this configuration represents a legacy Passpoint configuration
443      * (Release N or older).  This is used for migrating Passpoint configuration from N to O.
444      * This will no longer be needed after O.
445      * @hide
446      */
447     public boolean isLegacyPasspointConfig = false;
448     /**
449      * @hide
450      * Uid of app creating the configuration
451      */
452     @SystemApi
453     public int creatorUid;
454 
455     /**
456      * @hide
457      * Uid of last app issuing a connection related command
458      */
459     public int lastConnectUid;
460 
461     /**
462      * @hide
463      * Uid of last app modifying the configuration
464      */
465     @SystemApi
466     public int lastUpdateUid;
467 
468     /**
469      * @hide
470      * Universal name for app creating the configuration
471      *    see {#link {@link PackageManager#getNameForUid(int)}
472      */
473     @SystemApi
474     public String creatorName;
475 
476     /**
477      * @hide
478      * Universal name for app updating the configuration
479      *    see {#link {@link PackageManager#getNameForUid(int)}
480      */
481     @SystemApi
482     public String lastUpdateName;
483 
484     /**
485      * @hide
486      * Status of user approval for connection
487      */
488     public int userApproved = USER_UNSPECIFIED;
489 
490     /** The Below RSSI thresholds are used to configure AutoJoin
491      *  - GOOD/LOW/BAD thresholds are used so as to calculate link score
492      *  - UNWANTED_SOFT are used by the blacklisting logic so as to handle
493      *  the unwanted network message coming from CS
494      *  - UNBLACKLIST thresholds are used so as to tweak the speed at which
495      *  the network is unblacklisted (i.e. if
496      *          it is seen with good RSSI, it is blacklisted faster)
497      *  - INITIAL_AUTOJOIN_ATTEMPT, used to determine how close from
498      *  the network we need to be before autojoin kicks in
499      */
500     /** @hide **/
501     public static int INVALID_RSSI = -127;
502 
503     /**
504      * @hide
505      * A summary of the RSSI and Band status for that configuration
506      * This is used as a temporary value by the auto-join controller
507      */
508     public static final class Visibility {
509         public int rssi5;   // strongest 5GHz RSSI
510         public int rssi24;  // strongest 2.4GHz RSSI
511         public int num5;    // number of BSSIDs on 5GHz
512         public int num24;   // number of BSSIDs on 2.4GHz
513         public long age5;   // timestamp of the strongest 5GHz BSSID (last time it was seen)
514         public long age24;  // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
515         public String BSSID24;
516         public String BSSID5;
517         public int score; // Debug only, indicate last score used for autojoin/cell-handover
518         public int currentNetworkBoost; // Debug only, indicate boost applied to RSSI if current
519         public int bandPreferenceBoost; // Debug only, indicate boost applied to RSSI if current
520         public int lastChoiceBoost; // Debug only, indicate last choice applied to this configuration
521         public String lastChoiceConfig; // Debug only, indicate last choice applied to this configuration
522 
Visibility()523         public Visibility() {
524             rssi5 = INVALID_RSSI;
525             rssi24 = INVALID_RSSI;
526         }
527 
Visibility(Visibility source)528         public Visibility(Visibility source) {
529             rssi5 = source.rssi5;
530             rssi24 = source.rssi24;
531             age24 = source.age24;
532             age5 = source.age5;
533             num24 = source.num24;
534             num5 = source.num5;
535             BSSID5 = source.BSSID5;
536             BSSID24 = source.BSSID24;
537         }
538 
539         @Override
toString()540         public String toString() {
541             StringBuilder sbuf = new StringBuilder();
542             sbuf.append("[");
543             if (rssi24 > INVALID_RSSI) {
544                 sbuf.append(Integer.toString(rssi24));
545                 sbuf.append(",");
546                 sbuf.append(Integer.toString(num24));
547                 if (BSSID24 != null) sbuf.append(",").append(BSSID24);
548             }
549             sbuf.append("; ");
550             if (rssi5 > INVALID_RSSI) {
551                 sbuf.append(Integer.toString(rssi5));
552                 sbuf.append(",");
553                 sbuf.append(Integer.toString(num5));
554                 if (BSSID5 != null) sbuf.append(",").append(BSSID5);
555             }
556             if (score != 0) {
557                 sbuf.append("; ").append(score);
558                 sbuf.append(", ").append(currentNetworkBoost);
559                 sbuf.append(", ").append(bandPreferenceBoost);
560                 if (lastChoiceConfig != null) {
561                     sbuf.append(", ").append(lastChoiceBoost);
562                     sbuf.append(", ").append(lastChoiceConfig);
563                 }
564             }
565             sbuf.append("]");
566             return sbuf.toString();
567         }
568     }
569 
570     /** @hide
571      * Cache the visibility status of this configuration.
572      * Visibility can change at any time depending on scan results availability.
573      * Owner of the WifiConfiguration is responsible to set this field based on
574      * recent scan results.
575      ***/
576     public Visibility visibility;
577 
578     /** @hide
579      * calculate and set Visibility for that configuration.
580      *
581      * age in milliseconds: we will consider only ScanResults that are more recent,
582      * i.e. younger.
583      ***/
setVisibility(Visibility status)584     public void setVisibility(Visibility status) {
585         visibility = status;
586     }
587 
588     // States for the userApproved field
589     /**
590      * @hide
591      * User hasn't specified if connection is okay
592      */
593     public static final int USER_UNSPECIFIED = 0;
594     /**
595      * @hide
596      * User has approved this for connection
597      */
598     public static final int USER_APPROVED = 1;
599     /**
600      * @hide
601      * User has banned this from connection
602      */
603     public static final int USER_BANNED = 2;
604     /**
605      * @hide
606      * Waiting for user input
607      */
608     public static final int USER_PENDING = 3;
609 
610     /**
611      * @hide
612      * Number of reports indicating no Internet Access
613      */
614     public int numNoInternetAccessReports;
615 
616     /**
617      * @hide
618      * For debug: date at which the config was last updated
619      */
620     public String updateTime;
621 
622     /**
623      * @hide
624      * For debug: date at which the config was last updated
625      */
626     public String creationTime;
627 
628     /**
629      * @hide
630      * The WiFi configuration is considered to have no internet access for purpose of autojoining
631      * if there has been a report of it having no internet access, and, it never have had
632      * internet access in the past.
633      */
634     @SystemApi
hasNoInternetAccess()635     public boolean hasNoInternetAccess() {
636         return numNoInternetAccessReports > 0 && !validatedInternetAccess;
637     }
638 
639     /**
640      * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
641      * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
642      * this configuration and selects "don't ask again".
643      * @hide
644      */
645     public boolean noInternetAccessExpected;
646 
647     /**
648      * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
649      * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
650      * this configuration and selects "don't ask again".
651      * @hide
652      */
653     @SystemApi
isNoInternetAccessExpected()654     public boolean isNoInternetAccessExpected() {
655         return noInternetAccessExpected;
656     }
657 
658     /**
659      * @hide
660      * Last time the system was connected to this configuration.
661      */
662     public long lastConnected;
663 
664     /**
665      * @hide
666      * Last time the system tried to connect and failed.
667      */
668     public long lastConnectionFailure;
669 
670     /**
671      * @hide
672      * Last time the system tried to roam and failed because of authentication failure or DHCP
673      * RENEW failure.
674      */
675     public long lastRoamingFailure;
676 
677     /** @hide */
678     public static int ROAMING_FAILURE_IP_CONFIG = 1;
679     /** @hide */
680     public static int ROAMING_FAILURE_AUTH_FAILURE = 2;
681 
682     /**
683      * @hide
684      * Initial amount of time this Wifi configuration gets blacklisted for network switching
685      * because of roaming failure
686      */
687     public long roamingFailureBlackListTimeMilli = 1000;
688 
689     /**
690      * @hide
691      * Last roaming failure reason code
692      */
693     public int lastRoamingFailureReason;
694 
695     /**
696      * @hide
697      * Last time the system was disconnected to this configuration.
698      */
699     public long lastDisconnected;
700 
701     /**
702      * Set if the configuration was self added by the framework
703      * This boolean is cleared if we get a connect/save/ update or
704      * any wifiManager command that indicate the user interacted with the configuration
705      * since we will now consider that the configuration belong to him.
706      * @hide
707      */
708     public boolean selfAdded;
709 
710     /**
711      * Set if the configuration was self added by the framework
712      * This boolean is set once and never cleared. It is used
713      * so as we never loose track of who created the
714      * configuration in the first place.
715      * @hide
716      */
717     public boolean didSelfAdd;
718 
719     /**
720      * Peer WifiConfiguration this WifiConfiguration was added for
721      * @hide
722      */
723     public String peerWifiConfiguration;
724 
725     /**
726      * @hide
727      * Indicate that a WifiConfiguration is temporary and should not be saved
728      * nor considered by AutoJoin.
729      */
730     public boolean ephemeral;
731 
732     /**
733      * @hide
734      * Indicate that a WifiConfiguration is temporary and should not be saved
735      * nor considered by AutoJoin.
736      */
737     @SystemApi
isEphemeral()738     public boolean isEphemeral() {
739       return ephemeral;
740     }
741 
742     /**
743      * @hide
744      * A hint about whether or not the network represented by this WifiConfiguration
745      * is metered. This is hinted at via the meteredHint bit on DHCP results set in
746      * {@link com.android.server.wifi.WifiStateMachine}, or via a network score in
747      * {@link com.android.server.wifi.ExternalScoreEvaluator}.
748      */
749     @SystemApi
750     public boolean meteredHint;
751 
752     /**
753      * @hide
754      * Indicates if a user has specified the WifiConfiguration to be metered. Users
755      * can toggle if a network is metered within Settings -> Data Usage -> Network
756      * Restrictions.
757      */
758     public boolean meteredOverride;
759 
760     /**
761      * @hide
762      * Setting this value will force scan results associated with this configuration to
763      * be included in the bucket of networks that are externally scored.
764      * If not set, associated scan results will be treated as legacy saved networks and
765      * will take precedence over networks in the scored category.
766      */
767     @SystemApi
768     public boolean useExternalScores;
769 
770     /**
771      * @hide
772      * Number of time the scorer overrode a the priority based choice, when comparing two
773      * WifiConfigurations, note that since comparing WifiConfiguration happens very often
774      * potentially at every scan, this number might become very large, even on an idle
775      * system.
776      */
777     @SystemApi
778     public int numScorerOverride;
779 
780     /**
781      * @hide
782      * Number of time the scorer overrode a the priority based choice, and the comparison
783      * triggered a network switch
784      */
785     @SystemApi
786     public int numScorerOverrideAndSwitchedNetwork;
787 
788     /**
789      * @hide
790      * Number of time we associated to this configuration.
791      */
792     @SystemApi
793     public int numAssociation;
794 
795     /** @hide
796      * Boost given to RSSI on a home network for the purpose of calculating the score
797      * This adds stickiness to home networks, as defined by:
798      * - less than 4 known BSSIDs
799      * - PSK only
800      * - TODO: add a test to verify that all BSSIDs are behind same gateway
801      ***/
802     public static final int HOME_NETWORK_RSSI_BOOST = 5;
803 
804     /**
805      * @hide
806      * This class is used to contain all the information and API used for quality network selection
807      */
808     public static class NetworkSelectionStatus {
809         /**
810          * Quality Network Selection Status enable, temporary disabled, permanently disabled
811          */
812         /**
813          * This network is allowed to join Quality Network Selection
814          */
815         public static final int NETWORK_SELECTION_ENABLED = 0;
816         /**
817          * network was temporary disabled. Can be re-enabled after a time period expire
818          */
819         public static final int NETWORK_SELECTION_TEMPORARY_DISABLED  = 1;
820         /**
821          * network was permanently disabled.
822          */
823         public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED  = 2;
824         /**
825          * Maximum Network selection status
826          */
827         public static final int NETWORK_SELECTION_STATUS_MAX = 3;
828 
829         /**
830          * Quality network selection status String (for debug purpose). Use Quality network
831          * selection status value as index to extec the corresponding debug string
832          */
833         public static final String[] QUALITY_NETWORK_SELECTION_STATUS = {
834                 "NETWORK_SELECTION_ENABLED",
835                 "NETWORK_SELECTION_TEMPORARY_DISABLED",
836                 "NETWORK_SELECTION_PERMANENTLY_DISABLED"};
837 
838         //Quality Network disabled reasons
839         /**
840          * Default value. Means not disabled
841          */
842         public static final int NETWORK_SELECTION_ENABLE = 0;
843         /**
844          * The starting index for network selection disabled reasons
845          */
846         public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
847         /**
848          * @deprecated it is not used any more.
849          * This network is disabled because higher layer (>2) network is bad
850          */
851         public static final int DISABLED_BAD_LINK = 1;
852         /**
853          * This network is disabled because multiple association rejects
854          */
855         public static final int DISABLED_ASSOCIATION_REJECTION = 2;
856         /**
857          * This network is disabled because multiple authentication failure
858          */
859         public static final int DISABLED_AUTHENTICATION_FAILURE = 3;
860         /**
861          * This network is disabled because multiple DHCP failure
862          */
863         public static final int DISABLED_DHCP_FAILURE = 4;
864         /**
865          * This network is disabled because of security network but no credentials
866          */
867         public static final int DISABLED_DNS_FAILURE = 5;
868         /**
869          * This network is disabled because we started WPS
870          */
871         public static final int DISABLED_WPS_START = 6;
872         /**
873          * This network is disabled because EAP-TLS failure
874          */
875         public static final int DISABLED_TLS_VERSION_MISMATCH = 7;
876         // Values above are for temporary disablement; values below are for permanent disablement.
877         /**
878          * This network is disabled due to absence of user credentials
879          */
880         public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 8;
881         /**
882          * This network is disabled because no Internet connected and user do not want
883          */
884         public static final int DISABLED_NO_INTERNET = 9;
885         /**
886          * This network is disabled due to WifiManager disable it explicitly
887          */
888         public static final int DISABLED_BY_WIFI_MANAGER = 10;
889         /**
890          * This network is disabled due to user switching
891          */
892         public static final int DISABLED_DUE_TO_USER_SWITCH = 11;
893         /**
894          * This Maximum disable reason value
895          */
896         public static final int NETWORK_SELECTION_DISABLED_MAX = 12;
897 
898         /**
899          * Quality network selection disable reason String (for debug purpose)
900          */
901         public static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
902                 "NETWORK_SELECTION_ENABLE",
903                 "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated
904                 "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
905                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
906                 "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
907                 "NETWORK_SELECTION_DISABLED_DNS_FAILURE",
908                 "NETWORK_SELECTION_DISABLED_WPS_START",
909                 "NETWORK_SELECTION_DISABLED_TLS_VERSION",
910                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
911                 "NETWORK_SELECTION_DISABLED_NO_INTERNET",
912                 "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
913                 "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH"
914         };
915 
916         /**
917          * Invalid time stamp for network selection disable
918          */
919         public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
920 
921         /**
922          *  This constant indicates the current configuration has connect choice set
923          */
924         private static final int CONNECT_CHOICE_EXISTS = 1;
925 
926         /**
927          *  This constant indicates the current configuration does not have connect choice set
928          */
929         private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
930 
931         // fields for QualityNetwork Selection
932         /**
933          * Network selection status, should be in one of three status: enable, temporaily disabled
934          * or permanently disabled
935          */
936         private int mStatus;
937 
938         /**
939          * Reason for disable this network
940          */
941         private int mNetworkSelectionDisableReason;
942 
943         /**
944          * Last time we temporarily disabled the configuration
945          */
946         private long mTemporarilyDisabledTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
947 
948         /**
949          * counter for each Network selection disable reason
950          */
951         private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
952 
953         /**
954          * Connect Choice over this configuration
955          *
956          * When current wifi configuration is visible to the user but user explicitly choose to
957          * connect to another network X, the another networks X's configure key will be stored here.
958          * We will consider user has a preference of X over this network. And in the future,
959          * network selection will always give X a higher preference over this configuration.
960          * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
961          */
962         private String mConnectChoice;
963 
964         /**
965          * The system timestamp when we records the connectChoice. This value is obtained from
966          * System.currentTimeMillis
967          */
968         private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
969 
970         /**
971          * Used to cache the temporary candidate during the network selection procedure. It will be
972          * kept updating once a new scan result has a higher score than current one
973          */
974         private ScanResult mCandidate;
975 
976         /**
977          * Used to cache the score of the current temporary candidate during the network
978          * selection procedure.
979          */
980         private int mCandidateScore;
981 
982         /**
983          * Indicate whether this network is visible in latest Qualified Network Selection. This
984          * means there is scan result found related to this Configuration and meet the minimum
985          * requirement. The saved network need not join latest Qualified Network Selection. For
986          * example, it is disabled. True means network is visible in latest Qualified Network
987          * Selection and false means network is invisible
988          */
989         private boolean mSeenInLastQualifiedNetworkSelection;
990 
991         /**
992          * Boolean indicating if we have ever successfully connected to this network.
993          *
994          * This value will be set to true upon a successful connection.
995          * This value will be set to false if a previous value was not stored in the config or if
996          * the credentials are updated (ex. a password change).
997          */
998         private boolean mHasEverConnected;
999 
1000         /**
1001          * Boolean indicating whether {@link com.android.server.wifi.RecommendedNetworkEvaluator}
1002          * chose not to connect to this network in the last qualified network selection process.
1003          */
1004         private boolean mNotRecommended;
1005 
1006         /**
1007          * Set whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
1008          * recommend connecting to this network.
1009          */
setNotRecommended(boolean notRecommended)1010         public void setNotRecommended(boolean notRecommended) {
1011             mNotRecommended = notRecommended;
1012         }
1013 
1014         /**
1015          * Returns whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
1016          * recommend connecting to this network.
1017          */
isNotRecommended()1018         public boolean isNotRecommended() {
1019             return mNotRecommended;
1020         }
1021 
1022         /**
1023          * set whether this network is visible in latest Qualified Network Selection
1024          * @param seen value set to candidate
1025          */
setSeenInLastQualifiedNetworkSelection(boolean seen)1026         public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
1027             mSeenInLastQualifiedNetworkSelection =  seen;
1028         }
1029 
1030         /**
1031          * get whether this network is visible in latest Qualified Network Selection
1032          * @return returns true -- network is visible in latest Qualified Network Selection
1033          *         false -- network is invisible in latest Qualified Network Selection
1034          */
getSeenInLastQualifiedNetworkSelection()1035         public boolean getSeenInLastQualifiedNetworkSelection() {
1036             return mSeenInLastQualifiedNetworkSelection;
1037         }
1038         /**
1039          * set the temporary candidate of current network selection procedure
1040          * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
1041          */
setCandidate(ScanResult scanCandidate)1042         public void setCandidate(ScanResult scanCandidate) {
1043             mCandidate = scanCandidate;
1044         }
1045 
1046         /**
1047          * get the temporary candidate of current network selection procedure
1048          * @return  returns {@link ScanResult} temporary candidate of current network selection
1049          * procedure
1050          */
getCandidate()1051         public ScanResult getCandidate() {
1052             return mCandidate;
1053         }
1054 
1055         /**
1056          * set the score of the temporary candidate of current network selection procedure
1057          * @param score value set to mCandidateScore
1058          */
setCandidateScore(int score)1059         public void setCandidateScore(int score) {
1060             mCandidateScore = score;
1061         }
1062 
1063         /**
1064          * get the score of the temporary candidate of current network selection procedure
1065          * @return returns score of the temporary candidate of current network selection procedure
1066          */
getCandidateScore()1067         public int getCandidateScore() {
1068             return mCandidateScore;
1069         }
1070 
1071         /**
1072          * get user preferred choice over this configuration
1073          *@return returns configKey of user preferred choice over this configuration
1074          */
getConnectChoice()1075         public String getConnectChoice() {
1076             return mConnectChoice;
1077         }
1078 
1079         /**
1080          * set user preferred choice over this configuration
1081          * @param newConnectChoice, the configKey of user preferred choice over this configuration
1082          */
setConnectChoice(String newConnectChoice)1083         public void setConnectChoice(String newConnectChoice) {
1084             mConnectChoice = newConnectChoice;
1085         }
1086 
1087         /**
1088          * get the timeStamp when user select a choice over this configuration
1089          * @return returns when current connectChoice is set (time from System.currentTimeMillis)
1090          */
getConnectChoiceTimestamp()1091         public long getConnectChoiceTimestamp() {
1092             return mConnectChoiceTimestamp;
1093         }
1094 
1095         /**
1096          * set the timeStamp when user select a choice over this configuration
1097          * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
1098          *        be obtained from System.currentTimeMillis
1099          */
setConnectChoiceTimestamp(long timeStamp)1100         public void setConnectChoiceTimestamp(long timeStamp) {
1101             mConnectChoiceTimestamp = timeStamp;
1102         }
1103 
1104         /**
1105          * get current Quality network selection status
1106          * @return returns current Quality network selection status in String (for debug purpose)
1107          */
getNetworkStatusString()1108         public String getNetworkStatusString() {
1109             return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
1110         }
1111 
setHasEverConnected(boolean value)1112         public void setHasEverConnected(boolean value) {
1113             mHasEverConnected = value;
1114         }
1115 
getHasEverConnected()1116         public boolean getHasEverConnected() {
1117             return mHasEverConnected;
1118         }
1119 
NetworkSelectionStatus()1120         public NetworkSelectionStatus() {
1121             // previously stored configs will not have this parameter, so we default to false.
1122             mHasEverConnected = false;
1123         };
1124 
1125         /**
1126          * @param reason specific error reason
1127          * @return  corresponding network disable reason String (for debug purpose)
1128          */
getNetworkDisableReasonString(int reason)1129         public static String getNetworkDisableReasonString(int reason) {
1130             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1131                 return QUALITY_NETWORK_SELECTION_DISABLE_REASON[reason];
1132             } else {
1133                 return null;
1134             }
1135         }
1136         /**
1137          * get current network disable reason
1138          * @return current network disable reason in String (for debug purpose)
1139          */
getNetworkDisableReasonString()1140         public String getNetworkDisableReasonString() {
1141             return QUALITY_NETWORK_SELECTION_DISABLE_REASON[mNetworkSelectionDisableReason];
1142         }
1143 
1144         /**
1145          * get current network network selection status
1146          * @return return current network network selection status
1147          */
getNetworkSelectionStatus()1148         public int getNetworkSelectionStatus() {
1149             return mStatus;
1150         }
1151         /**
1152          * @return whether current network is enabled to join network selection
1153          */
isNetworkEnabled()1154         public boolean isNetworkEnabled() {
1155             return mStatus == NETWORK_SELECTION_ENABLED;
1156         }
1157 
1158         /**
1159          * @return whether current network is temporary disabled
1160          */
isNetworkTemporaryDisabled()1161         public boolean isNetworkTemporaryDisabled() {
1162             return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
1163         }
1164 
1165         /**
1166          * @return returns whether current network is permanently disabled
1167          */
isNetworkPermanentlyDisabled()1168         public boolean isNetworkPermanentlyDisabled() {
1169             return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
1170         }
1171 
1172         /**
1173          * set current networ work selection status
1174          * @param status network selection status to set
1175          */
setNetworkSelectionStatus(int status)1176         public void setNetworkSelectionStatus(int status) {
1177             if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) {
1178                 mStatus = status;
1179             }
1180         }
1181 
1182         /**
1183          * @return returns current network's disable reason
1184          */
getNetworkSelectionDisableReason()1185         public int getNetworkSelectionDisableReason() {
1186             return mNetworkSelectionDisableReason;
1187         }
1188 
1189         /**
1190          * set Network disable reason
1191          * @param  reason Network disable reason
1192          */
setNetworkSelectionDisableReason(int reason)1193         public void setNetworkSelectionDisableReason(int reason) {
1194             if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) {
1195                 mNetworkSelectionDisableReason = reason;
1196             } else {
1197                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1198             }
1199         }
1200 
1201         /**
1202          * check whether network is disabled by this reason
1203          * @param reason a specific disable reason
1204          * @return true -- network is disabled for this reason
1205          *         false -- network is not disabled for this reason
1206          */
isDisabledByReason(int reason)1207         public boolean isDisabledByReason(int reason) {
1208             return mNetworkSelectionDisableReason == reason;
1209         }
1210 
1211         /**
1212          * @param timeStamp Set when current network is disabled in millisecond since January 1,
1213          * 1970 00:00:00.0 UTC
1214          */
setDisableTime(long timeStamp)1215         public void setDisableTime(long timeStamp) {
1216             mTemporarilyDisabledTimestamp = timeStamp;
1217         }
1218 
1219         /**
1220          * @return returns when current network is disabled in millisecond since January 1,
1221          * 1970 00:00:00.0 UTC
1222          */
getDisableTime()1223         public long getDisableTime() {
1224             return mTemporarilyDisabledTimestamp;
1225         }
1226 
1227         /**
1228          * get the disable counter of a specific reason
1229          * @param  reason specific failure reason
1230          * @exception throw IllegalArgumentException for illegal input
1231          * @return counter number for specific error reason.
1232          */
getDisableReasonCounter(int reason)1233         public int getDisableReasonCounter(int reason) {
1234             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1235                 return mNetworkSeclectionDisableCounter[reason];
1236             } else {
1237                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1238             }
1239         }
1240 
1241         /**
1242          * set the counter of a specific failure reason
1243          * @param reason reason for disable error
1244          * @param value the counter value for this specific reason
1245          * @exception throw IllegalArgumentException for illegal input
1246          */
setDisableReasonCounter(int reason, int value)1247         public void setDisableReasonCounter(int reason, int value) {
1248             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1249                 mNetworkSeclectionDisableCounter[reason] = value;
1250             } else {
1251                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1252             }
1253         }
1254 
1255         /**
1256          * increment the counter of a specific failure reason
1257          * @param reason a specific failure reason
1258          * @exception throw IllegalArgumentException for illegal input
1259          */
incrementDisableReasonCounter(int reason)1260         public void incrementDisableReasonCounter(int reason) {
1261             if (reason >= NETWORK_SELECTION_ENABLE  && reason < NETWORK_SELECTION_DISABLED_MAX) {
1262                 mNetworkSeclectionDisableCounter[reason]++;
1263             } else {
1264                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1265             }
1266         }
1267 
1268         /**
1269          * clear the counter of a specific failure reason
1270          * @hide
1271          * @param reason a specific failure reason
1272          * @exception throw IllegalArgumentException for illegal input
1273          */
clearDisableReasonCounter(int reason)1274         public void clearDisableReasonCounter(int reason) {
1275             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
1276                 mNetworkSeclectionDisableCounter[reason] = NETWORK_SELECTION_ENABLE;
1277             } else {
1278                 throw new IllegalArgumentException("Illegal reason value: " + reason);
1279             }
1280         }
1281 
1282         /**
1283          * clear all the failure reason counters
1284          */
clearDisableReasonCounter()1285         public void clearDisableReasonCounter() {
1286             Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE);
1287         }
1288 
1289         /**
1290          * BSSID for connection to this network (through network selection procedure)
1291          */
1292         private String mNetworkSelectionBSSID;
1293 
1294         /**
1295          * get current network Selection BSSID
1296          * @return current network Selection BSSID
1297          */
getNetworkSelectionBSSID()1298         public String getNetworkSelectionBSSID() {
1299             return mNetworkSelectionBSSID;
1300         }
1301 
1302         /**
1303          * set network Selection BSSID
1304          * @param bssid The target BSSID for assocaition
1305          */
setNetworkSelectionBSSID(String bssid)1306         public void setNetworkSelectionBSSID(String bssid) {
1307             mNetworkSelectionBSSID = bssid;
1308         }
1309 
copy(NetworkSelectionStatus source)1310         public void copy(NetworkSelectionStatus source) {
1311             mStatus = source.mStatus;
1312             mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason;
1313             for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
1314                     index++) {
1315                 mNetworkSeclectionDisableCounter[index] =
1316                         source.mNetworkSeclectionDisableCounter[index];
1317             }
1318             mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
1319             mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
1320             setSeenInLastQualifiedNetworkSelection(source.getSeenInLastQualifiedNetworkSelection());
1321             setCandidate(source.getCandidate());
1322             setCandidateScore(source.getCandidateScore());
1323             setConnectChoice(source.getConnectChoice());
1324             setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
1325             setHasEverConnected(source.getHasEverConnected());
1326             setNotRecommended(source.isNotRecommended());
1327         }
1328 
writeToParcel(Parcel dest)1329         public void writeToParcel(Parcel dest) {
1330             dest.writeInt(getNetworkSelectionStatus());
1331             dest.writeInt(getNetworkSelectionDisableReason());
1332             for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
1333                     index++) {
1334                 dest.writeInt(getDisableReasonCounter(index));
1335             }
1336             dest.writeLong(getDisableTime());
1337             dest.writeString(getNetworkSelectionBSSID());
1338             if (getConnectChoice() != null) {
1339                 dest.writeInt(CONNECT_CHOICE_EXISTS);
1340                 dest.writeString(getConnectChoice());
1341                 dest.writeLong(getConnectChoiceTimestamp());
1342             } else {
1343                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
1344             }
1345             dest.writeInt(getHasEverConnected() ? 1 : 0);
1346             dest.writeInt(isNotRecommended() ? 1 : 0);
1347         }
1348 
readFromParcel(Parcel in)1349         public void readFromParcel(Parcel in) {
1350             setNetworkSelectionStatus(in.readInt());
1351             setNetworkSelectionDisableReason(in.readInt());
1352             for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
1353                     index++) {
1354                 setDisableReasonCounter(index, in.readInt());
1355             }
1356             setDisableTime(in.readLong());
1357             setNetworkSelectionBSSID(in.readString());
1358             if (in.readInt() == CONNECT_CHOICE_EXISTS) {
1359                 setConnectChoice(in.readString());
1360                 setConnectChoiceTimestamp(in.readLong());
1361             } else {
1362                 setConnectChoice(null);
1363                 setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
1364             }
1365             setHasEverConnected(in.readInt() != 0);
1366             setNotRecommended(in.readInt() != 0);
1367         }
1368     }
1369 
1370     /**
1371      * @hide
1372      * network selection related member
1373      */
1374     private NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
1375 
1376     /**
1377      * @hide
1378      * @return network selection status
1379      */
getNetworkSelectionStatus()1380     public NetworkSelectionStatus getNetworkSelectionStatus() {
1381         return mNetworkSelectionStatus;
1382     }
1383 
1384     /**
1385      * Set the network selection status
1386      * @hide
1387      */
setNetworkSelectionStatus(NetworkSelectionStatus status)1388     public void setNetworkSelectionStatus(NetworkSelectionStatus status) {
1389         mNetworkSelectionStatus = status;
1390     }
1391 
1392     /**
1393      * @hide
1394      * Linked Configurations: represent the set of Wificonfigurations that are equivalent
1395      * regarding roaming and auto-joining.
1396      * The linked configuration may or may not have same SSID, and may or may not have same
1397      * credentials.
1398      * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
1399      */
1400     public HashMap<String, Integer>  linkedConfigurations;
1401 
WifiConfiguration()1402     public WifiConfiguration() {
1403         networkId = INVALID_NETWORK_ID;
1404         SSID = null;
1405         BSSID = null;
1406         FQDN = null;
1407         roamingConsortiumIds = new long[0];
1408         priority = 0;
1409         hiddenSSID = false;
1410         allowedKeyManagement = new BitSet();
1411         allowedProtocols = new BitSet();
1412         allowedAuthAlgorithms = new BitSet();
1413         allowedPairwiseCiphers = new BitSet();
1414         allowedGroupCiphers = new BitSet();
1415         wepKeys = new String[4];
1416         for (int i = 0; i < wepKeys.length; i++) {
1417             wepKeys[i] = null;
1418         }
1419         enterpriseConfig = new WifiEnterpriseConfig();
1420         selfAdded = false;
1421         didSelfAdd = false;
1422         ephemeral = false;
1423         meteredHint = false;
1424         meteredOverride = false;
1425         useExternalScores = false;
1426         validatedInternetAccess = false;
1427         mIpConfiguration = new IpConfiguration();
1428         lastUpdateUid = -1;
1429         creatorUid = -1;
1430         shared = true;
1431         dtimInterval = 0;
1432     }
1433 
1434     /**
1435      * Identify if this configuration represents a Passpoint network
1436      */
isPasspoint()1437     public boolean isPasspoint() {
1438         return !TextUtils.isEmpty(FQDN)
1439                 && !TextUtils.isEmpty(providerFriendlyName)
1440                 && enterpriseConfig != null
1441                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
1442     }
1443 
1444     /**
1445      * Helper function, identify if a configuration is linked
1446      * @hide
1447      */
isLinked(WifiConfiguration config)1448     public boolean isLinked(WifiConfiguration config) {
1449         if (config != null) {
1450             if (config.linkedConfigurations != null && linkedConfigurations != null) {
1451                 if (config.linkedConfigurations.get(configKey()) != null
1452                         && linkedConfigurations.get(config.configKey()) != null) {
1453                     return true;
1454                 }
1455             }
1456         }
1457         return  false;
1458     }
1459 
1460     /**
1461      * Helper function, idenfity if a configuration should be treated as an enterprise network
1462      * @hide
1463      */
isEnterprise()1464     public boolean isEnterprise() {
1465         return (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
1466                 || allowedKeyManagement.get(KeyMgmt.IEEE8021X))
1467                 && enterpriseConfig != null
1468                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
1469     }
1470 
1471     @Override
toString()1472     public String toString() {
1473         StringBuilder sbuf = new StringBuilder();
1474         if (this.status == WifiConfiguration.Status.CURRENT) {
1475             sbuf.append("* ");
1476         } else if (this.status == WifiConfiguration.Status.DISABLED) {
1477             sbuf.append("- DSBLE ");
1478         }
1479         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
1480                 append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
1481                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
1482                 .append(" PRIO: ").append(this.priority)
1483                 .append(" HIDDEN: ").append(this.hiddenSSID)
1484                 .append('\n');
1485 
1486 
1487         sbuf.append(" NetworkSelectionStatus ")
1488                 .append(mNetworkSelectionStatus.getNetworkStatusString() + "\n");
1489         if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) {
1490             sbuf.append(" mNetworkSelectionDisableReason ")
1491                     .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n");
1492 
1493             for (int index = mNetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
1494                     index < mNetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
1495                 if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) {
1496                     sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index)
1497                             + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index)
1498                             + "\n");
1499                 }
1500             }
1501         }
1502         if (mNetworkSelectionStatus.getConnectChoice() != null) {
1503             sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
1504             sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
1505                     .getConnectChoiceTimestamp());
1506         }
1507         sbuf.append(" hasEverConnected: ")
1508                 .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n");
1509 
1510         if (this.numAssociation > 0) {
1511             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
1512         }
1513         if (this.numNoInternetAccessReports > 0) {
1514             sbuf.append(" numNoInternetAccessReports ");
1515             sbuf.append(this.numNoInternetAccessReports).append("\n");
1516         }
1517         if (this.updateTime != null) {
1518             sbuf.append("update ").append(this.updateTime).append("\n");
1519         }
1520         if (this.creationTime != null) {
1521             sbuf.append("creation").append(this.creationTime).append("\n");
1522         }
1523         if (this.didSelfAdd) sbuf.append(" didSelfAdd");
1524         if (this.selfAdded) sbuf.append(" selfAdded");
1525         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
1526         if (this.ephemeral) sbuf.append(" ephemeral");
1527         if (this.meteredHint) sbuf.append(" meteredHint");
1528         if (this.meteredOverride) sbuf.append(" meteredOverride");
1529         if (this.useExternalScores) sbuf.append(" useExternalScores");
1530         if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
1531             || this.ephemeral || this.meteredHint || this.meteredOverride
1532             || this.useExternalScores) {
1533             sbuf.append("\n");
1534         }
1535         sbuf.append(" KeyMgmt:");
1536         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
1537             if (this.allowedKeyManagement.get(k)) {
1538                 sbuf.append(" ");
1539                 if (k < KeyMgmt.strings.length) {
1540                     sbuf.append(KeyMgmt.strings[k]);
1541                 } else {
1542                     sbuf.append("??");
1543                 }
1544             }
1545         }
1546         sbuf.append(" Protocols:");
1547         for (int p = 0; p < this.allowedProtocols.size(); p++) {
1548             if (this.allowedProtocols.get(p)) {
1549                 sbuf.append(" ");
1550                 if (p < Protocol.strings.length) {
1551                     sbuf.append(Protocol.strings[p]);
1552                 } else {
1553                     sbuf.append("??");
1554                 }
1555             }
1556         }
1557         sbuf.append('\n');
1558         sbuf.append(" AuthAlgorithms:");
1559         for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) {
1560             if (this.allowedAuthAlgorithms.get(a)) {
1561                 sbuf.append(" ");
1562                 if (a < AuthAlgorithm.strings.length) {
1563                     sbuf.append(AuthAlgorithm.strings[a]);
1564                 } else {
1565                     sbuf.append("??");
1566                 }
1567             }
1568         }
1569         sbuf.append('\n');
1570         sbuf.append(" PairwiseCiphers:");
1571         for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) {
1572             if (this.allowedPairwiseCiphers.get(pc)) {
1573                 sbuf.append(" ");
1574                 if (pc < PairwiseCipher.strings.length) {
1575                     sbuf.append(PairwiseCipher.strings[pc]);
1576                 } else {
1577                     sbuf.append("??");
1578                 }
1579             }
1580         }
1581         sbuf.append('\n');
1582         sbuf.append(" GroupCiphers:");
1583         for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) {
1584             if (this.allowedGroupCiphers.get(gc)) {
1585                 sbuf.append(" ");
1586                 if (gc < GroupCipher.strings.length) {
1587                     sbuf.append(GroupCipher.strings[gc]);
1588                 } else {
1589                     sbuf.append("??");
1590                 }
1591             }
1592         }
1593         sbuf.append('\n').append(" PSK: ");
1594         if (this.preSharedKey != null) {
1595             sbuf.append('*');
1596         }
1597         sbuf.append("\nEnterprise config:\n");
1598         sbuf.append(enterpriseConfig);
1599 
1600         sbuf.append("IP config:\n");
1601         sbuf.append(mIpConfiguration.toString());
1602 
1603         if (mNetworkSelectionStatus.getNetworkSelectionBSSID() != null) {
1604             sbuf.append(" networkSelectionBSSID="
1605                     + mNetworkSelectionStatus.getNetworkSelectionBSSID());
1606         }
1607         long now_ms = System.currentTimeMillis();
1608         if (mNetworkSelectionStatus.getDisableTime() != NetworkSelectionStatus
1609                 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP) {
1610             sbuf.append('\n');
1611             long diff = now_ms - mNetworkSelectionStatus.getDisableTime();
1612             if (diff <= 0) {
1613                 sbuf.append(" blackListed since <incorrect>");
1614             } else {
1615                 sbuf.append(" blackListed: ").append(Long.toString(diff / 1000)).append("sec ");
1616             }
1617         }
1618         if (creatorUid != 0) sbuf.append(" cuid=" + creatorUid);
1619         if (creatorName != null) sbuf.append(" cname=" + creatorName);
1620         if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
1621         if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
1622         sbuf.append(" lcuid=" + lastConnectUid);
1623         sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
1624         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
1625         sbuf.append(" ");
1626 
1627         if (this.lastConnected != 0) {
1628             sbuf.append('\n');
1629             long diff = now_ms - this.lastConnected;
1630             if (diff <= 0) {
1631                 sbuf.append("lastConnected since <incorrect>");
1632             } else {
1633                 sbuf.append("lastConnected: ").append(Long.toString(diff / 1000)).append("sec ");
1634             }
1635         }
1636         if (this.lastConnectionFailure != 0) {
1637             sbuf.append('\n');
1638             long diff = now_ms - this.lastConnectionFailure;
1639             if (diff <= 0) {
1640                 sbuf.append("lastConnectionFailure since <incorrect> ");
1641             } else {
1642                 sbuf.append("lastConnectionFailure: ").append(Long.toString(diff / 1000));
1643                 sbuf.append("sec ");
1644             }
1645         }
1646         if (this.lastRoamingFailure != 0) {
1647             sbuf.append('\n');
1648             long diff = now_ms - this.lastRoamingFailure;
1649             if (diff <= 0) {
1650                 sbuf.append("lastRoamingFailure since <incorrect> ");
1651             } else {
1652                 sbuf.append("lastRoamingFailure: ").append(Long.toString(diff / 1000));
1653                 sbuf.append("sec ");
1654             }
1655         }
1656         sbuf.append("roamingFailureBlackListTimeMilli: ").
1657                 append(Long.toString(this.roamingFailureBlackListTimeMilli));
1658         sbuf.append('\n');
1659         if (this.linkedConfigurations != null) {
1660             for (String key : this.linkedConfigurations.keySet()) {
1661                 sbuf.append(" linked: ").append(key);
1662                 sbuf.append('\n');
1663             }
1664         }
1665 
1666         return sbuf.toString();
1667     }
1668 
1669     /** {@hide} */
getPrintableSsid()1670     public String getPrintableSsid() {
1671         if (SSID == null) return "";
1672         final int length = SSID.length();
1673         if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
1674             return SSID.substring(1, length - 1);
1675         }
1676 
1677         /** The ascii-encoded string format is P"<ascii-encoded-string>"
1678          * The decoding is implemented in the supplicant for a newly configured
1679          * network.
1680          */
1681         if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
1682                 (SSID.charAt(length-1) == '"')) {
1683             WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
1684                     SSID.substring(2, length - 1));
1685             return wifiSsid.toString();
1686         }
1687         return SSID;
1688     }
1689 
1690     /** @hide **/
userApprovedAsString(int userApproved)1691     public static String userApprovedAsString(int userApproved) {
1692         switch (userApproved) {
1693             case USER_APPROVED:
1694                 return "USER_APPROVED";
1695             case USER_BANNED:
1696                 return "USER_BANNED";
1697             case USER_UNSPECIFIED:
1698                 return "USER_UNSPECIFIED";
1699             default:
1700                 return "INVALID";
1701         }
1702     }
1703 
1704     /**
1705      * Get an identifier for associating credentials with this config
1706      * @param current configuration contains values for additional fields
1707      *                that are not part of this configuration. Used
1708      *                when a config with some fields is passed by an application.
1709      * @throws IllegalStateException if config is invalid for key id generation
1710      * @hide
1711      */
getKeyIdForCredentials(WifiConfiguration current)1712     public String getKeyIdForCredentials(WifiConfiguration current) {
1713         String keyMgmt = null;
1714 
1715         try {
1716             // Get current config details for fields that are not initialized
1717             if (TextUtils.isEmpty(SSID)) SSID = current.SSID;
1718             if (allowedKeyManagement.cardinality() == 0) {
1719                 allowedKeyManagement = current.allowedKeyManagement;
1720             }
1721             if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
1722                 keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
1723             }
1724             if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
1725                 keyMgmt = KeyMgmt.strings[KeyMgmt.OSEN];
1726             }
1727             if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
1728                 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
1729             }
1730 
1731             if (TextUtils.isEmpty(keyMgmt)) {
1732                 throw new IllegalStateException("Not an EAP network");
1733             }
1734 
1735             return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" +
1736                     trimStringForKeyId(enterpriseConfig.getKeyId(current != null ?
1737                             current.enterpriseConfig : null));
1738         } catch (NullPointerException e) {
1739             throw new IllegalStateException("Invalid config details");
1740         }
1741     }
1742 
trimStringForKeyId(String string)1743     private String trimStringForKeyId(String string) {
1744         // Remove quotes and spaces
1745         return string.replace("\"", "").replace(" ", "");
1746     }
1747 
readBitSet(Parcel src)1748     private static BitSet readBitSet(Parcel src) {
1749         int cardinality = src.readInt();
1750 
1751         BitSet set = new BitSet();
1752         for (int i = 0; i < cardinality; i++) {
1753             set.set(src.readInt());
1754         }
1755 
1756         return set;
1757     }
1758 
writeBitSet(Parcel dest, BitSet set)1759     private static void writeBitSet(Parcel dest, BitSet set) {
1760         int nextSetBit = -1;
1761 
1762         dest.writeInt(set.cardinality());
1763 
1764         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
1765             dest.writeInt(nextSetBit);
1766         }
1767     }
1768 
1769     /** @hide */
getAuthType()1770     public int getAuthType() {
1771         if (allowedKeyManagement.cardinality() > 1) {
1772             throw new IllegalStateException("More than one auth type set");
1773         }
1774         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
1775             return KeyMgmt.WPA_PSK;
1776         } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
1777             return KeyMgmt.WPA2_PSK;
1778         } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
1779             return KeyMgmt.WPA_EAP;
1780         } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
1781             return KeyMgmt.IEEE8021X;
1782         }
1783         return KeyMgmt.NONE;
1784     }
1785 
1786     /* @hide
1787      * Cache the config key, this seems useful as a speed up since a lot of
1788      * lookups in the config store are done and based on this key.
1789      */
1790     String mCachedConfigKey;
1791 
1792     /** @hide
1793      *  return the string used to calculate the hash in WifiConfigStore
1794      *  and uniquely identify this WifiConfiguration
1795      */
configKey(boolean allowCached)1796     public String configKey(boolean allowCached) {
1797         String key;
1798         if (allowCached && mCachedConfigKey != null) {
1799             key = mCachedConfigKey;
1800         } else if (providerFriendlyName != null) {
1801             key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
1802             if (!shared) {
1803                 key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
1804             }
1805         } else {
1806             if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
1807                 key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
1808             } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
1809                     allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
1810                 key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
1811             } else if (wepKeys[0] != null) {
1812                 key = SSID + "WEP";
1813             } else {
1814                 key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
1815             }
1816             if (!shared) {
1817                 key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
1818             }
1819             mCachedConfigKey = key;
1820         }
1821         return key;
1822     }
1823 
1824     /** @hide
1825      * get configKey, force calculating the config string
1826      */
configKey()1827     public String configKey() {
1828         return configKey(false);
1829     }
1830 
1831     /** @hide */
getIpConfiguration()1832     public IpConfiguration getIpConfiguration() {
1833         return mIpConfiguration;
1834     }
1835 
1836     /** @hide */
setIpConfiguration(IpConfiguration ipConfiguration)1837     public void setIpConfiguration(IpConfiguration ipConfiguration) {
1838         mIpConfiguration = ipConfiguration;
1839     }
1840 
1841     /** @hide */
getStaticIpConfiguration()1842     public StaticIpConfiguration getStaticIpConfiguration() {
1843         return mIpConfiguration.getStaticIpConfiguration();
1844     }
1845 
1846     /** @hide */
setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration)1847     public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
1848         mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration);
1849     }
1850 
1851     /** @hide */
getIpAssignment()1852     public IpConfiguration.IpAssignment getIpAssignment() {
1853         return mIpConfiguration.ipAssignment;
1854     }
1855 
1856     /** @hide */
setIpAssignment(IpConfiguration.IpAssignment ipAssignment)1857     public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
1858         mIpConfiguration.ipAssignment = ipAssignment;
1859     }
1860 
1861     /** @hide */
getProxySettings()1862     public IpConfiguration.ProxySettings getProxySettings() {
1863         return mIpConfiguration.proxySettings;
1864     }
1865 
1866     /** @hide */
setProxySettings(IpConfiguration.ProxySettings proxySettings)1867     public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
1868         mIpConfiguration.proxySettings = proxySettings;
1869     }
1870 
1871     /**
1872      * Returns the HTTP proxy used by this object.
1873      * @return a {@link ProxyInfo httpProxy} representing the proxy specified by this
1874      *                  WifiConfiguration, or {@code null} if no proxy is specified.
1875      */
getHttpProxy()1876     public ProxyInfo getHttpProxy() {
1877         if (mIpConfiguration.proxySettings == IpConfiguration.ProxySettings.NONE) {
1878             return null;
1879         }
1880         return new ProxyInfo(mIpConfiguration.httpProxy);
1881     }
1882 
1883     /**
1884      * Set the {@link ProxyInfo} for this WifiConfiguration.
1885      * @param httpProxy {@link ProxyInfo} representing the httpProxy to be used by this
1886      *                  WifiConfiguration. Setting this {@code null} will explicitly set no proxy,
1887      *                  removing any proxy that was previously set.
1888      * @exception throw IllegalArgumentException for invalid httpProxy
1889      */
setHttpProxy(ProxyInfo httpProxy)1890     public void setHttpProxy(ProxyInfo httpProxy) {
1891         if (httpProxy == null) {
1892             mIpConfiguration.setProxySettings(IpConfiguration.ProxySettings.NONE);
1893             mIpConfiguration.setHttpProxy(null);
1894             return;
1895         }
1896         ProxyInfo httpProxyCopy;
1897         ProxySettings proxySettingCopy;
1898         if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
1899             proxySettingCopy = IpConfiguration.ProxySettings.PAC;
1900             // Construct a new PAC URL Proxy
1901             httpProxyCopy = new ProxyInfo(httpProxy.getPacFileUrl(), httpProxy.getPort());
1902         } else {
1903             proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
1904             // Construct a new HTTP Proxy
1905             httpProxyCopy = new ProxyInfo(httpProxy.getHost(), httpProxy.getPort(),
1906                     httpProxy.getExclusionListAsString());
1907         }
1908         if (!httpProxyCopy.isValid()) {
1909             throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
1910         }
1911         mIpConfiguration.setProxySettings(proxySettingCopy);
1912         mIpConfiguration.setHttpProxy(httpProxyCopy);
1913     }
1914 
1915     /** @hide */
setProxy(ProxySettings settings, ProxyInfo proxy)1916     public void setProxy(ProxySettings settings, ProxyInfo proxy) {
1917         mIpConfiguration.proxySettings = settings;
1918         mIpConfiguration.httpProxy = proxy;
1919     }
1920 
1921     /** Implement the Parcelable interface {@hide} */
describeContents()1922     public int describeContents() {
1923         return 0;
1924     }
1925 
1926     /** @hide */
setPasspointManagementObjectTree(String passpointManagementObjectTree)1927     public void setPasspointManagementObjectTree(String passpointManagementObjectTree) {
1928         mPasspointManagementObjectTree = passpointManagementObjectTree;
1929     }
1930 
1931     /** @hide */
getMoTree()1932     public String getMoTree() {
1933         return mPasspointManagementObjectTree;
1934     }
1935 
1936     /** copy constructor {@hide} */
WifiConfiguration(WifiConfiguration source)1937     public WifiConfiguration(WifiConfiguration source) {
1938         if (source != null) {
1939             networkId = source.networkId;
1940             status = source.status;
1941             SSID = source.SSID;
1942             BSSID = source.BSSID;
1943             FQDN = source.FQDN;
1944             roamingConsortiumIds = source.roamingConsortiumIds.clone();
1945             providerFriendlyName = source.providerFriendlyName;
1946             isHomeProviderNetwork = source.isHomeProviderNetwork;
1947             preSharedKey = source.preSharedKey;
1948 
1949             mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
1950             apBand = source.apBand;
1951             apChannel = source.apChannel;
1952 
1953             wepKeys = new String[4];
1954             for (int i = 0; i < wepKeys.length; i++) {
1955                 wepKeys[i] = source.wepKeys[i];
1956             }
1957 
1958             wepTxKeyIndex = source.wepTxKeyIndex;
1959             priority = source.priority;
1960             hiddenSSID = source.hiddenSSID;
1961             allowedKeyManagement   = (BitSet) source.allowedKeyManagement.clone();
1962             allowedProtocols       = (BitSet) source.allowedProtocols.clone();
1963             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
1964             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
1965             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
1966             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
1967 
1968             defaultGwMacAddress = source.defaultGwMacAddress;
1969 
1970             mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
1971 
1972             if ((source.linkedConfigurations != null)
1973                     && (source.linkedConfigurations.size() > 0)) {
1974                 linkedConfigurations = new HashMap<String, Integer>();
1975                 linkedConfigurations.putAll(source.linkedConfigurations);
1976             }
1977             mCachedConfigKey = null; //force null configKey
1978             selfAdded = source.selfAdded;
1979             validatedInternetAccess = source.validatedInternetAccess;
1980             isLegacyPasspointConfig = source.isLegacyPasspointConfig;
1981             ephemeral = source.ephemeral;
1982             meteredHint = source.meteredHint;
1983             meteredOverride = source.meteredOverride;
1984             useExternalScores = source.useExternalScores;
1985             if (source.visibility != null) {
1986                 visibility = new Visibility(source.visibility);
1987             }
1988 
1989             lastFailure = source.lastFailure;
1990             didSelfAdd = source.didSelfAdd;
1991             lastConnectUid = source.lastConnectUid;
1992             lastUpdateUid = source.lastUpdateUid;
1993             creatorUid = source.creatorUid;
1994             creatorName = source.creatorName;
1995             lastUpdateName = source.lastUpdateName;
1996             peerWifiConfiguration = source.peerWifiConfiguration;
1997 
1998             lastConnected = source.lastConnected;
1999             lastDisconnected = source.lastDisconnected;
2000             lastConnectionFailure = source.lastConnectionFailure;
2001             lastRoamingFailure = source.lastRoamingFailure;
2002             lastRoamingFailureReason = source.lastRoamingFailureReason;
2003             roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
2004             numScorerOverride = source.numScorerOverride;
2005             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
2006             numAssociation = source.numAssociation;
2007             userApproved = source.userApproved;
2008             numNoInternetAccessReports = source.numNoInternetAccessReports;
2009             noInternetAccessExpected = source.noInternetAccessExpected;
2010             creationTime = source.creationTime;
2011             updateTime = source.updateTime;
2012             shared = source.shared;
2013         }
2014     }
2015 
2016     /** Implement the Parcelable interface {@hide} */
2017     @Override
writeToParcel(Parcel dest, int flags)2018     public void writeToParcel(Parcel dest, int flags) {
2019         dest.writeInt(networkId);
2020         dest.writeInt(status);
2021         mNetworkSelectionStatus.writeToParcel(dest);
2022         dest.writeString(SSID);
2023         dest.writeString(BSSID);
2024         dest.writeInt(apBand);
2025         dest.writeInt(apChannel);
2026         dest.writeString(FQDN);
2027         dest.writeString(providerFriendlyName);
2028         dest.writeInt(isHomeProviderNetwork ? 1 : 0);
2029         dest.writeInt(roamingConsortiumIds.length);
2030         for (long roamingConsortiumId : roamingConsortiumIds) {
2031             dest.writeLong(roamingConsortiumId);
2032         }
2033         dest.writeString(preSharedKey);
2034         for (String wepKey : wepKeys) {
2035             dest.writeString(wepKey);
2036         }
2037         dest.writeInt(wepTxKeyIndex);
2038         dest.writeInt(priority);
2039         dest.writeInt(hiddenSSID ? 1 : 0);
2040         dest.writeInt(requirePMF ? 1 : 0);
2041         dest.writeString(updateIdentifier);
2042 
2043         writeBitSet(dest, allowedKeyManagement);
2044         writeBitSet(dest, allowedProtocols);
2045         writeBitSet(dest, allowedAuthAlgorithms);
2046         writeBitSet(dest, allowedPairwiseCiphers);
2047         writeBitSet(dest, allowedGroupCiphers);
2048 
2049         dest.writeParcelable(enterpriseConfig, flags);
2050 
2051         dest.writeParcelable(mIpConfiguration, flags);
2052         dest.writeString(dhcpServer);
2053         dest.writeString(defaultGwMacAddress);
2054         dest.writeInt(selfAdded ? 1 : 0);
2055         dest.writeInt(didSelfAdd ? 1 : 0);
2056         dest.writeInt(validatedInternetAccess ? 1 : 0);
2057         dest.writeInt(isLegacyPasspointConfig ? 1 : 0);
2058         dest.writeInt(ephemeral ? 1 : 0);
2059         dest.writeInt(meteredHint ? 1 : 0);
2060         dest.writeInt(meteredOverride ? 1 : 0);
2061         dest.writeInt(useExternalScores ? 1 : 0);
2062         dest.writeInt(creatorUid);
2063         dest.writeInt(lastConnectUid);
2064         dest.writeInt(lastUpdateUid);
2065         dest.writeString(creatorName);
2066         dest.writeString(lastUpdateName);
2067         dest.writeLong(lastConnectionFailure);
2068         dest.writeLong(lastRoamingFailure);
2069         dest.writeInt(lastRoamingFailureReason);
2070         dest.writeLong(roamingFailureBlackListTimeMilli);
2071         dest.writeInt(numScorerOverride);
2072         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
2073         dest.writeInt(numAssociation);
2074         dest.writeInt(userApproved);
2075         dest.writeInt(numNoInternetAccessReports);
2076         dest.writeInt(noInternetAccessExpected ? 1 : 0);
2077         dest.writeInt(shared ? 1 : 0);
2078         dest.writeString(mPasspointManagementObjectTree);
2079     }
2080 
2081     /** Implement the Parcelable interface {@hide} */
2082     public static final Creator<WifiConfiguration> CREATOR =
2083         new Creator<WifiConfiguration>() {
2084             public WifiConfiguration createFromParcel(Parcel in) {
2085                 WifiConfiguration config = new WifiConfiguration();
2086                 config.networkId = in.readInt();
2087                 config.status = in.readInt();
2088                 config.mNetworkSelectionStatus.readFromParcel(in);
2089                 config.SSID = in.readString();
2090                 config.BSSID = in.readString();
2091                 config.apBand = in.readInt();
2092                 config.apChannel = in.readInt();
2093                 config.FQDN = in.readString();
2094                 config.providerFriendlyName = in.readString();
2095                 config.isHomeProviderNetwork = in.readInt() != 0;
2096                 int numRoamingConsortiumIds = in.readInt();
2097                 config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
2098                 for (int i = 0; i < numRoamingConsortiumIds; i++) {
2099                     config.roamingConsortiumIds[i] = in.readLong();
2100                 }
2101                 config.preSharedKey = in.readString();
2102                 for (int i = 0; i < config.wepKeys.length; i++) {
2103                     config.wepKeys[i] = in.readString();
2104                 }
2105                 config.wepTxKeyIndex = in.readInt();
2106                 config.priority = in.readInt();
2107                 config.hiddenSSID = in.readInt() != 0;
2108                 config.requirePMF = in.readInt() != 0;
2109                 config.updateIdentifier = in.readString();
2110 
2111                 config.allowedKeyManagement   = readBitSet(in);
2112                 config.allowedProtocols       = readBitSet(in);
2113                 config.allowedAuthAlgorithms  = readBitSet(in);
2114                 config.allowedPairwiseCiphers = readBitSet(in);
2115                 config.allowedGroupCiphers    = readBitSet(in);
2116 
2117                 config.enterpriseConfig = in.readParcelable(null);
2118                 config.mIpConfiguration = in.readParcelable(null);
2119                 config.dhcpServer = in.readString();
2120                 config.defaultGwMacAddress = in.readString();
2121                 config.selfAdded = in.readInt() != 0;
2122                 config.didSelfAdd = in.readInt() != 0;
2123                 config.validatedInternetAccess = in.readInt() != 0;
2124                 config.isLegacyPasspointConfig = in.readInt() != 0;
2125                 config.ephemeral = in.readInt() != 0;
2126                 config.meteredHint = in.readInt() != 0;
2127                 config.meteredOverride = in.readInt() != 0;
2128                 config.useExternalScores = in.readInt() != 0;
2129                 config.creatorUid = in.readInt();
2130                 config.lastConnectUid = in.readInt();
2131                 config.lastUpdateUid = in.readInt();
2132                 config.creatorName = in.readString();
2133                 config.lastUpdateName = in.readString();
2134                 config.lastConnectionFailure = in.readLong();
2135                 config.lastRoamingFailure = in.readLong();
2136                 config.lastRoamingFailureReason = in.readInt();
2137                 config.roamingFailureBlackListTimeMilli = in.readLong();
2138                 config.numScorerOverride = in.readInt();
2139                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
2140                 config.numAssociation = in.readInt();
2141                 config.userApproved = in.readInt();
2142                 config.numNoInternetAccessReports = in.readInt();
2143                 config.noInternetAccessExpected = in.readInt() != 0;
2144                 config.shared = in.readInt() != 0;
2145                 config.mPasspointManagementObjectTree = in.readString();
2146                 return config;
2147             }
2148 
2149             public WifiConfiguration[] newArray(int size) {
2150                 return new WifiConfiguration[size];
2151             }
2152         };
2153 
2154     /**
2155      * Serializes the object for backup
2156      * @hide
2157      */
getBytesForBackup()2158     public byte[] getBytesForBackup() throws IOException {
2159         ByteArrayOutputStream baos = new ByteArrayOutputStream();
2160         DataOutputStream out = new DataOutputStream(baos);
2161 
2162         out.writeInt(BACKUP_VERSION);
2163         BackupUtils.writeString(out, SSID);
2164         out.writeInt(apBand);
2165         out.writeInt(apChannel);
2166         BackupUtils.writeString(out, preSharedKey);
2167         out.writeInt(getAuthType());
2168         return baos.toByteArray();
2169     }
2170 
2171     /**
2172      * Deserializes a byte array into the WiFiConfiguration Object
2173      * @hide
2174      */
getWifiConfigFromBackup(DataInputStream in)2175     public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException,
2176             BackupUtils.BadVersionException {
2177         WifiConfiguration config = new WifiConfiguration();
2178         int version = in.readInt();
2179         if (version < 1 || version > BACKUP_VERSION) {
2180             throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
2181         }
2182 
2183         if (version == 1) return null; // Version 1 is a bad dataset.
2184 
2185         config.SSID = BackupUtils.readString(in);
2186         config.apBand = in.readInt();
2187         config.apChannel = in.readInt();
2188         config.preSharedKey = BackupUtils.readString(in);
2189         config.allowedKeyManagement.set(in.readInt());
2190         return config;
2191     }
2192 }
2193