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