OSDN Git Service

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