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