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