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