Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2010 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 com.android.settings.wifi;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.net.IpConfiguration;
     22 import android.net.IpConfiguration.IpAssignment;
     23 import android.net.IpConfiguration.ProxySettings;
     24 import android.net.LinkAddress;
     25 import android.net.NetworkInfo.DetailedState;
     26 import android.net.NetworkUtils;
     27 import android.net.ProxyInfo;
     28 import android.net.StaticIpConfiguration;
     29 import android.net.Uri;
     30 import android.net.wifi.WifiConfiguration;
     31 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
     32 import android.net.wifi.WifiConfiguration.KeyMgmt;
     33 import android.net.wifi.WifiEnterpriseConfig;
     34 import android.net.wifi.WifiEnterpriseConfig.Eap;
     35 import android.net.wifi.WifiEnterpriseConfig.Phase2;
     36 import android.net.wifi.WifiInfo;
     37 import android.os.Handler;
     38 import android.os.UserManager;
     39 import android.security.Credentials;
     40 import android.security.KeyStore;
     41 import android.support.annotation.VisibleForTesting;
     42 import android.text.Editable;
     43 import android.text.InputType;
     44 import android.text.TextUtils;
     45 import android.text.TextWatcher;
     46 import android.util.Log;
     47 import android.view.KeyEvent;
     48 import android.view.View;
     49 import android.view.ViewGroup;
     50 import android.view.inputmethod.EditorInfo;
     51 import android.widget.AdapterView;
     52 import android.widget.ArrayAdapter;
     53 import android.widget.Button;
     54 import android.widget.CheckBox;
     55 import android.widget.CompoundButton;
     56 import android.widget.CompoundButton.OnCheckedChangeListener;
     57 import android.widget.EditText;
     58 import android.widget.ScrollView;
     59 import android.widget.Spinner;
     60 import android.widget.TextView;
     61 
     62 import com.android.settings.ProxySelector;
     63 import com.android.settings.R;
     64 import com.android.settingslib.Utils;
     65 import com.android.settingslib.utils.ThreadUtils;
     66 import com.android.settingslib.wifi.AccessPoint;
     67 
     68 import java.net.Inet4Address;
     69 import java.net.InetAddress;
     70 import java.util.ArrayList;
     71 import java.util.Arrays;
     72 import java.util.Iterator;
     73 
     74 /**
     75  * The class for allowing UIs like {@link WifiDialog} and {@link WifiConfigUiBase} to
     76  * share the logic for controlling buttons, text fields, etc.
     77  */
     78 public class WifiConfigController implements TextWatcher,
     79         AdapterView.OnItemSelectedListener, OnCheckedChangeListener,
     80         TextView.OnEditorActionListener, View.OnKeyListener {
     81     private static final String TAG = "WifiConfigController";
     82 
     83     private static final String SYSTEM_CA_STORE_PATH = "/system/etc/security/cacerts";
     84 
     85     private final WifiConfigUiBase mConfigUi;
     86     private final View mView;
     87     private final AccessPoint mAccessPoint;
     88 
     89     /* This value comes from "wifi_ip_settings" resource array */
     90     private static final int DHCP = 0;
     91     private static final int STATIC_IP = 1;
     92 
     93     /* Constants used for referring to the hidden state of a network. */
     94     public static final int HIDDEN_NETWORK = 1;
     95     public static final int NOT_HIDDEN_NETWORK = 0;
     96 
     97     /* These values come from "wifi_proxy_settings" resource array */
     98     public static final int PROXY_NONE = 0;
     99     public static final int PROXY_STATIC = 1;
    100     public static final int PROXY_PAC = 2;
    101 
    102     /* These values come from "wifi_eap_method" resource array */
    103     public static final int WIFI_EAP_METHOD_PEAP = 0;
    104     public static final int WIFI_EAP_METHOD_TLS  = 1;
    105     public static final int WIFI_EAP_METHOD_TTLS = 2;
    106     public static final int WIFI_EAP_METHOD_PWD  = 3;
    107     public static final int WIFI_EAP_METHOD_SIM  = 4;
    108     public static final int WIFI_EAP_METHOD_AKA  = 5;
    109     public static final int WIFI_EAP_METHOD_AKA_PRIME  = 6;
    110 
    111     /* These values come from "wifi_peap_phase2_entries" resource array */
    112     public static final int WIFI_PEAP_PHASE2_NONE       = 0;
    113     public static final int WIFI_PEAP_PHASE2_MSCHAPV2   = 1;
    114     public static final int WIFI_PEAP_PHASE2_GTC        = 2;
    115     public static final int WIFI_PEAP_PHASE2_SIM        = 3;
    116     public static final int WIFI_PEAP_PHASE2_AKA        = 4;
    117     public static final int WIFI_PEAP_PHASE2_AKA_PRIME  = 5;
    118 
    119 
    120     /* Phase2 methods supported by PEAP are limited */
    121     private final ArrayAdapter<String> mPhase2PeapAdapter;
    122     /* Full list of phase2 methods */
    123     private final ArrayAdapter<String> mPhase2FullAdapter;
    124 
    125     // e.g. AccessPoint.SECURITY_NONE
    126     private int mAccessPointSecurity;
    127     private TextView mPasswordView;
    128 
    129     private String mUnspecifiedCertString;
    130     private String mMultipleCertSetString;
    131     private String mUseSystemCertsString;
    132     private String mDoNotProvideEapUserCertString;
    133     private String mDoNotValidateEapServerString;
    134 
    135     private ScrollView mDialogContainer;
    136     private Spinner mSecuritySpinner;
    137     private Spinner mEapMethodSpinner;
    138     private Spinner mEapCaCertSpinner;
    139     private TextView mEapDomainView;
    140     private Spinner mPhase2Spinner;
    141     // Associated with mPhase2Spinner, one of mPhase2FullAdapter or mPhase2PeapAdapter
    142     private ArrayAdapter<String> mPhase2Adapter;
    143     private Spinner mEapUserCertSpinner;
    144     private TextView mEapIdentityView;
    145     private TextView mEapAnonymousView;
    146 
    147     private Spinner mIpSettingsSpinner;
    148     private TextView mIpAddressView;
    149     private TextView mGatewayView;
    150     private TextView mNetworkPrefixLengthView;
    151     private TextView mDns1View;
    152     private TextView mDns2View;
    153 
    154     private Spinner mProxySettingsSpinner;
    155     private Spinner mMeteredSettingsSpinner;
    156     private Spinner mHiddenSettingsSpinner;
    157     private TextView mHiddenWarningView;
    158     private TextView mProxyHostView;
    159     private TextView mProxyPortView;
    160     private TextView mProxyExclusionListView;
    161     private TextView mProxyPacView;
    162     private CheckBox mSharedCheckBox;
    163 
    164     private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED;
    165     private ProxySettings mProxySettings = ProxySettings.UNASSIGNED;
    166     private ProxyInfo mHttpProxy = null;
    167     private StaticIpConfiguration mStaticIpConfiguration = null;
    168 
    169     private String[] mLevels;
    170     private int mMode;
    171     private TextView mSsidView;
    172 
    173     private Context mContext;
    174 
    175     public WifiConfigController(WifiConfigUiBase parent, View view, AccessPoint accessPoint,
    176             int mode) {
    177         mConfigUi = parent;
    178 
    179         mView = view;
    180         mAccessPoint = accessPoint;
    181         mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE :
    182                 accessPoint.getSecurity();
    183         mMode = mode;
    184 
    185         mContext = mConfigUi.getContext();
    186         final Resources res = mContext.getResources();
    187 
    188         mLevels = res.getStringArray(R.array.wifi_signal);
    189         if (Utils.isWifiOnly(mContext) || !mContext.getResources().getBoolean(
    190                 com.android.internal.R.bool.config_eap_sim_based_auth_supported)) {
    191             mPhase2PeapAdapter = new ArrayAdapter<String>(
    192                     mContext, android.R.layout.simple_spinner_item,
    193                     res.getStringArray(R.array.wifi_peap_phase2_entries));
    194         } else {
    195             mPhase2PeapAdapter = new ArrayAdapter<String>(
    196                     mContext, android.R.layout.simple_spinner_item,
    197                     res.getStringArray(R.array.wifi_peap_phase2_entries_with_sim_auth));
    198         }
    199         mPhase2PeapAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    200 
    201         mPhase2FullAdapter = new ArrayAdapter<String>(
    202                 mContext, android.R.layout.simple_spinner_item,
    203                 res.getStringArray(R.array.wifi_phase2_entries));
    204         mPhase2FullAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    205 
    206         mUnspecifiedCertString = mContext.getString(R.string.wifi_unspecified);
    207         mMultipleCertSetString = mContext.getString(R.string.wifi_multiple_cert_added);
    208         mUseSystemCertsString = mContext.getString(R.string.wifi_use_system_certs);
    209         mDoNotProvideEapUserCertString =
    210             mContext.getString(R.string.wifi_do_not_provide_eap_user_cert);
    211         mDoNotValidateEapServerString =
    212             mContext.getString(R.string.wifi_do_not_validate_eap_server);
    213 
    214         mDialogContainer = mView.findViewById(R.id.dialog_scrollview);
    215         mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
    216         mIpSettingsSpinner.setOnItemSelectedListener(this);
    217         mProxySettingsSpinner = (Spinner) mView.findViewById(R.id.proxy_settings);
    218         mProxySettingsSpinner.setOnItemSelectedListener(this);
    219         mSharedCheckBox = (CheckBox) mView.findViewById(R.id.shared);
    220         mMeteredSettingsSpinner = mView.findViewById(R.id.metered_settings);
    221         mHiddenSettingsSpinner = mView.findViewById(R.id.hidden_settings);
    222         mHiddenSettingsSpinner.setOnItemSelectedListener(this);
    223         mHiddenWarningView = mView.findViewById(R.id.hidden_settings_warning);
    224         mHiddenWarningView.setVisibility(
    225                 mHiddenSettingsSpinner.getSelectedItemPosition() == NOT_HIDDEN_NETWORK
    226                         ? View.GONE
    227                         : View.VISIBLE);
    228 
    229         if (mAccessPoint == null) { // new network
    230             mConfigUi.setTitle(R.string.wifi_add_network);
    231 
    232             mSsidView = (TextView) mView.findViewById(R.id.ssid);
    233             mSsidView.addTextChangedListener(this);
    234             mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security));
    235             mSecuritySpinner.setOnItemSelectedListener(this);
    236             mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
    237 
    238             showIpConfigFields();
    239             showProxyFields();
    240             mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE);
    241             // Hidden option can be changed only when the user adds a network manually.
    242             mView.findViewById(R.id.hidden_settings_field).setVisibility(View.VISIBLE);
    243             ((CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox))
    244                     .setOnCheckedChangeListener(this);
    245 
    246             mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
    247         } else {
    248             if (!mAccessPoint.isPasspointConfig()) {
    249                 mConfigUi.setTitle(mAccessPoint.getSsid());
    250             } else {
    251                 mConfigUi.setTitle(mAccessPoint.getConfigName());
    252             }
    253 
    254             ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
    255 
    256             boolean showAdvancedFields = false;
    257             if (mAccessPoint.isSaved()) {
    258                 WifiConfiguration config = mAccessPoint.getConfig();
    259                 mMeteredSettingsSpinner.setSelection(config.meteredOverride);
    260                 mHiddenSettingsSpinner.setSelection(config.hiddenSSID
    261                         ? HIDDEN_NETWORK
    262                         : NOT_HIDDEN_NETWORK);
    263                 if (config.getIpAssignment() == IpAssignment.STATIC) {
    264                     mIpSettingsSpinner.setSelection(STATIC_IP);
    265                     showAdvancedFields = true;
    266                     // Display IP address.
    267                     StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
    268                     if (staticConfig != null && staticConfig.ipAddress != null) {
    269                         addRow(group, R.string.wifi_ip_address,
    270                                 staticConfig.ipAddress.getAddress().getHostAddress());
    271                     }
    272                 } else {
    273                     mIpSettingsSpinner.setSelection(DHCP);
    274                 }
    275 
    276                 mSharedCheckBox.setEnabled(config.shared);
    277                 if (!config.shared) {
    278                     showAdvancedFields = true;
    279                 }
    280 
    281                 if (config.getProxySettings() == ProxySettings.STATIC) {
    282                     mProxySettingsSpinner.setSelection(PROXY_STATIC);
    283                     showAdvancedFields = true;
    284                 } else if (config.getProxySettings() == ProxySettings.PAC) {
    285                     mProxySettingsSpinner.setSelection(PROXY_PAC);
    286                     showAdvancedFields = true;
    287                 } else {
    288                     mProxySettingsSpinner.setSelection(PROXY_NONE);
    289                 }
    290                 if (config != null && config.isPasspoint()) {
    291                     addRow(group, R.string.passpoint_label,
    292                             String.format(mContext.getString(R.string.passpoint_content),
    293                             config.providerFriendlyName));
    294                 }
    295             }
    296 
    297             if ((!mAccessPoint.isSaved() && !mAccessPoint.isActive()
    298                     && !mAccessPoint.isPasspointConfig())
    299                     || mMode != WifiConfigUiBase.MODE_VIEW) {
    300                 showSecurityFields();
    301                 showIpConfigFields();
    302                 showProxyFields();
    303                 final CheckBox advancedTogglebox =
    304                         (CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox);
    305                 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(
    306                         mAccessPoint.isCarrierAp() ? View.GONE : View.VISIBLE);
    307                 advancedTogglebox.setOnCheckedChangeListener(this);
    308                 advancedTogglebox.setChecked(showAdvancedFields);
    309                 mView.findViewById(R.id.wifi_advanced_fields)
    310                         .setVisibility(showAdvancedFields ? View.VISIBLE : View.GONE);
    311                 if (mAccessPoint.isCarrierAp()) {
    312                     addRow(group, R.string.wifi_carrier_connect,
    313                             String.format(mContext.getString(R.string.wifi_carrier_content),
    314                             mAccessPoint.getCarrierName()));
    315                 }
    316             }
    317 
    318             if (mMode == WifiConfigUiBase.MODE_MODIFY) {
    319                 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
    320             } else if (mMode == WifiConfigUiBase.MODE_CONNECT) {
    321                 mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
    322             } else {
    323                 final DetailedState state = mAccessPoint.getDetailedState();
    324                 final String signalLevel = getSignalString();
    325 
    326                 if ((state == null || state == DetailedState.DISCONNECTED) && signalLevel != null) {
    327                     mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
    328                 } else {
    329                     if (state != null) {
    330                         boolean isEphemeral = mAccessPoint.isEphemeral();
    331                         WifiConfiguration config = mAccessPoint.getConfig();
    332                         String providerFriendlyName = null;
    333                         if (config != null && config.isPasspoint()) {
    334                             providerFriendlyName = config.providerFriendlyName;
    335                         }
    336                         String summary = AccessPoint.getSummary(
    337                                 mConfigUi.getContext(), state, isEphemeral, providerFriendlyName);
    338                         addRow(group, R.string.wifi_status, summary);
    339                     }
    340 
    341                     if (signalLevel != null) {
    342                         addRow(group, R.string.wifi_signal, signalLevel);
    343                     }
    344 
    345                     WifiInfo info = mAccessPoint.getInfo();
    346                     if (info != null && info.getLinkSpeed() != -1) {
    347                         addRow(group, R.string.wifi_speed, String.format(
    348                                 res.getString(R.string.link_speed), info.getLinkSpeed()));
    349                     }
    350 
    351                     if (info != null && info.getFrequency() != -1) {
    352                         final int frequency = info.getFrequency();
    353                         String band = null;
    354 
    355                         if (frequency >= AccessPoint.LOWER_FREQ_24GHZ
    356                                 && frequency < AccessPoint.HIGHER_FREQ_24GHZ) {
    357                             band = res.getString(R.string.wifi_band_24ghz);
    358                         } else if (frequency >= AccessPoint.LOWER_FREQ_5GHZ
    359                                 && frequency < AccessPoint.HIGHER_FREQ_5GHZ) {
    360                             band = res.getString(R.string.wifi_band_5ghz);
    361                         } else {
    362                             Log.e(TAG, "Unexpected frequency " + frequency);
    363                         }
    364                         if (band != null) {
    365                             addRow(group, R.string.wifi_frequency, band);
    366                         }
    367                     }
    368 
    369                     addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
    370                     mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
    371                 }
    372                 if (mAccessPoint.isSaved() || mAccessPoint.isActive()
    373                         || mAccessPoint.isPasspointConfig()) {
    374                     mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
    375                 }
    376             }
    377         }
    378 
    379         if (!isSplitSystemUser()) {
    380             mSharedCheckBox.setVisibility(View.GONE);
    381         }
    382 
    383         mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel));
    384         if (mConfigUi.getSubmitButton() != null) {
    385             enableSubmitIfAppropriate();
    386         }
    387 
    388         // After done view show and hide, request focus from parent view
    389         mView.findViewById(R.id.l_wifidialog).requestFocus();
    390     }
    391 
    392     @VisibleForTesting
    393     boolean isSplitSystemUser() {
    394         final UserManager userManager =
    395                 (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    396         return userManager.isSplitSystemUser();
    397     }
    398 
    399     private void addRow(ViewGroup group, int name, String value) {
    400         View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false);
    401         ((TextView) row.findViewById(R.id.name)).setText(name);
    402         ((TextView) row.findViewById(R.id.value)).setText(value);
    403         group.addView(row);
    404     }
    405 
    406     @VisibleForTesting
    407     String getSignalString() {
    408         if (!mAccessPoint.isReachable()) {
    409             return null;
    410         }
    411         final int level = mAccessPoint.getLevel();
    412 
    413         return (level > -1 && level < mLevels.length) ? mLevels[level] : null;
    414     }
    415 
    416     void hideForgetButton() {
    417         Button forget = mConfigUi.getForgetButton();
    418         if (forget == null) return;
    419 
    420         forget.setVisibility(View.GONE);
    421     }
    422 
    423     void hideSubmitButton() {
    424         Button submit = mConfigUi.getSubmitButton();
    425         if (submit == null) return;
    426 
    427         submit.setVisibility(View.GONE);
    428     }
    429 
    430     /* show submit button if password, ip and proxy settings are valid */
    431     void enableSubmitIfAppropriate() {
    432         Button submit = mConfigUi.getSubmitButton();
    433         if (submit == null) return;
    434 
    435         submit.setEnabled(isSubmittable());
    436     }
    437 
    438     boolean isValidPsk(String password) {
    439         if (password.length() == 64 && password.matches("[0-9A-Fa-f]{64}")) {
    440             return true;
    441         } else if (password.length() >= 8 && password.length() <= 63) {
    442             return true;
    443         }
    444         return false;
    445     }
    446 
    447     boolean isSubmittable() {
    448         boolean enabled = false;
    449         boolean passwordInvalid = false;
    450         if (mPasswordView != null
    451                 && ((mAccessPointSecurity == AccessPoint.SECURITY_WEP
    452                         && mPasswordView.length() == 0)
    453                     || (mAccessPointSecurity == AccessPoint.SECURITY_PSK
    454                            && !isValidPsk(mPasswordView.getText().toString())))) {
    455             passwordInvalid = true;
    456         }
    457         if ((mSsidView != null && mSsidView.length() == 0)
    458                 // If Accesspoint is not saved, apply passwordInvalid check
    459                 || ((mAccessPoint == null || !mAccessPoint.isSaved()) && passwordInvalid
    460                 // If AccessPoint is saved (modifying network) and password is changed, apply
    461                 // Invalid password check
    462                 || mAccessPoint != null && mAccessPoint.isSaved() && passwordInvalid
    463                     && mPasswordView.length() > 0)) {
    464             enabled = false;
    465         } else {
    466             enabled = ipAndProxyFieldsAreValid();
    467         }
    468         if (mEapCaCertSpinner != null
    469                 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) {
    470             String caCertSelection = (String) mEapCaCertSpinner.getSelectedItem();
    471             if (caCertSelection.equals(mUnspecifiedCertString)) {
    472                 // Disallow submit if the user has not selected a CA certificate for an EAP network
    473                 // configuration.
    474                 enabled = false;
    475             }
    476             if (caCertSelection.equals(mUseSystemCertsString)
    477                     && mEapDomainView != null
    478                     && mView.findViewById(R.id.l_domain).getVisibility() != View.GONE
    479                     && TextUtils.isEmpty(mEapDomainView.getText().toString())) {
    480                 // Disallow submit if the user chooses to use system certificates for EAP server
    481                 // validation, but does not provide a domain.
    482                 enabled = false;
    483             }
    484         }
    485         if (mEapUserCertSpinner != null
    486                 && mView.findViewById(R.id.l_user_cert).getVisibility() != View.GONE
    487                 && ((String) mEapUserCertSpinner.getSelectedItem())
    488                        .equals(mUnspecifiedCertString)) {
    489             // Disallow submit if the user has not selected a user certificate for an EAP network
    490             // configuration.
    491             enabled = false;
    492         }
    493         return enabled;
    494     }
    495 
    496     void showWarningMessagesIfAppropriate() {
    497         mView.findViewById(R.id.no_ca_cert_warning).setVisibility(View.GONE);
    498         mView.findViewById(R.id.no_domain_warning).setVisibility(View.GONE);
    499         mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.GONE);
    500 
    501         if (mSsidView != null) {
    502             final String ssid = mSsidView.getText().toString();
    503             if (WifiUtils.isSSIDTooLong(ssid)) {
    504                 mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE);
    505             }
    506         }
    507         if (mEapCaCertSpinner != null
    508                 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) {
    509             String caCertSelection = (String) mEapCaCertSpinner.getSelectedItem();
    510             if (caCertSelection.equals(mDoNotValidateEapServerString)) {
    511                 // Display warning if user chooses not to validate the EAP server with a
    512                 // user-supplied CA certificate in an EAP network configuration.
    513                 mView.findViewById(R.id.no_ca_cert_warning).setVisibility(View.VISIBLE);
    514             }
    515             if (caCertSelection.equals(mUseSystemCertsString)
    516                     && mEapDomainView != null
    517                     && mView.findViewById(R.id.l_domain).getVisibility() != View.GONE
    518                     && TextUtils.isEmpty(mEapDomainView.getText().toString())) {
    519                 // Display warning if user chooses to use pre-installed public CA certificates
    520                 // without restricting the server domain that these certificates can be used to
    521                 // validate.
    522                 mView.findViewById(R.id.no_domain_warning).setVisibility(View.VISIBLE);
    523             }
    524         }
    525     }
    526 
    527     public WifiConfiguration getConfig() {
    528         if (mMode == WifiConfigUiBase.MODE_VIEW) {
    529             return null;
    530         }
    531 
    532         WifiConfiguration config = new WifiConfiguration();
    533 
    534         if (mAccessPoint == null) {
    535             config.SSID = AccessPoint.convertToQuotedString(
    536                     mSsidView.getText().toString());
    537             // If the user adds a network manually, assume that it is hidden.
    538             config.hiddenSSID = mHiddenSettingsSpinner.getSelectedItemPosition() == HIDDEN_NETWORK;
    539         } else if (!mAccessPoint.isSaved()) {
    540             config.SSID = AccessPoint.convertToQuotedString(
    541                     mAccessPoint.getSsidStr());
    542         } else {
    543             config.networkId = mAccessPoint.getConfig().networkId;
    544             config.hiddenSSID = mAccessPoint.getConfig().hiddenSSID;
    545         }
    546 
    547         config.shared = mSharedCheckBox.isChecked();
    548 
    549         switch (mAccessPointSecurity) {
    550             case AccessPoint.SECURITY_NONE:
    551                 config.allowedKeyManagement.set(KeyMgmt.NONE);
    552                 break;
    553 
    554             case AccessPoint.SECURITY_WEP:
    555                 config.allowedKeyManagement.set(KeyMgmt.NONE);
    556                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
    557                 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
    558                 if (mPasswordView.length() != 0) {
    559                     int length = mPasswordView.length();
    560                     String password = mPasswordView.getText().toString();
    561                     // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
    562                     if ((length == 10 || length == 26 || length == 58)
    563                             && password.matches("[0-9A-Fa-f]*")) {
    564                         config.wepKeys[0] = password;
    565                     } else {
    566                         config.wepKeys[0] = '"' + password + '"';
    567                     }
    568                 }
    569                 break;
    570 
    571             case AccessPoint.SECURITY_PSK:
    572                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
    573                 if (mPasswordView.length() != 0) {
    574                     String password = mPasswordView.getText().toString();
    575                     if (password.matches("[0-9A-Fa-f]{64}")) {
    576                         config.preSharedKey = password;
    577                     } else {
    578                         config.preSharedKey = '"' + password + '"';
    579                     }
    580                 }
    581                 break;
    582 
    583             case AccessPoint.SECURITY_EAP:
    584                 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
    585                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
    586                 config.enterpriseConfig = new WifiEnterpriseConfig();
    587                 int eapMethod = mEapMethodSpinner.getSelectedItemPosition();
    588                 int phase2Method = mPhase2Spinner.getSelectedItemPosition();
    589                 config.enterpriseConfig.setEapMethod(eapMethod);
    590                 switch (eapMethod) {
    591                     case Eap.PEAP:
    592                         // PEAP supports limited phase2 values
    593                         // Map the index from the mPhase2PeapAdapter to the one used
    594                         // by the API which has the full list of PEAP methods.
    595                         switch(phase2Method) {
    596                             case WIFI_PEAP_PHASE2_NONE:
    597                                 config.enterpriseConfig.setPhase2Method(Phase2.NONE);
    598                                 break;
    599                             case WIFI_PEAP_PHASE2_MSCHAPV2:
    600                                 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
    601                                 break;
    602                             case WIFI_PEAP_PHASE2_GTC:
    603                                 config.enterpriseConfig.setPhase2Method(Phase2.GTC);
    604                                 break;
    605                             case WIFI_PEAP_PHASE2_SIM:
    606                                 config.enterpriseConfig.setPhase2Method(Phase2.SIM);
    607                                 break;
    608                             case WIFI_PEAP_PHASE2_AKA:
    609                                 config.enterpriseConfig.setPhase2Method(Phase2.AKA);
    610                                 break;
    611                             case WIFI_PEAP_PHASE2_AKA_PRIME:
    612                                 config.enterpriseConfig.setPhase2Method(Phase2.AKA_PRIME);
    613                                 break;
    614                             default:
    615                                 Log.e(TAG, "Unknown phase2 method" + phase2Method);
    616                                 break;
    617                         }
    618                         break;
    619                     default:
    620                         // The default index from mPhase2FullAdapter maps to the API
    621                         config.enterpriseConfig.setPhase2Method(phase2Method);
    622                         break;
    623                 }
    624 
    625                 String caCert = (String) mEapCaCertSpinner.getSelectedItem();
    626                 config.enterpriseConfig.setCaCertificateAliases(null);
    627                 config.enterpriseConfig.setCaPath(null);
    628                 config.enterpriseConfig.setDomainSuffixMatch(mEapDomainView.getText().toString());
    629                 if (caCert.equals(mUnspecifiedCertString)
    630                         || caCert.equals(mDoNotValidateEapServerString)) {
    631                     // ca_cert already set to null, so do nothing.
    632                 } else if (caCert.equals(mUseSystemCertsString)) {
    633                     config.enterpriseConfig.setCaPath(SYSTEM_CA_STORE_PATH);
    634                 } else if (caCert.equals(mMultipleCertSetString)) {
    635                     if (mAccessPoint != null) {
    636                         if (!mAccessPoint.isSaved()) {
    637                             Log.e(TAG, "Multiple certs can only be set "
    638                                     + "when editing saved network");
    639                         }
    640                         config.enterpriseConfig.setCaCertificateAliases(
    641                                 mAccessPoint
    642                                         .getConfig()
    643                                         .enterpriseConfig
    644                                         .getCaCertificateAliases());
    645                     }
    646                 } else {
    647                     config.enterpriseConfig.setCaCertificateAliases(new String[] {caCert});
    648                 }
    649 
    650                 // ca_cert or ca_path should not both be non-null, since we only intend to let
    651                 // the use either their own certificate, or the system certificates, not both.
    652                 // The variable that is not used must explicitly be set to null, so that a
    653                 // previously-set value on a saved configuration will be erased on an update.
    654                 if (config.enterpriseConfig.getCaCertificateAliases() != null
    655                         && config.enterpriseConfig.getCaPath() != null) {
    656                     Log.e(TAG, "ca_cert ("
    657                             + config.enterpriseConfig.getCaCertificateAliases()
    658                             + ") and ca_path ("
    659                             + config.enterpriseConfig.getCaPath()
    660                             + ") should not both be non-null");
    661                 }
    662 
    663                 String clientCert = (String) mEapUserCertSpinner.getSelectedItem();
    664                 if (clientCert.equals(mUnspecifiedCertString)
    665                         || clientCert.equals(mDoNotProvideEapUserCertString)) {
    666                     // Note: |clientCert| should not be able to take the value |unspecifiedCert|,
    667                     // since we prevent such configurations from being saved.
    668                     clientCert = "";
    669                 }
    670                 config.enterpriseConfig.setClientCertificateAlias(clientCert);
    671                 if (eapMethod == Eap.SIM || eapMethod == Eap.AKA || eapMethod == Eap.AKA_PRIME) {
    672                     config.enterpriseConfig.setIdentity("");
    673                     config.enterpriseConfig.setAnonymousIdentity("");
    674                 } else if (eapMethod == Eap.PWD) {
    675                     config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString());
    676                     config.enterpriseConfig.setAnonymousIdentity("");
    677                 } else {
    678                     config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString());
    679                     config.enterpriseConfig.setAnonymousIdentity(
    680                             mEapAnonymousView.getText().toString());
    681                 }
    682 
    683                 if (mPasswordView.isShown()) {
    684                     // For security reasons, a previous password is not displayed to user.
    685                     // Update only if it has been changed.
    686                     if (mPasswordView.length() > 0) {
    687                         config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
    688                     }
    689                 } else {
    690                     // clear password
    691                     config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
    692                 }
    693                 break;
    694             default:
    695                 return null;
    696         }
    697 
    698         config.setIpConfiguration(
    699                 new IpConfiguration(mIpAssignment, mProxySettings,
    700                                     mStaticIpConfiguration, mHttpProxy));
    701         if (mMeteredSettingsSpinner != null) {
    702             config.meteredOverride = mMeteredSettingsSpinner.getSelectedItemPosition();
    703         }
    704 
    705         return config;
    706     }
    707 
    708     private boolean ipAndProxyFieldsAreValid() {
    709         mIpAssignment =
    710                 (mIpSettingsSpinner != null
    711                     && mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP)
    712                 ? IpAssignment.STATIC
    713                 : IpAssignment.DHCP;
    714 
    715         if (mIpAssignment == IpAssignment.STATIC) {
    716             mStaticIpConfiguration = new StaticIpConfiguration();
    717             int result = validateIpConfigFields(mStaticIpConfiguration);
    718             if (result != 0) {
    719                 return false;
    720             }
    721         }
    722 
    723         final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition();
    724         mProxySettings = ProxySettings.NONE;
    725         mHttpProxy = null;
    726         if (selectedPosition == PROXY_STATIC && mProxyHostView != null) {
    727             mProxySettings = ProxySettings.STATIC;
    728             String host = mProxyHostView.getText().toString();
    729             String portStr = mProxyPortView.getText().toString();
    730             String exclusionList = mProxyExclusionListView.getText().toString();
    731             int port = 0;
    732             int result = 0;
    733             try {
    734                 port = Integer.parseInt(portStr);
    735                 result = ProxySelector.validate(host, portStr, exclusionList);
    736             } catch (NumberFormatException e) {
    737                 result = R.string.proxy_error_invalid_port;
    738             }
    739             if (result == 0) {
    740                 mHttpProxy = new ProxyInfo(host, port, exclusionList);
    741             } else {
    742                 return false;
    743             }
    744         } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) {
    745             mProxySettings = ProxySettings.PAC;
    746             CharSequence uriSequence = mProxyPacView.getText();
    747             if (TextUtils.isEmpty(uriSequence)) {
    748                 return false;
    749             }
    750             Uri uri = Uri.parse(uriSequence.toString());
    751             if (uri == null) {
    752                 return false;
    753             }
    754             mHttpProxy = new ProxyInfo(uri);
    755         }
    756         return true;
    757     }
    758 
    759     private Inet4Address getIPv4Address(String text) {
    760         try {
    761             return (Inet4Address) NetworkUtils.numericToInetAddress(text);
    762         } catch (IllegalArgumentException | ClassCastException e) {
    763             return null;
    764         }
    765     }
    766 
    767     private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) {
    768         if (mIpAddressView == null) return 0;
    769 
    770         String ipAddr = mIpAddressView.getText().toString();
    771         if (TextUtils.isEmpty(ipAddr)) return R.string.wifi_ip_settings_invalid_ip_address;
    772 
    773         Inet4Address inetAddr = getIPv4Address(ipAddr);
    774         if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) {
    775             return R.string.wifi_ip_settings_invalid_ip_address;
    776         }
    777 
    778         int networkPrefixLength = -1;
    779         try {
    780             networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
    781             if (networkPrefixLength < 0 || networkPrefixLength > 32) {
    782                 return R.string.wifi_ip_settings_invalid_network_prefix_length;
    783             }
    784             staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
    785         } catch (NumberFormatException e) {
    786             // Set the hint as default after user types in ip address
    787             mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
    788                     R.string.wifi_network_prefix_length_hint));
    789         } catch (IllegalArgumentException e) {
    790             return R.string.wifi_ip_settings_invalid_ip_address;
    791         }
    792 
    793         String gateway = mGatewayView.getText().toString();
    794         if (TextUtils.isEmpty(gateway)) {
    795             try {
    796                 //Extract a default gateway from IP address
    797                 InetAddress netPart = NetworkUtils.getNetworkPart(inetAddr, networkPrefixLength);
    798                 byte[] addr = netPart.getAddress();
    799                 addr[addr.length - 1] = 1;
    800                 mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
    801             } catch (RuntimeException ee) {
    802             } catch (java.net.UnknownHostException u) {
    803             }
    804         } else {
    805             InetAddress gatewayAddr = getIPv4Address(gateway);
    806             if (gatewayAddr == null) {
    807                 return R.string.wifi_ip_settings_invalid_gateway;
    808             }
    809             if (gatewayAddr.isMulticastAddress()) {
    810                 return R.string.wifi_ip_settings_invalid_gateway;
    811             }
    812             staticIpConfiguration.gateway = gatewayAddr;
    813         }
    814 
    815         String dns = mDns1View.getText().toString();
    816         InetAddress dnsAddr = null;
    817 
    818         if (TextUtils.isEmpty(dns)) {
    819             //If everything else is valid, provide hint as a default option
    820             mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
    821         } else {
    822             dnsAddr = getIPv4Address(dns);
    823             if (dnsAddr == null) {
    824                 return R.string.wifi_ip_settings_invalid_dns;
    825             }
    826             staticIpConfiguration.dnsServers.add(dnsAddr);
    827         }
    828 
    829         if (mDns2View.length() > 0) {
    830             dns = mDns2View.getText().toString();
    831             dnsAddr = getIPv4Address(dns);
    832             if (dnsAddr == null) {
    833                 return R.string.wifi_ip_settings_invalid_dns;
    834             }
    835             staticIpConfiguration.dnsServers.add(dnsAddr);
    836         }
    837         return 0;
    838     }
    839 
    840     private void showSecurityFields() {
    841         if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
    842             mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
    843             return;
    844         }
    845         mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE);
    846 
    847         if (mPasswordView == null) {
    848             mPasswordView = (TextView) mView.findViewById(R.id.password);
    849             mPasswordView.addTextChangedListener(this);
    850             mPasswordView.setOnEditorActionListener(this);
    851             mPasswordView.setOnKeyListener(this);
    852             ((CheckBox) mView.findViewById(R.id.show_password))
    853                 .setOnCheckedChangeListener(this);
    854 
    855             if (mAccessPoint != null && mAccessPoint.isSaved()) {
    856                 mPasswordView.setHint(R.string.wifi_unchanged);
    857             }
    858         }
    859 
    860         if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) {
    861             mView.findViewById(R.id.eap).setVisibility(View.GONE);
    862             return;
    863         }
    864         mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
    865 
    866         if (mEapMethodSpinner == null) {
    867             mEapMethodSpinner = (Spinner) mView.findViewById(R.id.method);
    868             mEapMethodSpinner.setOnItemSelectedListener(this);
    869             if (Utils.isWifiOnly(mContext) || !mContext.getResources().getBoolean(
    870                     com.android.internal.R.bool.config_eap_sim_based_auth_supported)) {
    871                 String[] eapMethods = mContext.getResources().getStringArray(
    872                         R.array.eap_method_without_sim_auth);
    873                 ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(mContext,
    874                         android.R.layout.simple_spinner_item, eapMethods);
    875                 spinnerAdapter.setDropDownViewResource(
    876                         android.R.layout.simple_spinner_dropdown_item);
    877                 mEapMethodSpinner.setAdapter(spinnerAdapter);
    878             }
    879             mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2);
    880             mPhase2Spinner.setOnItemSelectedListener(this);
    881             mEapCaCertSpinner = (Spinner) mView.findViewById(R.id.ca_cert);
    882             mEapCaCertSpinner.setOnItemSelectedListener(this);
    883             mEapDomainView = (TextView) mView.findViewById(R.id.domain);
    884             mEapDomainView.addTextChangedListener(this);
    885             mEapUserCertSpinner = (Spinner) mView.findViewById(R.id.user_cert);
    886             mEapUserCertSpinner.setOnItemSelectedListener(this);
    887             mEapIdentityView = (TextView) mView.findViewById(R.id.identity);
    888             mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous);
    889 
    890             if (mAccessPoint != null && mAccessPoint.isCarrierAp()) {
    891                 mEapMethodSpinner.setSelection(mAccessPoint.getCarrierApEapType());
    892             }
    893 
    894             loadCertificates(
    895                     mEapCaCertSpinner,
    896                     Credentials.CA_CERTIFICATE,
    897                     mDoNotValidateEapServerString,
    898                     false,
    899                     true);
    900             loadCertificates(
    901                     mEapUserCertSpinner,
    902                     Credentials.USER_PRIVATE_KEY,
    903                     mDoNotProvideEapUserCertString,
    904                     false,
    905                     false);
    906 
    907             // Modifying an existing network
    908             if (mAccessPoint != null && mAccessPoint.isSaved()) {
    909                 WifiEnterpriseConfig enterpriseConfig = mAccessPoint.getConfig().enterpriseConfig;
    910                 int eapMethod = enterpriseConfig.getEapMethod();
    911                 int phase2Method = enterpriseConfig.getPhase2Method();
    912                 mEapMethodSpinner.setSelection(eapMethod);
    913                 showEapFieldsByMethod(eapMethod);
    914                 switch (eapMethod) {
    915                     case Eap.PEAP:
    916                         switch (phase2Method) {
    917                             case Phase2.NONE:
    918                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_NONE);
    919                                 break;
    920                             case Phase2.MSCHAPV2:
    921                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_MSCHAPV2);
    922                                 break;
    923                             case Phase2.GTC:
    924                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_GTC);
    925                                 break;
    926                             case Phase2.SIM:
    927                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_SIM);
    928                                 break;
    929                             case Phase2.AKA:
    930                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_AKA);
    931                                 break;
    932                             case Phase2.AKA_PRIME:
    933                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_AKA_PRIME);
    934                                 break;
    935                             default:
    936                                 Log.e(TAG, "Invalid phase 2 method " + phase2Method);
    937                                 break;
    938                         }
    939                         break;
    940                     default:
    941                         mPhase2Spinner.setSelection(phase2Method);
    942                         break;
    943                 }
    944                 if (!TextUtils.isEmpty(enterpriseConfig.getCaPath())) {
    945                     setSelection(mEapCaCertSpinner, mUseSystemCertsString);
    946                 } else {
    947                     String[] caCerts = enterpriseConfig.getCaCertificateAliases();
    948                     if (caCerts == null) {
    949                         setSelection(mEapCaCertSpinner, mDoNotValidateEapServerString);
    950                     } else if (caCerts.length == 1) {
    951                         setSelection(mEapCaCertSpinner, caCerts[0]);
    952                     } else {
    953                         // Reload the cert spinner with an extra "multiple certificates added" item.
    954                         loadCertificates(
    955                                 mEapCaCertSpinner,
    956                                 Credentials.CA_CERTIFICATE,
    957                                 mDoNotValidateEapServerString,
    958                                 true,
    959                                 true);
    960                         setSelection(mEapCaCertSpinner, mMultipleCertSetString);
    961                     }
    962                 }
    963                 mEapDomainView.setText(enterpriseConfig.getDomainSuffixMatch());
    964                 String userCert = enterpriseConfig.getClientCertificateAlias();
    965                 if (TextUtils.isEmpty(userCert)) {
    966                     setSelection(mEapUserCertSpinner, mDoNotProvideEapUserCertString);
    967                 } else {
    968                     setSelection(mEapUserCertSpinner, userCert);
    969                 }
    970                 mEapIdentityView.setText(enterpriseConfig.getIdentity());
    971                 mEapAnonymousView.setText(enterpriseConfig.getAnonymousIdentity());
    972             } else {
    973                 mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2);
    974                 showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition());
    975             }
    976         } else {
    977             showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition());
    978         }
    979     }
    980 
    981     /**
    982      * EAP-PWD valid fields include
    983      *   identity
    984      *   password
    985      * EAP-PEAP valid fields include
    986      *   phase2: MSCHAPV2, GTC, SIM, AKA, AKA'
    987      *   ca_cert
    988      *   identity
    989      *   anonymous_identity
    990      *   password (not required for SIM, AKA, AKA')
    991      * EAP-TLS valid fields include
    992      *   user_cert
    993      *   ca_cert
    994      *   domain
    995      *   identity
    996      * EAP-TTLS valid fields include
    997      *   phase2: PAP, MSCHAP, MSCHAPV2, GTC
    998      *   ca_cert
    999      *   identity
   1000      *   anonymous_identity
   1001      *   password
   1002      */
   1003     private void showEapFieldsByMethod(int eapMethod) {
   1004         // Common defaults
   1005         mView.findViewById(R.id.l_method).setVisibility(View.VISIBLE);
   1006         mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE);
   1007         mView.findViewById(R.id.l_domain).setVisibility(View.VISIBLE);
   1008 
   1009         // Defaults for most of the EAP methods and over-riden by
   1010         // by certain EAP methods
   1011         mView.findViewById(R.id.l_ca_cert).setVisibility(View.VISIBLE);
   1012         mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE);
   1013         mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE);
   1014 
   1015         Context context = mConfigUi.getContext();
   1016         switch (eapMethod) {
   1017             case WIFI_EAP_METHOD_PWD:
   1018                 setPhase2Invisible();
   1019                 setCaCertInvisible();
   1020                 setDomainInvisible();
   1021                 setAnonymousIdentInvisible();
   1022                 setUserCertInvisible();
   1023                 break;
   1024             case WIFI_EAP_METHOD_TLS:
   1025                 mView.findViewById(R.id.l_user_cert).setVisibility(View.VISIBLE);
   1026                 setPhase2Invisible();
   1027                 setAnonymousIdentInvisible();
   1028                 setPasswordInvisible();
   1029                 break;
   1030             case WIFI_EAP_METHOD_PEAP:
   1031                 // Reset adapter if needed
   1032                 if (mPhase2Adapter != mPhase2PeapAdapter) {
   1033                     mPhase2Adapter = mPhase2PeapAdapter;
   1034                     mPhase2Spinner.setAdapter(mPhase2Adapter);
   1035                 }
   1036                 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
   1037                 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
   1038                 showPeapFields();
   1039                 setUserCertInvisible();
   1040                 break;
   1041             case WIFI_EAP_METHOD_TTLS:
   1042                 // Reset adapter if needed
   1043                 if (mPhase2Adapter != mPhase2FullAdapter) {
   1044                     mPhase2Adapter = mPhase2FullAdapter;
   1045                     mPhase2Spinner.setAdapter(mPhase2Adapter);
   1046                 }
   1047                 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
   1048                 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
   1049                 setUserCertInvisible();
   1050                 break;
   1051             case WIFI_EAP_METHOD_SIM:
   1052             case WIFI_EAP_METHOD_AKA:
   1053             case WIFI_EAP_METHOD_AKA_PRIME:
   1054                 setPhase2Invisible();
   1055                 setAnonymousIdentInvisible();
   1056                 setCaCertInvisible();
   1057                 setDomainInvisible();
   1058                 setUserCertInvisible();
   1059                 setPasswordInvisible();
   1060                 setIdentityInvisible();
   1061                 if (mAccessPoint != null && mAccessPoint.isCarrierAp()) {
   1062                     setEapMethodInvisible();
   1063                 }
   1064                 break;
   1065         }
   1066 
   1067         if (mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) {
   1068             String eapCertSelection = (String) mEapCaCertSpinner.getSelectedItem();
   1069             if (eapCertSelection.equals(mDoNotValidateEapServerString)
   1070                     || eapCertSelection.equals(mUnspecifiedCertString)) {
   1071                 // Domain suffix matching is not relevant if the user hasn't chosen a CA
   1072                 // certificate yet, or chooses not to validate the EAP server.
   1073                 setDomainInvisible();
   1074             }
   1075         }
   1076     }
   1077 
   1078     private void showPeapFields() {
   1079         int phase2Method = mPhase2Spinner.getSelectedItemPosition();
   1080         if (phase2Method == WIFI_PEAP_PHASE2_SIM || phase2Method == WIFI_PEAP_PHASE2_AKA
   1081                  || phase2Method == WIFI_PEAP_PHASE2_AKA_PRIME) {
   1082             mEapIdentityView.setText("");
   1083             mView.findViewById(R.id.l_identity).setVisibility(View.GONE);
   1084             setPasswordInvisible();
   1085         } else {
   1086             mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE);
   1087             mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
   1088             mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE);
   1089             mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE);
   1090         }
   1091     }
   1092 
   1093     private void setIdentityInvisible() {
   1094         mView.findViewById(R.id.l_identity).setVisibility(View.GONE);
   1095         mPhase2Spinner.setSelection(Phase2.NONE);
   1096     }
   1097 
   1098     private void setPhase2Invisible() {
   1099         mView.findViewById(R.id.l_phase2).setVisibility(View.GONE);
   1100         mPhase2Spinner.setSelection(Phase2.NONE);
   1101     }
   1102 
   1103     private void setCaCertInvisible() {
   1104         mView.findViewById(R.id.l_ca_cert).setVisibility(View.GONE);
   1105         setSelection(mEapCaCertSpinner, mUnspecifiedCertString);
   1106     }
   1107 
   1108     private void setDomainInvisible() {
   1109         mView.findViewById(R.id.l_domain).setVisibility(View.GONE);
   1110         mEapDomainView.setText("");
   1111     }
   1112 
   1113     private void setUserCertInvisible() {
   1114         mView.findViewById(R.id.l_user_cert).setVisibility(View.GONE);
   1115         setSelection(mEapUserCertSpinner, mUnspecifiedCertString);
   1116     }
   1117 
   1118     private void setAnonymousIdentInvisible() {
   1119         mView.findViewById(R.id.l_anonymous).setVisibility(View.GONE);
   1120         mEapAnonymousView.setText("");
   1121     }
   1122 
   1123     private void setPasswordInvisible() {
   1124         mPasswordView.setText("");
   1125         mView.findViewById(R.id.password_layout).setVisibility(View.GONE);
   1126         mView.findViewById(R.id.show_password_layout).setVisibility(View.GONE);
   1127     }
   1128 
   1129     private void setEapMethodInvisible() {
   1130         mView.findViewById(R.id.eap).setVisibility(View.GONE);
   1131     }
   1132 
   1133     private void showIpConfigFields() {
   1134         WifiConfiguration config = null;
   1135 
   1136         mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE);
   1137 
   1138         if (mAccessPoint != null && mAccessPoint.isSaved()) {
   1139             config = mAccessPoint.getConfig();
   1140         }
   1141 
   1142         if (mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) {
   1143             mView.findViewById(R.id.staticip).setVisibility(View.VISIBLE);
   1144             if (mIpAddressView == null) {
   1145                 mIpAddressView = (TextView) mView.findViewById(R.id.ipaddress);
   1146                 mIpAddressView.addTextChangedListener(this);
   1147                 mGatewayView = (TextView) mView.findViewById(R.id.gateway);
   1148                 mGatewayView.addTextChangedListener(this);
   1149                 mNetworkPrefixLengthView = (TextView) mView.findViewById(
   1150                         R.id.network_prefix_length);
   1151                 mNetworkPrefixLengthView.addTextChangedListener(this);
   1152                 mDns1View = (TextView) mView.findViewById(R.id.dns1);
   1153                 mDns1View.addTextChangedListener(this);
   1154                 mDns2View = (TextView) mView.findViewById(R.id.dns2);
   1155                 mDns2View.addTextChangedListener(this);
   1156             }
   1157             if (config != null) {
   1158                 StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
   1159                 if (staticConfig != null) {
   1160                     if (staticConfig.ipAddress != null) {
   1161                         mIpAddressView.setText(
   1162                                 staticConfig.ipAddress.getAddress().getHostAddress());
   1163                         mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
   1164                                 .getNetworkPrefixLength()));
   1165                     }
   1166 
   1167                     if (staticConfig.gateway != null) {
   1168                         mGatewayView.setText(staticConfig.gateway.getHostAddress());
   1169                     }
   1170 
   1171                     Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
   1172                     if (dnsIterator.hasNext()) {
   1173                         mDns1View.setText(dnsIterator.next().getHostAddress());
   1174                     }
   1175                     if (dnsIterator.hasNext()) {
   1176                         mDns2View.setText(dnsIterator.next().getHostAddress());
   1177                     }
   1178                 }
   1179             }
   1180         } else {
   1181             mView.findViewById(R.id.staticip).setVisibility(View.GONE);
   1182         }
   1183     }
   1184 
   1185     private void showProxyFields() {
   1186         WifiConfiguration config = null;
   1187 
   1188         mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE);
   1189 
   1190         if (mAccessPoint != null && mAccessPoint.isSaved()) {
   1191             config = mAccessPoint.getConfig();
   1192         }
   1193 
   1194         if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) {
   1195             setVisibility(R.id.proxy_warning_limited_support, View.VISIBLE);
   1196             setVisibility(R.id.proxy_fields, View.VISIBLE);
   1197             setVisibility(R.id.proxy_pac_field, View.GONE);
   1198             if (mProxyHostView == null) {
   1199                 mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname);
   1200                 mProxyHostView.addTextChangedListener(this);
   1201                 mProxyPortView = (TextView) mView.findViewById(R.id.proxy_port);
   1202                 mProxyPortView.addTextChangedListener(this);
   1203                 mProxyExclusionListView = (TextView) mView.findViewById(R.id.proxy_exclusionlist);
   1204                 mProxyExclusionListView.addTextChangedListener(this);
   1205             }
   1206             if (config != null) {
   1207                 ProxyInfo proxyProperties = config.getHttpProxy();
   1208                 if (proxyProperties != null) {
   1209                     mProxyHostView.setText(proxyProperties.getHost());
   1210                     mProxyPortView.setText(Integer.toString(proxyProperties.getPort()));
   1211                     mProxyExclusionListView.setText(proxyProperties.getExclusionListAsString());
   1212                 }
   1213             }
   1214         } else if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_PAC) {
   1215             setVisibility(R.id.proxy_warning_limited_support, View.GONE);
   1216             setVisibility(R.id.proxy_fields, View.GONE);
   1217             setVisibility(R.id.proxy_pac_field, View.VISIBLE);
   1218 
   1219             if (mProxyPacView == null) {
   1220                 mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac);
   1221                 mProxyPacView.addTextChangedListener(this);
   1222             }
   1223             if (config != null) {
   1224                 ProxyInfo proxyInfo = config.getHttpProxy();
   1225                 if (proxyInfo != null) {
   1226                     mProxyPacView.setText(proxyInfo.getPacFileUrl().toString());
   1227                 }
   1228             }
   1229         } else {
   1230             setVisibility(R.id.proxy_warning_limited_support, View.GONE);
   1231             setVisibility(R.id.proxy_fields, View.GONE);
   1232             setVisibility(R.id.proxy_pac_field, View.GONE);
   1233         }
   1234     }
   1235 
   1236     private void setVisibility(int id, int visibility) {
   1237         final View v = mView.findViewById(id);
   1238         if (v != null) {
   1239             v.setVisibility(visibility);
   1240         }
   1241     }
   1242 
   1243     @VisibleForTesting
   1244     KeyStore getKeyStore() {
   1245         return KeyStore.getInstance();
   1246     }
   1247 
   1248     private void loadCertificates(
   1249             Spinner spinner,
   1250             String prefix,
   1251             String noCertificateString,
   1252             boolean showMultipleCerts,
   1253             boolean showUsePreinstalledCertOption) {
   1254         final Context context = mConfigUi.getContext();
   1255 
   1256         ArrayList<String> certs = new ArrayList<String>();
   1257         certs.add(mUnspecifiedCertString);
   1258         if (showMultipleCerts) {
   1259             certs.add(mMultipleCertSetString);
   1260         }
   1261         if (showUsePreinstalledCertOption) {
   1262             certs.add(mUseSystemCertsString);
   1263         }
   1264         try {
   1265             certs.addAll(
   1266                 Arrays.asList(getKeyStore().list(prefix, android.os.Process.WIFI_UID)));
   1267         } catch (Exception e) {
   1268             Log.e(TAG, "can't get the certificate list from KeyStore");
   1269         }
   1270         certs.add(noCertificateString);
   1271 
   1272         final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
   1273                 context, android.R.layout.simple_spinner_item,
   1274                 certs.toArray(new String[certs.size()]));
   1275         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
   1276         spinner.setAdapter(adapter);
   1277     }
   1278 
   1279     private void setSelection(Spinner spinner, String value) {
   1280         if (value != null) {
   1281             @SuppressWarnings("unchecked")
   1282             ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
   1283             for (int i = adapter.getCount() - 1; i >= 0; --i) {
   1284                 if (value.equals(adapter.getItem(i))) {
   1285                     spinner.setSelection(i);
   1286                     break;
   1287                 }
   1288             }
   1289         }
   1290     }
   1291 
   1292     public int getMode() {
   1293         return mMode;
   1294     }
   1295 
   1296     @Override
   1297     public void afterTextChanged(Editable s) {
   1298         ThreadUtils.postOnMainThread(() -> {
   1299             showWarningMessagesIfAppropriate();
   1300             enableSubmitIfAppropriate();
   1301         });
   1302     }
   1303 
   1304     @Override
   1305     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
   1306         // work done in afterTextChanged
   1307     }
   1308 
   1309     @Override
   1310     public void onTextChanged(CharSequence s, int start, int before, int count) {
   1311         // work done in afterTextChanged
   1312     }
   1313 
   1314     @Override
   1315     public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
   1316         if (textView == mPasswordView) {
   1317             if (id == EditorInfo.IME_ACTION_DONE && isSubmittable()) {
   1318                 mConfigUi.dispatchSubmit();
   1319                 return true;
   1320             }
   1321         }
   1322         return false;
   1323     }
   1324 
   1325     @Override
   1326     public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
   1327         if (view == mPasswordView) {
   1328             if (keyCode == KeyEvent.KEYCODE_ENTER && isSubmittable()) {
   1329                 mConfigUi.dispatchSubmit();
   1330                 return true;
   1331             }
   1332         }
   1333         return false;
   1334     }
   1335 
   1336     @Override
   1337     public void onCheckedChanged(CompoundButton view, boolean isChecked) {
   1338         if (view.getId() == R.id.show_password) {
   1339             int pos = mPasswordView.getSelectionEnd();
   1340             mPasswordView.setInputType(InputType.TYPE_CLASS_TEXT
   1341                     | (isChecked ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
   1342                                  : InputType.TYPE_TEXT_VARIATION_PASSWORD));
   1343             if (pos >= 0) {
   1344                 ((EditText) mPasswordView).setSelection(pos);
   1345             }
   1346         } else if (view.getId() == R.id.wifi_advanced_togglebox) {
   1347             final View advancedToggle = mView.findViewById(R.id.wifi_advanced_toggle);
   1348             final int toggleVisibility;
   1349             final int stringID;
   1350             if (isChecked) {
   1351                 toggleVisibility = View.VISIBLE;
   1352                 stringID = R.string.wifi_advanced_toggle_description_expanded;
   1353             } else {
   1354                 toggleVisibility = View.GONE;
   1355                 stringID = R.string.wifi_advanced_toggle_description_collapsed;
   1356             }
   1357             mView.findViewById(R.id.wifi_advanced_fields).setVisibility(toggleVisibility);
   1358             advancedToggle.setContentDescription(mContext.getString(stringID));
   1359         }
   1360     }
   1361 
   1362     @Override
   1363     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
   1364         if (parent == mSecuritySpinner) {
   1365             mAccessPointSecurity = position;
   1366             showSecurityFields();
   1367         } else if (parent == mEapMethodSpinner || parent == mEapCaCertSpinner) {
   1368             showSecurityFields();
   1369         } else if (parent == mPhase2Spinner
   1370                 && mEapMethodSpinner.getSelectedItemPosition() == WIFI_EAP_METHOD_PEAP) {
   1371             showPeapFields();
   1372         } else if (parent == mProxySettingsSpinner) {
   1373             showProxyFields();
   1374         } else if (parent == mHiddenSettingsSpinner) {
   1375             mHiddenWarningView.setVisibility(
   1376                     position == NOT_HIDDEN_NETWORK
   1377                             ? View.GONE
   1378                             : View.VISIBLE);
   1379             if (position == HIDDEN_NETWORK) {
   1380                 mDialogContainer.post(() -> {
   1381                   mDialogContainer.fullScroll(View.FOCUS_DOWN);
   1382                 });
   1383             }
   1384         } else {
   1385             showIpConfigFields();
   1386         }
   1387         showWarningMessagesIfAppropriate();
   1388         enableSubmitIfAppropriate();
   1389     }
   1390 
   1391     @Override
   1392     public void onNothingSelected(AdapterView<?> parent) {
   1393         //
   1394     }
   1395 
   1396     /**
   1397      * Make the characters of the password visible if show_password is checked.
   1398      */
   1399     public void updatePassword() {
   1400         TextView passwdView = (TextView) mView.findViewById(R.id.password);
   1401         passwdView.setInputType(InputType.TYPE_CLASS_TEXT
   1402                 | (((CheckBox) mView.findViewById(R.id.show_password)).isChecked()
   1403                    ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
   1404                    : InputType.TYPE_TEXT_VARIATION_PASSWORD));
   1405     }
   1406 
   1407     public AccessPoint getAccessPoint() {
   1408         return mAccessPoint;
   1409     }
   1410 }
   1411