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.security.Credentials;
     39 import android.security.KeyStore;
     40 import android.text.Editable;
     41 import android.text.InputType;
     42 import android.text.TextWatcher;
     43 import android.text.TextUtils;
     44 import android.util.Log;
     45 import android.view.View;
     46 import android.view.ViewGroup;
     47 import android.widget.AdapterView;
     48 import android.widget.ArrayAdapter;
     49 import android.widget.Button;
     50 import android.widget.CheckBox;
     51 import android.widget.CompoundButton;
     52 import android.widget.CompoundButton.OnCheckedChangeListener;
     53 import android.widget.EditText;
     54 import android.widget.Spinner;
     55 import android.widget.TextView;
     56 
     57 import com.android.settings.ProxySelector;
     58 import com.android.settings.R;
     59 import com.android.settingslib.wifi.AccessPoint;
     60 import com.android.settings.Utils;
     61 
     62 import java.net.InetAddress;
     63 import java.net.Inet4Address;
     64 import java.util.Iterator;
     65 
     66 /**
     67  * The class for allowing UIs like {@link WifiDialog} and {@link WifiConfigUiBase} to
     68  * share the logic for controlling buttons, text fields, etc.
     69  */
     70 public class WifiConfigController implements TextWatcher,
     71        AdapterView.OnItemSelectedListener, OnCheckedChangeListener {
     72     private static final String TAG = "WifiConfigController";
     73 
     74     private final WifiConfigUiBase mConfigUi;
     75     private final View mView;
     76     private final AccessPoint mAccessPoint;
     77 
     78     /* This value comes from "wifi_ip_settings" resource array */
     79     private static final int DHCP = 0;
     80     private static final int STATIC_IP = 1;
     81 
     82     /* These values come from "wifi_proxy_settings" resource array */
     83     public static final int PROXY_NONE = 0;
     84     public static final int PROXY_STATIC = 1;
     85     public static final int PROXY_PAC = 2;
     86 
     87     /* These values come from "wifi_eap_method" resource array */
     88     public static final int WIFI_EAP_METHOD_PEAP = 0;
     89     public static final int WIFI_EAP_METHOD_TLS  = 1;
     90     public static final int WIFI_EAP_METHOD_TTLS = 2;
     91     public static final int WIFI_EAP_METHOD_PWD  = 3;
     92     public static final int WIFI_EAP_METHOD_SIM  = 4;
     93     public static final int WIFI_EAP_METHOD_AKA  = 5;
     94     public static final int WIFI_EAP_METHOD_AKA_PRIME  = 6;
     95 
     96     /* These values come from "wifi_peap_phase2_entries" resource array */
     97     public static final int WIFI_PEAP_PHASE2_NONE 	    = 0;
     98     public static final int WIFI_PEAP_PHASE2_MSCHAPV2 	= 1;
     99     public static final int WIFI_PEAP_PHASE2_GTC        = 2;
    100 
    101     /* Phase2 methods supported by PEAP are limited */
    102     private final ArrayAdapter<String> PHASE2_PEAP_ADAPTER;
    103     /* Full list of phase2 methods */
    104     private final ArrayAdapter<String> PHASE2_FULL_ADAPTER;
    105 
    106     private final Handler mTextViewChangedHandler;
    107 
    108     // e.g. AccessPoint.SECURITY_NONE
    109     private int mAccessPointSecurity;
    110     private TextView mPasswordView;
    111 
    112     private String unspecifiedCert = "unspecified";
    113     private static final int unspecifiedCertIndex = 0;
    114 
    115     private Spinner mSecuritySpinner;
    116     private Spinner mEapMethodSpinner;
    117     private Spinner mEapCaCertSpinner;
    118     private Spinner mPhase2Spinner;
    119     // Associated with mPhase2Spinner, one of PHASE2_FULL_ADAPTER or PHASE2_PEAP_ADAPTER
    120     private ArrayAdapter<String> mPhase2Adapter;
    121     private Spinner mEapUserCertSpinner;
    122     private TextView mEapIdentityView;
    123     private TextView mEapAnonymousView;
    124 
    125     private Spinner mIpSettingsSpinner;
    126     private TextView mIpAddressView;
    127     private TextView mGatewayView;
    128     private TextView mNetworkPrefixLengthView;
    129     private TextView mDns1View;
    130     private TextView mDns2View;
    131 
    132     private Spinner mProxySettingsSpinner;
    133     private TextView mProxyHostView;
    134     private TextView mProxyPortView;
    135     private TextView mProxyExclusionListView;
    136     private TextView mProxyPacView;
    137 
    138     private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED;
    139     private ProxySettings mProxySettings = ProxySettings.UNASSIGNED;
    140     private ProxyInfo mHttpProxy = null;
    141     private StaticIpConfiguration mStaticIpConfiguration = null;
    142 
    143     private String[] mLevels;
    144     private boolean mEdit;
    145     private boolean mModify;
    146     private TextView mSsidView;
    147 
    148     private Context mContext;
    149 
    150     public WifiConfigController(
    151             WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit,
    152             boolean modify) {
    153         mConfigUi = parent;
    154 
    155         mView = view;
    156         mAccessPoint = accessPoint;
    157         mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE :
    158                 accessPoint.getSecurity();
    159         mEdit = edit;
    160         mModify = modify;
    161 
    162         mTextViewChangedHandler = new Handler();
    163         mContext = mConfigUi.getContext();
    164         final Resources res = mContext.getResources();
    165 
    166         mLevels = res.getStringArray(R.array.wifi_signal);
    167         PHASE2_PEAP_ADAPTER = new ArrayAdapter<String>(
    168             mContext, android.R.layout.simple_spinner_item,
    169             res.getStringArray(R.array.wifi_peap_phase2_entries));
    170         PHASE2_PEAP_ADAPTER.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    171 
    172         PHASE2_FULL_ADAPTER = new ArrayAdapter<String>(
    173                 mContext, android.R.layout.simple_spinner_item,
    174                 res.getStringArray(R.array.wifi_phase2_entries));
    175         PHASE2_FULL_ADAPTER.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    176 
    177         unspecifiedCert = mContext.getString(R.string.wifi_unspecified);
    178         mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
    179         mIpSettingsSpinner.setOnItemSelectedListener(this);
    180         mProxySettingsSpinner = (Spinner) mView.findViewById(R.id.proxy_settings);
    181         mProxySettingsSpinner.setOnItemSelectedListener(this);
    182 
    183         if (mAccessPoint == null) { // new network
    184             mConfigUi.setTitle(R.string.wifi_add_network);
    185 
    186             mSsidView = (TextView) mView.findViewById(R.id.ssid);
    187             mSsidView.addTextChangedListener(this);
    188             mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security));
    189             mSecuritySpinner.setOnItemSelectedListener(this);
    190             mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
    191 
    192             showIpConfigFields();
    193             showProxyFields();
    194             mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE);
    195             ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox))
    196                     .setOnCheckedChangeListener(this);
    197 
    198 
    199             mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
    200         } else {
    201             mConfigUi.setTitle(mAccessPoint.getSsid());
    202 
    203             ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
    204 
    205             boolean showAdvancedFields = false;
    206             if (mAccessPoint.isSaved()) {
    207                 WifiConfiguration config = mAccessPoint.getConfig();
    208                 if (config.getIpAssignment() == IpAssignment.STATIC) {
    209                     mIpSettingsSpinner.setSelection(STATIC_IP);
    210                     showAdvancedFields = true;
    211                     // Display IP address.
    212                     StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
    213                     if (staticConfig != null && staticConfig.ipAddress != null) {
    214                         addRow(group, R.string.wifi_ip_address,
    215                            staticConfig.ipAddress.getAddress().getHostAddress());
    216                     }
    217                 } else {
    218                     mIpSettingsSpinner.setSelection(DHCP);
    219                 }
    220 
    221 
    222                 if (config.getProxySettings() == ProxySettings.STATIC) {
    223                     mProxySettingsSpinner.setSelection(PROXY_STATIC);
    224                     showAdvancedFields = true;
    225                 } else if (config.getProxySettings() == ProxySettings.PAC) {
    226                     mProxySettingsSpinner.setSelection(PROXY_PAC);
    227                     showAdvancedFields = true;
    228                 } else {
    229                     mProxySettingsSpinner.setSelection(PROXY_NONE);
    230                 }
    231                 if (config != null && config.isPasspoint()) {
    232                     addRow(group, R.string.passpoint_label, String.format(
    233                         mContext.getString(R.string.passpoint_content), config.providerFriendlyName));
    234                 }
    235             }
    236 
    237             if ((!mAccessPoint.isSaved() && !mAccessPoint.isActive())
    238                     || mEdit) {
    239                 showSecurityFields();
    240                 showIpConfigFields();
    241                 showProxyFields();
    242                 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE);
    243                 ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox))
    244                     .setOnCheckedChangeListener(this);
    245                 if (showAdvancedFields) {
    246                     ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox)).setChecked(true);
    247                     mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE);
    248                 }
    249             }
    250 
    251             if (mModify) {
    252                 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
    253             } else {
    254                 final DetailedState state = mAccessPoint.getDetailedState();
    255                 final String signalLevel = getSignalString();
    256 
    257                 if (state == null && signalLevel != null) {
    258                     mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
    259                 } else {
    260                     if (state != null) {
    261                         boolean isEphemeral = mAccessPoint.isEphemeral();
    262                         WifiConfiguration config = mAccessPoint.getConfig();
    263                         String providerFriendlyName = null;
    264                         if (config != null && config.isPasspoint()) {
    265                             providerFriendlyName = config.providerFriendlyName;
    266                         }
    267                         String summary = AccessPoint.getSummary(
    268                                 mConfigUi.getContext(), state, isEphemeral, providerFriendlyName);
    269                         addRow(group, R.string.wifi_status, summary);
    270                     }
    271 
    272                     if (signalLevel != null) {
    273                         addRow(group, R.string.wifi_signal, signalLevel);
    274                     }
    275 
    276                     WifiInfo info = mAccessPoint.getInfo();
    277                     if (info != null && info.getLinkSpeed() != -1) {
    278                         addRow(group, R.string.wifi_speed, String.format(
    279                                 res.getString(R.string.link_speed), info.getLinkSpeed()));
    280                     }
    281 
    282                     if (info != null && info.getFrequency() != -1) {
    283                         final int frequency = info.getFrequency();
    284                         String band = null;
    285 
    286                         if (frequency >= AccessPoint.LOWER_FREQ_24GHZ
    287                                 && frequency < AccessPoint.HIGHER_FREQ_24GHZ) {
    288                             band = res.getString(R.string.wifi_band_24ghz);
    289                         } else if (frequency >= AccessPoint.LOWER_FREQ_5GHZ
    290                                 && frequency < AccessPoint.HIGHER_FREQ_5GHZ) {
    291                             band = res.getString(R.string.wifi_band_5ghz);
    292                         } else {
    293                             Log.e(TAG, "Unexpected frequency " + frequency);
    294                         }
    295                         if (band != null) {
    296                             addRow(group, R.string.wifi_frequency, band);
    297                         }
    298                     }
    299 
    300                     addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
    301                     mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
    302                 }
    303                 if (mAccessPoint.isSaved() || mAccessPoint.isActive()) {
    304                     mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
    305                 }
    306             }
    307         }
    308 
    309         mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel));
    310         if (mConfigUi.getSubmitButton() != null) {
    311             enableSubmitIfAppropriate();
    312         }
    313     }
    314 
    315     private void addRow(ViewGroup group, int name, String value) {
    316         View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false);
    317         ((TextView) row.findViewById(R.id.name)).setText(name);
    318         ((TextView) row.findViewById(R.id.value)).setText(value);
    319         group.addView(row);
    320     }
    321 
    322     private String getSignalString(){
    323         final int level = mAccessPoint.getLevel();
    324 
    325         return (level > -1 && level < mLevels.length) ? mLevels[level] : null;
    326     }
    327 
    328     void hideForgetButton() {
    329         Button forget = mConfigUi.getForgetButton();
    330         if (forget == null) return;
    331 
    332         forget.setVisibility(View.GONE);
    333     }
    334 
    335     void hideSubmitButton() {
    336         Button submit = mConfigUi.getSubmitButton();
    337         if (submit == null) return;
    338 
    339         submit.setVisibility(View.GONE);
    340     }
    341 
    342     /* show submit button if password, ip and proxy settings are valid */
    343     void enableSubmitIfAppropriate() {
    344         Button submit = mConfigUi.getSubmitButton();
    345         if (submit == null) return;
    346 
    347         boolean enabled = false;
    348         boolean passwordInvalid = false;
    349 
    350         if (mPasswordView != null &&
    351             ((mAccessPointSecurity == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
    352             (mAccessPointSecurity == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8))) {
    353             passwordInvalid = true;
    354         }
    355 
    356         if ((mSsidView != null && mSsidView.length() == 0) ||
    357             ((mAccessPoint == null || !mAccessPoint.isSaved()) &&
    358             passwordInvalid)) {
    359             enabled = false;
    360         } else {
    361             if (ipAndProxyFieldsAreValid()) {
    362                 enabled = true;
    363             } else {
    364                 enabled = false;
    365             }
    366         }
    367         submit.setEnabled(enabled);
    368     }
    369 
    370     /* package */ WifiConfiguration getConfig() {
    371         if (!mEdit) {
    372             return null;
    373         }
    374 
    375         WifiConfiguration config = new WifiConfiguration();
    376 
    377         if (mAccessPoint == null) {
    378             config.SSID = AccessPoint.convertToQuotedString(
    379                     mSsidView.getText().toString());
    380             // If the user adds a network manually, assume that it is hidden.
    381             config.hiddenSSID = true;
    382         } else if (!mAccessPoint.isSaved()) {
    383             config.SSID = AccessPoint.convertToQuotedString(
    384                     mAccessPoint.getSsidStr());
    385         } else {
    386             config.networkId = mAccessPoint.getConfig().networkId;
    387         }
    388 
    389         switch (mAccessPointSecurity) {
    390             case AccessPoint.SECURITY_NONE:
    391                 config.allowedKeyManagement.set(KeyMgmt.NONE);
    392                 break;
    393 
    394             case AccessPoint.SECURITY_WEP:
    395                 config.allowedKeyManagement.set(KeyMgmt.NONE);
    396                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
    397                 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
    398                 if (mPasswordView.length() != 0) {
    399                     int length = mPasswordView.length();
    400                     String password = mPasswordView.getText().toString();
    401                     // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
    402                     if ((length == 10 || length == 26 || length == 58) &&
    403                             password.matches("[0-9A-Fa-f]*")) {
    404                         config.wepKeys[0] = password;
    405                     } else {
    406                         config.wepKeys[0] = '"' + password + '"';
    407                     }
    408                 }
    409                 break;
    410 
    411             case AccessPoint.SECURITY_PSK:
    412                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
    413                 if (mPasswordView.length() != 0) {
    414                     String password = mPasswordView.getText().toString();
    415                     if (password.matches("[0-9A-Fa-f]{64}")) {
    416                         config.preSharedKey = password;
    417                     } else {
    418                         config.preSharedKey = '"' + password + '"';
    419                     }
    420                 }
    421                 break;
    422 
    423             case AccessPoint.SECURITY_EAP:
    424                 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
    425                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
    426                 config.enterpriseConfig = new WifiEnterpriseConfig();
    427                 int eapMethod = mEapMethodSpinner.getSelectedItemPosition();
    428                 int phase2Method = mPhase2Spinner.getSelectedItemPosition();
    429                 config.enterpriseConfig.setEapMethod(eapMethod);
    430                 switch (eapMethod) {
    431                     case Eap.PEAP:
    432                         // PEAP supports limited phase2 values
    433                         // Map the index from the PHASE2_PEAP_ADAPTER to the one used
    434                         // by the API which has the full list of PEAP methods.
    435                         switch(phase2Method) {
    436                             case WIFI_PEAP_PHASE2_NONE:
    437                                 config.enterpriseConfig.setPhase2Method(Phase2.NONE);
    438                                 break;
    439                             case WIFI_PEAP_PHASE2_MSCHAPV2:
    440                                 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
    441                                 break;
    442                             case WIFI_PEAP_PHASE2_GTC:
    443                                 config.enterpriseConfig.setPhase2Method(Phase2.GTC);
    444                                 break;
    445                             default:
    446                                 Log.e(TAG, "Unknown phase2 method" + phase2Method);
    447                                 break;
    448                         }
    449                         break;
    450                     default:
    451                         // The default index from PHASE2_FULL_ADAPTER maps to the API
    452                         config.enterpriseConfig.setPhase2Method(phase2Method);
    453                         break;
    454                 }
    455                 String caCert = (String) mEapCaCertSpinner.getSelectedItem();
    456                 if (caCert.equals(unspecifiedCert)) caCert = "";
    457                 config.enterpriseConfig.setCaCertificateAlias(caCert);
    458                 String clientCert = (String) mEapUserCertSpinner.getSelectedItem();
    459                 if (clientCert.equals(unspecifiedCert)) clientCert = "";
    460                 config.enterpriseConfig.setClientCertificateAlias(clientCert);
    461                 config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString());
    462                 config.enterpriseConfig.setAnonymousIdentity(
    463                         mEapAnonymousView.getText().toString());
    464 
    465                 if (mPasswordView.isShown()) {
    466                     // For security reasons, a previous password is not displayed to user.
    467                     // Update only if it has been changed.
    468                     if (mPasswordView.length() > 0) {
    469                         config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
    470                     }
    471                 } else {
    472                     // clear password
    473                     config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
    474                 }
    475                 break;
    476             default:
    477                 return null;
    478         }
    479 
    480         config.setIpConfiguration(
    481                 new IpConfiguration(mIpAssignment, mProxySettings,
    482                                     mStaticIpConfiguration, mHttpProxy));
    483 
    484         return config;
    485     }
    486 
    487     private boolean ipAndProxyFieldsAreValid() {
    488         mIpAssignment = (mIpSettingsSpinner != null &&
    489                 mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) ?
    490                 IpAssignment.STATIC : IpAssignment.DHCP;
    491 
    492         if (mIpAssignment == IpAssignment.STATIC) {
    493             mStaticIpConfiguration = new StaticIpConfiguration();
    494             int result = validateIpConfigFields(mStaticIpConfiguration);
    495             if (result != 0) {
    496                 return false;
    497             }
    498         }
    499 
    500         final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition();
    501         mProxySettings = ProxySettings.NONE;
    502         mHttpProxy = null;
    503         if (selectedPosition == PROXY_STATIC && mProxyHostView != null) {
    504             mProxySettings = ProxySettings.STATIC;
    505             String host = mProxyHostView.getText().toString();
    506             String portStr = mProxyPortView.getText().toString();
    507             String exclusionList = mProxyExclusionListView.getText().toString();
    508             int port = 0;
    509             int result = 0;
    510             try {
    511                 port = Integer.parseInt(portStr);
    512                 result = ProxySelector.validate(host, portStr, exclusionList);
    513             } catch (NumberFormatException e) {
    514                 result = R.string.proxy_error_invalid_port;
    515             }
    516             if (result == 0) {
    517                 mHttpProxy = new ProxyInfo(host, port, exclusionList);
    518             } else {
    519                 return false;
    520             }
    521         } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) {
    522             mProxySettings = ProxySettings.PAC;
    523             CharSequence uriSequence = mProxyPacView.getText();
    524             if (TextUtils.isEmpty(uriSequence)) {
    525                 return false;
    526             }
    527             Uri uri = Uri.parse(uriSequence.toString());
    528             if (uri == null) {
    529                 return false;
    530             }
    531             mHttpProxy = new ProxyInfo(uri);
    532         }
    533         return true;
    534     }
    535 
    536     private Inet4Address getIPv4Address(String text) {
    537         try {
    538             return (Inet4Address) NetworkUtils.numericToInetAddress(text);
    539         } catch (IllegalArgumentException|ClassCastException e) {
    540             return null;
    541         }
    542     }
    543 
    544     private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) {
    545         if (mIpAddressView == null) return 0;
    546 
    547         String ipAddr = mIpAddressView.getText().toString();
    548         if (TextUtils.isEmpty(ipAddr)) return R.string.wifi_ip_settings_invalid_ip_address;
    549 
    550         Inet4Address inetAddr = getIPv4Address(ipAddr);
    551         if (inetAddr == null) {
    552             return R.string.wifi_ip_settings_invalid_ip_address;
    553         }
    554 
    555         int networkPrefixLength = -1;
    556         try {
    557             networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
    558             if (networkPrefixLength < 0 || networkPrefixLength > 32) {
    559                 return R.string.wifi_ip_settings_invalid_network_prefix_length;
    560             }
    561             staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
    562         } catch (NumberFormatException e) {
    563             // Set the hint as default after user types in ip address
    564             mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
    565                     R.string.wifi_network_prefix_length_hint));
    566         }
    567 
    568         String gateway = mGatewayView.getText().toString();
    569         if (TextUtils.isEmpty(gateway)) {
    570             try {
    571                 //Extract a default gateway from IP address
    572                 InetAddress netPart = NetworkUtils.getNetworkPart(inetAddr, networkPrefixLength);
    573                 byte[] addr = netPart.getAddress();
    574                 addr[addr.length-1] = 1;
    575                 mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
    576             } catch (RuntimeException ee) {
    577             } catch (java.net.UnknownHostException u) {
    578             }
    579         } else {
    580             InetAddress gatewayAddr = getIPv4Address(gateway);
    581             if (gatewayAddr == null) {
    582                 return R.string.wifi_ip_settings_invalid_gateway;
    583             }
    584             staticIpConfiguration.gateway = gatewayAddr;
    585         }
    586 
    587         String dns = mDns1View.getText().toString();
    588         InetAddress dnsAddr = null;
    589 
    590         if (TextUtils.isEmpty(dns)) {
    591             //If everything else is valid, provide hint as a default option
    592             mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
    593         } else {
    594             dnsAddr = getIPv4Address(dns);
    595             if (dnsAddr == null) {
    596                 return R.string.wifi_ip_settings_invalid_dns;
    597             }
    598             staticIpConfiguration.dnsServers.add(dnsAddr);
    599         }
    600 
    601         if (mDns2View.length() > 0) {
    602             dns = mDns2View.getText().toString();
    603             dnsAddr = getIPv4Address(dns);
    604             if (dnsAddr == null) {
    605                 return R.string.wifi_ip_settings_invalid_dns;
    606             }
    607             staticIpConfiguration.dnsServers.add(dnsAddr);
    608         }
    609         return 0;
    610     }
    611 
    612     private void showSecurityFields() {
    613         if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
    614             mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
    615             return;
    616         }
    617         mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE);
    618 
    619         if (mPasswordView == null) {
    620             mPasswordView = (TextView) mView.findViewById(R.id.password);
    621             mPasswordView.addTextChangedListener(this);
    622             ((CheckBox) mView.findViewById(R.id.show_password))
    623                 .setOnCheckedChangeListener(this);
    624 
    625             if (mAccessPoint != null && mAccessPoint.isSaved()) {
    626                 mPasswordView.setHint(R.string.wifi_unchanged);
    627             }
    628         }
    629 
    630         if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) {
    631             mView.findViewById(R.id.eap).setVisibility(View.GONE);
    632             return;
    633         }
    634         mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
    635 
    636         if (mEapMethodSpinner == null) {
    637             mEapMethodSpinner = (Spinner) mView.findViewById(R.id.method);
    638             mEapMethodSpinner.setOnItemSelectedListener(this);
    639             if (Utils.isWifiOnly(mContext) || !mContext.getResources().getBoolean(
    640                     com.android.internal.R.bool.config_eap_sim_based_auth_supported)) {
    641                 String[] eapMethods = mContext.getResources().getStringArray(
    642                         R.array.eap_method_without_sim_auth);
    643                 ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(mContext,
    644                         android.R.layout.simple_spinner_item, eapMethods);
    645                 spinnerAdapter.setDropDownViewResource(
    646                         android.R.layout.simple_spinner_dropdown_item);
    647                 mEapMethodSpinner.setAdapter(spinnerAdapter);
    648             }
    649             mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2);
    650             mEapCaCertSpinner = (Spinner) mView.findViewById(R.id.ca_cert);
    651             mEapUserCertSpinner = (Spinner) mView.findViewById(R.id.user_cert);
    652             mEapIdentityView = (TextView) mView.findViewById(R.id.identity);
    653             mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous);
    654 
    655             loadCertificates(mEapCaCertSpinner, Credentials.CA_CERTIFICATE);
    656             loadCertificates(mEapUserCertSpinner, Credentials.USER_PRIVATE_KEY);
    657 
    658             // Modifying an existing network
    659             if (mAccessPoint != null && mAccessPoint.isSaved()) {
    660                 WifiEnterpriseConfig enterpriseConfig = mAccessPoint.getConfig().enterpriseConfig;
    661                 int eapMethod = enterpriseConfig.getEapMethod();
    662                 int phase2Method = enterpriseConfig.getPhase2Method();
    663                 mEapMethodSpinner.setSelection(eapMethod);
    664                 showEapFieldsByMethod(eapMethod);
    665                 switch (eapMethod) {
    666                     case Eap.PEAP:
    667                         switch (phase2Method) {
    668                             case Phase2.NONE:
    669                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_NONE);
    670                                 break;
    671                             case Phase2.MSCHAPV2:
    672                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_MSCHAPV2);
    673                                 break;
    674                             case Phase2.GTC:
    675                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_GTC);
    676                                 break;
    677                             default:
    678                                 Log.e(TAG, "Invalid phase 2 method " + phase2Method);
    679                                 break;
    680                         }
    681                         break;
    682                     default:
    683                         mPhase2Spinner.setSelection(phase2Method);
    684                         break;
    685                 }
    686                 setSelection(mEapCaCertSpinner, enterpriseConfig.getCaCertificateAlias());
    687                 setSelection(mEapUserCertSpinner, enterpriseConfig.getClientCertificateAlias());
    688                 mEapIdentityView.setText(enterpriseConfig.getIdentity());
    689                 mEapAnonymousView.setText(enterpriseConfig.getAnonymousIdentity());
    690             } else {
    691                 showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition());
    692             }
    693         } else {
    694             showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition());
    695         }
    696     }
    697 
    698     /**
    699      * EAP-PWD valid fields include
    700      *   identity
    701      *   password
    702      * EAP-PEAP valid fields include
    703      *   phase2: MSCHAPV2, GTC
    704      *   ca_cert
    705      *   identity
    706      *   anonymous_identity
    707      *   password
    708      * EAP-TLS valid fields include
    709      *   user_cert
    710      *   ca_cert
    711      *   identity
    712      * EAP-TTLS valid fields include
    713      *   phase2: PAP, MSCHAP, MSCHAPV2, GTC
    714      *   ca_cert
    715      *   identity
    716      *   anonymous_identity
    717      *   password
    718      */
    719     private void showEapFieldsByMethod(int eapMethod) {
    720         // Common defaults
    721         mView.findViewById(R.id.l_method).setVisibility(View.VISIBLE);
    722         mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE);
    723 
    724         // Defaults for most of the EAP methods and over-riden by
    725         // by certain EAP methods
    726         mView.findViewById(R.id.l_ca_cert).setVisibility(View.VISIBLE);
    727         mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE);
    728         mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE);
    729 
    730         Context context = mConfigUi.getContext();
    731         switch (eapMethod) {
    732             case WIFI_EAP_METHOD_PWD:
    733                 setPhase2Invisible();
    734                 setCaCertInvisible();
    735                 setAnonymousIdentInvisible();
    736                 setUserCertInvisible();
    737                 break;
    738             case WIFI_EAP_METHOD_TLS:
    739                 mView.findViewById(R.id.l_user_cert).setVisibility(View.VISIBLE);
    740                 setPhase2Invisible();
    741                 setAnonymousIdentInvisible();
    742                 setPasswordInvisible();
    743                 break;
    744             case WIFI_EAP_METHOD_PEAP:
    745                 // Reset adapter if needed
    746                 if (mPhase2Adapter != PHASE2_PEAP_ADAPTER) {
    747                     mPhase2Adapter = PHASE2_PEAP_ADAPTER;
    748                     mPhase2Spinner.setAdapter(mPhase2Adapter);
    749                 }
    750                 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
    751                 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
    752                 setUserCertInvisible();
    753                 break;
    754             case WIFI_EAP_METHOD_TTLS:
    755                 // Reset adapter if needed
    756                 if (mPhase2Adapter != PHASE2_FULL_ADAPTER) {
    757                     mPhase2Adapter = PHASE2_FULL_ADAPTER;
    758                     mPhase2Spinner.setAdapter(mPhase2Adapter);
    759                 }
    760                 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
    761                 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
    762                 setUserCertInvisible();
    763                 break;
    764             case WIFI_EAP_METHOD_SIM:
    765             case WIFI_EAP_METHOD_AKA:
    766             case WIFI_EAP_METHOD_AKA_PRIME:
    767                 setPhase2Invisible();
    768                 setAnonymousIdentInvisible();
    769                 setCaCertInvisible();
    770                 setUserCertInvisible();
    771                 setPasswordInvisible();
    772                 setIdentityInvisible();
    773                 break;
    774         }
    775     }
    776 
    777     private void setIdentityInvisible() {
    778         mView.findViewById(R.id.l_identity).setVisibility(View.GONE);
    779         mPhase2Spinner.setSelection(Phase2.NONE);
    780     }
    781 
    782     private void setPhase2Invisible() {
    783         mView.findViewById(R.id.l_phase2).setVisibility(View.GONE);
    784         mPhase2Spinner.setSelection(Phase2.NONE);
    785     }
    786 
    787     private void setCaCertInvisible() {
    788         mView.findViewById(R.id.l_ca_cert).setVisibility(View.GONE);
    789         mEapCaCertSpinner.setSelection(unspecifiedCertIndex);
    790     }
    791 
    792     private void setUserCertInvisible() {
    793         mView.findViewById(R.id.l_user_cert).setVisibility(View.GONE);
    794         mEapUserCertSpinner.setSelection(unspecifiedCertIndex);
    795     }
    796 
    797     private void setAnonymousIdentInvisible() {
    798         mView.findViewById(R.id.l_anonymous).setVisibility(View.GONE);
    799         mEapAnonymousView.setText("");
    800     }
    801 
    802     private void setPasswordInvisible() {
    803         mPasswordView.setText("");
    804         mView.findViewById(R.id.password_layout).setVisibility(View.GONE);
    805         mView.findViewById(R.id.show_password_layout).setVisibility(View.GONE);
    806     }
    807 
    808     private void showIpConfigFields() {
    809         WifiConfiguration config = null;
    810 
    811         mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE);
    812 
    813         if (mAccessPoint != null && mAccessPoint.isSaved()) {
    814             config = mAccessPoint.getConfig();
    815         }
    816 
    817         if (mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) {
    818             mView.findViewById(R.id.staticip).setVisibility(View.VISIBLE);
    819             if (mIpAddressView == null) {
    820                 mIpAddressView = (TextView) mView.findViewById(R.id.ipaddress);
    821                 mIpAddressView.addTextChangedListener(this);
    822                 mGatewayView = (TextView) mView.findViewById(R.id.gateway);
    823                 mGatewayView.addTextChangedListener(this);
    824                 mNetworkPrefixLengthView = (TextView) mView.findViewById(
    825                         R.id.network_prefix_length);
    826                 mNetworkPrefixLengthView.addTextChangedListener(this);
    827                 mDns1View = (TextView) mView.findViewById(R.id.dns1);
    828                 mDns1View.addTextChangedListener(this);
    829                 mDns2View = (TextView) mView.findViewById(R.id.dns2);
    830                 mDns2View.addTextChangedListener(this);
    831             }
    832             if (config != null) {
    833                 StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
    834                 if (staticConfig != null) {
    835                     if (staticConfig.ipAddress != null) {
    836                         mIpAddressView.setText(
    837                                 staticConfig.ipAddress.getAddress().getHostAddress());
    838                         mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
    839                                 .getNetworkPrefixLength()));
    840                     }
    841 
    842                     if (staticConfig.gateway != null) {
    843                         mGatewayView.setText(staticConfig.gateway.getHostAddress());
    844                     }
    845 
    846                     Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
    847                     if (dnsIterator.hasNext()) {
    848                         mDns1View.setText(dnsIterator.next().getHostAddress());
    849                     }
    850                     if (dnsIterator.hasNext()) {
    851                         mDns2View.setText(dnsIterator.next().getHostAddress());
    852                     }
    853                 }
    854             }
    855         } else {
    856             mView.findViewById(R.id.staticip).setVisibility(View.GONE);
    857         }
    858     }
    859 
    860     private void showProxyFields() {
    861         WifiConfiguration config = null;
    862 
    863         mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE);
    864 
    865         if (mAccessPoint != null && mAccessPoint.isSaved()) {
    866             config = mAccessPoint.getConfig();
    867         }
    868 
    869         if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) {
    870             setVisibility(R.id.proxy_warning_limited_support, View.VISIBLE);
    871             setVisibility(R.id.proxy_fields, View.VISIBLE);
    872             setVisibility(R.id.proxy_pac_field, View.GONE);
    873             if (mProxyHostView == null) {
    874                 mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname);
    875                 mProxyHostView.addTextChangedListener(this);
    876                 mProxyPortView = (TextView) mView.findViewById(R.id.proxy_port);
    877                 mProxyPortView.addTextChangedListener(this);
    878                 mProxyExclusionListView = (TextView) mView.findViewById(R.id.proxy_exclusionlist);
    879                 mProxyExclusionListView.addTextChangedListener(this);
    880             }
    881             if (config != null) {
    882                 ProxyInfo proxyProperties = config.getHttpProxy();
    883                 if (proxyProperties != null) {
    884                     mProxyHostView.setText(proxyProperties.getHost());
    885                     mProxyPortView.setText(Integer.toString(proxyProperties.getPort()));
    886                     mProxyExclusionListView.setText(proxyProperties.getExclusionListAsString());
    887                 }
    888             }
    889         } else if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_PAC) {
    890             setVisibility(R.id.proxy_warning_limited_support, View.GONE);
    891             setVisibility(R.id.proxy_fields, View.GONE);
    892             setVisibility(R.id.proxy_pac_field, View.VISIBLE);
    893 
    894             if (mProxyPacView == null) {
    895                 mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac);
    896                 mProxyPacView.addTextChangedListener(this);
    897             }
    898             if (config != null) {
    899                 ProxyInfo proxyInfo = config.getHttpProxy();
    900                 if (proxyInfo != null) {
    901                     mProxyPacView.setText(proxyInfo.getPacFileUrl().toString());
    902                 }
    903             }
    904         } else {
    905             setVisibility(R.id.proxy_warning_limited_support, View.GONE);
    906             setVisibility(R.id.proxy_fields, View.GONE);
    907             setVisibility(R.id.proxy_pac_field, View.GONE);
    908         }
    909     }
    910 
    911     private void setVisibility(int id, int visibility) {
    912         final View v = mView.findViewById(id);
    913         if (v != null) {
    914             v.setVisibility(visibility);
    915         }
    916     }
    917 
    918     private void loadCertificates(Spinner spinner, String prefix) {
    919         final Context context = mConfigUi.getContext();
    920 
    921         String[] certs = KeyStore.getInstance().list(prefix, android.os.Process.WIFI_UID);
    922         if (certs == null || certs.length == 0) {
    923             certs = new String[] {unspecifiedCert};
    924         } else {
    925             final String[] array = new String[certs.length + 1];
    926             array[0] = unspecifiedCert;
    927             System.arraycopy(certs, 0, array, 1, certs.length);
    928             certs = array;
    929         }
    930 
    931         final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
    932                 context, android.R.layout.simple_spinner_item, certs);
    933         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    934         spinner.setAdapter(adapter);
    935     }
    936 
    937     private void setSelection(Spinner spinner, String value) {
    938         if (value != null) {
    939             @SuppressWarnings("unchecked")
    940             ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
    941             for (int i = adapter.getCount() - 1; i >= 0; --i) {
    942                 if (value.equals(adapter.getItem(i))) {
    943                     spinner.setSelection(i);
    944                     break;
    945                 }
    946             }
    947         }
    948     }
    949 
    950     public boolean isEdit() {
    951         return mEdit;
    952     }
    953 
    954     public boolean isModify() {
    955         return mModify;
    956     }
    957 
    958     @Override
    959     public void afterTextChanged(Editable s) {
    960         mTextViewChangedHandler.post(new Runnable() {
    961                 public void run() {
    962                     enableSubmitIfAppropriate();
    963                 }
    964             });
    965     }
    966 
    967     @Override
    968     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    969         // work done in afterTextChanged
    970     }
    971 
    972     @Override
    973     public void onTextChanged(CharSequence s, int start, int before, int count) {
    974         // work done in afterTextChanged
    975     }
    976 
    977     @Override
    978     public void onCheckedChanged(CompoundButton view, boolean isChecked) {
    979         if (view.getId() == R.id.show_password) {
    980             int pos = mPasswordView.getSelectionEnd();
    981             mPasswordView.setInputType(
    982                     InputType.TYPE_CLASS_TEXT | (isChecked ?
    983                             InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
    984                                 InputType.TYPE_TEXT_VARIATION_PASSWORD));
    985             if (pos >= 0) {
    986                 ((EditText)mPasswordView).setSelection(pos);
    987             }
    988         } else if (view.getId() == R.id.wifi_advanced_togglebox) {
    989             if (isChecked) {
    990                 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE);
    991             } else {
    992                 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.GONE);
    993             }
    994         }
    995     }
    996 
    997     @Override
    998     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    999         if (parent == mSecuritySpinner) {
   1000             mAccessPointSecurity = position;
   1001             showSecurityFields();
   1002         } else if (parent == mEapMethodSpinner) {
   1003             showSecurityFields();
   1004         } else if (parent == mProxySettingsSpinner) {
   1005             showProxyFields();
   1006         } else {
   1007             showIpConfigFields();
   1008         }
   1009         enableSubmitIfAppropriate();
   1010     }
   1011 
   1012     @Override
   1013     public void onNothingSelected(AdapterView<?> parent) {
   1014         //
   1015     }
   1016 
   1017     /**
   1018      * Make the characters of the password visible if show_password is checked.
   1019      */
   1020     public void updatePassword() {
   1021         TextView passwdView = (TextView) mView.findViewById(R.id.password);
   1022         passwdView.setInputType(
   1023                 InputType.TYPE_CLASS_TEXT |
   1024                 (((CheckBox) mView.findViewById(R.id.show_password)).isChecked() ?
   1025                 InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
   1026                 InputType.TYPE_TEXT_VARIATION_PASSWORD));
   1027     }
   1028 }
   1029