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