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