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