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