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          * This network is disabled because higher layer (>2) network is bad
    821          */
    822         public static final int DISABLED_BAD_LINK = 1;
    823         /**
    824          * This network is disabled because multiple association rejects
    825          */
    826         public static final int DISABLED_ASSOCIATION_REJECTION = 2;
    827         /**
    828          * This network is disabled because multiple authentication failure
    829          */
    830         public static final int DISABLED_AUTHENTICATION_FAILURE = 3;
    831         /**
    832          * This network is disabled because multiple DHCP failure
    833          */
    834         public static final int DISABLED_DHCP_FAILURE = 4;
    835         /**
    836          * This network is disabled because of security network but no credentials
    837          */
    838         public static final int DISABLED_DNS_FAILURE = 5;
    839         /**
    840          * This network is disabled because EAP-TLS failure
    841          */
    842         public static final int DISABLED_TLS_VERSION_MISMATCH = 6;
    843         /**
    844          * This network is disabled due to WifiManager disable it explicitly
    845          */
    846         public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 7;
    847         /**
    848          * This network is disabled because no Internet connected and user do not want
    849          */
    850         public static final int DISABLED_NO_INTERNET = 8;
    851         /**
    852          * This network is disabled due to WifiManager disable it explicitly
    853          */
    854         public static final int DISABLED_BY_WIFI_MANAGER = 9;
    855         /**
    856          * This Maximum disable reason value
    857          */
    858         public static final int NETWORK_SELECTION_DISABLED_MAX = 10;
    859 
    860         /**
    861          * Quality network selection disable reason String (for debug purpose)
    862          */
    863         private static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
    864                 "NETWORK_SELECTION_ENABLE",
    865                 "NETWORK_SELECTION_DISABLED_BAD_LINK",
    866                 "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ",
    867                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE",
    868                 "NETWORK_SELECTION_DISABLED_DHCP_FAILURE",
    869                 "NETWORK_SELECTION_DISABLED_DNS_FAILURE",
    870                 "NETWORK_SELECTION_DISABLED_TLS_VERSION",
    871                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
    872                 "NETWORK_SELECTION_DISABLED_NO_INTERNET",
    873                 "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER"};
    874 
    875         /**
    876          * Invalid time stamp for network selection disable
    877          */
    878         public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
    879 
    880         /**
    881          *  This constant indicates the current configuration has connect choice set
    882          */
    883         private static final int CONNECT_CHOICE_EXISTS = 1;
    884 
    885         /**
    886          *  This constant indicates the current configuration does not have connect choice set
    887          */
    888         private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
    889 
    890         // fields for QualityNetwork Selection
    891         /**
    892          * Network selection status, should be in one of three status: enable, temporaily disabled
    893          * or permanently disabled
    894          */
    895         private int mStatus;
    896 
    897         /**
    898          * Reason for disable this network
    899          */
    900         private int mNetworkSelectionDisableReason;
    901 
    902         /**
    903          * Last time we temporarily disabled the configuration
    904          */
    905         private long mTemporarilyDisabledTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
    906 
    907         /**
    908          * counter for each Network selection disable reason
    909          */
    910         private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
    911 
    912         /**
    913          * Connect Choice over this configuration
    914          *
    915          * When current wifi configuration is visible to the user but user explicitly choose to
    916          * connect to another network X, the another networks X's configure key will be stored here.
    917          * We will consider user has a preference of X over this network. And in the future,
    918          * network selection will always give X a higher preference over this configuration.
    919          * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
    920          */
    921         private String mConnectChoice;
    922 
    923         /**
    924          * The system timestamp when we records the connectChoice. This value is obtained from
    925          * System.currentTimeMillis
    926          */
    927         private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
    928 
    929         /**
    930          * Used to cache the temporary candidate during the network selection procedure. It will be
    931          * kept updating once a new scan result has a higher score than current one
    932          */
    933         private ScanResult mCandidate;
    934 
    935         /**
    936          * Used to cache the score of the current temporary candidate during the network
    937          * selection procedure.
    938          */
    939         private int mCandidateScore;
    940 
    941         /**
    942          * Indicate whether this network is visible in latest Qualified Network Selection. This
    943          * means there is scan result found related to this Configuration and meet the minimum
    944          * requirement. The saved network need not join latest Qualified Network Selection. For
    945          * example, it is disabled. True means network is visible in latest Qualified Network
    946          * Selection and false means network is invisible
    947          */
    948         private boolean mSeenInLastQualifiedNetworkSelection;
    949 
    950         /**
    951          * Boolean indicating if we have ever successfully connected to this network.
    952          *
    953          * This value will be set to true upon a successful connection.
    954          * This value will be set to false if a previous value was not stored in the config or if
    955          * the credentials are updated (ex. a password change).
    956          */
    957         private boolean mHasEverConnected;
    958 
    959         /**
    960          * set whether this network is visible in latest Qualified Network Selection
    961          * @param seen value set to candidate
    962          */
    963         public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
    964             mSeenInLastQualifiedNetworkSelection =  seen;
    965         }
    966 
    967         /**
    968          * get whether this network is visible in latest Qualified Network Selection
    969          * @return returns true -- network is visible in latest Qualified Network Selection
    970          *         false -- network is invisible in latest Qualified Network Selection
    971          */
    972         public boolean getSeenInLastQualifiedNetworkSelection() {
    973             return mSeenInLastQualifiedNetworkSelection;
    974         }
    975         /**
    976          * set the temporary candidate of current network selection procedure
    977          * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
    978          */
    979         public void setCandidate(ScanResult scanCandidate) {
    980             mCandidate = scanCandidate;
    981         }
    982 
    983         /**
    984          * get the temporary candidate of current network selection procedure
    985          * @return  returns {@link ScanResult} temporary candidate of current network selection
    986          * procedure
    987          */
    988         public ScanResult getCandidate() {
    989             return mCandidate;
    990         }
    991 
    992         /**
    993          * set the score of the temporary candidate of current network selection procedure
    994          * @param score value set to mCandidateScore
    995          */
    996         public void setCandidateScore(int score) {
    997             mCandidateScore = score;
    998         }
    999 
   1000         /**
   1001          * get the score of the temporary candidate of current network selection procedure
   1002          * @return returns score of the temporary candidate of current network selection procedure
   1003          */
   1004         public int getCandidateScore() {
   1005             return mCandidateScore;
   1006         }
   1007 
   1008         /**
   1009          * get user preferred choice over this configuration
   1010          *@return returns configKey of user preferred choice over this configuration
   1011          */
   1012         public String getConnectChoice() {
   1013             return mConnectChoice;
   1014         }
   1015 
   1016         /**
   1017          * set user preferred choice over this configuration
   1018          * @param newConnectChoice, the configKey of user preferred choice over this configuration
   1019          */
   1020         public void setConnectChoice(String newConnectChoice) {
   1021             mConnectChoice = newConnectChoice;
   1022         }
   1023 
   1024         /**
   1025          * get the timeStamp when user select a choice over this configuration
   1026          * @return returns when current connectChoice is set (time from System.currentTimeMillis)
   1027          */
   1028         public long getConnectChoiceTimestamp() {
   1029             return mConnectChoiceTimestamp;
   1030         }
   1031 
   1032         /**
   1033          * set the timeStamp when user select a choice over this configuration
   1034          * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
   1035          *        be obtained from System.currentTimeMillis
   1036          */
   1037         public void setConnectChoiceTimestamp(long timeStamp) {
   1038             mConnectChoiceTimestamp = timeStamp;
   1039         }
   1040 
   1041         /**
   1042          * get current Quality network selection status
   1043          * @return returns current Quality network selection status in String (for debug purpose)
   1044          */
   1045         public String getNetworkStatusString() {
   1046             return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
   1047         }
   1048 
   1049         public void setHasEverConnected(boolean value) {
   1050             mHasEverConnected = value;
   1051         }
   1052 
   1053         public boolean getHasEverConnected() {
   1054             return mHasEverConnected;
   1055         }
   1056 
   1057         private NetworkSelectionStatus() {
   1058             // previously stored configs will not have this parameter, so we default to false.
   1059             mHasEverConnected = false;
   1060         };
   1061 
   1062         /**
   1063          * @param reason specific error reason
   1064          * @return  corresponding network disable reason String (for debug purpose)
   1065          */
   1066         public static String getNetworkDisableReasonString(int reason) {
   1067             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
   1068                 return QUALITY_NETWORK_SELECTION_DISABLE_REASON[reason];
   1069             } else {
   1070                 return null;
   1071             }
   1072         }
   1073         /**
   1074          * get current network disable reason
   1075          * @return current network disable reason in String (for debug purpose)
   1076          */
   1077         public String getNetworkDisableReasonString() {
   1078             return QUALITY_NETWORK_SELECTION_DISABLE_REASON[mNetworkSelectionDisableReason];
   1079         }
   1080 
   1081         /**
   1082          * get current network network selection status
   1083          * @return return current network network selection status
   1084          */
   1085         public int getNetworkSelectionStatus() {
   1086             return mStatus;
   1087         }
   1088         /**
   1089          * @return whether current network is enabled to join network selection
   1090          */
   1091         public boolean isNetworkEnabled() {
   1092             return mStatus == NETWORK_SELECTION_ENABLED;
   1093         }
   1094 
   1095         /**
   1096          * @return whether current network is temporary disabled
   1097          */
   1098         public boolean isNetworkTemporaryDisabled() {
   1099             return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED;
   1100         }
   1101 
   1102         /**
   1103          * @return returns whether current network is permanently disabled
   1104          */
   1105         public boolean isNetworkPermanentlyDisabled() {
   1106             return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
   1107         }
   1108 
   1109         /**
   1110          * set current networ work selection status
   1111          * @param status network selection status to set
   1112          */
   1113         public void setNetworkSelectionStatus(int status) {
   1114             if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) {
   1115                 mStatus = status;
   1116             }
   1117         }
   1118 
   1119         /**
   1120          * @return returns current network's disable reason
   1121          */
   1122         public int getNetworkSelectionDisableReason() {
   1123             return mNetworkSelectionDisableReason;
   1124         }
   1125 
   1126         /**
   1127          * set Network disable reason
   1128          * @param  reason Network disable reason
   1129          */
   1130         public void setNetworkSelectionDisableReason(int reason) {
   1131             if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) {
   1132                 mNetworkSelectionDisableReason = reason;
   1133             } else {
   1134                 throw new IllegalArgumentException("Illegal reason value: " + reason);
   1135             }
   1136         }
   1137 
   1138         /**
   1139          * check whether network is disabled by this reason
   1140          * @param reason a specific disable reason
   1141          * @return true -- network is disabled for this reason
   1142          *         false -- network is not disabled for this reason
   1143          */
   1144         public boolean isDisabledByReason(int reason) {
   1145             return mNetworkSelectionDisableReason == reason;
   1146         }
   1147 
   1148         /**
   1149          * @param timeStamp Set when current network is disabled in millisecond since January 1,
   1150          * 1970 00:00:00.0 UTC
   1151          */
   1152         public void setDisableTime(long timeStamp) {
   1153             mTemporarilyDisabledTimestamp = timeStamp;
   1154         }
   1155 
   1156         /**
   1157          * @return returns when current network is disabled in millisecond since January 1,
   1158          * 1970 00:00:00.0 UTC
   1159          */
   1160         public long getDisableTime() {
   1161             return mTemporarilyDisabledTimestamp;
   1162         }
   1163 
   1164         /**
   1165          * get the disable counter of a specific reason
   1166          * @param  reason specific failure reason
   1167          * @exception throw IllegalArgumentException for illegal input
   1168          * @return counter number for specific error reason.
   1169          */
   1170         public int getDisableReasonCounter(int reason) {
   1171             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
   1172                 return mNetworkSeclectionDisableCounter[reason];
   1173             } else {
   1174                 throw new IllegalArgumentException("Illegal reason value: " + reason);
   1175             }
   1176         }
   1177 
   1178         /**
   1179          * set the counter of a specific failure reason
   1180          * @param reason reason for disable error
   1181          * @param value the counter value for this specific reason
   1182          * @exception throw IllegalArgumentException for illegal input
   1183          */
   1184         public void setDisableReasonCounter(int reason, int value) {
   1185             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
   1186                 mNetworkSeclectionDisableCounter[reason] = value;
   1187             } else {
   1188                 throw new IllegalArgumentException("Illegal reason value: " + reason);
   1189             }
   1190         }
   1191 
   1192         /**
   1193          * increment the counter of a specific failure reason
   1194          * @param reason a specific failure reason
   1195          * @exception throw IllegalArgumentException for illegal input
   1196          */
   1197         public void incrementDisableReasonCounter(int reason) {
   1198             if (reason >= NETWORK_SELECTION_ENABLE  && reason < NETWORK_SELECTION_DISABLED_MAX) {
   1199                 mNetworkSeclectionDisableCounter[reason]++;
   1200             } else {
   1201                 throw new IllegalArgumentException("Illegal reason value: " + reason);
   1202             }
   1203         }
   1204 
   1205         /**
   1206          * clear the counter of a specific failure reason
   1207          * @hide
   1208          * @param reason a specific failure reason
   1209          * @exception throw IllegalArgumentException for illegal input
   1210          */
   1211         public void clearDisableReasonCounter(int reason) {
   1212             if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) {
   1213                 mNetworkSeclectionDisableCounter[reason] = NETWORK_SELECTION_ENABLE;
   1214             } else {
   1215                 throw new IllegalArgumentException("Illegal reason value: " + reason);
   1216             }
   1217         }
   1218 
   1219         /**
   1220          * clear all the failure reason counters
   1221          */
   1222         public void clearDisableReasonCounter() {
   1223             Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE);
   1224         }
   1225 
   1226         /**
   1227          * BSSID for connection to this network (through network selection procedure)
   1228          */
   1229         private String mNetworkSelectionBSSID;
   1230 
   1231         /**
   1232          * get current network Selection BSSID
   1233          * @return current network Selection BSSID
   1234          */
   1235         public String getNetworkSelectionBSSID() {
   1236             return mNetworkSelectionBSSID;
   1237         }
   1238 
   1239         /**
   1240          * set network Selection BSSID
   1241          * @param bssid The target BSSID for assocaition
   1242          */
   1243         public void setNetworkSelectionBSSID(String bssid) {
   1244             mNetworkSelectionBSSID = bssid;
   1245         }
   1246 
   1247         public void copy(NetworkSelectionStatus source) {
   1248             mStatus = source.mStatus;
   1249             mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason;
   1250             for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
   1251                     index++) {
   1252                 mNetworkSeclectionDisableCounter[index] =
   1253                         source.mNetworkSeclectionDisableCounter[index];
   1254             }
   1255             mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
   1256             mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
   1257             setConnectChoice(source.getConnectChoice());
   1258             setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
   1259             setHasEverConnected(source.getHasEverConnected());
   1260         }
   1261 
   1262         public void writeToParcel(Parcel dest) {
   1263             dest.writeInt(getNetworkSelectionStatus());
   1264             dest.writeInt(getNetworkSelectionDisableReason());
   1265             for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
   1266                     index++) {
   1267                 dest.writeInt(getDisableReasonCounter(index));
   1268             }
   1269             dest.writeLong(getDisableTime());
   1270             dest.writeString(getNetworkSelectionBSSID());
   1271             if (getConnectChoice() != null) {
   1272                 dest.writeInt(CONNECT_CHOICE_EXISTS);
   1273                 dest.writeString(getConnectChoice());
   1274                 dest.writeLong(getConnectChoiceTimestamp());
   1275             } else {
   1276                 dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
   1277             }
   1278             dest.writeInt(getHasEverConnected() ? 1 : 0);
   1279         }
   1280 
   1281         public void readFromParcel(Parcel in) {
   1282             setNetworkSelectionStatus(in.readInt());
   1283             setNetworkSelectionDisableReason(in.readInt());
   1284             for (int index = NETWORK_SELECTION_ENABLE; index < NETWORK_SELECTION_DISABLED_MAX;
   1285                     index++) {
   1286                 setDisableReasonCounter(index, in.readInt());
   1287             }
   1288             setDisableTime(in.readLong());
   1289             setNetworkSelectionBSSID(in.readString());
   1290             if (in.readInt() == CONNECT_CHOICE_EXISTS) {
   1291                 setConnectChoice(in.readString());
   1292                 setConnectChoiceTimestamp(in.readLong());
   1293             } else {
   1294                 setConnectChoice(null);
   1295                 setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
   1296             }
   1297             setHasEverConnected(in.readInt() != 0);
   1298         }
   1299     }
   1300 
   1301     /**
   1302      * @hide
   1303      * network selection related member
   1304      */
   1305     private final NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
   1306 
   1307     /**
   1308      * @hide
   1309      * @return network selection status
   1310      */
   1311     public NetworkSelectionStatus getNetworkSelectionStatus() {
   1312         return mNetworkSelectionStatus;
   1313     }
   1314     /**
   1315      * @hide
   1316      * Linked Configurations: represent the set of Wificonfigurations that are equivalent
   1317      * regarding roaming and auto-joining.
   1318      * The linked configuration may or may not have same SSID, and may or may not have same
   1319      * credentials.
   1320      * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
   1321      */
   1322     public HashMap<String, Integer>  linkedConfigurations;
   1323 
   1324     public WifiConfiguration() {
   1325         networkId = INVALID_NETWORK_ID;
   1326         SSID = null;
   1327         BSSID = null;
   1328         FQDN = null;
   1329         roamingConsortiumIds = new long[0];
   1330         priority = 0;
   1331         hiddenSSID = false;
   1332         allowedKeyManagement = new BitSet();
   1333         allowedProtocols = new BitSet();
   1334         allowedAuthAlgorithms = new BitSet();
   1335         allowedPairwiseCiphers = new BitSet();
   1336         allowedGroupCiphers = new BitSet();
   1337         wepKeys = new String[4];
   1338         for (int i = 0; i < wepKeys.length; i++) {
   1339             wepKeys[i] = null;
   1340         }
   1341         enterpriseConfig = new WifiEnterpriseConfig();
   1342         selfAdded = false;
   1343         didSelfAdd = false;
   1344         ephemeral = false;
   1345         meteredHint = false;
   1346         useExternalScores = false;
   1347         validatedInternetAccess = false;
   1348         mIpConfiguration = new IpConfiguration();
   1349         lastUpdateUid = -1;
   1350         creatorUid = -1;
   1351         shared = true;
   1352         dtimInterval = 0;
   1353     }
   1354 
   1355     /**
   1356      * Identify if this configuration represents a passpoint network
   1357      */
   1358     public boolean isPasspoint() {
   1359         return !TextUtils.isEmpty(FQDN)
   1360                 && !TextUtils.isEmpty(providerFriendlyName)
   1361                 && enterpriseConfig != null
   1362                 && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
   1363     }
   1364 
   1365     /**
   1366      * Helper function, identify if a configuration is linked
   1367      * @hide
   1368      */
   1369     public boolean isLinked(WifiConfiguration config) {
   1370         if (config != null) {
   1371             if (config.linkedConfigurations != null && linkedConfigurations != null) {
   1372                 if (config.linkedConfigurations.get(configKey()) != null
   1373                         && linkedConfigurations.get(config.configKey()) != null) {
   1374                     return true;
   1375                 }
   1376             }
   1377         }
   1378         return  false;
   1379     }
   1380 
   1381     /**
   1382      * Helper function, idenfity if a configuration should be treated as an enterprise network
   1383      * @hide
   1384      */
   1385     public boolean isEnterprise() {
   1386         return allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
   1387             allowedKeyManagement.get(KeyMgmt.IEEE8021X);
   1388     }
   1389 
   1390     @Override
   1391     public String toString() {
   1392         StringBuilder sbuf = new StringBuilder();
   1393         if (this.status == WifiConfiguration.Status.CURRENT) {
   1394             sbuf.append("* ");
   1395         } else if (this.status == WifiConfiguration.Status.DISABLED) {
   1396             sbuf.append("- DSBLE ");
   1397         }
   1398         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
   1399                 append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
   1400                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
   1401                 .append(" PRIO: ").append(this.priority)
   1402                 .append(" HIDDEN: ").append(this.hiddenSSID)
   1403                 .append('\n');
   1404 
   1405 
   1406         sbuf.append(" NetworkSelectionStatus ")
   1407                 .append(mNetworkSelectionStatus.getNetworkStatusString() + "\n");
   1408         if (mNetworkSelectionStatus.getNetworkSelectionDisableReason() > 0) {
   1409             sbuf.append(" mNetworkSelectionDisableReason ")
   1410                     .append(mNetworkSelectionStatus.getNetworkDisableReasonString() + "\n");
   1411 
   1412             for (int index = mNetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
   1413                     index < mNetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; index++) {
   1414                 if (mNetworkSelectionStatus.getDisableReasonCounter(index) != 0) {
   1415                     sbuf.append(NetworkSelectionStatus.getNetworkDisableReasonString(index)
   1416                             + " counter:" + mNetworkSelectionStatus.getDisableReasonCounter(index)
   1417                             + "\n");
   1418                 }
   1419             }
   1420         }
   1421         if (mNetworkSelectionStatus.getConnectChoice() != null) {
   1422             sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
   1423             sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
   1424                     .getConnectChoiceTimestamp());
   1425         }
   1426         sbuf.append(" hasEverConnected: ")
   1427                 .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n");
   1428 
   1429         if (this.numAssociation > 0) {
   1430             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
   1431         }
   1432         if (this.numNoInternetAccessReports > 0) {
   1433             sbuf.append(" numNoInternetAccessReports ");
   1434             sbuf.append(this.numNoInternetAccessReports).append("\n");
   1435         }
   1436         if (this.updateTime != null) {
   1437             sbuf.append("update ").append(this.updateTime).append("\n");
   1438         }
   1439         if (this.creationTime != null) {
   1440             sbuf.append("creation").append(this.creationTime).append("\n");
   1441         }
   1442         if (this.didSelfAdd) sbuf.append(" didSelfAdd");
   1443         if (this.selfAdded) sbuf.append(" selfAdded");
   1444         if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
   1445         if (this.ephemeral) sbuf.append(" ephemeral");
   1446         if (this.meteredHint) sbuf.append(" meteredHint");
   1447         if (this.useExternalScores) sbuf.append(" useExternalScores");
   1448         if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
   1449             || this.ephemeral || this.meteredHint || this.useExternalScores) {
   1450             sbuf.append("\n");
   1451         }
   1452         sbuf.append(" KeyMgmt:");
   1453         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
   1454             if (this.allowedKeyManagement.get(k)) {
   1455                 sbuf.append(" ");
   1456                 if (k < KeyMgmt.strings.length) {
   1457                     sbuf.append(KeyMgmt.strings[k]);
   1458                 } else {
   1459                     sbuf.append("??");
   1460                 }
   1461             }
   1462         }
   1463         sbuf.append(" Protocols:");
   1464         for (int p = 0; p < this.allowedProtocols.size(); p++) {
   1465             if (this.allowedProtocols.get(p)) {
   1466                 sbuf.append(" ");
   1467                 if (p < Protocol.strings.length) {
   1468                     sbuf.append(Protocol.strings[p]);
   1469                 } else {
   1470                     sbuf.append("??");
   1471                 }
   1472             }
   1473         }
   1474         sbuf.append('\n');
   1475         sbuf.append(" AuthAlgorithms:");
   1476         for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) {
   1477             if (this.allowedAuthAlgorithms.get(a)) {
   1478                 sbuf.append(" ");
   1479                 if (a < AuthAlgorithm.strings.length) {
   1480                     sbuf.append(AuthAlgorithm.strings[a]);
   1481                 } else {
   1482                     sbuf.append("??");
   1483                 }
   1484             }
   1485         }
   1486         sbuf.append('\n');
   1487         sbuf.append(" PairwiseCiphers:");
   1488         for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) {
   1489             if (this.allowedPairwiseCiphers.get(pc)) {
   1490                 sbuf.append(" ");
   1491                 if (pc < PairwiseCipher.strings.length) {
   1492                     sbuf.append(PairwiseCipher.strings[pc]);
   1493                 } else {
   1494                     sbuf.append("??");
   1495                 }
   1496             }
   1497         }
   1498         sbuf.append('\n');
   1499         sbuf.append(" GroupCiphers:");
   1500         for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) {
   1501             if (this.allowedGroupCiphers.get(gc)) {
   1502                 sbuf.append(" ");
   1503                 if (gc < GroupCipher.strings.length) {
   1504                     sbuf.append(GroupCipher.strings[gc]);
   1505                 } else {
   1506                     sbuf.append("??");
   1507                 }
   1508             }
   1509         }
   1510         sbuf.append('\n').append(" PSK: ");
   1511         if (this.preSharedKey != null) {
   1512             sbuf.append('*');
   1513         }
   1514         sbuf.append("\nEnterprise config:\n");
   1515         sbuf.append(enterpriseConfig);
   1516 
   1517         sbuf.append("IP config:\n");
   1518         sbuf.append(mIpConfiguration.toString());
   1519 
   1520         if (mNetworkSelectionStatus.getNetworkSelectionBSSID() != null) {
   1521             sbuf.append(" networkSelectionBSSID="
   1522                     + mNetworkSelectionStatus.getNetworkSelectionBSSID());
   1523         }
   1524         long now_ms = System.currentTimeMillis();
   1525         if (mNetworkSelectionStatus.getDisableTime() != NetworkSelectionStatus
   1526                 .INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP) {
   1527             sbuf.append('\n');
   1528             long diff = now_ms - mNetworkSelectionStatus.getDisableTime();
   1529             if (diff <= 0) {
   1530                 sbuf.append(" blackListed since <incorrect>");
   1531             } else {
   1532                 sbuf.append(" blackListed: ").append(Long.toString(diff / 1000)).append("sec ");
   1533             }
   1534         }
   1535         if (creatorUid != 0) sbuf.append(" cuid=" + creatorUid);
   1536         if (creatorName != null) sbuf.append(" cname=" + creatorName);
   1537         if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
   1538         if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
   1539         sbuf.append(" lcuid=" + lastConnectUid);
   1540         sbuf.append(" userApproved=" + userApprovedAsString(userApproved));
   1541         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
   1542         sbuf.append(" ");
   1543 
   1544         if (this.lastConnected != 0) {
   1545             sbuf.append('\n');
   1546             long diff = now_ms - this.lastConnected;
   1547             if (diff <= 0) {
   1548                 sbuf.append("lastConnected since <incorrect>");
   1549             } else {
   1550                 sbuf.append("lastConnected: ").append(Long.toString(diff / 1000)).append("sec ");
   1551             }
   1552         }
   1553         if (this.lastConnectionFailure != 0) {
   1554             sbuf.append('\n');
   1555             long diff = now_ms - this.lastConnectionFailure;
   1556             if (diff <= 0) {
   1557                 sbuf.append("lastConnectionFailure since <incorrect> ");
   1558             } else {
   1559                 sbuf.append("lastConnectionFailure: ").append(Long.toString(diff / 1000));
   1560                 sbuf.append("sec ");
   1561             }
   1562         }
   1563         if (this.lastRoamingFailure != 0) {
   1564             sbuf.append('\n');
   1565             long diff = now_ms - this.lastRoamingFailure;
   1566             if (diff <= 0) {
   1567                 sbuf.append("lastRoamingFailure since <incorrect> ");
   1568             } else {
   1569                 sbuf.append("lastRoamingFailure: ").append(Long.toString(diff / 1000));
   1570                 sbuf.append("sec ");
   1571             }
   1572         }
   1573         sbuf.append("roamingFailureBlackListTimeMilli: ").
   1574                 append(Long.toString(this.roamingFailureBlackListTimeMilli));
   1575         sbuf.append('\n');
   1576         if (this.linkedConfigurations != null) {
   1577             for (String key : this.linkedConfigurations.keySet()) {
   1578                 sbuf.append(" linked: ").append(key);
   1579                 sbuf.append('\n');
   1580             }
   1581         }
   1582         sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
   1583         sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
   1584         sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
   1585         sbuf.append('\n');
   1586         sbuf.append("ticksLow: ").append(this.numTicksAtLowRSSI);
   1587         sbuf.append(" ticksBad: ").append(this.numTicksAtBadRSSI);
   1588         sbuf.append(" ticksNotHigh: ").append(this.numTicksAtNotHighRSSI);
   1589         sbuf.append('\n');
   1590         sbuf.append("triggeredJoin: ").append(this.numUserTriggeredJoinAttempts);
   1591         sbuf.append('\n');
   1592 
   1593         return sbuf.toString();
   1594     }
   1595 
   1596     /** {@hide} */
   1597     public String getPrintableSsid() {
   1598         if (SSID == null) return "";
   1599         final int length = SSID.length();
   1600         if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
   1601             return SSID.substring(1, length - 1);
   1602         }
   1603 
   1604         /** The ascii-encoded string format is P"<ascii-encoded-string>"
   1605          * The decoding is implemented in the supplicant for a newly configured
   1606          * network.
   1607          */
   1608         if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
   1609                 (SSID.charAt(length-1) == '"')) {
   1610             WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
   1611                     SSID.substring(2, length - 1));
   1612             return wifiSsid.toString();
   1613         }
   1614         return SSID;
   1615     }
   1616 
   1617     /** @hide **/
   1618     public static String userApprovedAsString(int userApproved) {
   1619         switch (userApproved) {
   1620             case USER_APPROVED:
   1621                 return "USER_APPROVED";
   1622             case USER_BANNED:
   1623                 return "USER_BANNED";
   1624             case USER_UNSPECIFIED:
   1625                 return "USER_UNSPECIFIED";
   1626             default:
   1627                 return "INVALID";
   1628         }
   1629     }
   1630 
   1631     /**
   1632      * Get an identifier for associating credentials with this config
   1633      * @param current configuration contains values for additional fields
   1634      *                that are not part of this configuration. Used
   1635      *                when a config with some fields is passed by an application.
   1636      * @throws IllegalStateException if config is invalid for key id generation
   1637      * @hide
   1638      */
   1639     public String getKeyIdForCredentials(WifiConfiguration current) {
   1640         String keyMgmt = null;
   1641 
   1642         try {
   1643             // Get current config details for fields that are not initialized
   1644             if (TextUtils.isEmpty(SSID)) SSID = current.SSID;
   1645             if (allowedKeyManagement.cardinality() == 0) {
   1646                 allowedKeyManagement = current.allowedKeyManagement;
   1647             }
   1648             if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
   1649                 keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
   1650             }
   1651             if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
   1652                 keyMgmt = KeyMgmt.strings[KeyMgmt.OSEN];
   1653             }
   1654             if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
   1655                 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
   1656             }
   1657 
   1658             if (TextUtils.isEmpty(keyMgmt)) {
   1659                 throw new IllegalStateException("Not an EAP network");
   1660             }
   1661 
   1662             return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" +
   1663                     trimStringForKeyId(enterpriseConfig.getKeyId(current != null ?
   1664                             current.enterpriseConfig : null));
   1665         } catch (NullPointerException e) {
   1666             throw new IllegalStateException("Invalid config details");
   1667         }
   1668     }
   1669 
   1670     private String trimStringForKeyId(String string) {
   1671         // Remove quotes and spaces
   1672         return string.replace("\"", "").replace(" ", "");
   1673     }
   1674 
   1675     private static BitSet readBitSet(Parcel src) {
   1676         int cardinality = src.readInt();
   1677 
   1678         BitSet set = new BitSet();
   1679         for (int i = 0; i < cardinality; i++) {
   1680             set.set(src.readInt());
   1681         }
   1682 
   1683         return set;
   1684     }
   1685 
   1686     private static void writeBitSet(Parcel dest, BitSet set) {
   1687         int nextSetBit = -1;
   1688 
   1689         dest.writeInt(set.cardinality());
   1690 
   1691         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) {
   1692             dest.writeInt(nextSetBit);
   1693         }
   1694     }
   1695 
   1696     /** @hide */
   1697     public int getAuthType() {
   1698         if (allowedKeyManagement.cardinality() > 1) {
   1699             throw new IllegalStateException("More than one auth type set");
   1700         }
   1701         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
   1702             return KeyMgmt.WPA_PSK;
   1703         } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
   1704             return KeyMgmt.WPA2_PSK;
   1705         } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
   1706             return KeyMgmt.WPA_EAP;
   1707         } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
   1708             return KeyMgmt.IEEE8021X;
   1709         }
   1710         return KeyMgmt.NONE;
   1711     }
   1712 
   1713     /* @hide
   1714      * Cache the config key, this seems useful as a speed up since a lot of
   1715      * lookups in the config store are done and based on this key.
   1716      */
   1717     String mCachedConfigKey;
   1718 
   1719     /** @hide
   1720      *  return the string used to calculate the hash in WifiConfigStore
   1721      *  and uniquely identify this WifiConfiguration
   1722      */
   1723     public String configKey(boolean allowCached) {
   1724         String key;
   1725         if (allowCached && mCachedConfigKey != null) {
   1726             key = mCachedConfigKey;
   1727         } else if (providerFriendlyName != null) {
   1728             key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
   1729             if (!shared) {
   1730                 key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
   1731             }
   1732         } else {
   1733             if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
   1734                 key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
   1735             } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
   1736                     allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
   1737                 key = SSID + KeyMgmt.strings[KeyMgmt.WPA_EAP];
   1738             } else if (wepKeys[0] != null) {
   1739                 key = SSID + "WEP";
   1740             } else {
   1741                 key = SSID + KeyMgmt.strings[KeyMgmt.NONE];
   1742             }
   1743             if (!shared) {
   1744                 key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
   1745             }
   1746             mCachedConfigKey = key;
   1747         }
   1748         return key;
   1749     }
   1750 
   1751     /** @hide
   1752      * get configKey, force calculating the config string
   1753      */
   1754     public String configKey() {
   1755         return configKey(false);
   1756     }
   1757 
   1758     /** @hide */
   1759     public IpConfiguration getIpConfiguration() {
   1760         return mIpConfiguration;
   1761     }
   1762 
   1763     /** @hide */
   1764     public void setIpConfiguration(IpConfiguration ipConfiguration) {
   1765         mIpConfiguration = ipConfiguration;
   1766     }
   1767 
   1768     /** @hide */
   1769     public StaticIpConfiguration getStaticIpConfiguration() {
   1770         return mIpConfiguration.getStaticIpConfiguration();
   1771     }
   1772 
   1773     /** @hide */
   1774     public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) {
   1775         mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration);
   1776     }
   1777 
   1778     /** @hide */
   1779     public IpConfiguration.IpAssignment getIpAssignment() {
   1780         return mIpConfiguration.ipAssignment;
   1781     }
   1782 
   1783     /** @hide */
   1784     public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
   1785         mIpConfiguration.ipAssignment = ipAssignment;
   1786     }
   1787 
   1788     /** @hide */
   1789     public IpConfiguration.ProxySettings getProxySettings() {
   1790         return mIpConfiguration.proxySettings;
   1791     }
   1792 
   1793     /** @hide */
   1794     public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
   1795         mIpConfiguration.proxySettings = proxySettings;
   1796     }
   1797 
   1798     /** @hide */
   1799     public ProxyInfo getHttpProxy() {
   1800         return mIpConfiguration.httpProxy;
   1801     }
   1802 
   1803     /** @hide */
   1804     public void setHttpProxy(ProxyInfo httpProxy) {
   1805         mIpConfiguration.httpProxy = httpProxy;
   1806     }
   1807 
   1808     /** @hide */
   1809     public void setProxy(ProxySettings settings, ProxyInfo proxy) {
   1810         mIpConfiguration.proxySettings = settings;
   1811         mIpConfiguration.httpProxy = proxy;
   1812     }
   1813 
   1814     /** Implement the Parcelable interface {@hide} */
   1815     public int describeContents() {
   1816         return 0;
   1817     }
   1818 
   1819     /** @hide */
   1820     public void setPasspointManagementObjectTree(String passpointManagementObjectTree) {
   1821         mPasspointManagementObjectTree = passpointManagementObjectTree;
   1822     }
   1823 
   1824     /** @hide */
   1825     public String getMoTree() {
   1826         return mPasspointManagementObjectTree;
   1827     }
   1828 
   1829     /** copy constructor {@hide} */
   1830     public WifiConfiguration(WifiConfiguration source) {
   1831         if (source != null) {
   1832             networkId = source.networkId;
   1833             status = source.status;
   1834             SSID = source.SSID;
   1835             BSSID = source.BSSID;
   1836             FQDN = source.FQDN;
   1837             roamingConsortiumIds = source.roamingConsortiumIds.clone();
   1838             providerFriendlyName = source.providerFriendlyName;
   1839             preSharedKey = source.preSharedKey;
   1840 
   1841             mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
   1842             apBand = source.apBand;
   1843             apChannel = source.apChannel;
   1844 
   1845             wepKeys = new String[4];
   1846             for (int i = 0; i < wepKeys.length; i++) {
   1847                 wepKeys[i] = source.wepKeys[i];
   1848             }
   1849 
   1850             wepTxKeyIndex = source.wepTxKeyIndex;
   1851             priority = source.priority;
   1852             hiddenSSID = source.hiddenSSID;
   1853             allowedKeyManagement   = (BitSet) source.allowedKeyManagement.clone();
   1854             allowedProtocols       = (BitSet) source.allowedProtocols.clone();
   1855             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
   1856             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
   1857             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
   1858             enterpriseConfig = new WifiEnterpriseConfig(source.enterpriseConfig);
   1859 
   1860             defaultGwMacAddress = source.defaultGwMacAddress;
   1861 
   1862             mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
   1863 
   1864             if ((source.linkedConfigurations != null)
   1865                     && (source.linkedConfigurations.size() > 0)) {
   1866                 linkedConfigurations = new HashMap<String, Integer>();
   1867                 linkedConfigurations.putAll(source.linkedConfigurations);
   1868             }
   1869             mCachedConfigKey = null; //force null configKey
   1870             selfAdded = source.selfAdded;
   1871             validatedInternetAccess = source.validatedInternetAccess;
   1872             ephemeral = source.ephemeral;
   1873             meteredHint = source.meteredHint;
   1874             useExternalScores = source.useExternalScores;
   1875             if (source.visibility != null) {
   1876                 visibility = new Visibility(source.visibility);
   1877             }
   1878 
   1879             lastFailure = source.lastFailure;
   1880             didSelfAdd = source.didSelfAdd;
   1881             lastConnectUid = source.lastConnectUid;
   1882             lastUpdateUid = source.lastUpdateUid;
   1883             creatorUid = source.creatorUid;
   1884             creatorName = source.creatorName;
   1885             lastUpdateName = source.lastUpdateName;
   1886             peerWifiConfiguration = source.peerWifiConfiguration;
   1887 
   1888             lastConnected = source.lastConnected;
   1889             lastDisconnected = source.lastDisconnected;
   1890             lastConnectionFailure = source.lastConnectionFailure;
   1891             lastRoamingFailure = source.lastRoamingFailure;
   1892             lastRoamingFailureReason = source.lastRoamingFailureReason;
   1893             roamingFailureBlackListTimeMilli = source.roamingFailureBlackListTimeMilli;
   1894             numScorerOverride = source.numScorerOverride;
   1895             numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork;
   1896             numAssociation = source.numAssociation;
   1897             numUserTriggeredWifiDisableLowRSSI = source.numUserTriggeredWifiDisableLowRSSI;
   1898             numUserTriggeredWifiDisableBadRSSI = source.numUserTriggeredWifiDisableBadRSSI;
   1899             numUserTriggeredWifiDisableNotHighRSSI = source.numUserTriggeredWifiDisableNotHighRSSI;
   1900             numTicksAtLowRSSI = source.numTicksAtLowRSSI;
   1901             numTicksAtBadRSSI = source.numTicksAtBadRSSI;
   1902             numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
   1903             numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
   1904             userApproved = source.userApproved;
   1905             numNoInternetAccessReports = source.numNoInternetAccessReports;
   1906             noInternetAccessExpected = source.noInternetAccessExpected;
   1907             creationTime = source.creationTime;
   1908             updateTime = source.updateTime;
   1909             shared = source.shared;
   1910         }
   1911     }
   1912 
   1913     /** Implement the Parcelable interface {@hide} */
   1914     @Override
   1915     public void writeToParcel(Parcel dest, int flags) {
   1916         dest.writeInt(networkId);
   1917         dest.writeInt(status);
   1918         mNetworkSelectionStatus.writeToParcel(dest);
   1919         dest.writeString(SSID);
   1920         dest.writeString(BSSID);
   1921         dest.writeInt(apBand);
   1922         dest.writeInt(apChannel);
   1923         dest.writeString(FQDN);
   1924         dest.writeString(providerFriendlyName);
   1925         dest.writeInt(roamingConsortiumIds.length);
   1926         for (long roamingConsortiumId : roamingConsortiumIds) {
   1927             dest.writeLong(roamingConsortiumId);
   1928         }
   1929         dest.writeString(preSharedKey);
   1930         for (String wepKey : wepKeys) {
   1931             dest.writeString(wepKey);
   1932         }
   1933         dest.writeInt(wepTxKeyIndex);
   1934         dest.writeInt(priority);
   1935         dest.writeInt(hiddenSSID ? 1 : 0);
   1936         dest.writeInt(requirePMF ? 1 : 0);
   1937         dest.writeString(updateIdentifier);
   1938 
   1939         writeBitSet(dest, allowedKeyManagement);
   1940         writeBitSet(dest, allowedProtocols);
   1941         writeBitSet(dest, allowedAuthAlgorithms);
   1942         writeBitSet(dest, allowedPairwiseCiphers);
   1943         writeBitSet(dest, allowedGroupCiphers);
   1944 
   1945         dest.writeParcelable(enterpriseConfig, flags);
   1946 
   1947         dest.writeParcelable(mIpConfiguration, flags);
   1948         dest.writeString(dhcpServer);
   1949         dest.writeString(defaultGwMacAddress);
   1950         dest.writeInt(selfAdded ? 1 : 0);
   1951         dest.writeInt(didSelfAdd ? 1 : 0);
   1952         dest.writeInt(validatedInternetAccess ? 1 : 0);
   1953         dest.writeInt(ephemeral ? 1 : 0);
   1954         dest.writeInt(meteredHint ? 1 : 0);
   1955         dest.writeInt(useExternalScores ? 1 : 0);
   1956         dest.writeInt(creatorUid);
   1957         dest.writeInt(lastConnectUid);
   1958         dest.writeInt(lastUpdateUid);
   1959         dest.writeString(creatorName);
   1960         dest.writeString(lastUpdateName);
   1961         dest.writeLong(lastConnectionFailure);
   1962         dest.writeLong(lastRoamingFailure);
   1963         dest.writeInt(lastRoamingFailureReason);
   1964         dest.writeLong(roamingFailureBlackListTimeMilli);
   1965         dest.writeInt(numScorerOverride);
   1966         dest.writeInt(numScorerOverrideAndSwitchedNetwork);
   1967         dest.writeInt(numAssociation);
   1968         dest.writeInt(numUserTriggeredWifiDisableLowRSSI);
   1969         dest.writeInt(numUserTriggeredWifiDisableBadRSSI);
   1970         dest.writeInt(numUserTriggeredWifiDisableNotHighRSSI);
   1971         dest.writeInt(numTicksAtLowRSSI);
   1972         dest.writeInt(numTicksAtBadRSSI);
   1973         dest.writeInt(numTicksAtNotHighRSSI);
   1974         dest.writeInt(numUserTriggeredJoinAttempts);
   1975         dest.writeInt(userApproved);
   1976         dest.writeInt(numNoInternetAccessReports);
   1977         dest.writeInt(noInternetAccessExpected ? 1 : 0);
   1978         dest.writeInt(shared ? 1 : 0);
   1979         dest.writeString(mPasspointManagementObjectTree);
   1980     }
   1981 
   1982     /** Implement the Parcelable interface {@hide} */
   1983     public static final Creator<WifiConfiguration> CREATOR =
   1984         new Creator<WifiConfiguration>() {
   1985             public WifiConfiguration createFromParcel(Parcel in) {
   1986                 WifiConfiguration config = new WifiConfiguration();
   1987                 config.networkId = in.readInt();
   1988                 config.status = in.readInt();
   1989                 config.mNetworkSelectionStatus.readFromParcel(in);
   1990                 config.SSID = in.readString();
   1991                 config.BSSID = in.readString();
   1992                 config.apBand = in.readInt();
   1993                 config.apChannel = in.readInt();
   1994                 config.FQDN = in.readString();
   1995                 config.providerFriendlyName = in.readString();
   1996                 int numRoamingConsortiumIds = in.readInt();
   1997                 config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
   1998                 for (int i = 0; i < numRoamingConsortiumIds; i++) {
   1999                     config.roamingConsortiumIds[i] = in.readLong();
   2000                 }
   2001                 config.preSharedKey = in.readString();
   2002                 for (int i = 0; i < config.wepKeys.length; i++) {
   2003                     config.wepKeys[i] = in.readString();
   2004                 }
   2005                 config.wepTxKeyIndex = in.readInt();
   2006                 config.priority = in.readInt();
   2007                 config.hiddenSSID = in.readInt() != 0;
   2008                 config.requirePMF = in.readInt() != 0;
   2009                 config.updateIdentifier = in.readString();
   2010 
   2011                 config.allowedKeyManagement   = readBitSet(in);
   2012                 config.allowedProtocols       = readBitSet(in);
   2013                 config.allowedAuthAlgorithms  = readBitSet(in);
   2014                 config.allowedPairwiseCiphers = readBitSet(in);
   2015                 config.allowedGroupCiphers    = readBitSet(in);
   2016 
   2017                 config.enterpriseConfig = in.readParcelable(null);
   2018                 config.mIpConfiguration = in.readParcelable(null);
   2019                 config.dhcpServer = in.readString();
   2020                 config.defaultGwMacAddress = in.readString();
   2021                 config.selfAdded = in.readInt() != 0;
   2022                 config.didSelfAdd = in.readInt() != 0;
   2023                 config.validatedInternetAccess = in.readInt() != 0;
   2024                 config.ephemeral = in.readInt() != 0;
   2025                 config.meteredHint = in.readInt() != 0;
   2026                 config.useExternalScores = in.readInt() != 0;
   2027                 config.creatorUid = in.readInt();
   2028                 config.lastConnectUid = in.readInt();
   2029                 config.lastUpdateUid = in.readInt();
   2030                 config.creatorName = in.readString();
   2031                 config.lastUpdateName = in.readString();
   2032                 config.lastConnectionFailure = in.readLong();
   2033                 config.lastRoamingFailure = in.readLong();
   2034                 config.lastRoamingFailureReason = in.readInt();
   2035                 config.roamingFailureBlackListTimeMilli = in.readLong();
   2036                 config.numScorerOverride = in.readInt();
   2037                 config.numScorerOverrideAndSwitchedNetwork = in.readInt();
   2038                 config.numAssociation = in.readInt();
   2039                 config.numUserTriggeredWifiDisableLowRSSI = in.readInt();
   2040                 config.numUserTriggeredWifiDisableBadRSSI = in.readInt();
   2041                 config.numUserTriggeredWifiDisableNotHighRSSI = in.readInt();
   2042                 config.numTicksAtLowRSSI = in.readInt();
   2043                 config.numTicksAtBadRSSI = in.readInt();
   2044                 config.numTicksAtNotHighRSSI = in.readInt();
   2045                 config.numUserTriggeredJoinAttempts = in.readInt();
   2046                 config.userApproved = in.readInt();
   2047                 config.numNoInternetAccessReports = in.readInt();
   2048                 config.noInternetAccessExpected = in.readInt() != 0;
   2049                 config.shared = in.readInt() != 0;
   2050                 config.mPasspointManagementObjectTree = in.readString();
   2051                 return config;
   2052             }
   2053 
   2054             public WifiConfiguration[] newArray(int size) {
   2055                 return new WifiConfiguration[size];
   2056             }
   2057         };
   2058 
   2059     /**
   2060      * Serializes the object for backup
   2061      * @hide
   2062      */
   2063     public byte[] getBytesForBackup() throws IOException {
   2064         ByteArrayOutputStream baos = new ByteArrayOutputStream();
   2065         DataOutputStream out = new DataOutputStream(baos);
   2066 
   2067         out.writeInt(BACKUP_VERSION);
   2068         BackupUtils.writeString(out, SSID);
   2069         out.writeInt(apBand);
   2070         out.writeInt(apChannel);
   2071         BackupUtils.writeString(out, preSharedKey);
   2072         out.writeInt(getAuthType());
   2073         return baos.toByteArray();
   2074     }
   2075 
   2076     /**
   2077      * Deserializes a byte array into the WiFiConfiguration Object
   2078      * @hide
   2079      */
   2080     public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException,
   2081             BackupUtils.BadVersionException {
   2082         WifiConfiguration config = new WifiConfiguration();
   2083         int version = in.readInt();
   2084         if (version < 1 || version > BACKUP_VERSION) {
   2085             throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
   2086         }
   2087 
   2088         if (version == 1) return null; // Version 1 is a bad dataset.
   2089 
   2090         config.SSID = BackupUtils.readString(in);
   2091         config.apBand = in.readInt();
   2092         config.apChannel = in.readInt();
   2093         config.preSharedKey = BackupUtils.readString(in);
   2094         config.allowedKeyManagement.set(in.readInt());
   2095         return config;
   2096     }
   2097 }
   2098