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