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