2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.wifi;
19 import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
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;
62 import com.android.settings.ProxySelector;
63 import com.android.settings.R;
65 import java.net.InetAddress;
66 import java.net.Inet4Address;
67 import java.util.Iterator;
70 * The class for allowing UIs like {@link WifiDialog} and {@link WifiConfigUiBase} to
71 * share the logic for controlling buttons, text fields, etc.
73 public class WifiConfigController implements TextWatcher,
74 AdapterView.OnItemSelectedListener, OnCheckedChangeListener {
75 private static final String TAG = "WifiConfigController";
77 private final WifiConfigUiBase mConfigUi;
78 private final View mView;
79 private final AccessPoint mAccessPoint;
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;
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;
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;
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;
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;
106 // True when this instance is used in SetupWizard XL context.
107 private final boolean mInXlSetupWizard;
109 private final Handler mTextViewChangedHandler;
111 // e.g. AccessPoint.SECURITY_NONE
112 private int mAccessPointSecurity;
113 private TextView mPasswordView;
115 private String unspecifiedCert = "unspecified";
116 private static final int unspecifiedCertIndex = 0;
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;
128 private Spinner mIpSettingsSpinner;
129 private TextView mIpAddressView;
130 private TextView mGatewayView;
131 private TextView mNetworkPrefixLengthView;
132 private TextView mDns1View;
133 private TextView mDns2View;
135 private Spinner mProxySettingsSpinner;
136 private TextView mProxyHostView;
137 private TextView mProxyPortView;
138 private TextView mProxyExclusionListView;
139 private TextView mProxyPacView;
141 private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED;
142 private ProxySettings mProxySettings = ProxySettings.UNASSIGNED;
143 private ProxyInfo mHttpProxy = null;
144 private StaticIpConfiguration mStaticIpConfiguration = null;
146 private String[] mLevels;
147 private boolean mEdit;
148 private TextView mSsidView;
150 private Context mContext;
152 public WifiConfigController(
153 WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit) {
155 mInXlSetupWizard = (parent instanceof WifiConfigUiForSetupWizardXL);
158 mAccessPoint = accessPoint;
159 mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE :
160 accessPoint.security;
163 mTextViewChangedHandler = new Handler();
164 mContext = mConfigUi.getContext();
165 final Resources res = mContext.getResources();
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);
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);
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);
184 if (mAccessPoint == null) { // new network
185 mConfigUi.setTitle(R.string.wifi_add_network);
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.
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);
201 mView.findViewById(R.id.type).setVisibility(View.VISIBLE);
204 showIpConfigFields();
206 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE);
207 ((CheckBox)mView.findViewById(R.id.wifi_advanced_togglebox))
208 .setOnCheckedChangeListener(this);
211 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
213 mConfigUi.setTitle(mAccessPoint.ssid);
215 ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
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());
230 mIpSettingsSpinner.setSelection(DHCP);
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;
241 mProxySettingsSpinner.setSelection(PROXY_NONE);
245 if (mAccessPoint.networkId == INVALID_NETWORK_ID || mEdit) {
246 showSecurityFields();
247 showIpConfigFields();
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);
259 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
261 final DetailedState state = mAccessPoint.getState();
262 final String signalLevel = getSignalString();
264 if (state == null && signalLevel != null) {
265 mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect));
268 addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(),
272 if (signalLevel != null) {
273 addRow(group, R.string.wifi_signal, signalLevel);
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);
282 if (info != null && info.getFrequency() != -1) {
283 final int frequency = info.getFrequency();
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);
293 Log.e(TAG, "Unexpected frequency " + frequency);
296 addRow(group, R.string.wifi_frequency, band);
300 addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
301 mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
303 if (mAccessPoint.networkId != INVALID_NETWORK_ID
304 && ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) {
305 mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
310 if (mEdit || (mAccessPoint.getState() == null && mAccessPoint.getLevel() != -1)){
311 mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel));
313 mConfigUi.setCancelButton(res.getString(R.string.wifi_display_options_done));
315 if (mConfigUi.getSubmitButton() != null) {
316 enableSubmitIfAppropriate();
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);
327 private String getSignalString(){
328 final int level = mAccessPoint.getLevel();
330 return (level > -1 && level < mLevels.length) ? mLevels[level] : null;
333 void hideSubmitButton() {
334 Button submit = mConfigUi.getSubmitButton();
335 if (submit == null) return;
337 submit.setVisibility(View.GONE);
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;
345 boolean enabled = false;
346 boolean passwordInvalid = false;
348 if (mPasswordView != null &&
349 ((mAccessPointSecurity == AccessPoint.SECURITY_WEP && mPasswordView.length() == 0) ||
350 (mAccessPointSecurity == AccessPoint.SECURITY_PSK && mPasswordView.length() < 8))) {
351 passwordInvalid = true;
354 if ((mSsidView != null && mSsidView.length() == 0) ||
355 ((mAccessPoint == null || mAccessPoint.networkId == INVALID_NETWORK_ID) &&
359 if (ipAndProxyFieldsAreValid()) {
365 submit.setEnabled(enabled);
368 /* package */ WifiConfiguration getConfig() {
369 if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID && !mEdit) {
373 WifiConfiguration config = new WifiConfiguration();
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(
384 config.networkId = mAccessPoint.networkId;
387 switch (mAccessPointSecurity) {
388 case AccessPoint.SECURITY_NONE:
389 config.allowedKeyManagement.set(KeyMgmt.NONE);
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;
404 config.wepKeys[0] = '"' + password + '"';
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;
416 config.preSharedKey = '"' + password + '"';
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);
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);
437 case WIFI_PEAP_PHASE2_MSCHAPV2:
438 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2);
440 case WIFI_PEAP_PHASE2_GTC:
441 config.enterpriseConfig.setPhase2Method(Phase2.GTC);
444 Log.e(TAG, "Unknown phase2 method" + phase2Method);
449 // The default index from PHASE2_FULL_ADAPTER maps to the API
450 config.enterpriseConfig.setPhase2Method(phase2Method);
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());
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());
471 config.enterpriseConfig.setPassword(mPasswordView.getText().toString());
478 config.setIpConfiguration(
479 new IpConfiguration(mIpAssignment, mProxySettings,
480 mStaticIpConfiguration, mHttpProxy));
485 private boolean ipAndProxyFieldsAreValid() {
486 mIpAssignment = (mIpSettingsSpinner != null &&
487 mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) ?
488 IpAssignment.STATIC : IpAssignment.DHCP;
490 if (mIpAssignment == IpAssignment.STATIC) {
491 mStaticIpConfiguration = new StaticIpConfiguration();
492 int result = validateIpConfigFields(mStaticIpConfiguration);
498 final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition();
499 mProxySettings = ProxySettings.NONE;
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();
509 port = Integer.parseInt(portStr);
510 result = ProxySelector.validate(host, portStr, exclusionList);
511 } catch (NumberFormatException e) {
512 result = R.string.proxy_error_invalid_port;
515 mHttpProxy = new ProxyInfo(host, port, exclusionList);
519 } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) {
520 mProxySettings = ProxySettings.PAC;
521 CharSequence uriSequence = mProxyPacView.getText();
522 if (TextUtils.isEmpty(uriSequence)) {
525 Uri uri = Uri.parse(uriSequence.toString());
529 mHttpProxy = new ProxyInfo(uri);
534 private Inet4Address getIPv4Address(String text) {
536 return (Inet4Address) NetworkUtils.numericToInetAddress(text);
537 } catch (IllegalArgumentException|ClassCastException e) {
542 private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) {
543 if (mIpAddressView == null) return 0;
545 String ipAddr = mIpAddressView.getText().toString();
546 if (TextUtils.isEmpty(ipAddr)) return R.string.wifi_ip_settings_invalid_ip_address;
548 Inet4Address inetAddr = getIPv4Address(ipAddr);
549 if (inetAddr == null) {
550 return R.string.wifi_ip_settings_invalid_ip_address;
553 int networkPrefixLength = -1;
555 networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString());
556 if (networkPrefixLength < 0 || networkPrefixLength > 32) {
557 return R.string.wifi_ip_settings_invalid_network_prefix_length;
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));
566 String gateway = mGatewayView.getText().toString();
567 if (TextUtils.isEmpty(gateway)) {
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) {
578 InetAddress gatewayAddr = getIPv4Address(gateway);
579 if (gatewayAddr == null) {
580 return R.string.wifi_ip_settings_invalid_gateway;
582 staticIpConfiguration.gateway = gatewayAddr;
585 String dns = mDns1View.getText().toString();
586 InetAddress dnsAddr = null;
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));
592 dnsAddr = getIPv4Address(dns);
593 if (dnsAddr == null) {
594 return R.string.wifi_ip_settings_invalid_dns;
596 staticIpConfiguration.dnsServers.add(dnsAddr);
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;
605 staticIpConfiguration.dnsServers.add(dnsAddr);
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)) {
618 if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) {
619 mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
622 mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE);
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);
630 if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
631 mPasswordView.setHint(R.string.wifi_unchanged);
635 if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) {
636 mView.findViewById(R.id.eap).setVisibility(View.GONE);
639 mView.findViewById(R.id.eap).setVisibility(View.VISIBLE);
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);
650 loadCertificates(mEapCaCertSpinner, Credentials.CA_CERTIFICATE);
651 loadCertificates(mEapUserCertSpinner, Credentials.USER_PRIVATE_KEY);
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);
662 switch (phase2Method) {
664 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_NONE);
666 case Phase2.MSCHAPV2:
667 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_MSCHAPV2);
670 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_GTC);
673 Log.e(TAG, "Invalid phase 2 method " + phase2Method);
678 mPhase2Spinner.setSelection(phase2Method);
681 setSelection(mEapCaCertSpinner, enterpriseConfig.getCaCertificateAlias());
682 setSelection(mEapUserCertSpinner, enterpriseConfig.getClientCertificateAlias());
683 mEapIdentityView.setText(enterpriseConfig.getIdentity());
684 mEapAnonymousView.setText(enterpriseConfig.getAnonymousIdentity());
686 // Choose a default for a new network and show only appropriate
688 mEapMethodSpinner.setSelection(Eap.PEAP);
689 showEapFieldsByMethod(Eap.PEAP);
692 showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition());
697 * EAP-PWD valid fields include
700 * EAP-PEAP valid fields include
701 * phase2: MSCHAPV2, GTC
706 * EAP-TLS valid fields include
710 * EAP-TTLS valid fields include
711 * phase2: PAP, MSCHAP, MSCHAPV2, GTC
717 private void showEapFieldsByMethod(int eapMethod) {
719 mView.findViewById(R.id.l_method).setVisibility(View.VISIBLE);
720 mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE);
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);
728 Context context = mConfigUi.getContext();
730 case WIFI_EAP_METHOD_PWD:
731 setPhase2Invisible();
732 setCaCertInvisible();
733 setAnonymousIdentInvisible();
734 setUserCertInvisible();
736 case WIFI_EAP_METHOD_TLS:
737 mView.findViewById(R.id.l_user_cert).setVisibility(View.VISIBLE);
738 setPhase2Invisible();
739 setAnonymousIdentInvisible();
740 setPasswordInvisible();
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);
748 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
749 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
750 setUserCertInvisible();
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);
758 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE);
759 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE);
760 setUserCertInvisible();
765 private void setPhase2Invisible() {
766 mView.findViewById(R.id.l_phase2).setVisibility(View.GONE);
767 mPhase2Spinner.setSelection(Phase2.NONE);
770 private void setCaCertInvisible() {
771 mView.findViewById(R.id.l_ca_cert).setVisibility(View.GONE);
772 mEapCaCertSpinner.setSelection(unspecifiedCertIndex);
775 private void setUserCertInvisible() {
776 mView.findViewById(R.id.l_user_cert).setVisibility(View.GONE);
777 mEapUserCertSpinner.setSelection(unspecifiedCertIndex);
780 private void setAnonymousIdentInvisible() {
781 mView.findViewById(R.id.l_anonymous).setVisibility(View.GONE);
782 mEapAnonymousView.setText("");
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);
791 private void showIpConfigFields() {
792 WifiConfiguration config = null;
794 mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE);
796 if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
797 config = mAccessPoint.getConfig();
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);
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()));
825 if (staticConfig.gateway != null) {
826 mGatewayView.setText(staticConfig.gateway.getHostAddress());
829 Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator();
830 if (dnsIterator.hasNext()) {
831 mDns1View.setText(dnsIterator.next().getHostAddress());
833 if (dnsIterator.hasNext()) {
834 mDns2View.setText(dnsIterator.next().getHostAddress());
839 mView.findViewById(R.id.staticip).setVisibility(View.GONE);
843 private void showProxyFields() {
844 WifiConfiguration config = null;
846 mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE);
848 if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
849 config = mAccessPoint.getConfig();
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);
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());
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);
877 if (mProxyPacView == null) {
878 mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac);
879 mProxyPacView.addTextChangedListener(this);
881 if (config != null) {
882 ProxyInfo proxyInfo = config.getHttpProxy();
883 if (proxyInfo != null) {
884 mProxyPacView.setText(proxyInfo.getPacFileUrl().toString());
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);
894 private void setVisibility(int id, int visibility) {
895 final View v = mView.findViewById(id);
897 v.setVisibility(visibility);
901 private void loadCertificates(Spinner spinner, String prefix) {
902 final Context context = mConfigUi.getContext();
904 String[] certs = KeyStore.getInstance().saw(prefix, android.os.Process.WIFI_UID);
905 if (certs == null || certs.length == 0) {
906 certs = new String[] {unspecifiedCert};
908 final String[] array = new String[certs.length + 1];
909 array[0] = unspecifiedCert;
910 System.arraycopy(certs, 0, array, 1, certs.length);
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);
920 private void setSelection(Spinner spinner, String value) {
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);
933 public boolean isEdit() {
938 public void afterTextChanged(Editable s) {
939 mTextViewChangedHandler.post(new Runnable() {
941 enableSubmitIfAppropriate();
947 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
948 // work done in afterTextChanged
952 public void onTextChanged(CharSequence s, int start, int before, int count) {
953 // work done in afterTextChanged
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));
965 ((EditText)mPasswordView).setSelection(pos);
967 } else if (view.getId() == R.id.wifi_advanced_togglebox) {
969 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE);
971 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.GONE);
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) {
986 showIpConfigFields();
988 enableSubmitIfAppropriate();
992 public void onNothingSelected(AdapterView<?> parent) {
997 * Make the characters of the password visible if show_password is checked.
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));
1006 ((EditText)mPasswordView).setSelection(pos);