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.SystemApi;
20import android.content.pm.PackageManager;
21import android.net.IpConfiguration;
22import android.net.IpConfiguration.ProxySettings;
23import android.net.ProxyInfo;
24import android.net.StaticIpConfiguration;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.text.TextUtils;
28import android.util.Log;
29
30import java.util.HashMap;
31import java.util.BitSet;
32import java.util.ArrayList;
33import java.util.Collections;
34import java.util.Comparator;
35import java.util.HashSet;
36
37/**
38 * A class representing a configured Wi-Fi network, including the
39 * security configuration.
40 */
41public class WifiConfiguration implements Parcelable {
42    private static final String TAG = "WifiConfiguration";
43    /** {@hide} */
44    public static final String ssidVarName = "ssid";
45    /** {@hide} */
46    public static final String bssidVarName = "bssid";
47    /** {@hide} */
48    public static final String pskVarName = "psk";
49    /** {@hide} */
50    public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" };
51    /** {@hide} */
52    public static final String wepTxKeyIdxVarName = "wep_tx_keyidx";
53    /** {@hide} */
54    public static final String priorityVarName = "priority";
55    /** {@hide} */
56    public static final String hiddenSSIDVarName = "scan_ssid";
57    /** {@hide} */
58    public static final String pmfVarName = "ieee80211w";
59    /** {@hide} */
60    public static final String updateIdentiferVarName = "update_identifier";
61    /** {@hide} */
62    public static final int INVALID_NETWORK_ID = -1;
63
64    /**
65     * Recognized key management schemes.
66     */
67    public static class KeyMgmt {
68        private KeyMgmt() { }
69
70        /** WPA is not used; plaintext or static WEP could be used. */
71        public static final int NONE = 0;
72        /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
73        public static final int WPA_PSK = 1;
74        /** WPA using EAP authentication. Generally used with an external authentication server. */
75        public static final int WPA_EAP = 2;
76        /** IEEE 802.1X using EAP authentication and (optionally) dynamically
77         * generated WEP keys. */
78        public static final int IEEE8021X = 3;
79
80        /** WPA2 pre-shared key for use with soft access point
81          * (requires {@code preSharedKey} to be specified).
82          * @hide
83          */
84        public static final int WPA2_PSK = 4;
85
86        public static final String varName = "key_mgmt";
87
88        public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X",
89                "WPA2_PSK" };
90    }
91
92    /**
93     * Recognized security protocols.
94     */
95    public static class Protocol {
96        private Protocol() { }
97
98        /** WPA/IEEE 802.11i/D3.0 */
99        public static final int WPA = 0;
100        /** WPA2/IEEE 802.11i */
101        public static final int RSN = 1;
102
103        public static final String varName = "proto";
104
105        public static final String[] strings = { "WPA", "RSN" };
106    }
107
108    /**
109     * Recognized IEEE 802.11 authentication algorithms.
110     */
111    public static class AuthAlgorithm {
112        private AuthAlgorithm() { }
113
114        /** Open System authentication (required for WPA/WPA2) */
115        public static final int OPEN = 0;
116        /** Shared Key authentication (requires static WEP keys) */
117        public static final int SHARED = 1;
118        /** LEAP/Network EAP (only used with LEAP) */
119        public static final int LEAP = 2;
120
121        public static final String varName = "auth_alg";
122
123        public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
124    }
125
126    /**
127     * Recognized pairwise ciphers for WPA.
128     */
129    public static class PairwiseCipher {
130        private PairwiseCipher() { }
131
132        /** Use only Group keys (deprecated) */
133        public static final int NONE = 0;
134        /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
135        public static final int TKIP = 1;
136        /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
137        public static final int CCMP = 2;
138
139        public static final String varName = "pairwise";
140
141        public static final String[] strings = { "NONE", "TKIP", "CCMP" };
142    }
143
144    /**
145     * Recognized group ciphers.
146     * <pre>
147     * CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
148     * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
149     * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
150     * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
151     * </pre>
152     */
153    public static class GroupCipher {
154        private GroupCipher() { }
155
156        /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) */
157        public static final int WEP40 = 0;
158        /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key */
159        public static final int WEP104 = 1;
160        /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
161        public static final int TKIP = 2;
162        /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
163        public static final int CCMP = 3;
164
165        public static final String varName = "group";
166
167        public static final String[] strings = { "WEP40", "WEP104", "TKIP", "CCMP" };
168    }
169
170    /** Possible status of a network configuration. */
171    public static class Status {
172        private Status() { }
173
174        /** this is the network we are currently connected to */
175        public static final int CURRENT = 0;
176        /** supplicant will not attempt to use this network */
177        public static final int DISABLED = 1;
178        /** supplicant will consider this network available for association */
179        public static final int ENABLED = 2;
180
181        public static final String[] strings = { "current", "disabled", "enabled" };
182    }
183
184    /** @hide */
185    public static final int DISABLED_UNKNOWN_REASON                         = 0;
186    /** @hide */
187    public static final int DISABLED_DNS_FAILURE                            = 1;
188    /** @hide */
189    public static final int DISABLED_DHCP_FAILURE                           = 2;
190    /** @hide */
191    public static final int DISABLED_AUTH_FAILURE                           = 3;
192    /** @hide */
193    public static final int DISABLED_ASSOCIATION_REJECT                     = 4;
194    /** @hide */
195    public static final int DISABLED_BY_WIFI_MANAGER                        = 5;
196
197    /** @hide */
198    public static final int UNKNOWN_UID = -1;
199
200    /**
201     * The ID number that the supplicant uses to identify this
202     * network configuration entry. This must be passed as an argument
203     * to most calls into the supplicant.
204     */
205    public int networkId;
206
207    /**
208     * The current status of this network configuration entry.
209     * @see Status
210     */
211    public int status;
212
213    /**
214     * The configuration needs to be written to networkHistory.txt
215     * @hide
216     */
217    public boolean dirty;
218
219    /**
220     * The code referring to a reason for disabling the network
221     * Valid when {@link #status} == Status.DISABLED
222     * @hide
223     */
224    public int disableReason;
225
226    /**
227     * The network's SSID. Can either be an ASCII string,
228     * which must be enclosed in double quotation marks
229     * (e.g., {@code "MyNetwork"}, or a string of
230     * hex digits,which are not enclosed in quotes
231     * (e.g., {@code 01a243f405}).
232     */
233    public String SSID;
234    /**
235     * When set, this network configuration entry should only be used when
236     * associating with the AP having the specified BSSID. The value is
237     * a string in the format of an Ethernet MAC address, e.g.,
238     * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
239     */
240    public String BSSID;
241
242    /**
243     * The band which AP resides on
244     * 0-2G  1-5G
245     * By default, 2G is chosen
246     * @hide
247     */
248    public int apBand = 0;
249
250    /**
251     * The channel which AP resides on,currently, US only
252     * 2G  1-11
253     * 5G  36,40,44,48,149,153,157,161,165
254     * 0 - find a random available channel according to the apBand
255     * @hide
256     */
257    public int apChannel = 0;
258
259    /**
260     * Pre-shared key for use with WPA-PSK.
261     * <p/>
262     * When the value of this key is read, the actual key is
263     * not returned, just a "*" if the key has a value, or the null
264     * string otherwise.
265     */
266    public String preSharedKey;
267    /**
268     * Up to four WEP keys. Either an ASCII string enclosed in double
269     * quotation marks (e.g., {@code "abcdef"} or a string
270     * of hex digits (e.g., {@code 0102030405}).
271     * <p/>
272     * When the value of one of these keys is read, the actual key is
273     * not returned, just a "*" if the key has a value, or the null
274     * string otherwise.
275     */
276    public String[] wepKeys;
277
278    /** Default WEP key index, ranging from 0 to 3. */
279    public int wepTxKeyIndex;
280
281    /**
282     * Priority determines the preference given to a network by {@code wpa_supplicant}
283     * when choosing an access point with which to associate.
284     */
285    public int priority;
286
287    /**
288     * This is a network that does not broadcast its SSID, so an
289     * SSID-specific probe request must be used for scans.
290     */
291    public boolean hiddenSSID;
292
293    /**
294     * This is a network that requries Protected Management Frames (PMF).
295     * @hide
296     */
297    public boolean requirePMF;
298
299    /**
300     * Update identifier, for Passpoint network.
301     * @hide
302     */
303    public String updateIdentifier;
304
305    /**
306     * The set of key management protocols supported by this configuration.
307     * See {@link KeyMgmt} for descriptions of the values.
308     * Defaults to WPA-PSK WPA-EAP.
309     */
310    public BitSet allowedKeyManagement;
311    /**
312     * The set of security protocols supported by this configuration.
313     * See {@link Protocol} for descriptions of the values.
314     * Defaults to WPA RSN.
315     */
316    public BitSet allowedProtocols;
317    /**
318     * The set of authentication protocols supported by this configuration.
319     * See {@link AuthAlgorithm} for descriptions of the values.
320     * Defaults to automatic selection.
321     */
322    public BitSet allowedAuthAlgorithms;
323    /**
324     * The set of pairwise ciphers for WPA supported by this configuration.
325     * See {@link PairwiseCipher} for descriptions of the values.
326     * Defaults to CCMP TKIP.
327     */
328    public BitSet allowedPairwiseCiphers;
329    /**
330     * The set of group ciphers supported by this configuration.
331     * See {@link GroupCipher} for descriptions of the values.
332     * Defaults to CCMP TKIP WEP104 WEP40.
333     */
334    public BitSet allowedGroupCiphers;
335    /**
336     * The enterprise configuration details specifying the EAP method,
337     * certificates and other settings associated with the EAP.
338     */
339    public WifiEnterpriseConfig enterpriseConfig;
340
341    /**
342     * Fully qualified domain name of a passpoint configuration
343     */
344    public String FQDN;
345
346    /**
347     * Name of passpoint credential provider
348     */
349    public String providerFriendlyName;
350
351    /**
352     * Roaming Consortium Id list for passpoint credential; identifies a set of networks where
353     * passpoint credential will be considered valid
354     */
355    public long[] roamingConsortiumIds;
356
357    /**
358     * @hide
359     */
360    private IpConfiguration mIpConfiguration;
361
362    /**
363     * @hide
364     * dhcp server MAC address if known
365     */
366    public String dhcpServer;
367
368    /**
369     * @hide
370     * default Gateway MAC address if known
371     */
372    public String defaultGwMacAddress;
373
374    /**
375     * @hide
376     * last failure
377     */
378    public String lastFailure;
379
380    /**
381     * @hide
382     * last time we connected, this configuration had validated internet access
383     */
384    public boolean validatedInternetAccess;
385
386    /**
387     * @hide
388     * Uid of app creating the configuration
389     */
390    @SystemApi
391    public int creatorUid;
392
393    /**
394     * @hide
395     * Uid of last app issuing a connection related command
396     */
397    public int lastConnectUid;
398
399    /**
400     * @hide
401     * Uid of last app modifying the configuration
402     */
403    @SystemApi
404    public int lastUpdateUid;
405
406    /**
407     * @hide
408     * Universal name for app creating the configuration
409     *    see {#link {@link PackageManager#getNameForUid(int)}
410     */
411    @SystemApi
412    public String creatorName;
413
414    /**
415     * @hide
416     * Universal name for app updating the configuration
417     *    see {#link {@link PackageManager#getNameForUid(int)}
418     */
419    @SystemApi
420    public String lastUpdateName;
421
422    /**
423     * @hide
424     * Uid used by autoJoin
425     */
426    public String autoJoinBSSID;
427
428    /**
429     * @hide
430     * Status of user approval for connection
431     */
432    public int userApproved = USER_UNSPECIFIED;
433
434    /** The Below RSSI thresholds are used to configure AutoJoin
435     *  - GOOD/LOW/BAD thresholds are used so as to calculate link score
436     *  - UNWANTED_SOFT are used by the blacklisting logic so as to handle
437     *  the unwanted network message coming from CS
438     *  - UNBLACKLIST thresholds are used so as to tweak the speed at which
439     *  the network is unblacklisted (i.e. if
440     *          it is seen with good RSSI, it is blacklisted faster)
441     *  - INITIAL_AUTOJOIN_ATTEMPT, used to determine how close from
442     *  the network we need to be before autojoin kicks in
443     */
444    /** @hide **/
445    public static int INVALID_RSSI = -127;
446
447    /** @hide **/
448    public static int UNWANTED_BLACKLIST_SOFT_RSSI_24 = -80;
449
450    /** @hide **/
451    public static int UNWANTED_BLACKLIST_SOFT_RSSI_5 = -70;
452
453    /** @hide **/
454    public static int GOOD_RSSI_24 = -65;
455
456    /** @hide **/
457    public static int LOW_RSSI_24 = -77;
458
459    /** @hide **/
460    public static int BAD_RSSI_24 = -87;
461
462    /** @hide **/
463    public static int GOOD_RSSI_5 = -60;
464
465    /** @hide **/
466    public static int LOW_RSSI_5 = -72;
467
468    /** @hide **/
469    public static int BAD_RSSI_5 = -82;
470
471    /** @hide **/
472    public static int UNWANTED_BLACKLIST_SOFT_BUMP = 4;
473
474    /** @hide **/
475    public static int UNWANTED_BLACKLIST_HARD_BUMP = 8;
476
477    /** @hide **/
478    public static int UNBLACKLIST_THRESHOLD_24_SOFT = -77;
479
480    /** @hide **/
481    public static int UNBLACKLIST_THRESHOLD_24_HARD = -68;
482
483    /** @hide **/
484    public static int UNBLACKLIST_THRESHOLD_5_SOFT = -63;
485
486    /** @hide **/
487    public static int UNBLACKLIST_THRESHOLD_5_HARD = -56;
488
489    /** @hide **/
490    public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_24 = -80;
491
492    /** @hide **/
493    public static int INITIAL_AUTO_JOIN_ATTEMPT_MIN_5 = -70;
494
495    /** @hide
496     * 5GHz band is prefered low over 2.4 if the 5GHz RSSI is higher than this threshold */
497    public static int A_BAND_PREFERENCE_RSSI_THRESHOLD = -65;
498
499    /** @hide
500     * 5GHz band is penalized if the 5GHz RSSI is lower than this threshold **/
501    public static int G_BAND_PREFERENCE_RSSI_THRESHOLD = -75;
502
503    /** @hide
504     * Boost given to RSSI on a home network for the purpose of calculating the score
505     * This adds stickiness to home networks, as defined by:
506     * - less than 4 known BSSIDs
507     * - PSK only
508     * - TODO: add a test to verify that all BSSIDs are behind same gateway
509     ***/
510    public static int HOME_NETWORK_RSSI_BOOST = 5;
511
512    /** @hide
513     * RSSI boost for configuration which use autoJoinUseAggressiveJoinAttemptThreshold
514     * To be more aggressive when initially attempting to auto join
515     */
516    public static int MAX_INITIAL_AUTO_JOIN_RSSI_BOOST = 8;
517
518    /**
519     * @hide
520     * A summary of the RSSI and Band status for that configuration
521     * This is used as a temporary value by the auto-join controller
522     */
523    public static final class Visibility {
524        public int rssi5;   // strongest 5GHz RSSI
525        public int rssi24;  // strongest 2.4GHz RSSI
526        public int num5;    // number of BSSIDs on 5GHz
527        public int num24;   // number of BSSIDs on 2.4GHz
528        public long age5;   // timestamp of the strongest 5GHz BSSID (last time it was seen)
529        public long age24;  // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
530        public String BSSID24;
531        public String BSSID5;
532        public int score; // Debug only, indicate last score used for autojoin/cell-handover
533        public int currentNetworkBoost; // Debug only, indicate boost applied to RSSI if current
534        public int bandPreferenceBoost; // Debug only, indicate boost applied to RSSI if current
535        public int lastChoiceBoost; // Debug only, indicate last choice applied to this configuration
536        public String lastChoiceConfig; // Debug only, indicate last choice applied to this configuration
537
538        public Visibility() {
539            rssi5 = INVALID_RSSI;
540            rssi24 = INVALID_RSSI;
541        }
542
543        public Visibility(Visibility source) {
544            rssi5 = source.rssi5;
545            rssi24 = source.rssi24;
546            age24 = source.age24;
547            age5 = source.age5;
548            num24 = source.num24;
549            num5 = source.num5;
550            BSSID5 = source.BSSID5;
551            BSSID24 = source.BSSID24;
552        }
553
554        @Override
555        public String toString() {
556            StringBuilder sbuf = new StringBuilder();
557            sbuf.append("[");
558            if (rssi24 > INVALID_RSSI) {
559                sbuf.append(Integer.toString(rssi24));
560                sbuf.append(",");
561                sbuf.append(Integer.toString(num24));
562                if (BSSID24 != null) sbuf.append(",").append(BSSID24);
563            }
564            sbuf.append("; ");
565            if (rssi5 > INVALID_RSSI) {
566                sbuf.append(Integer.toString(rssi5));
567                sbuf.append(",");
568                sbuf.append(Integer.toString(num5));
569                if (BSSID5 != null) sbuf.append(",").append(BSSID5);
570            }
571            if (score != 0) {
572                sbuf.append("; ").append(score);
573                sbuf.append(", ").append(currentNetworkBoost);
574                sbuf.append(", ").append(bandPreferenceBoost);
575                if (lastChoiceConfig != null) {
576                    sbuf.append(", ").append(lastChoiceBoost);
577                    sbuf.append(", ").append(lastChoiceConfig);
578                }
579            }
580            sbuf.append("]");
581            return sbuf.toString();
582        }
583    }
584
585    /** @hide
586     * Cache the visibility status of this configuration.
587     * Visibility can change at any time depending on scan results availability.
588     * Owner of the WifiConfiguration is responsible to set this field based on
589     * recent scan results.
590     ***/
591    public Visibility visibility;
592
593    /** @hide
594     * calculate and set Visibility for that configuration.
595     *
596     * age in milliseconds: we will consider only ScanResults that are more recent,
597     * i.e. younger.
598     ***/
599    public void setVisibility(Visibility status) {
600        visibility = status;
601    }
602
603    /** @hide */
604    public static final int AUTO_JOIN_ENABLED                   = 0;
605    /**
606     * if this is set, the WifiConfiguration cannot use linkages so as to bump
607     * it's relative priority.
608     * - status between and 128 indicate various level of blacklisting depending
609     * on the severity or frequency of the connection error
610     * - deleted status indicates that the user is deleting the configuration, and so
611     * although it may have been self added we will not re-self-add it, ignore it,
612     * not return it to applications, and not connect to it
613     * */
614
615    /** @hide
616     * network was temporary disabled due to bad connection, most likely due
617     * to weak RSSI */
618    public static final int AUTO_JOIN_TEMPORARY_DISABLED  = 1;
619    /** @hide
620     * network was temporary disabled due to bad connection, which cant be attributed
621     * to weak RSSI */
622    public static final int AUTO_JOIN_TEMPORARY_DISABLED_LINK_ERRORS  = 32;
623    /** @hide */
624    public static final int AUTO_JOIN_TEMPORARY_DISABLED_AT_SUPPLICANT  = 64;
625    /** @hide */
626    public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE  = 128;
627    /** @hide */
628    public static final int AUTO_JOIN_DISABLED_NO_CREDENTIALS = 160;
629    /** @hide */
630    public static final int AUTO_JOIN_DISABLED_USER_ACTION = 161;
631
632    /** @hide */
633    public static final int AUTO_JOIN_DELETED  = 200;
634
635    // States for the userApproved field
636    /**
637     * @hide
638     * User hasn't specified if connection is okay
639     */
640    public static final int USER_UNSPECIFIED = 0;
641    /**
642     * @hide
643     * User has approved this for connection
644     */
645    public static final int USER_APPROVED = 1;
646    /**
647     * @hide
648     * User has banned this from connection
649     */
650    public static final int USER_BANNED = 2;
651    /**
652     * @hide
653     * Waiting for user input
654     */
655    public static final int USER_PENDING = 3;
656
657    /**
658     * @hide
659     */
660    public int autoJoinStatus;
661
662    /**
663     * @hide
664     * Number of connection failures
665     */
666    public int numConnectionFailures;
667
668    /**
669     * @hide
670     * Number of IP config failures
671     */
672    public int numIpConfigFailures;
673
674    /**
675     * @hide
676     * Number of Auth failures
677     */
678    public int numAuthFailures;
679
680    /**
681     * @hide
682     * Number of reports indicating no Internet Access
683     */
684    public int numNoInternetAccessReports;
685
686    /**
687     * @hide
688     * For debug: date at which the config was last updated
689     */
690    public String updateTime;
691
692    /**
693     * @hide
694     * For debug: date at which the config was last updated
695     */
696    public String creationTime;
697
698    /**
699     * @hide
700     * The WiFi configuration is considered to have no internet access for purpose of autojoining
701     * if there has been a report of it having no internet access, and, it never have had
702     * internet access in the past.
703     */
704    public boolean hasNoInternetAccess() {
705        return numNoInternetAccessReports > 0 && !validatedInternetAccess;
706    }
707
708    /**
709     * The WiFi configuration is expected not to have Internet access (e.g., a wireless printer, a
710     * Chromecast hotspot, etc.). This will be set if the user explicitly confirms a connection to
711     * this configuration and selects "don't ask again".
712     * @hide
713     */
714    public boolean noInternetAccessExpected;
715
716    /**
717     * @hide
718     * Last time we blacklisted the configuration
719     */
720    public long blackListTimestamp;
721
722    /**
723     * @hide
724     * Last time the system was connected to this configuration.
725     */
726    public long lastConnected;
727
728    /**
729     * @hide
730     * Last time the system tried to connect and failed.
731     */
732    public long lastConnectionFailure;
733
734    /**
735     * @hide
736     * Last time the system tried to roam and failed because of authentication failure or DHCP
737     * RENEW failure.
738     */
739    public long lastRoamingFailure;
740
741    /** @hide */
742    public static int ROAMING_FAILURE_IP_CONFIG = 1;
743    /** @hide */
744    public static int ROAMING_FAILURE_AUTH_FAILURE = 2;
745
746    /**
747     * @hide
748     * Initial amount of time this Wifi configuration gets blacklisted for network switching
749     * because of roaming failure
750     */
751    public long roamingFailureBlackListTimeMilli = 1000;
752
753    /**
754     * @hide
755     * Last roaming failure reason code
756     */
757    public int lastRoamingFailureReason;
758
759    /**
760     * @hide
761     * Last time the system was disconnected to this configuration.
762     */
763    public long lastDisconnected;
764
765    /**
766     * Set if the configuration was self added by the framework
767     * This boolean is cleared if we get a connect/save/ update or
768     * any wifiManager command that indicate the user interacted with the configuration
769     * since we will now consider that the configuration belong to him.
770     * @hide
771     */
772    public boolean selfAdded;
773
774    /**
775     * Set if the configuration was self added by the framework
776     * This boolean is set once and never cleared. It is used
777     * so as we never loose track of who created the
778     * configuration in the first place.
779     * @hide
780     */
781    public boolean didSelfAdd;
782
783    /**
784     * Peer WifiConfiguration this WifiConfiguration was added for
785     * @hide
786     */
787    public String peerWifiConfiguration;
788
789    /**
790     * @hide
791     * Indicate that a WifiConfiguration is temporary and should not be saved
792     * nor considered by AutoJoin.
793     */
794    public boolean ephemeral;
795
796    /**
797     * @hide
798     * Indicate that we didn't auto-join because rssi was too low
799     */
800    public boolean autoJoinBailedDueToLowRssi;
801
802    /**
803     * @hide
804     * AutoJoin even though RSSI is 10dB below threshold
805     */
806    public int autoJoinUseAggressiveJoinAttemptThreshold;
807
808    /**
809     * @hide
810     * Number of time the scorer overrode a the priority based choice, when comparing two
811     * WifiConfigurations, note that since comparing WifiConfiguration happens very often
812     * potentially at every scan, this number might become very large, even on an idle
813     * system.
814     */
815    @SystemApi
816    public int numScorerOverride;
817
818    /**
819     * @hide
820     * Number of time the scorer overrode a the priority based choice, and the comparison
821     * triggered a network switch
822     */
823    @SystemApi
824    public int numScorerOverrideAndSwitchedNetwork;
825
826    /**
827     * @hide
828     * Number of time we associated to this configuration.
829     */
830    @SystemApi
831    public int numAssociation;
832
833    /**
834     * @hide
835     * Number of time user disabled WiFi while associated to this configuration with Low RSSI.
836     */
837    public int numUserTriggeredWifiDisableLowRSSI;
838
839    /**
840     * @hide
841     * Number of time user disabled WiFi while associated to this configuration with Bad RSSI.
842     */
843    public int numUserTriggeredWifiDisableBadRSSI;
844
845    /**
846     * @hide
847     * Number of time user disabled WiFi while associated to this configuration
848     * and RSSI was not HIGH.
849     */
850    public int numUserTriggeredWifiDisableNotHighRSSI;
851
852    /**
853     * @hide
854     * Number of ticks associated to this configuration with Low RSSI.
855     */
856    public int numTicksAtLowRSSI;
857
858    /**
859     * @hide
860     * Number of ticks associated to this configuration with Bad RSSI.
861     */
862    public int numTicksAtBadRSSI;
863
864    /**
865     * @hide
866     * Number of ticks associated to this configuration
867     * and RSSI was not HIGH.
868     */
869    public int numTicksAtNotHighRSSI;
870    /**
871     * @hide
872     * Number of time user (WifiManager) triggered association to this configuration.
873     * TODO: count this only for Wifi Settings uuid, so as to not count 3rd party apps
874     */
875    public int numUserTriggeredJoinAttempts;
876
877    /**
878     * @hide
879     * Connect choices
880     *
881     * remember the keys identifying the known WifiConfiguration over which this configuration
882     * was preferred by user or a "WiFi Network Management app", that is,
883     * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
884     * was visible to the user:
885     * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
886     *
887     * The integer represents the configuration's RSSI at that time (useful?)
888     *
889     * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
890     * the exact algorithm still fluctuating as of 5/7/2014
891     *
892     */
893    public HashMap<String, Integer> connectChoices;
894
895    /**
896     * @hide
897     * Linked Configurations: represent the set of Wificonfigurations that are equivalent
898     * regarding roaming and auto-joining.
899     * The linked configuration may or may not have same SSID, and may or may not have same
900     * credentials.
901     * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
902     */
903    public HashMap<String, Integer>  linkedConfigurations;
904
905    public WifiConfiguration() {
906        networkId = INVALID_NETWORK_ID;
907        SSID = null;
908        BSSID = null;
909        FQDN = null;
910        roamingConsortiumIds = new long[0];
911        priority = 0;
912        hiddenSSID = false;
913        disableReason = DISABLED_UNKNOWN_REASON;
914        allowedKeyManagement = new BitSet();
915        allowedProtocols = new BitSet();
916        allowedAuthAlgorithms = new BitSet();
917        allowedPairwiseCiphers = new BitSet();
918        allowedGroupCiphers = new BitSet();
919        wepKeys = new String[4];
920        for (int i = 0; i < wepKeys.length; i++) {
921            wepKeys[i] = null;
922        }
923        enterpriseConfig = new WifiEnterpriseConfig();
924        autoJoinStatus = AUTO_JOIN_ENABLED;
925        selfAdded = false;
926        didSelfAdd = false;
927        ephemeral = false;
928        validatedInternetAccess = false;
929        mIpConfiguration = new IpConfiguration();
930        lastUpdateUid = -1;
931        creatorUid = -1;
932    }
933
934    /**
935     * Identify if this configuration represents a passpoint network
936     */
937    public boolean isPasspoint() {
938        return !TextUtils.isEmpty(FQDN)
939                && !TextUtils.isEmpty(providerFriendlyName)
940                && enterpriseConfig != null
941                && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
942    }
943
944    /**
945     * Helper function, identify if a configuration is linked
946     * @hide
947     */
948    public boolean isLinked(WifiConfiguration config) {
949        if (config.linkedConfigurations != null && linkedConfigurations != null) {
950            if (config.linkedConfigurations.get(configKey()) != null
951                    && linkedConfigurations.get(config.configKey()) != null) {
952                return true;
953            }
954        }
955        return  false;
956    }
957
958    /**
959     * Helper function, idenfity if a configuration should be treated as an enterprise network
960     * @hide
961     */
962    public boolean isEnterprise() {
963        return allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
964            allowedKeyManagement.get(KeyMgmt.IEEE8021X);
965    }
966
967    /** @hide **/
968    public void setAutoJoinStatus(int status) {
969        if (status < 0) status = 0;
970        if (status == 0) {
971            blackListTimestamp = 0;
972        }  else if (status > autoJoinStatus) {
973            blackListTimestamp = System.currentTimeMillis();
974        }
975        if (status != autoJoinStatus) {
976            autoJoinStatus = status;
977            dirty = true;
978        }
979    }
980
981    @Override
982    public String toString() {
983        StringBuilder sbuf = new StringBuilder();
984        if (this.status == WifiConfiguration.Status.CURRENT) {
985            sbuf.append("* ");
986        } else if (this.status == WifiConfiguration.Status.DISABLED) {
987            sbuf.append("- DSBLE ");
988        }
989        sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
990                append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
991                append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN).
992                append(" PRIO: ").append(this.priority).
993                append('\n');
994        if (this.numConnectionFailures > 0) {
995            sbuf.append(" numConnectFailures ").append(this.numConnectionFailures).append("\n");
996        }
997        if (this.numIpConfigFailures > 0) {
998            sbuf.append(" numIpConfigFailures ").append(this.numIpConfigFailures).append("\n");
999        }
1000        if (this.numAuthFailures > 0) {
1001            sbuf.append(" numAuthFailures ").append(this.numAuthFailures).append("\n");
1002        }
1003        if (this.autoJoinStatus > 0) {
1004            sbuf.append(" autoJoinStatus ").append(this.autoJoinStatus).append("\n");
1005        }
1006        if (this.disableReason > 0) {
1007            sbuf.append(" disableReason ").append(this.disableReason).append("\n");
1008        }
1009        if (this.numAssociation > 0) {
1010            sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
1011        }
1012        if (this.numNoInternetAccessReports > 0) {
1013            sbuf.append(" numNoInternetAccessReports ");
1014            sbuf.append(this.numNoInternetAccessReports).append("\n");
1015        }
1016        if (this.updateTime != null) {
1017            sbuf.append("update ").append(this.updateTime).append("\n");
1018        }
1019        if (this.creationTime != null) {
1020            sbuf.append("creation").append(this.creationTime).append("\n");
1021        }
1022        if (this.didSelfAdd) sbuf.append(" didSelfAdd");
1023        if (this.selfAdded) sbuf.append(" selfAdded");
1024        if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
1025        if (this.ephemeral) sbuf.append(" ephemeral");
1026        if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess || this.ephemeral) {
1027            sbuf.append("\n");
1028        }
1029        sbuf.append(" KeyMgmt:");
1030        for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
1031            if (this.allowedKeyManagement.get(k)) {
1032                sbuf.append(" ");
1033                if (k < KeyMgmt.strings.length) {
1034                    sbuf.append(KeyMgmt.strings[k]);
1035                } else {
1036                    sbuf.append("??");
1037                }
1038            }
1039        }
1040        sbuf.append(" Protocols:");
1041        for (int p = 0; p < this.allowedProtocols.size(); p++) {
1042            if (this.allowedProtocols.get(p)) {
1043                sbuf.append(" ");
1044                if (p < Protocol.strings.length) {
1045                    sbuf.append(Protocol.strings[p]);
1046                } else {
1047                    sbuf.append("??");
1048                }
1049            }
1050        }
1051        sbuf.append('\n');
1052        sbuf.append(" AuthAlgorithms:");
1053        for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) {
1054            if (this.allowedAuthAlgorithms.get(a)) {
1055                sbuf.append(" ");
1056                if (a < AuthAlgorithm.strings.length) {
1057                    sbuf.append(AuthAlgorithm.strings[a]);
1058                } else {
1059                    sbuf.append("??");
1060                }
1061            }
1062        }
1063        sbuf.append('\n');
1064        sbuf.append(" PairwiseCiphers:");
1065        for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) {
1066            if (this.allowedPairwiseCiphers.get(pc)) {
1067                sbuf.append(" ");
1068                if (pc < PairwiseCipher.strings.length) {
1069                    sbuf.append(PairwiseCipher.strings[pc]);
1070                } else {
1071                    sbuf.append("??");
1072                }
1073            }
1074        }
1075        sbuf.append('\n');
1076        sbuf.append(" GroupCiphers:");
1077        for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) {
1078            if (this.allowedGroupCiphers.get(gc)) {
1079                sbuf.append(" ");
1080                if (gc < GroupCipher.strings.length) {
1081                    sbuf.append(GroupCipher.strings[gc]);
1082                } else {
1083                    sbuf.append("??");
1084                }
1085            }
1086        }
1087        sbuf.append('\n').append(" PSK: ");
1088        if (this.preSharedKey != null) {
1089            sbuf.append('*');
1090        }
1091        sbuf.append("\nEnterprise config:\n");
1092        sbuf.append(enterpriseConfig);
1093
1094        sbuf.append("IP config:\n");
1095        sbuf.append(mIpConfiguration.toString());
1096
1097        if (this.autoJoinBSSID != null) sbuf.append(" autoJoinBSSID=" + autoJoinBSSID);
1098        long now_ms = System.currentTimeMillis();
1099        if (this.blackListTimestamp != 0) {
1100            sbuf.append('\n');
1101            long diff = now_ms - this.blackListTimestamp;
1102            if (diff <= 0) {
1103                sbuf.append(" blackListed since <incorrect>");
1104            } else {
1105                sbuf.append(" blackListed: ").append(Long.toString(diff/1000)).append( "sec ");
1106            }
1107        }
1108        if (creatorUid != 0)  sbuf.append(" cuid=" + Integer.toString(creatorUid));
1109        if (creatorName != null) sbuf.append(" cname=" + creatorName);
1110        if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
1111        if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
1112        sbuf.append(" lcuid=" + lastConnectUid);
1113        sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
1114        sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
1115        sbuf.append(" ");
1116
1117        if (this.lastConnected != 0) {
1118            sbuf.append('\n');
1119            long diff = now_ms - this.lastConnected;
1120            if (diff <= 0) {
1121                sbuf.append("lastConnected since <incorrect>");
1122            } else {
1123                sbuf.append("lastConnected: ").append(Long.toString(diff/1000)).append( "sec ");
1124            }
1125        }
1126        if (this.lastConnectionFailure != 0) {
1127            sbuf.append('\n');
1128            long diff = now_ms - this.lastConnectionFailure;
1129            if (diff <= 0) {
1130                sbuf.append("lastConnectionFailure since <incorrect> ");
1131            } else {
1132                sbuf.append("lastConnectionFailure: ").append(Long.toString(diff/1000));
1133                sbuf.append( "sec ");
1134            }
1135        }
1136        if (this.lastRoamingFailure != 0) {
1137            sbuf.append('\n');
1138            long diff = now_ms - this.lastRoamingFailure;
1139            if (diff <= 0) {
1140                sbuf.append("lastRoamingFailure since <incorrect> ");
1141            } else {
1142                sbuf.append("lastRoamingFailure: ").append(Long.toString(diff/1000));
1143                sbuf.append( "sec ");
1144            }
1145        }
1146        sbuf.append("roamingFailureBlackListTimeMilli: ").
1147                append(Long.toString(this.roamingFailureBlackListTimeMilli));
1148        sbuf.append('\n');
1149        if (this.linkedConfigurations != null) {
1150            for(String key : this.linkedConfigurations.keySet()) {
1151                sbuf.append(" linked: ").append(key);
1152                sbuf.append('\n');
1153            }
1154        }
1155        if (this.connectChoices != null) {
1156            for(String key : this.connectChoices.keySet()) {
1157                Integer choice = this.connectChoices.get(key);
1158                if (choice != null) {
1159                    sbuf.append(" choice: ").append(key);
1160                    sbuf.append(" = ").append(choice);
1161                    sbuf.append('\n');
1162                }
1163            }
1164        }
1165        sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
1166        sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
1167        sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
1168        sbuf.append('\n');
1169        sbuf.append("ticksLow: ").append(this.numTicksAtLowRSSI);
1170        sbuf.append(" ticksBad: ").append(this.numTicksAtBadRSSI);
1171        sbuf.append(" ticksNotHigh: ").append(this.numTicksAtNotHighRSSI);
1172        sbuf.append('\n');
1173        sbuf.append("triggeredJoin: ").append(this.numUserTriggeredJoinAttempts);
1174        sbuf.append('\n');
1175        sbuf.append("autoJoinBailedDueToLowRssi: ").append(this.autoJoinBailedDueToLowRssi);
1176        sbuf.append('\n');
1177        sbuf.append("autoJoinUseAggressiveJoinAttemptThreshold: ");
1178        sbuf.append(this.autoJoinUseAggressiveJoinAttemptThreshold);
1179        sbuf.append('\n');
1180
1181        return sbuf.toString();
1182    }
1183
1184    /**
1185     * Construct a WifiConfiguration from a scanned network
1186     * @param scannedAP the scan result used to construct the config entry
1187     * TODO: figure out whether this is a useful way to construct a new entry.
1188     *
1189    public WifiConfiguration(ScanResult scannedAP) {
1190        networkId = -1;
1191        SSID = scannedAP.SSID;
1192        BSSID = scannedAP.BSSID;
1193    }
1194    */
1195
1196    /** {@hide} */
1197    public String getPrintableSsid() {
1198        if (SSID == null) return "";
1199        final int length = SSID.length();
1200        if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
1201            return SSID.substring(1, length - 1);
1202        }
1203
1204        /** The ascii-encoded string format is P"<ascii-encoded-string>"
1205         * The decoding is implemented in the supplicant for a newly configured
1206         * network.
1207         */
1208        if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
1209                (SSID.charAt(length-1) == '"')) {
1210            WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
1211                    SSID.substring(2, length - 1));
1212            return wifiSsid.toString();
1213        }
1214        return SSID;
1215    }
1216
1217    /** @hide **/
1218    public static String userApprovedAsString(int userApproved) {
1219        switch (userApproved) {
1220            case USER_APPROVED:
1221                return "USER_APPROVED";
1222            case USER_BANNED:
1223                return "USER_BANNED";
1224            case USER_UNSPECIFIED:
1225                return "USER_UNSPECIFIED";
1226            default:
1227                return "INVALID";
1228        }
1229    }
1230
1231    /**
1232     * Get an identifier for associating credentials with this config
1233     * @param current configuration contains values for additional fields
1234     *                that are not part of this configuration. Used
1235     *                when a config with some fields is passed by an application.
1236     * @throws IllegalStateException if config is invalid for key id generation
1237     * @hide
1238     */
1239    public String getKeyIdForCredentials(WifiConfiguration current) {
1240        String keyMgmt = null;
1241
1242        try {
1243            // Get current config details for fields that are not initialized
1244            if (TextUtils.isEmpty(SSID)) SSID = current.SSID;
1245            if (allowedKeyManagement.cardinality() == 0) {
1246                allowedKeyManagement = current.allowedKeyManagement;
1247            }
1248            if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
1249                keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
1250            }
1251            if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
1252                keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
1253            }
1254
1255            if (TextUtils.isEmpty(keyMgmt)) {
1256                throw new IllegalStateException("Not an EAP network");
1257            }
1258
1259            return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" +
1260                    trimStringForKeyId(enterpriseConfig.getKeyId(current != null ?
1261                            current.enterpriseConfig : null));
1262        } catch (NullPointerException e) {
1263            throw new IllegalStateException("Invalid config details");
1264        }
1265    }
1266
1267    private String trimStringForKeyId(String string) {
1268        // Remove quotes and spaces
1269        return string.replace("\"", "").replace(" ", "");
1270    }
1271
1272    private static BitSet readBitSet(Parcel src) {
1273        int cardinality = src.readInt();
1274
1275        BitSet set = new BitSet();
1276        for (int i = 0; i < cardinality; i++) {
1277            set.set(src.readInt());
1278        }
1279
1280        return set;
1281    }
1282
1283    private static void writeBitSet(Parcel dest, BitSet set) {
1284        int nextSetBit = -1;
1285
1286        dest.writeInt(set.cardinality());
1287
1288        while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
1289            dest.writeInt(nextSetBit);
1290        }
1291    }
1292
1293    /** @hide */
1294    public int getAuthType() {
1295        if (allowedKeyManagement.cardinality() > 1) {
1296            throw new IllegalStateException("More than one auth type set");
1297        }
1298        if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
1299            return KeyMgmt.WPA_PSK;
1300        } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
1301            return KeyMgmt.WPA2_PSK;
1302        } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
1303            return KeyMgmt.WPA_EAP;
1304        } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
1305            return KeyMgmt.IEEE8021X;
1306        }
1307        return KeyMgmt.NONE;
1308    }
1309
1310    /* @hide
1311     * Cache the config key, this seems useful as a speed up since a lot of
1312     * lookups in the config store are done and based on this key.
1313     */
1314    String mCachedConfigKey;
1315
1316    /** @hide
1317     *  return the string used to calculate the hash in WifiConfigStore
1318     *  and uniquely identify this WifiConfiguration
1319     */
1320    public String configKey(boolean allowCached) {
1321        String key;
1322        if (allowCached && mCachedConfigKey != null) {
1323            key = mCachedConfigKey;
1324        } else if (providerFriendlyName != null) {
1325            key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
1326        } else {
1327            if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
1328                key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
1329            } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
1330                    allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
1331                key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
1332            } else if (wepKeys[0] != null) {
1333                key = SSID + "WEP";
1334            } else {
1335                key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
1336            }
1337            mCachedConfigKey = key;
1338        }
1339        return key;
1340    }
1341
1342    /** @hide
1343     * get configKey, force calculating the config string
1344     */
1345    public String configKey() {
1346        return configKey(false);
1347    }
1348
1349    /** @hide
1350     * return the config key string based on a scan result
1351     */
1352    static public String configKey(ScanResult result) {
1353        String key = "\"" + result.SSID + "\"";
1354
1355        if (result.capabilities.contains("WEP")) {
1356            key = key + "-WEP";
1357        }
1358
1359        if (result.capabilities.contains("PSK")) {
1360            key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
1361        }
1362
1363        if (result.capabilities.contains("EAP")) {
1364            key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
1365        }
1366
1367        return key;
1368    }
1369
1370    /** @hide */
1371    public IpConfiguration getIpConfiguration() {
1372        return mIpConfiguration;
1373    }
1374
1375    /** @hide */
1376    public void setIpConfiguration(IpConfiguration ipConfiguration) {
1377        mIpConfiguration = ipConfiguration;
1378    }
1379
1380    /** @hide */
1381    public StaticIpConfiguration getStaticIpConfiguration() {
1382        return mIpConfiguration.getStaticIpConfiguration();
1383    }
1384
1385    /** @hide */
1386    public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
1387        mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration);
1388    }
1389
1390    /** @hide */
1391    public IpConfiguration.IpAssignment getIpAssignment() {
1392        return mIpConfiguration.ipAssignment;
1393    }
1394
1395    /** @hide */
1396    public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
1397        mIpConfiguration.ipAssignment = ipAssignment;
1398    }
1399
1400    /** @hide */
1401    public IpConfiguration.ProxySettings getProxySettings() {
1402        return mIpConfiguration.proxySettings;
1403    }
1404
1405    /** @hide */
1406    public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
1407        mIpConfiguration.proxySettings = proxySettings;
1408    }
1409
1410    /** @hide */
1411    public ProxyInfo getHttpProxy() {
1412        return mIpConfiguration.httpProxy;
1413    }
1414
1415    /** @hide */
1416    public void setHttpProxy(ProxyInfo httpProxy) {
1417        mIpConfiguration.httpProxy = httpProxy;
1418    }
1419
1420    /** @hide */
1421    public void setProxy(ProxySettings settings, ProxyInfo proxy) {
1422        mIpConfiguration.proxySettings = settings;
1423        mIpConfiguration.httpProxy = proxy;
1424    }
1425
1426    /** Implement the Parcelable interface {@hide} */
1427    public int describeContents() {
1428        return 0;
1429    }
1430
1431    /** copy constructor {@hide} */
1432    public WifiConfiguration(WifiConfiguration source) {
1433        if (source != null) {
1434            networkId = source.networkId;
1435            status = source.status;
1436            disableReason = source.disableReason;
1437            disableReason = source.disableReason;
1438            SSID = source.SSID;
1439            BSSID = source.BSSID;
1440            FQDN = source.FQDN;
1441            roamingConsortiumIds = source.roamingConsortiumIds.clone();
1442            providerFriendlyName = source.providerFriendlyName;
1443            preSharedKey = source.preSharedKey;
1444
1445            apBand = source.apBand;
1446            apChannel = source.apChannel;
1447
1448            wepKeys = new String[4];
1449            for (int i = 0; i < wepKeys.length; i++) {
1450                wepKeys[i] = source.wepKeys[i];
1451            }
1452
1453            wepTxKeyIndex = source.wepTxKeyIndex;
1454            priority = source.priority;
1455            hiddenSSID = source.hiddenSSID;
1456            allowedKeyManagement   = (BitSet) source.allowedKeyManagement.clone();
1457            allowedProtocols       = (BitSet) source.allowedProtocols.clone();
1458            allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
1459            allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
1460            allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
1461
1462            enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
1463
1464            defaultGwMacAddress = source.defaultGwMacAddress;
1465
1466            mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
1467
1468            if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
1469                connectChoices = new HashMap<String, Integer>();
1470                connectChoices.putAll(source.connectChoices);
1471            }
1472
1473            if ((source.linkedConfigurations != null)
1474                    && (source.linkedConfigurations.size() > 0)) {
1475                linkedConfigurations = new HashMap<String, Integer>();
1476                linkedConfigurations.putAll(source.linkedConfigurations);
1477            }
1478            mCachedConfigKey = null; //force null configKey
1479            autoJoinStatus = source.autoJoinStatus;
1480            selfAdded = source.selfAdded;
1481            validatedInternetAccess = source.validatedInternetAccess;
1482            ephemeral = source.ephemeral;
1483            if (source.visibility != null) {
1484                visibility = new Visibility(source.visibility);
1485            }
1486
1487            lastFailure = source.lastFailure;
1488            didSelfAdd = source.didSelfAdd;
1489            lastConnectUid = source.lastConnectUid;
1490            lastUpdateUid = source.lastUpdateUid;
1491            creatorUid = source.creatorUid;
1492            creatorName = source.creatorName;
1493            lastUpdateName = source.lastUpdateName;
1494            peerWifiConfiguration = source.peerWifiConfiguration;
1495            blackListTimestamp = source.blackListTimestamp;
1496            lastConnected = source.lastConnected;
1497            lastDisconnected = source.lastDisconnected;
1498            lastConnectionFailure = source.lastConnectionFailure;
1499            lastRoamingFailure = source.lastRoamingFailure;
1500            lastRoamingFailureReason = source.lastRoamingFailureReason;
1501            roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
1502            numConnectionFailures = source.numConnectionFailures;
1503            numIpConfigFailures = source.numIpConfigFailures;
1504            numAuthFailures = source.numAuthFailures;
1505            numScorerOverride = source.numScorerOverride;
1506            numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
1507            numAssociation = source.numAssociation;
1508            numUserTriggeredWifiDisableLowRSSI = source.numUserTriggeredWifiDisableLowRSSI;
1509            numUserTriggeredWifiDisableBadRSSI = source.numUserTriggeredWifiDisableBadRSSI;
1510            numUserTriggeredWifiDisableNotHighRSSI = source.numUserTriggeredWifiDisableNotHighRSSI;
1511            numTicksAtLowRSSI = source.numTicksAtLowRSSI;
1512            numTicksAtBadRSSI = source.numTicksAtBadRSSI;
1513            numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
1514            numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
1515            autoJoinBSSID = source.autoJoinBSSID;
1516            autoJoinUseAggressiveJoinAttemptThreshold
1517                    = source.autoJoinUseAggressiveJoinAttemptThreshold;
1518            autoJoinBailedDueToLowRssi = source.autoJoinBailedDueToLowRssi;
1519            dirty = source.dirty;
1520            userApproved = source.userApproved;
1521            numNoInternetAccessReports = source.numNoInternetAccessReports;
1522            noInternetAccessExpected = source.noInternetAccessExpected;
1523            creationTime = source.creationTime;
1524            updateTime = source.updateTime;
1525        }
1526    }
1527
1528    /** {@hide} */
1529    //public static final int NOTHING_TAG = 0;
1530    /** {@hide} */
1531    //public static final int SCAN_CACHE_TAG = 1;
1532
1533    /** Implement the Parcelable interface {@hide} */
1534    @Override
1535    public void writeToParcel(Parcel dest, int flags) {
1536        dest.writeInt(networkId);
1537        dest.writeInt(status);
1538        dest.writeInt(disableReason);
1539        dest.writeString(SSID);
1540        dest.writeString(BSSID);
1541        dest.writeInt(apBand);
1542        dest.writeInt(apChannel);
1543        dest.writeString(autoJoinBSSID);
1544        dest.writeString(FQDN);
1545        dest.writeString(providerFriendlyName);
1546        dest.writeInt(roamingConsortiumIds.length);
1547        for (long roamingConsortiumId : roamingConsortiumIds) {
1548            dest.writeLong(roamingConsortiumId);
1549        }
1550        dest.writeString(preSharedKey);
1551        for (String wepKey : wepKeys) {
1552            dest.writeString(wepKey);
1553        }
1554        dest.writeInt(wepTxKeyIndex);
1555        dest.writeInt(priority);
1556        dest.writeInt(hiddenSSID ? 1 : 0);
1557        dest.writeInt(requirePMF ? 1 : 0);
1558        dest.writeString(updateIdentifier);
1559
1560        writeBitSet(dest, allowedKeyManagement);
1561        writeBitSet(dest, allowedProtocols);
1562        writeBitSet(dest, allowedAuthAlgorithms);
1563        writeBitSet(dest, allowedPairwiseCiphers);
1564        writeBitSet(dest, allowedGroupCiphers);
1565
1566        dest.writeParcelable(enterpriseConfig, flags);
1567
1568        dest.writeParcelable(mIpConfiguration, flags);
1569        dest.writeString(dhcpServer);
1570        dest.writeString(defaultGwMacAddress);
1571        dest.writeInt(autoJoinStatus);
1572        dest.writeInt(selfAdded ? 1 : 0);
1573        dest.writeInt(didSelfAdd ? 1 : 0);
1574        dest.writeInt(validatedInternetAccess ? 1 : 0);
1575        dest.writeInt(ephemeral ? 1 : 0);
1576        dest.writeInt(creatorUid);
1577        dest.writeInt(lastConnectUid);
1578        dest.writeInt(lastUpdateUid);
1579        dest.writeString(creatorName);
1580        dest.writeString(lastUpdateName);
1581        dest.writeLong(blackListTimestamp);
1582        dest.writeLong(lastConnectionFailure);
1583        dest.writeLong(lastRoamingFailure);
1584        dest.writeInt(lastRoamingFailureReason);
1585        dest.writeLong(roamingFailureBlackListTimeMilli);
1586        dest.writeInt(numConnectionFailures);
1587        dest.writeInt(numIpConfigFailures);
1588        dest.writeInt(numAuthFailures);
1589        dest.writeInt(numScorerOverride);
1590        dest.writeInt(numScorerOverrideAndSwitchedNetwork);
1591        dest.writeInt(numAssociation);
1592        dest.writeInt(numUserTriggeredWifiDisableLowRSSI);
1593        dest.writeInt(numUserTriggeredWifiDisableBadRSSI);
1594        dest.writeInt(numUserTriggeredWifiDisableNotHighRSSI);
1595        dest.writeInt(numTicksAtLowRSSI);
1596        dest.writeInt(numTicksAtBadRSSI);
1597        dest.writeInt(numTicksAtNotHighRSSI);
1598        dest.writeInt(numUserTriggeredJoinAttempts);
1599        dest.writeInt(autoJoinUseAggressiveJoinAttemptThreshold);
1600        dest.writeInt(autoJoinBailedDueToLowRssi ? 1 : 0);
1601        dest.writeInt(userApproved);
1602        dest.writeInt(numNoInternetAccessReports);
1603        dest.writeInt(noInternetAccessExpected ? 1 : 0);
1604    }
1605
1606    /** Implement the Parcelable interface {@hide} */
1607    public static final Creator<WifiConfiguration> CREATOR =
1608        new Creator<WifiConfiguration>() {
1609            public WifiConfiguration createFromParcel(Parcel in) {
1610                WifiConfiguration config = new WifiConfiguration();
1611                config.networkId = in.readInt();
1612                config.status = in.readInt();
1613                config.disableReason = in.readInt();
1614                config.SSID = in.readString();
1615                config.BSSID = in.readString();
1616                config.apBand = in.readInt();
1617                config.apChannel = in.readInt();
1618                config.autoJoinBSSID = in.readString();
1619                config.FQDN = in.readString();
1620                config.providerFriendlyName = in.readString();
1621                int numRoamingConsortiumIds = in.readInt();
1622                config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
1623                for (int i = 0; i < numRoamingConsortiumIds; i++) {
1624                    config.roamingConsortiumIds[i] = in.readLong();
1625                }
1626                config.preSharedKey = in.readString();
1627                for (int i = 0; i < config.wepKeys.length; i++) {
1628                    config.wepKeys[i] = in.readString();
1629                }
1630                config.wepTxKeyIndex = in.readInt();
1631                config.priority = in.readInt();
1632                config.hiddenSSID = in.readInt() != 0;
1633                config.requirePMF = in.readInt() != 0;
1634                config.updateIdentifier = in.readString();
1635
1636                config.allowedKeyManagement   = readBitSet(in);
1637                config.allowedProtocols       = readBitSet(in);
1638                config.allowedAuthAlgorithms  = readBitSet(in);
1639                config.allowedPairwiseCiphers = readBitSet(in);
1640                config.allowedGroupCiphers    = readBitSet(in);
1641
1642                config.enterpriseConfig = in.readParcelable(null);
1643
1644                config.mIpConfiguration = in.readParcelable(null);
1645                config.dhcpServer = in.readString();
1646                config.defaultGwMacAddress = in.readString();
1647                config.autoJoinStatus = in.readInt();
1648                config.selfAdded = in.readInt() != 0;
1649                config.didSelfAdd = in.readInt() != 0;
1650                config.validatedInternetAccess = in.readInt() != 0;
1651                config.ephemeral = in.readInt() != 0;
1652                config.creatorUid = in.readInt();
1653                config.lastConnectUid = in.readInt();
1654                config.lastUpdateUid = in.readInt();
1655                config.creatorName = in.readString();
1656                config.lastUpdateName = in.readString();
1657                config.blackListTimestamp = in.readLong();
1658                config.lastConnectionFailure = in.readLong();
1659                config.lastRoamingFailure = in.readLong();
1660                config.lastRoamingFailureReason = in.readInt();
1661                config.roamingFailureBlackListTimeMilli = in.readLong();
1662                config.numConnectionFailures = in.readInt();
1663                config.numIpConfigFailures = in.readInt();
1664                config.numAuthFailures = in.readInt();
1665                config.numScorerOverride = in.readInt();
1666                config.numScorerOverrideAndSwitchedNetwork = in.readInt();
1667                config.numAssociation = in.readInt();
1668                config.numUserTriggeredWifiDisableLowRSSI = in.readInt();
1669                config.numUserTriggeredWifiDisableBadRSSI = in.readInt();
1670                config.numUserTriggeredWifiDisableNotHighRSSI = in.readInt();
1671                config.numTicksAtLowRSSI = in.readInt();
1672                config.numTicksAtBadRSSI = in.readInt();
1673                config.numTicksAtNotHighRSSI = in.readInt();
1674                config.numUserTriggeredJoinAttempts = in.readInt();
1675                config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
1676                config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
1677                config.userApproved = in.readInt();
1678                config.numNoInternetAccessReports = in.readInt();
1679                config.noInternetAccessExpected = in.readInt() != 0;
1680                return config;
1681            }
1682
1683            public WifiConfiguration[] newArray(int size) {
1684                return new WifiConfiguration[size];
1685            }
1686        };
1687}
1688