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