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