• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
WifiConfigController( WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit)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 && !mAccessPoint.isActive())
246                     || mEdit) {
247                 showSecurityFields();
248                 showIpConfigFields();
249                 showProxyFields();
250                 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE);
251                 ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox))
252                     .setOnCheckedChangeListener(this);
253                 if (showAdvancedFields) {
254                     ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox)).setChecked(true);
255                     mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE);
256                 }
257             }
258 
259             if (mEdit) {
260                 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
261             } else {
262                 final DetailedState state = mAccessPoint.getState();
263                 final String signalLevel = getSignalString();
264 
265                 if (state == null && signalLevel != null) {
266                     mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
267                 } else {
268                     if (state != null) {
269                         addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(),
270                                 state, mAccessPoint.networkId ==
271                                 WifiConfiguration.INVALID_NETWORK_ID));
272                     }
273 
274                     if (signalLevel != null) {
275                         addRow(group, R.string.wifi_signal, signalLevel);
276                     }
277 
278                     WifiInfo info = mAccessPoint.getInfo();
279                     if (info != null && info.getLinkSpeed() != -1) {
280                         addRow(group, R.string.wifi_speed, info.getLinkSpeed()
281                                 + WifiInfo.LINK_SPEED_UNITS);
282                     }
283 
284                     if (info != null && info.getFrequency() != -1) {
285                         final int frequency = info.getFrequency();
286                         String band = null;
287 
288                         if (frequency >= AccessPoint.LOWER_FREQ_24GHZ
289                                 && frequency < AccessPoint.HIGHER_FREQ_24GHZ) {
290                             band = res.getString(R.string.wifi_band_24ghz);
291                         } else if (frequency >= AccessPoint.LOWER_FREQ_5GHZ
292                                 && frequency < AccessPoint.HIGHER_FREQ_5GHZ) {
293                             band = res.getString(R.string.wifi_band_5ghz);
294                         } else {
295                             Log.e(TAG, "Unexpected frequency " + frequency);
296                         }
297                         if (band != null) {
298                             addRow(group, R.string.wifi_frequency, band);
299                         }
300                     }
301 
302                     addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
303                     mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
304                 }
305                 if ((mAccessPoint.networkId != INVALID_NETWORK_ID || mAccessPoint.isActive())
306                         && ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) {
307                     mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
308                 }
309             }
310         }
311 
312         if ((mEdit) || (mAccessPoint != null
313                 && mAccessPoint.getState() == null && mAccessPoint.getLevel() != -1)){
314             mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel));
315         }else{
316             mConfigUi.setCancelButton(res.getString(R.string.wifi_display_options_done));
317         }
318         if (mConfigUi.getSubmitButton() != null) {
319             enableSubmitIfAppropriate();
320         }
321     }
322 
addRow(ViewGroup group, int name, String value)323     private void addRow(ViewGroup group, int name, String value) {
324         View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false);
325         ((TextView) row.findViewById(R.id.name)).setText(name);
326         ((TextView) row.findViewById(R.id.value)).setText(value);
327         group.addView(row);
328     }
329 
getSignalString()330     private String getSignalString(){
331         final int level = mAccessPoint.getLevel();
332 
333         return (level > -1 && level < mLevels.length) ? mLevels[level] : null;
334     }
335 
hideSubmitButton()336     void hideSubmitButton() {
337         Button submit = mConfigUi.getSubmitButton();
338         if (submit == null) return;
339 
340         submit.setVisibility(View.GONE);
341     }
342 
343     /* show submit button if password, ip and proxy settings are valid */
enableSubmitIfAppropriate()344     void enableSubmitIfAppropriate() {
345         Button submit = mConfigUi.getSubmitButton();
346         if (submit == null) return;
347 
348         boolean enabled = false;
349         boolean passwordInvalid = false;
350 
351         if (mPasswordView != null &&
352             ((mAccessPointSecurity == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
353             (mAccessPointSecurity == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8))) {
354             passwordInvalid = true;
355         }
356 
357         if ((mSsidView != null && mSsidView.length() == 0) ||
358             ((mAccessPoint == null || mAccessPoint.networkId == INVALID_NETWORK_ID) &&
359             passwordInvalid)) {
360             enabled = false;
361         } else {
362             if (ipAndProxyFieldsAreValid()) {
363                 enabled = true;
364             } else {
365                 enabled = false;
366             }
367         }
368         submit.setEnabled(enabled);
369     }
370 
getConfig()371     /* package */ WifiConfiguration getConfig() {
372         if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID && !mEdit) {
373             return null;
374         }
375 
376         WifiConfiguration config = new WifiConfiguration();
377 
378         if (mAccessPoint == null) {
379             config.SSID = AccessPoint.convertToQuotedString(
380                     mSsidView.getText().toString());
381             // If the user adds a network manually, assume that it is hidden.
382             config.hiddenSSID = true;
383         } else if (mAccessPoint.networkId == INVALID_NETWORK_ID) {
384             config.SSID = AccessPoint.convertToQuotedString(
385                     mAccessPoint.ssid);
386         } else {
387             config.networkId = mAccessPoint.networkId;
388         }
389 
390         switch (mAccessPointSecurity) {
391             case AccessPoint.SECURITY_NONE:
392                 config.allowedKeyManagement.set(KeyMgmt.NONE);
393                 break;
394 
395             case AccessPoint.SECURITY_WEP:
396                 config.allowedKeyManagement.set(KeyMgmt.NONE);
397                 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
398                 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
399                 if (mPasswordView.length() != 0) {
400                     int length = mPasswordView.length();
401                     String password = mPasswordView.getText().toString();
402                     // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
403                     if ((length == 10 || length == 26 || length == 58) &&
404                             password.matches("[0-9A-Fa-f]*")) {
405                         config.wepKeys[0] = password;
406                     } else {
407                         config.wepKeys[0] = '"' + password + '"';
408                     }
409                 }
410                 break;
411 
412             case AccessPoint.SECURITY_PSK:
413                 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
414                 if (mPasswordView.length() != 0) {
415                     String password = mPasswordView.getText().toString();
416                     if (password.matches("[0-9A-Fa-f]{64}")) {
417                         config.preSharedKey = password;
418                     } else {
419                         config.preSharedKey = '"' + password + '"';
420                     }
421                 }
422                 break;
423 
424             case AccessPoint.SECURITY_EAP:
425                 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
426                 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
427                 config.enterpriseConfig = new WifiEnterpriseConfig();
428                 int eapMethod = mEapMethodSpinner.getSelectedItemPosition();
429                 int phase2Method = mPhase2Spinner.getSelectedItemPosition();
430                 config.enterpriseConfig.setEapMethod(eapMethod);
431                 switch (eapMethod) {
432                     case Eap.PEAP:
433                         // PEAP supports limited phase2 values
434                         // Map the index from the PHASE2_PEAP_ADAPTER to the one used
435                         // by the API which has the full list of PEAP methods.
436                         switch(phase2Method) {
437                             case WIFI_PEAP_PHASE2_NONE:
438                                 config.enterpriseConfig.setPhase2Method(Phase2.NONE);
439                                 break;
440                             case WIFI_PEAP_PHASE2_MSCHAPV2:
441                                 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
442                                 break;
443                             case WIFI_PEAP_PHASE2_GTC:
444                                 config.enterpriseConfig.setPhase2Method(Phase2.GTC);
445                                 break;
446                             default:
447                                 Log.e(TAG, "Unknown phase2 method" + phase2Method);
448                                 break;
449                         }
450                         break;
451                     default:
452                         // The default index from PHASE2_FULL_ADAPTER maps to the API
453                         config.enterpriseConfig.setPhase2Method(phase2Method);
454                         break;
455                 }
456                 String caCert = (String) mEapCaCertSpinner.getSelectedItem();
457                 if (caCert.equals(unspecifiedCert)) caCert = "";
458                 config.enterpriseConfig.setCaCertificateAlias(caCert);
459                 String clientCert = (String) mEapUserCertSpinner.getSelectedItem();
460                 if (clientCert.equals(unspecifiedCert)) clientCert = "";
461                 config.enterpriseConfig.setClientCertificateAlias(clientCert);
462                 config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString());
463                 config.enterpriseConfig.setAnonymousIdentity(
464                         mEapAnonymousView.getText().toString());
465 
466                 if (mPasswordView.isShown()) {
467                     // For security reasons, a previous password is not displayed to user.
468                     // Update only if it has been changed.
469                     if (mPasswordView.length() > 0) {
470                         config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
471                     }
472                 } else {
473                     // clear password
474                     config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
475                 }
476                 break;
477             default:
478                 return null;
479         }
480 
481         config.setIpConfiguration(
482                 new IpConfiguration(mIpAssignment, mProxySettings,
483                                     mStaticIpConfiguration, mHttpProxy));
484 
485         return config;
486     }
487 
ipAndProxyFieldsAreValid()488     private boolean ipAndProxyFieldsAreValid() {
489         mIpAssignment = (mIpSettingsSpinner != null &&
490                 mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) ?
491                 IpAssignment.STATIC : IpAssignment.DHCP;
492 
493         if (mIpAssignment == IpAssignment.STATIC) {
494             mStaticIpConfiguration = new StaticIpConfiguration();
495             int result = validateIpConfigFields(mStaticIpConfiguration);
496             if (result != 0) {
497                 return false;
498             }
499         }
500 
501         final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition();
502         mProxySettings = ProxySettings.NONE;
503         mHttpProxy = null;
504         if (selectedPosition == PROXY_STATIC && mProxyHostView != null) {
505             mProxySettings = ProxySettings.STATIC;
506             String host = mProxyHostView.getText().toString();
507             String portStr = mProxyPortView.getText().toString();
508             String exclusionList = mProxyExclusionListView.getText().toString();
509             int port = 0;
510             int result = 0;
511             try {
512                 port = Integer.parseInt(portStr);
513                 result = ProxySelector.validate(host, portStr, exclusionList);
514             } catch (NumberFormatException e) {
515                 result = R.string.proxy_error_invalid_port;
516             }
517             if (result == 0) {
518                 mHttpProxy = new ProxyInfo(host, port, exclusionList);
519             } else {
520                 return false;
521             }
522         } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) {
523             mProxySettings = ProxySettings.PAC;
524             CharSequence uriSequence = mProxyPacView.getText();
525             if (TextUtils.isEmpty(uriSequence)) {
526                 return false;
527             }
528             Uri uri = Uri.parse(uriSequence.toString());
529             if (uri == null) {
530                 return false;
531             }
532             mHttpProxy = new ProxyInfo(uri);
533         }
534         return true;
535     }
536 
getIPv4Address(String text)537     private Inet4Address getIPv4Address(String text) {
538         try {
539             return (Inet4Address) NetworkUtils.numericToInetAddress(text);
540         } catch (IllegalArgumentException|ClassCastException e) {
541             return null;
542         }
543     }
544 
validateIpConfigFields(StaticIpConfiguration staticIpConfiguration)545     private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) {
546         if (mIpAddressView == null) return 0;
547 
548         String ipAddr = mIpAddressView.getText().toString();
549         if (TextUtils.isEmpty(ipAddr)) return R.string.wifi_ip_settings_invalid_ip_address;
550 
551         Inet4Address inetAddr = getIPv4Address(ipAddr);
552         if (inetAddr == null) {
553             return R.string.wifi_ip_settings_invalid_ip_address;
554         }
555 
556         int networkPrefixLength = -1;
557         try {
558             networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
559             if (networkPrefixLength < 0 || networkPrefixLength > 32) {
560                 return R.string.wifi_ip_settings_invalid_network_prefix_length;
561             }
562             staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength);
563         } catch (NumberFormatException e) {
564             // Set the hint as default after user types in ip address
565             mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString(
566                     R.string.wifi_network_prefix_length_hint));
567         }
568 
569         String gateway = mGatewayView.getText().toString();
570         if (TextUtils.isEmpty(gateway)) {
571             try {
572                 //Extract a default gateway from IP address
573                 InetAddress netPart = NetworkUtils.getNetworkPart(inetAddr, networkPrefixLength);
574                 byte[] addr = netPart.getAddress();
575                 addr[addr.length-1] = 1;
576                 mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress());
577             } catch (RuntimeException ee) {
578             } catch (java.net.UnknownHostException u) {
579             }
580         } else {
581             InetAddress gatewayAddr = getIPv4Address(gateway);
582             if (gatewayAddr == null) {
583                 return R.string.wifi_ip_settings_invalid_gateway;
584             }
585             staticIpConfiguration.gateway = gatewayAddr;
586         }
587 
588         String dns = mDns1View.getText().toString();
589         InetAddress dnsAddr = null;
590 
591         if (TextUtils.isEmpty(dns)) {
592             //If everything else is valid, provide hint as a default option
593             mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint));
594         } else {
595             dnsAddr = getIPv4Address(dns);
596             if (dnsAddr == null) {
597                 return R.string.wifi_ip_settings_invalid_dns;
598             }
599             staticIpConfiguration.dnsServers.add(dnsAddr);
600         }
601 
602         if (mDns2View.length() > 0) {
603             dns = mDns2View.getText().toString();
604             dnsAddr = getIPv4Address(dns);
605             if (dnsAddr == null) {
606                 return R.string.wifi_ip_settings_invalid_dns;
607             }
608             staticIpConfiguration.dnsServers.add(dnsAddr);
609         }
610         return 0;
611     }
612 
showSecurityFields()613     private void showSecurityFields() {
614         if (mInXlSetupWizard) {
615             // Note: XL SetupWizard won't hide "EAP" settings here.
616             if (!((WifiSettingsForSetupWizardXL)mConfigUi.getContext()).initSecurityFields(mView,
617                         mAccessPointSecurity)) {
618                 return;
619             }
620         }
621         if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
622             mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
623             return;
624         }
625         mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE);
626 
627         if (mPasswordView == null) {
628             mPasswordView = (TextView) mView.findViewById(R.id.password);
629             mPasswordView.addTextChangedListener(this);
630             ((CheckBox) mView.findViewById(R.id.show_password))
631                 .setOnCheckedChangeListener(this);
632 
633             if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
634                 mPasswordView.setHint(R.string.wifi_unchanged);
635             }
636         }
637 
638         if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) {
639             mView.findViewById(R.id.eap).setVisibility(View.GONE);
640             return;
641         }
642         mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
643 
644         if (mEapMethodSpinner == null) {
645             mEapMethodSpinner = (Spinner) mView.findViewById(R.id.method);
646             mEapMethodSpinner.setOnItemSelectedListener(this);
647             mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2);
648             mEapCaCertSpinner = (Spinner) mView.findViewById(R.id.ca_cert);
649             mEapUserCertSpinner = (Spinner) mView.findViewById(R.id.user_cert);
650             mEapIdentityView = (TextView) mView.findViewById(R.id.identity);
651             mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous);
652 
653             loadCertificates(mEapCaCertSpinner, Credentials.CA_CERTIFICATE);
654             loadCertificates(mEapUserCertSpinner, Credentials.USER_PRIVATE_KEY);
655 
656             // Modifying an existing network
657             if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
658                 WifiEnterpriseConfig enterpriseConfig = mAccessPoint.getConfig().enterpriseConfig;
659                 int eapMethod = enterpriseConfig.getEapMethod();
660                 int phase2Method = enterpriseConfig.getPhase2Method();
661                 mEapMethodSpinner.setSelection(eapMethod);
662                 showEapFieldsByMethod(eapMethod);
663                 switch (eapMethod) {
664                     case Eap.PEAP:
665                         switch (phase2Method) {
666                             case Phase2.NONE:
667                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_NONE);
668                                 break;
669                             case Phase2.MSCHAPV2:
670                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_MSCHAPV2);
671                                 break;
672                             case Phase2.GTC:
673                                 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_GTC);
674                                 break;
675                             default:
676                                 Log.e(TAG, "Invalid phase 2 method " + phase2Method);
677                                 break;
678                         }
679                         break;
680                     default:
681                         mPhase2Spinner.setSelection(phase2Method);
682                         break;
683                 }
684                 setSelection(mEapCaCertSpinner, enterpriseConfig.getCaCertificateAlias());
685                 setSelection(mEapUserCertSpinner, enterpriseConfig.getClientCertificateAlias());
686                 mEapIdentityView.setText(enterpriseConfig.getIdentity());
687                 mEapAnonymousView.setText(enterpriseConfig.getAnonymousIdentity());
688             } else {
689                 // Choose a default for a new network and show only appropriate
690                 // fields
691                 mEapMethodSpinner.setSelection(Eap.PEAP);
692                 showEapFieldsByMethod(Eap.PEAP);
693             }
694         } else {
695             showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition());
696         }
697     }
698 
699     /**
700      * EAP-PWD valid fields include
701      *   identity
702      *   password
703      * EAP-PEAP valid fields include
704      *   phase2: MSCHAPV2, GTC
705      *   ca_cert
706      *   identity
707      *   anonymous_identity
708      *   password
709      * EAP-TLS valid fields include
710      *   user_cert
711      *   ca_cert
712      *   identity
713      * EAP-TTLS valid fields include
714      *   phase2: PAP, MSCHAP, MSCHAPV2, GTC
715      *   ca_cert
716      *   identity
717      *   anonymous_identity
718      *   password
719      */
showEapFieldsByMethod(int eapMethod)720     private void showEapFieldsByMethod(int eapMethod) {
721         // Common defaults
722         mView.findViewById(R.id.l_method).setVisibility(View.VISIBLE);
723         mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE);
724 
725         // Defaults for most of the EAP methods and over-riden by
726         // by certain EAP methods
727         mView.findViewById(R.id.l_ca_cert).setVisibility(View.VISIBLE);
728         mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE);
729         mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE);
730 
731         Context context = mConfigUi.getContext();
732         switch (eapMethod) {
733             case WIFI_EAP_METHOD_PWD:
734                 setPhase2Invisible();
735                 setCaCertInvisible();
736                 setAnonymousIdentInvisible();
737                 setUserCertInvisible();
738                 break;
739             case WIFI_EAP_METHOD_TLS:
740                 mView.findViewById(R.id.l_user_cert).setVisibility(View.VISIBLE);
741                 setPhase2Invisible();
742                 setAnonymousIdentInvisible();
743                 setPasswordInvisible();
744                 break;
745             case WIFI_EAP_METHOD_PEAP:
746                 // Reset adapter if needed
747                 if (mPhase2Adapter != PHASE2_PEAP_ADAPTER) {
748                     mPhase2Adapter = PHASE2_PEAP_ADAPTER;
749                     mPhase2Spinner.setAdapter(mPhase2Adapter);
750                 }
751                 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
752                 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
753                 setUserCertInvisible();
754                 break;
755             case WIFI_EAP_METHOD_TTLS:
756                 // Reset adapter if needed
757                 if (mPhase2Adapter != PHASE2_FULL_ADAPTER) {
758                     mPhase2Adapter = PHASE2_FULL_ADAPTER;
759                     mPhase2Spinner.setAdapter(mPhase2Adapter);
760                 }
761                 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
762                 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
763                 setUserCertInvisible();
764                 break;
765         }
766     }
767 
setPhase2Invisible()768     private void setPhase2Invisible() {
769         mView.findViewById(R.id.l_phase2).setVisibility(View.GONE);
770         mPhase2Spinner.setSelection(Phase2.NONE);
771     }
772 
setCaCertInvisible()773     private void setCaCertInvisible() {
774         mView.findViewById(R.id.l_ca_cert).setVisibility(View.GONE);
775         mEapCaCertSpinner.setSelection(unspecifiedCertIndex);
776     }
777 
setUserCertInvisible()778     private void setUserCertInvisible() {
779         mView.findViewById(R.id.l_user_cert).setVisibility(View.GONE);
780         mEapUserCertSpinner.setSelection(unspecifiedCertIndex);
781     }
782 
setAnonymousIdentInvisible()783     private void setAnonymousIdentInvisible() {
784         mView.findViewById(R.id.l_anonymous).setVisibility(View.GONE);
785         mEapAnonymousView.setText("");
786     }
787 
setPasswordInvisible()788     private void setPasswordInvisible() {
789         mPasswordView.setText("");
790         mView.findViewById(R.id.password_layout).setVisibility(View.GONE);
791         mView.findViewById(R.id.show_password_layout).setVisibility(View.GONE);
792     }
793 
showIpConfigFields()794     private void showIpConfigFields() {
795         WifiConfiguration config = null;
796 
797         mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE);
798 
799         if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
800             config = mAccessPoint.getConfig();
801         }
802 
803         if (mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) {
804             mView.findViewById(R.id.staticip).setVisibility(View.VISIBLE);
805             if (mIpAddressView == null) {
806                 mIpAddressView = (TextView) mView.findViewById(R.id.ipaddress);
807                 mIpAddressView.addTextChangedListener(this);
808                 mGatewayView = (TextView) mView.findViewById(R.id.gateway);
809                 mGatewayView.addTextChangedListener(this);
810                 mNetworkPrefixLengthView = (TextView) mView.findViewById(
811                         R.id.network_prefix_length);
812                 mNetworkPrefixLengthView.addTextChangedListener(this);
813                 mDns1View = (TextView) mView.findViewById(R.id.dns1);
814                 mDns1View.addTextChangedListener(this);
815                 mDns2View = (TextView) mView.findViewById(R.id.dns2);
816                 mDns2View.addTextChangedListener(this);
817             }
818             if (config != null) {
819                 StaticIpConfiguration staticConfig = config.getStaticIpConfiguration();
820                 if (staticConfig != null) {
821                     if (staticConfig.ipAddress != null) {
822                         mIpAddressView.setText(
823                                 staticConfig.ipAddress.getAddress().getHostAddress());
824                         mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress
825                                 .getNetworkPrefixLength()));
826                     }
827 
828                     if (staticConfig.gateway != null) {
829                         mGatewayView.setText(staticConfig.gateway.getHostAddress());
830                     }
831 
832                     Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
833                     if (dnsIterator.hasNext()) {
834                         mDns1View.setText(dnsIterator.next().getHostAddress());
835                     }
836                     if (dnsIterator.hasNext()) {
837                         mDns2View.setText(dnsIterator.next().getHostAddress());
838                     }
839                 }
840             }
841         } else {
842             mView.findViewById(R.id.staticip).setVisibility(View.GONE);
843         }
844     }
845 
showProxyFields()846     private void showProxyFields() {
847         WifiConfiguration config = null;
848 
849         mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE);
850 
851         if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
852             config = mAccessPoint.getConfig();
853         }
854 
855         if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) {
856             setVisibility(R.id.proxy_warning_limited_support, View.VISIBLE);
857             setVisibility(R.id.proxy_fields, View.VISIBLE);
858             setVisibility(R.id.proxy_pac_field, View.GONE);
859             if (mProxyHostView == null) {
860                 mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname);
861                 mProxyHostView.addTextChangedListener(this);
862                 mProxyPortView = (TextView) mView.findViewById(R.id.proxy_port);
863                 mProxyPortView.addTextChangedListener(this);
864                 mProxyExclusionListView = (TextView) mView.findViewById(R.id.proxy_exclusionlist);
865                 mProxyExclusionListView.addTextChangedListener(this);
866             }
867             if (config != null) {
868                 ProxyInfo proxyProperties = config.getHttpProxy();
869                 if (proxyProperties != null) {
870                     mProxyHostView.setText(proxyProperties.getHost());
871                     mProxyPortView.setText(Integer.toString(proxyProperties.getPort()));
872                     mProxyExclusionListView.setText(proxyProperties.getExclusionListAsString());
873                 }
874             }
875         } else if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_PAC) {
876             setVisibility(R.id.proxy_warning_limited_support, View.GONE);
877             setVisibility(R.id.proxy_fields, View.GONE);
878             setVisibility(R.id.proxy_pac_field, View.VISIBLE);
879 
880             if (mProxyPacView == null) {
881                 mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac);
882                 mProxyPacView.addTextChangedListener(this);
883             }
884             if (config != null) {
885                 ProxyInfo proxyInfo = config.getHttpProxy();
886                 if (proxyInfo != null) {
887                     mProxyPacView.setText(proxyInfo.getPacFileUrl().toString());
888                 }
889             }
890         } else {
891             setVisibility(R.id.proxy_warning_limited_support, View.GONE);
892             setVisibility(R.id.proxy_fields, View.GONE);
893             setVisibility(R.id.proxy_pac_field, View.GONE);
894         }
895     }
896 
setVisibility(int id, int visibility)897     private void setVisibility(int id, int visibility) {
898         final View v = mView.findViewById(id);
899         if (v != null) {
900             v.setVisibility(visibility);
901         }
902     }
903 
loadCertificates(Spinner spinner, String prefix)904     private void loadCertificates(Spinner spinner, String prefix) {
905         final Context context = mConfigUi.getContext();
906 
907         String[] certs = KeyStore.getInstance().saw(prefix, android.os.Process.WIFI_UID);
908         if (certs == null || certs.length == 0) {
909             certs = new String[] {unspecifiedCert};
910         } else {
911             final String[] array = new String[certs.length + 1];
912             array[0] = unspecifiedCert;
913             System.arraycopy(certs, 0, array, 1, certs.length);
914             certs = array;
915         }
916 
917         final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
918                 context, android.R.layout.simple_spinner_item, certs);
919         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
920         spinner.setAdapter(adapter);
921     }
922 
setSelection(Spinner spinner, String value)923     private void setSelection(Spinner spinner, String value) {
924         if (value != null) {
925             @SuppressWarnings("unchecked")
926             ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter();
927             for (int i = adapter.getCount() - 1; i >= 0; --i) {
928                 if (value.equals(adapter.getItem(i))) {
929                     spinner.setSelection(i);
930                     break;
931                 }
932             }
933         }
934     }
935 
isEdit()936     public boolean isEdit() {
937         return mEdit;
938     }
939 
940     @Override
afterTextChanged(Editable s)941     public void afterTextChanged(Editable s) {
942         mTextViewChangedHandler.post(new Runnable() {
943                 public void run() {
944                     enableSubmitIfAppropriate();
945                 }
946             });
947     }
948 
949     @Override
beforeTextChanged(CharSequence s, int start, int count, int after)950     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
951         // work done in afterTextChanged
952     }
953 
954     @Override
onTextChanged(CharSequence s, int start, int before, int count)955     public void onTextChanged(CharSequence s, int start, int before, int count) {
956         // work done in afterTextChanged
957     }
958 
959     @Override
onCheckedChanged(CompoundButton view, boolean isChecked)960     public void onCheckedChanged(CompoundButton view, boolean isChecked) {
961         if (view.getId() == R.id.show_password) {
962             int pos = mPasswordView.getSelectionEnd();
963             mPasswordView.setInputType(
964                     InputType.TYPE_CLASS_TEXT | (isChecked ?
965                             InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
966                                 InputType.TYPE_TEXT_VARIATION_PASSWORD));
967             if (pos >= 0) {
968                 ((EditText)mPasswordView).setSelection(pos);
969             }
970         } else if (view.getId() == R.id.wifi_advanced_togglebox) {
971             if (isChecked) {
972                 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE);
973             } else {
974                 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.GONE);
975             }
976         }
977     }
978 
979     @Override
onItemSelected(AdapterView<?> parent, View view, int position, long id)980     public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
981         if (parent == mSecuritySpinner) {
982             mAccessPointSecurity = position;
983             showSecurityFields();
984         } else if (parent == mEapMethodSpinner) {
985             showSecurityFields();
986         } else if (parent == mProxySettingsSpinner) {
987             showProxyFields();
988         } else {
989             showIpConfigFields();
990         }
991         enableSubmitIfAppropriate();
992     }
993 
994     @Override
onNothingSelected(AdapterView<?> parent)995     public void onNothingSelected(AdapterView<?> parent) {
996         //
997     }
998 
999     /**
1000      * Make the characters of the password visible if show_password is checked.
1001      */
updatePasswordVisibility(boolean checked)1002     private void updatePasswordVisibility(boolean checked) {
1003         int pos = mPasswordView.getSelectionEnd();
1004         mPasswordView.setInputType(
1005                 InputType.TYPE_CLASS_TEXT | (checked ?
1006                         InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD :
1007                             InputType.TYPE_TEXT_VARIATION_PASSWORD));
1008         if (pos >= 0) {
1009             ((EditText)mPasswordView).setSelection(pos);
1010         }
1011     }
1012 }
1013