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