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 17package com.android.settings.wifi; 18 19import android.content.Context; 20import android.content.res.Resources; 21import android.net.IpConfiguration; 22import android.net.IpConfiguration.IpAssignment; 23import android.net.IpConfiguration.ProxySettings; 24import android.net.LinkAddress; 25import android.net.NetworkInfo.DetailedState; 26import android.net.NetworkUtils; 27import android.net.ProxyInfo; 28import android.net.StaticIpConfiguration; 29import android.net.Uri; 30import android.net.wifi.WifiConfiguration; 31import android.net.wifi.WifiConfiguration.AuthAlgorithm; 32import android.net.wifi.WifiConfiguration.KeyMgmt; 33import android.net.wifi.WifiEnterpriseConfig; 34import android.net.wifi.WifiEnterpriseConfig.Eap; 35import android.net.wifi.WifiEnterpriseConfig.Phase2; 36import android.net.wifi.WifiInfo; 37import android.os.Handler; 38import android.os.UserManager; 39import android.security.Credentials; 40import android.security.KeyStore; 41import android.support.annotation.VisibleForTesting; 42import android.text.Editable; 43import android.text.InputType; 44import android.text.TextUtils; 45import android.text.TextWatcher; 46import android.util.Log; 47import android.view.KeyEvent; 48import android.view.View; 49import android.view.ViewGroup; 50import android.view.inputmethod.EditorInfo; 51import android.widget.AdapterView; 52import android.widget.ArrayAdapter; 53import android.widget.Button; 54import android.widget.CheckBox; 55import android.widget.CompoundButton; 56import android.widget.CompoundButton.OnCheckedChangeListener; 57import android.widget.EditText; 58import android.widget.ScrollView; 59import android.widget.Spinner; 60import android.widget.TextView; 61 62import com.android.settings.ProxySelector; 63import com.android.settings.R; 64import com.android.settingslib.Utils; 65import com.android.settingslib.utils.ThreadUtils; 66import com.android.settingslib.wifi.AccessPoint; 67 68import java.net.Inet4Address; 69import java.net.InetAddress; 70import java.util.ArrayList; 71import java.util.Arrays; 72import java.util.Iterator; 73 74/** 75 * The class for allowing UIs like {@link WifiDialog} and {@link WifiConfigUiBase} to 76 * share the logic for controlling buttons, text fields, etc. 77 */ 78public class WifiConfigController implements TextWatcher, 79 AdapterView.OnItemSelectedListener, OnCheckedChangeListener, 80 TextView.OnEditorActionListener, View.OnKeyListener { 81 private static final String TAG = "WifiConfigController"; 82 83 private static final String SYSTEM_CA_STORE_PATH = "/system/etc/security/cacerts"; 84 85 private final WifiConfigUiBase mConfigUi; 86 private final View mView; 87 private final AccessPoint mAccessPoint; 88 89 /* This value comes from "wifi_ip_settings" resource array */ 90 private static final int DHCP = 0; 91 private static final int STATIC_IP = 1; 92 93 /* Constants used for referring to the hidden state of a network. */ 94 public static final int HIDDEN_NETWORK = 1; 95 public static final int NOT_HIDDEN_NETWORK = 0; 96 97 /* These values come from "wifi_proxy_settings" resource array */ 98 public static final int PROXY_NONE = 0; 99 public static final int PROXY_STATIC = 1; 100 public static final int PROXY_PAC = 2; 101 102 /* These values come from "wifi_eap_method" resource array */ 103 public static final int WIFI_EAP_METHOD_PEAP = 0; 104 public static final int WIFI_EAP_METHOD_TLS = 1; 105 public static final int WIFI_EAP_METHOD_TTLS = 2; 106 public static final int WIFI_EAP_METHOD_PWD = 3; 107 public static final int WIFI_EAP_METHOD_SIM = 4; 108 public static final int WIFI_EAP_METHOD_AKA = 5; 109 public static final int WIFI_EAP_METHOD_AKA_PRIME = 6; 110 111 /* These values come from "wifi_peap_phase2_entries" resource array */ 112 public static final int WIFI_PEAP_PHASE2_NONE = 0; 113 public static final int WIFI_PEAP_PHASE2_MSCHAPV2 = 1; 114 public static final int WIFI_PEAP_PHASE2_GTC = 2; 115 public static final int WIFI_PEAP_PHASE2_SIM = 3; 116 public static final int WIFI_PEAP_PHASE2_AKA = 4; 117 public static final int WIFI_PEAP_PHASE2_AKA_PRIME = 5; 118 119 120 /* Phase2 methods supported by PEAP are limited */ 121 private final ArrayAdapter<String> mPhase2PeapAdapter; 122 /* Full list of phase2 methods */ 123 private final ArrayAdapter<String> mPhase2FullAdapter; 124 125 // e.g. AccessPoint.SECURITY_NONE 126 private int mAccessPointSecurity; 127 private TextView mPasswordView; 128 129 private String mUnspecifiedCertString; 130 private String mMultipleCertSetString; 131 private String mUseSystemCertsString; 132 private String mDoNotProvideEapUserCertString; 133 private String mDoNotValidateEapServerString; 134 135 private ScrollView mDialogContainer; 136 private Spinner mSecuritySpinner; 137 private Spinner mEapMethodSpinner; 138 private Spinner mEapCaCertSpinner; 139 private TextView mEapDomainView; 140 private Spinner mPhase2Spinner; 141 // Associated with mPhase2Spinner, one of mPhase2FullAdapter or mPhase2PeapAdapter 142 private ArrayAdapter<String> mPhase2Adapter; 143 private Spinner mEapUserCertSpinner; 144 private TextView mEapIdentityView; 145 private TextView mEapAnonymousView; 146 147 private Spinner mIpSettingsSpinner; 148 private TextView mIpAddressView; 149 private TextView mGatewayView; 150 private TextView mNetworkPrefixLengthView; 151 private TextView mDns1View; 152 private TextView mDns2View; 153 154 private Spinner mProxySettingsSpinner; 155 private Spinner mMeteredSettingsSpinner; 156 private Spinner mHiddenSettingsSpinner; 157 private TextView mHiddenWarningView; 158 private TextView mProxyHostView; 159 private TextView mProxyPortView; 160 private TextView mProxyExclusionListView; 161 private TextView mProxyPacView; 162 private CheckBox mSharedCheckBox; 163 164 private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED; 165 private ProxySettings mProxySettings = ProxySettings.UNASSIGNED; 166 private ProxyInfo mHttpProxy = null; 167 private StaticIpConfiguration mStaticIpConfiguration = null; 168 169 private String[] mLevels; 170 private int mMode; 171 private TextView mSsidView; 172 173 private Context mContext; 174 175 public WifiConfigController(WifiConfigUiBase parent, View view, AccessPoint accessPoint, 176 int mode) { 177 mConfigUi = parent; 178 179 mView = view; 180 mAccessPoint = accessPoint; 181 mAccessPointSecurity = (accessPoint == null) ? AccessPoint.SECURITY_NONE : 182 accessPoint.getSecurity(); 183 mMode = mode; 184 185 mContext = mConfigUi.getContext(); 186 final Resources res = mContext.getResources(); 187 188 mLevels = res.getStringArray(R.array.wifi_signal); 189 if (Utils.isWifiOnly(mContext) || !mContext.getResources().getBoolean( 190 com.android.internal.R.bool.config_eap_sim_based_auth_supported)) { 191 mPhase2PeapAdapter = new ArrayAdapter<String>( 192 mContext, android.R.layout.simple_spinner_item, 193 res.getStringArray(R.array.wifi_peap_phase2_entries)); 194 } else { 195 mPhase2PeapAdapter = new ArrayAdapter<String>( 196 mContext, android.R.layout.simple_spinner_item, 197 res.getStringArray(R.array.wifi_peap_phase2_entries_with_sim_auth)); 198 } 199 mPhase2PeapAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 200 201 mPhase2FullAdapter = new ArrayAdapter<String>( 202 mContext, android.R.layout.simple_spinner_item, 203 res.getStringArray(R.array.wifi_phase2_entries)); 204 mPhase2FullAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 205 206 mUnspecifiedCertString = mContext.getString(R.string.wifi_unspecified); 207 mMultipleCertSetString = mContext.getString(R.string.wifi_multiple_cert_added); 208 mUseSystemCertsString = mContext.getString(R.string.wifi_use_system_certs); 209 mDoNotProvideEapUserCertString = 210 mContext.getString(R.string.wifi_do_not_provide_eap_user_cert); 211 mDoNotValidateEapServerString = 212 mContext.getString(R.string.wifi_do_not_validate_eap_server); 213 214 mDialogContainer = mView.findViewById(R.id.dialog_scrollview); 215 mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings); 216 mIpSettingsSpinner.setOnItemSelectedListener(this); 217 mProxySettingsSpinner = (Spinner) mView.findViewById(R.id.proxy_settings); 218 mProxySettingsSpinner.setOnItemSelectedListener(this); 219 mSharedCheckBox = (CheckBox) mView.findViewById(R.id.shared); 220 mMeteredSettingsSpinner = mView.findViewById(R.id.metered_settings); 221 mHiddenSettingsSpinner = mView.findViewById(R.id.hidden_settings); 222 mHiddenSettingsSpinner.setOnItemSelectedListener(this); 223 mHiddenWarningView = mView.findViewById(R.id.hidden_settings_warning); 224 mHiddenWarningView.setVisibility( 225 mHiddenSettingsSpinner.getSelectedItemPosition() == NOT_HIDDEN_NETWORK 226 ? View.GONE 227 : View.VISIBLE); 228 229 if (mAccessPoint == null) { // new network 230 mConfigUi.setTitle(R.string.wifi_add_network); 231 232 mSsidView = (TextView) mView.findViewById(R.id.ssid); 233 mSsidView.addTextChangedListener(this); 234 mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security)); 235 mSecuritySpinner.setOnItemSelectedListener(this); 236 mView.findViewById(R.id.type).setVisibility(View.VISIBLE); 237 238 showIpConfigFields(); 239 showProxyFields(); 240 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE); 241 // Hidden option can be changed only when the user adds a network manually. 242 mView.findViewById(R.id.hidden_settings_field).setVisibility(View.VISIBLE); 243 ((CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox)) 244 .setOnCheckedChangeListener(this); 245 246 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save)); 247 } else { 248 if (!mAccessPoint.isPasspointConfig()) { 249 mConfigUi.setTitle(mAccessPoint.getSsid()); 250 } else { 251 mConfigUi.setTitle(mAccessPoint.getConfigName()); 252 } 253 254 ViewGroup group = (ViewGroup) mView.findViewById(R.id.info); 255 256 boolean showAdvancedFields = false; 257 if (mAccessPoint.isSaved()) { 258 WifiConfiguration config = mAccessPoint.getConfig(); 259 mMeteredSettingsSpinner.setSelection(config.meteredOverride); 260 mHiddenSettingsSpinner.setSelection(config.hiddenSSID 261 ? HIDDEN_NETWORK 262 : NOT_HIDDEN_NETWORK); 263 if (config.getIpAssignment() == IpAssignment.STATIC) { 264 mIpSettingsSpinner.setSelection(STATIC_IP); 265 showAdvancedFields = true; 266 // Display IP address. 267 StaticIpConfiguration staticConfig = config.getStaticIpConfiguration(); 268 if (staticConfig != null && staticConfig.ipAddress != null) { 269 addRow(group, R.string.wifi_ip_address, 270 staticConfig.ipAddress.getAddress().getHostAddress()); 271 } 272 } else { 273 mIpSettingsSpinner.setSelection(DHCP); 274 } 275 276 mSharedCheckBox.setEnabled(config.shared); 277 if (!config.shared) { 278 showAdvancedFields = true; 279 } 280 281 if (config.getProxySettings() == ProxySettings.STATIC) { 282 mProxySettingsSpinner.setSelection(PROXY_STATIC); 283 showAdvancedFields = true; 284 } else if (config.getProxySettings() == ProxySettings.PAC) { 285 mProxySettingsSpinner.setSelection(PROXY_PAC); 286 showAdvancedFields = true; 287 } else { 288 mProxySettingsSpinner.setSelection(PROXY_NONE); 289 } 290 if (config != null && config.isPasspoint()) { 291 addRow(group, R.string.passpoint_label, 292 String.format(mContext.getString(R.string.passpoint_content), 293 config.providerFriendlyName)); 294 } 295 } 296 297 if ((!mAccessPoint.isSaved() && !mAccessPoint.isActive() 298 && !mAccessPoint.isPasspointConfig()) 299 || mMode != WifiConfigUiBase.MODE_VIEW) { 300 showSecurityFields(); 301 showIpConfigFields(); 302 showProxyFields(); 303 final CheckBox advancedTogglebox = 304 (CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox); 305 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility( 306 mAccessPoint.isCarrierAp() ? View.GONE : View.VISIBLE); 307 advancedTogglebox.setOnCheckedChangeListener(this); 308 advancedTogglebox.setChecked(showAdvancedFields); 309 mView.findViewById(R.id.wifi_advanced_fields) 310 .setVisibility(showAdvancedFields ? View.VISIBLE : View.GONE); 311 if (mAccessPoint.isCarrierAp()) { 312 addRow(group, R.string.wifi_carrier_connect, 313 String.format(mContext.getString(R.string.wifi_carrier_content), 314 mAccessPoint.getCarrierName())); 315 } 316 } 317 318 if (mMode == WifiConfigUiBase.MODE_MODIFY) { 319 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save)); 320 } else if (mMode == WifiConfigUiBase.MODE_CONNECT) { 321 mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect)); 322 } else { 323 final DetailedState state = mAccessPoint.getDetailedState(); 324 final String signalLevel = getSignalString(); 325 326 if ((state == null || state == DetailedState.DISCONNECTED) && signalLevel != null) { 327 mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect)); 328 } else { 329 if (state != null) { 330 boolean isEphemeral = mAccessPoint.isEphemeral(); 331 WifiConfiguration config = mAccessPoint.getConfig(); 332 String providerFriendlyName = null; 333 if (config != null && config.isPasspoint()) { 334 providerFriendlyName = config.providerFriendlyName; 335 } 336 String summary = AccessPoint.getSummary( 337 mConfigUi.getContext(), state, isEphemeral, providerFriendlyName); 338 addRow(group, R.string.wifi_status, summary); 339 } 340 341 if (signalLevel != null) { 342 addRow(group, R.string.wifi_signal, signalLevel); 343 } 344 345 WifiInfo info = mAccessPoint.getInfo(); 346 if (info != null && info.getLinkSpeed() != -1) { 347 addRow(group, R.string.wifi_speed, String.format( 348 res.getString(R.string.link_speed), info.getLinkSpeed())); 349 } 350 351 if (info != null && info.getFrequency() != -1) { 352 final int frequency = info.getFrequency(); 353 String band = null; 354 355 if (frequency >= AccessPoint.LOWER_FREQ_24GHZ 356 && frequency < AccessPoint.HIGHER_FREQ_24GHZ) { 357 band = res.getString(R.string.wifi_band_24ghz); 358 } else if (frequency >= AccessPoint.LOWER_FREQ_5GHZ 359 && frequency < AccessPoint.HIGHER_FREQ_5GHZ) { 360 band = res.getString(R.string.wifi_band_5ghz); 361 } else { 362 Log.e(TAG, "Unexpected frequency " + frequency); 363 } 364 if (band != null) { 365 addRow(group, R.string.wifi_frequency, band); 366 } 367 } 368 369 addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false)); 370 mView.findViewById(R.id.ip_fields).setVisibility(View.GONE); 371 } 372 if (mAccessPoint.isSaved() || mAccessPoint.isActive() 373 || mAccessPoint.isPasspointConfig()) { 374 mConfigUi.setForgetButton(res.getString(R.string.wifi_forget)); 375 } 376 } 377 } 378 379 if (!isSplitSystemUser()) { 380 mSharedCheckBox.setVisibility(View.GONE); 381 } 382 383 mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel)); 384 if (mConfigUi.getSubmitButton() != null) { 385 enableSubmitIfAppropriate(); 386 } 387 388 // After done view show and hide, request focus from parent view 389 mView.findViewById(R.id.l_wifidialog).requestFocus(); 390 } 391 392 @VisibleForTesting 393 boolean isSplitSystemUser() { 394 final UserManager userManager = 395 (UserManager) mContext.getSystemService(Context.USER_SERVICE); 396 return userManager.isSplitSystemUser(); 397 } 398 399 private void addRow(ViewGroup group, int name, String value) { 400 View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false); 401 ((TextView) row.findViewById(R.id.name)).setText(name); 402 ((TextView) row.findViewById(R.id.value)).setText(value); 403 group.addView(row); 404 } 405 406 @VisibleForTesting 407 String getSignalString() { 408 if (!mAccessPoint.isReachable()) { 409 return null; 410 } 411 final int level = mAccessPoint.getLevel(); 412 413 return (level > -1 && level < mLevels.length) ? mLevels[level] : null; 414 } 415 416 void hideForgetButton() { 417 Button forget = mConfigUi.getForgetButton(); 418 if (forget == null) return; 419 420 forget.setVisibility(View.GONE); 421 } 422 423 void hideSubmitButton() { 424 Button submit = mConfigUi.getSubmitButton(); 425 if (submit == null) return; 426 427 submit.setVisibility(View.GONE); 428 } 429 430 /* show submit button if password, ip and proxy settings are valid */ 431 void enableSubmitIfAppropriate() { 432 Button submit = mConfigUi.getSubmitButton(); 433 if (submit == null) return; 434 435 submit.setEnabled(isSubmittable()); 436 } 437 438 boolean isValidPsk(String password) { 439 if (password.length() == 64 && password.matches("[0-9A-Fa-f]{64}")) { 440 return true; 441 } else if (password.length() >= 8 && password.length() <= 63) { 442 return true; 443 } 444 return false; 445 } 446 447 boolean isSubmittable() { 448 boolean enabled = false; 449 boolean passwordInvalid = false; 450 if (mPasswordView != null 451 && ((mAccessPointSecurity == AccessPoint.SECURITY_WEP 452 && mPasswordView.length() == 0) 453 || (mAccessPointSecurity == AccessPoint.SECURITY_PSK 454 && !isValidPsk(mPasswordView.getText().toString())))) { 455 passwordInvalid = true; 456 } 457 if ((mSsidView != null && mSsidView.length() == 0) 458 // If Accesspoint is not saved, apply passwordInvalid check 459 || ((mAccessPoint == null || !mAccessPoint.isSaved()) && passwordInvalid 460 // If AccessPoint is saved (modifying network) and password is changed, apply 461 // Invalid password check 462 || mAccessPoint != null && mAccessPoint.isSaved() && passwordInvalid 463 && mPasswordView.length() > 0)) { 464 enabled = false; 465 } else { 466 enabled = ipAndProxyFieldsAreValid(); 467 } 468 if (mEapCaCertSpinner != null 469 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) { 470 String caCertSelection = (String) mEapCaCertSpinner.getSelectedItem(); 471 if (caCertSelection.equals(mUnspecifiedCertString)) { 472 // Disallow submit if the user has not selected a CA certificate for an EAP network 473 // configuration. 474 enabled = false; 475 } 476 if (caCertSelection.equals(mUseSystemCertsString) 477 && mEapDomainView != null 478 && mView.findViewById(R.id.l_domain).getVisibility() != View.GONE 479 && TextUtils.isEmpty(mEapDomainView.getText().toString())) { 480 // Disallow submit if the user chooses to use system certificates for EAP server 481 // validation, but does not provide a domain. 482 enabled = false; 483 } 484 } 485 if (mEapUserCertSpinner != null 486 && mView.findViewById(R.id.l_user_cert).getVisibility() != View.GONE 487 && ((String) mEapUserCertSpinner.getSelectedItem()) 488 .equals(mUnspecifiedCertString)) { 489 // Disallow submit if the user has not selected a user certificate for an EAP network 490 // configuration. 491 enabled = false; 492 } 493 return enabled; 494 } 495 496 void showWarningMessagesIfAppropriate() { 497 mView.findViewById(R.id.no_ca_cert_warning).setVisibility(View.GONE); 498 mView.findViewById(R.id.no_domain_warning).setVisibility(View.GONE); 499 mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.GONE); 500 501 if (mSsidView != null) { 502 final String ssid = mSsidView.getText().toString(); 503 if (WifiUtils.isSSIDTooLong(ssid)) { 504 mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE); 505 } 506 } 507 if (mEapCaCertSpinner != null 508 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) { 509 String caCertSelection = (String) mEapCaCertSpinner.getSelectedItem(); 510 if (caCertSelection.equals(mDoNotValidateEapServerString)) { 511 // Display warning if user chooses not to validate the EAP server with a 512 // user-supplied CA certificate in an EAP network configuration. 513 mView.findViewById(R.id.no_ca_cert_warning).setVisibility(View.VISIBLE); 514 } 515 if (caCertSelection.equals(mUseSystemCertsString) 516 && mEapDomainView != null 517 && mView.findViewById(R.id.l_domain).getVisibility() != View.GONE 518 && TextUtils.isEmpty(mEapDomainView.getText().toString())) { 519 // Display warning if user chooses to use pre-installed public CA certificates 520 // without restricting the server domain that these certificates can be used to 521 // validate. 522 mView.findViewById(R.id.no_domain_warning).setVisibility(View.VISIBLE); 523 } 524 } 525 } 526 527 public WifiConfiguration getConfig() { 528 if (mMode == WifiConfigUiBase.MODE_VIEW) { 529 return null; 530 } 531 532 WifiConfiguration config = new WifiConfiguration(); 533 534 if (mAccessPoint == null) { 535 config.SSID = AccessPoint.convertToQuotedString( 536 mSsidView.getText().toString()); 537 // If the user adds a network manually, assume that it is hidden. 538 config.hiddenSSID = mHiddenSettingsSpinner.getSelectedItemPosition() == HIDDEN_NETWORK; 539 } else if (!mAccessPoint.isSaved()) { 540 config.SSID = AccessPoint.convertToQuotedString( 541 mAccessPoint.getSsidStr()); 542 } else { 543 config.networkId = mAccessPoint.getConfig().networkId; 544 config.hiddenSSID = mAccessPoint.getConfig().hiddenSSID; 545 } 546 547 config.shared = mSharedCheckBox.isChecked(); 548 549 switch (mAccessPointSecurity) { 550 case AccessPoint.SECURITY_NONE: 551 config.allowedKeyManagement.set(KeyMgmt.NONE); 552 break; 553 554 case AccessPoint.SECURITY_WEP: 555 config.allowedKeyManagement.set(KeyMgmt.NONE); 556 config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); 557 config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); 558 if (mPasswordView.length() != 0) { 559 int length = mPasswordView.length(); 560 String password = mPasswordView.getText().toString(); 561 // WEP-40, WEP-104, and 256-bit WEP (WEP-232?) 562 if ((length == 10 || length == 26 || length == 58) 563 && password.matches("[0-9A-Fa-f]*")) { 564 config.wepKeys[0] = password; 565 } else { 566 config.wepKeys[0] = '"' + password + '"'; 567 } 568 } 569 break; 570 571 case AccessPoint.SECURITY_PSK: 572 config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); 573 if (mPasswordView.length() != 0) { 574 String password = mPasswordView.getText().toString(); 575 if (password.matches("[0-9A-Fa-f]{64}")) { 576 config.preSharedKey = password; 577 } else { 578 config.preSharedKey = '"' + password + '"'; 579 } 580 } 581 break; 582 583 case AccessPoint.SECURITY_EAP: 584 config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); 585 config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); 586 config.enterpriseConfig = new WifiEnterpriseConfig(); 587 int eapMethod = mEapMethodSpinner.getSelectedItemPosition(); 588 int phase2Method = mPhase2Spinner.getSelectedItemPosition(); 589 config.enterpriseConfig.setEapMethod(eapMethod); 590 switch (eapMethod) { 591 case Eap.PEAP: 592 // PEAP supports limited phase2 values 593 // Map the index from the mPhase2PeapAdapter to the one used 594 // by the API which has the full list of PEAP methods. 595 switch(phase2Method) { 596 case WIFI_PEAP_PHASE2_NONE: 597 config.enterpriseConfig.setPhase2Method(Phase2.NONE); 598 break; 599 case WIFI_PEAP_PHASE2_MSCHAPV2: 600 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2); 601 break; 602 case WIFI_PEAP_PHASE2_GTC: 603 config.enterpriseConfig.setPhase2Method(Phase2.GTC); 604 break; 605 case WIFI_PEAP_PHASE2_SIM: 606 config.enterpriseConfig.setPhase2Method(Phase2.SIM); 607 break; 608 case WIFI_PEAP_PHASE2_AKA: 609 config.enterpriseConfig.setPhase2Method(Phase2.AKA); 610 break; 611 case WIFI_PEAP_PHASE2_AKA_PRIME: 612 config.enterpriseConfig.setPhase2Method(Phase2.AKA_PRIME); 613 break; 614 default: 615 Log.e(TAG, "Unknown phase2 method" + phase2Method); 616 break; 617 } 618 break; 619 default: 620 // The default index from mPhase2FullAdapter maps to the API 621 config.enterpriseConfig.setPhase2Method(phase2Method); 622 break; 623 } 624 625 String caCert = (String) mEapCaCertSpinner.getSelectedItem(); 626 config.enterpriseConfig.setCaCertificateAliases(null); 627 config.enterpriseConfig.setCaPath(null); 628 config.enterpriseConfig.setDomainSuffixMatch(mEapDomainView.getText().toString()); 629 if (caCert.equals(mUnspecifiedCertString) 630 || caCert.equals(mDoNotValidateEapServerString)) { 631 // ca_cert already set to null, so do nothing. 632 } else if (caCert.equals(mUseSystemCertsString)) { 633 config.enterpriseConfig.setCaPath(SYSTEM_CA_STORE_PATH); 634 } else if (caCert.equals(mMultipleCertSetString)) { 635 if (mAccessPoint != null) { 636 if (!mAccessPoint.isSaved()) { 637 Log.e(TAG, "Multiple certs can only be set " 638 + "when editing saved network"); 639 } 640 config.enterpriseConfig.setCaCertificateAliases( 641 mAccessPoint 642 .getConfig() 643 .enterpriseConfig 644 .getCaCertificateAliases()); 645 } 646 } else { 647 config.enterpriseConfig.setCaCertificateAliases(new String[] {caCert}); 648 } 649 650 // ca_cert or ca_path should not both be non-null, since we only intend to let 651 // the use either their own certificate, or the system certificates, not both. 652 // The variable that is not used must explicitly be set to null, so that a 653 // previously-set value on a saved configuration will be erased on an update. 654 if (config.enterpriseConfig.getCaCertificateAliases() != null 655 && config.enterpriseConfig.getCaPath() != null) { 656 Log.e(TAG, "ca_cert (" 657 + config.enterpriseConfig.getCaCertificateAliases() 658 + ") and ca_path (" 659 + config.enterpriseConfig.getCaPath() 660 + ") should not both be non-null"); 661 } 662 663 String clientCert = (String) mEapUserCertSpinner.getSelectedItem(); 664 if (clientCert.equals(mUnspecifiedCertString) 665 || clientCert.equals(mDoNotProvideEapUserCertString)) { 666 // Note: |clientCert| should not be able to take the value |unspecifiedCert|, 667 // since we prevent such configurations from being saved. 668 clientCert = ""; 669 } 670 config.enterpriseConfig.setClientCertificateAlias(clientCert); 671 if (eapMethod == Eap.SIM || eapMethod == Eap.AKA || eapMethod == Eap.AKA_PRIME) { 672 config.enterpriseConfig.setIdentity(""); 673 config.enterpriseConfig.setAnonymousIdentity(""); 674 } else if (eapMethod == Eap.PWD) { 675 config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString()); 676 config.enterpriseConfig.setAnonymousIdentity(""); 677 } else { 678 config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString()); 679 config.enterpriseConfig.setAnonymousIdentity( 680 mEapAnonymousView.getText().toString()); 681 } 682 683 if (mPasswordView.isShown()) { 684 // For security reasons, a previous password is not displayed to user. 685 // Update only if it has been changed. 686 if (mPasswordView.length() > 0) { 687 config.enterpriseConfig.setPassword(mPasswordView.getText().toString()); 688 } 689 } else { 690 // clear password 691 config.enterpriseConfig.setPassword(mPasswordView.getText().toString()); 692 } 693 break; 694 default: 695 return null; 696 } 697 698 config.setIpConfiguration( 699 new IpConfiguration(mIpAssignment, mProxySettings, 700 mStaticIpConfiguration, mHttpProxy)); 701 if (mMeteredSettingsSpinner != null) { 702 config.meteredOverride = mMeteredSettingsSpinner.getSelectedItemPosition(); 703 } 704 705 return config; 706 } 707 708 private boolean ipAndProxyFieldsAreValid() { 709 mIpAssignment = 710 (mIpSettingsSpinner != null 711 && mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) 712 ? IpAssignment.STATIC 713 : IpAssignment.DHCP; 714 715 if (mIpAssignment == IpAssignment.STATIC) { 716 mStaticIpConfiguration = new StaticIpConfiguration(); 717 int result = validateIpConfigFields(mStaticIpConfiguration); 718 if (result != 0) { 719 return false; 720 } 721 } 722 723 final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition(); 724 mProxySettings = ProxySettings.NONE; 725 mHttpProxy = null; 726 if (selectedPosition == PROXY_STATIC && mProxyHostView != null) { 727 mProxySettings = ProxySettings.STATIC; 728 String host = mProxyHostView.getText().toString(); 729 String portStr = mProxyPortView.getText().toString(); 730 String exclusionList = mProxyExclusionListView.getText().toString(); 731 int port = 0; 732 int result = 0; 733 try { 734 port = Integer.parseInt(portStr); 735 result = ProxySelector.validate(host, portStr, exclusionList); 736 } catch (NumberFormatException e) { 737 result = R.string.proxy_error_invalid_port; 738 } 739 if (result == 0) { 740 mHttpProxy = new ProxyInfo(host, port, exclusionList); 741 } else { 742 return false; 743 } 744 } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) { 745 mProxySettings = ProxySettings.PAC; 746 CharSequence uriSequence = mProxyPacView.getText(); 747 if (TextUtils.isEmpty(uriSequence)) { 748 return false; 749 } 750 Uri uri = Uri.parse(uriSequence.toString()); 751 if (uri == null) { 752 return false; 753 } 754 mHttpProxy = new ProxyInfo(uri); 755 } 756 return true; 757 } 758 759 private Inet4Address getIPv4Address(String text) { 760 try { 761 return (Inet4Address) NetworkUtils.numericToInetAddress(text); 762 } catch (IllegalArgumentException | ClassCastException e) { 763 return null; 764 } 765 } 766 767 private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) { 768 if (mIpAddressView == null) return 0; 769 770 String ipAddr = mIpAddressView.getText().toString(); 771 if (TextUtils.isEmpty(ipAddr)) return R.string.wifi_ip_settings_invalid_ip_address; 772 773 Inet4Address inetAddr = getIPv4Address(ipAddr); 774 if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) { 775 return R.string.wifi_ip_settings_invalid_ip_address; 776 } 777 778 int networkPrefixLength = -1; 779 try { 780 networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString()); 781 if (networkPrefixLength < 0 || networkPrefixLength > 32) { 782 return R.string.wifi_ip_settings_invalid_network_prefix_length; 783 } 784 staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength); 785 } catch (NumberFormatException e) { 786 // Set the hint as default after user types in ip address 787 mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString( 788 R.string.wifi_network_prefix_length_hint)); 789 } catch (IllegalArgumentException e) { 790 return R.string.wifi_ip_settings_invalid_ip_address; 791 } 792 793 String gateway = mGatewayView.getText().toString(); 794 if (TextUtils.isEmpty(gateway)) { 795 try { 796 //Extract a default gateway from IP address 797 InetAddress netPart = NetworkUtils.getNetworkPart(inetAddr, networkPrefixLength); 798 byte[] addr = netPart.getAddress(); 799 addr[addr.length - 1] = 1; 800 mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress()); 801 } catch (RuntimeException ee) { 802 } catch (java.net.UnknownHostException u) { 803 } 804 } else { 805 InetAddress gatewayAddr = getIPv4Address(gateway); 806 if (gatewayAddr == null) { 807 return R.string.wifi_ip_settings_invalid_gateway; 808 } 809 if (gatewayAddr.isMulticastAddress()) { 810 return R.string.wifi_ip_settings_invalid_gateway; 811 } 812 staticIpConfiguration.gateway = gatewayAddr; 813 } 814 815 String dns = mDns1View.getText().toString(); 816 InetAddress dnsAddr = null; 817 818 if (TextUtils.isEmpty(dns)) { 819 //If everything else is valid, provide hint as a default option 820 mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint)); 821 } else { 822 dnsAddr = getIPv4Address(dns); 823 if (dnsAddr == null) { 824 return R.string.wifi_ip_settings_invalid_dns; 825 } 826 staticIpConfiguration.dnsServers.add(dnsAddr); 827 } 828 829 if (mDns2View.length() > 0) { 830 dns = mDns2View.getText().toString(); 831 dnsAddr = getIPv4Address(dns); 832 if (dnsAddr == null) { 833 return R.string.wifi_ip_settings_invalid_dns; 834 } 835 staticIpConfiguration.dnsServers.add(dnsAddr); 836 } 837 return 0; 838 } 839 840 private void showSecurityFields() { 841 if (mAccessPointSecurity == AccessPoint.SECURITY_NONE) { 842 mView.findViewById(R.id.security_fields).setVisibility(View.GONE); 843 return; 844 } 845 mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE); 846 847 if (mPasswordView == null) { 848 mPasswordView = (TextView) mView.findViewById(R.id.password); 849 mPasswordView.addTextChangedListener(this); 850 mPasswordView.setOnEditorActionListener(this); 851 mPasswordView.setOnKeyListener(this); 852 ((CheckBox) mView.findViewById(R.id.show_password)) 853 .setOnCheckedChangeListener(this); 854 855 if (mAccessPoint != null && mAccessPoint.isSaved()) { 856 mPasswordView.setHint(R.string.wifi_unchanged); 857 } 858 } 859 860 if (mAccessPointSecurity != AccessPoint.SECURITY_EAP) { 861 mView.findViewById(R.id.eap).setVisibility(View.GONE); 862 return; 863 } 864 mView.findViewById(R.id.eap).setVisibility(View.VISIBLE); 865 866 if (mEapMethodSpinner == null) { 867 mEapMethodSpinner = (Spinner) mView.findViewById(R.id.method); 868 mEapMethodSpinner.setOnItemSelectedListener(this); 869 if (Utils.isWifiOnly(mContext) || !mContext.getResources().getBoolean( 870 com.android.internal.R.bool.config_eap_sim_based_auth_supported)) { 871 String[] eapMethods = mContext.getResources().getStringArray( 872 R.array.eap_method_without_sim_auth); 873 ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(mContext, 874 android.R.layout.simple_spinner_item, eapMethods); 875 spinnerAdapter.setDropDownViewResource( 876 android.R.layout.simple_spinner_dropdown_item); 877 mEapMethodSpinner.setAdapter(spinnerAdapter); 878 } 879 mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2); 880 mPhase2Spinner.setOnItemSelectedListener(this); 881 mEapCaCertSpinner = (Spinner) mView.findViewById(R.id.ca_cert); 882 mEapCaCertSpinner.setOnItemSelectedListener(this); 883 mEapDomainView = (TextView) mView.findViewById(R.id.domain); 884 mEapDomainView.addTextChangedListener(this); 885 mEapUserCertSpinner = (Spinner) mView.findViewById(R.id.user_cert); 886 mEapUserCertSpinner.setOnItemSelectedListener(this); 887 mEapIdentityView = (TextView) mView.findViewById(R.id.identity); 888 mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous); 889 890 if (mAccessPoint != null && mAccessPoint.isCarrierAp()) { 891 mEapMethodSpinner.setSelection(mAccessPoint.getCarrierApEapType()); 892 } 893 894 loadCertificates( 895 mEapCaCertSpinner, 896 Credentials.CA_CERTIFICATE, 897 mDoNotValidateEapServerString, 898 false, 899 true); 900 loadCertificates( 901 mEapUserCertSpinner, 902 Credentials.USER_PRIVATE_KEY, 903 mDoNotProvideEapUserCertString, 904 false, 905 false); 906 907 // Modifying an existing network 908 if (mAccessPoint != null && mAccessPoint.isSaved()) { 909 WifiEnterpriseConfig enterpriseConfig = mAccessPoint.getConfig().enterpriseConfig; 910 int eapMethod = enterpriseConfig.getEapMethod(); 911 int phase2Method = enterpriseConfig.getPhase2Method(); 912 mEapMethodSpinner.setSelection(eapMethod); 913 showEapFieldsByMethod(eapMethod); 914 switch (eapMethod) { 915 case Eap.PEAP: 916 switch (phase2Method) { 917 case Phase2.NONE: 918 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_NONE); 919 break; 920 case Phase2.MSCHAPV2: 921 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_MSCHAPV2); 922 break; 923 case Phase2.GTC: 924 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_GTC); 925 break; 926 case Phase2.SIM: 927 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_SIM); 928 break; 929 case Phase2.AKA: 930 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_AKA); 931 break; 932 case Phase2.AKA_PRIME: 933 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_AKA_PRIME); 934 break; 935 default: 936 Log.e(TAG, "Invalid phase 2 method " + phase2Method); 937 break; 938 } 939 break; 940 default: 941 mPhase2Spinner.setSelection(phase2Method); 942 break; 943 } 944 if (!TextUtils.isEmpty(enterpriseConfig.getCaPath())) { 945 setSelection(mEapCaCertSpinner, mUseSystemCertsString); 946 } else { 947 String[] caCerts = enterpriseConfig.getCaCertificateAliases(); 948 if (caCerts == null) { 949 setSelection(mEapCaCertSpinner, mDoNotValidateEapServerString); 950 } else if (caCerts.length == 1) { 951 setSelection(mEapCaCertSpinner, caCerts[0]); 952 } else { 953 // Reload the cert spinner with an extra "multiple certificates added" item. 954 loadCertificates( 955 mEapCaCertSpinner, 956 Credentials.CA_CERTIFICATE, 957 mDoNotValidateEapServerString, 958 true, 959 true); 960 setSelection(mEapCaCertSpinner, mMultipleCertSetString); 961 } 962 } 963 mEapDomainView.setText(enterpriseConfig.getDomainSuffixMatch()); 964 String userCert = enterpriseConfig.getClientCertificateAlias(); 965 if (TextUtils.isEmpty(userCert)) { 966 setSelection(mEapUserCertSpinner, mDoNotProvideEapUserCertString); 967 } else { 968 setSelection(mEapUserCertSpinner, userCert); 969 } 970 mEapIdentityView.setText(enterpriseConfig.getIdentity()); 971 mEapAnonymousView.setText(enterpriseConfig.getAnonymousIdentity()); 972 } else { 973 mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2); 974 showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition()); 975 } 976 } else { 977 showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition()); 978 } 979 } 980 981 /** 982 * EAP-PWD valid fields include 983 * identity 984 * password 985 * EAP-PEAP valid fields include 986 * phase2: MSCHAPV2, GTC, SIM, AKA, AKA' 987 * ca_cert 988 * identity 989 * anonymous_identity 990 * password (not required for SIM, AKA, AKA') 991 * EAP-TLS valid fields include 992 * user_cert 993 * ca_cert 994 * domain 995 * identity 996 * EAP-TTLS valid fields include 997 * phase2: PAP, MSCHAP, MSCHAPV2, GTC 998 * ca_cert 999 * identity 1000 * anonymous_identity 1001 * password 1002 */ 1003 private void showEapFieldsByMethod(int eapMethod) { 1004 // Common defaults 1005 mView.findViewById(R.id.l_method).setVisibility(View.VISIBLE); 1006 mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE); 1007 mView.findViewById(R.id.l_domain).setVisibility(View.VISIBLE); 1008 1009 // Defaults for most of the EAP methods and over-riden by 1010 // by certain EAP methods 1011 mView.findViewById(R.id.l_ca_cert).setVisibility(View.VISIBLE); 1012 mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE); 1013 mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE); 1014 1015 Context context = mConfigUi.getContext(); 1016 switch (eapMethod) { 1017 case WIFI_EAP_METHOD_PWD: 1018 setPhase2Invisible(); 1019 setCaCertInvisible(); 1020 setDomainInvisible(); 1021 setAnonymousIdentInvisible(); 1022 setUserCertInvisible(); 1023 break; 1024 case WIFI_EAP_METHOD_TLS: 1025 mView.findViewById(R.id.l_user_cert).setVisibility(View.VISIBLE); 1026 setPhase2Invisible(); 1027 setAnonymousIdentInvisible(); 1028 setPasswordInvisible(); 1029 break; 1030 case WIFI_EAP_METHOD_PEAP: 1031 // Reset adapter if needed 1032 if (mPhase2Adapter != mPhase2PeapAdapter) { 1033 mPhase2Adapter = mPhase2PeapAdapter; 1034 mPhase2Spinner.setAdapter(mPhase2Adapter); 1035 } 1036 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE); 1037 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE); 1038 showPeapFields(); 1039 setUserCertInvisible(); 1040 break; 1041 case WIFI_EAP_METHOD_TTLS: 1042 // Reset adapter if needed 1043 if (mPhase2Adapter != mPhase2FullAdapter) { 1044 mPhase2Adapter = mPhase2FullAdapter; 1045 mPhase2Spinner.setAdapter(mPhase2Adapter); 1046 } 1047 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE); 1048 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE); 1049 setUserCertInvisible(); 1050 break; 1051 case WIFI_EAP_METHOD_SIM: 1052 case WIFI_EAP_METHOD_AKA: 1053 case WIFI_EAP_METHOD_AKA_PRIME: 1054 setPhase2Invisible(); 1055 setAnonymousIdentInvisible(); 1056 setCaCertInvisible(); 1057 setDomainInvisible(); 1058 setUserCertInvisible(); 1059 setPasswordInvisible(); 1060 setIdentityInvisible(); 1061 if (mAccessPoint != null && mAccessPoint.isCarrierAp()) { 1062 setEapMethodInvisible(); 1063 } 1064 break; 1065 } 1066 1067 if (mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) { 1068 String eapCertSelection = (String) mEapCaCertSpinner.getSelectedItem(); 1069 if (eapCertSelection.equals(mDoNotValidateEapServerString) 1070 || eapCertSelection.equals(mUnspecifiedCertString)) { 1071 // Domain suffix matching is not relevant if the user hasn't chosen a CA 1072 // certificate yet, or chooses not to validate the EAP server. 1073 setDomainInvisible(); 1074 } 1075 } 1076 } 1077 1078 private void showPeapFields() { 1079 int phase2Method = mPhase2Spinner.getSelectedItemPosition(); 1080 if (phase2Method == WIFI_PEAP_PHASE2_SIM || phase2Method == WIFI_PEAP_PHASE2_AKA 1081 || phase2Method == WIFI_PEAP_PHASE2_AKA_PRIME) { 1082 mEapIdentityView.setText(""); 1083 mView.findViewById(R.id.l_identity).setVisibility(View.GONE); 1084 setPasswordInvisible(); 1085 } else { 1086 mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE); 1087 mView.findViewById(R.id.l_anonymous).setVisibility(View.VISIBLE); 1088 mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE); 1089 mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE); 1090 } 1091 } 1092 1093 private void setIdentityInvisible() { 1094 mView.findViewById(R.id.l_identity).setVisibility(View.GONE); 1095 mPhase2Spinner.setSelection(Phase2.NONE); 1096 } 1097 1098 private void setPhase2Invisible() { 1099 mView.findViewById(R.id.l_phase2).setVisibility(View.GONE); 1100 mPhase2Spinner.setSelection(Phase2.NONE); 1101 } 1102 1103 private void setCaCertInvisible() { 1104 mView.findViewById(R.id.l_ca_cert).setVisibility(View.GONE); 1105 setSelection(mEapCaCertSpinner, mUnspecifiedCertString); 1106 } 1107 1108 private void setDomainInvisible() { 1109 mView.findViewById(R.id.l_domain).setVisibility(View.GONE); 1110 mEapDomainView.setText(""); 1111 } 1112 1113 private void setUserCertInvisible() { 1114 mView.findViewById(R.id.l_user_cert).setVisibility(View.GONE); 1115 setSelection(mEapUserCertSpinner, mUnspecifiedCertString); 1116 } 1117 1118 private void setAnonymousIdentInvisible() { 1119 mView.findViewById(R.id.l_anonymous).setVisibility(View.GONE); 1120 mEapAnonymousView.setText(""); 1121 } 1122 1123 private void setPasswordInvisible() { 1124 mPasswordView.setText(""); 1125 mView.findViewById(R.id.password_layout).setVisibility(View.GONE); 1126 mView.findViewById(R.id.show_password_layout).setVisibility(View.GONE); 1127 } 1128 1129 private void setEapMethodInvisible() { 1130 mView.findViewById(R.id.eap).setVisibility(View.GONE); 1131 } 1132 1133 private void showIpConfigFields() { 1134 WifiConfiguration config = null; 1135 1136 mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE); 1137 1138 if (mAccessPoint != null && mAccessPoint.isSaved()) { 1139 config = mAccessPoint.getConfig(); 1140 } 1141 1142 if (mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) { 1143 mView.findViewById(R.id.staticip).setVisibility(View.VISIBLE); 1144 if (mIpAddressView == null) { 1145 mIpAddressView = (TextView) mView.findViewById(R.id.ipaddress); 1146 mIpAddressView.addTextChangedListener(this); 1147 mGatewayView = (TextView) mView.findViewById(R.id.gateway); 1148 mGatewayView.addTextChangedListener(this); 1149 mNetworkPrefixLengthView = (TextView) mView.findViewById( 1150 R.id.network_prefix_length); 1151 mNetworkPrefixLengthView.addTextChangedListener(this); 1152 mDns1View = (TextView) mView.findViewById(R.id.dns1); 1153 mDns1View.addTextChangedListener(this); 1154 mDns2View = (TextView) mView.findViewById(R.id.dns2); 1155 mDns2View.addTextChangedListener(this); 1156 } 1157 if (config != null) { 1158 StaticIpConfiguration staticConfig = config.getStaticIpConfiguration(); 1159 if (staticConfig != null) { 1160 if (staticConfig.ipAddress != null) { 1161 mIpAddressView.setText( 1162 staticConfig.ipAddress.getAddress().getHostAddress()); 1163 mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress 1164 .getNetworkPrefixLength())); 1165 } 1166 1167 if (staticConfig.gateway != null) { 1168 mGatewayView.setText(staticConfig.gateway.getHostAddress()); 1169 } 1170 1171 Iterator<InetAddress> dnsIterator = staticConfig.dnsServers.iterator(); 1172 if (dnsIterator.hasNext()) { 1173 mDns1View.setText(dnsIterator.next().getHostAddress()); 1174 } 1175 if (dnsIterator.hasNext()) { 1176 mDns2View.setText(dnsIterator.next().getHostAddress()); 1177 } 1178 } 1179 } 1180 } else { 1181 mView.findViewById(R.id.staticip).setVisibility(View.GONE); 1182 } 1183 } 1184 1185 private void showProxyFields() { 1186 WifiConfiguration config = null; 1187 1188 mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE); 1189 1190 if (mAccessPoint != null && mAccessPoint.isSaved()) { 1191 config = mAccessPoint.getConfig(); 1192 } 1193 1194 if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) { 1195 setVisibility(R.id.proxy_warning_limited_support, View.VISIBLE); 1196 setVisibility(R.id.proxy_fields, View.VISIBLE); 1197 setVisibility(R.id.proxy_pac_field, View.GONE); 1198 if (mProxyHostView == null) { 1199 mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname); 1200 mProxyHostView.addTextChangedListener(this); 1201 mProxyPortView = (TextView) mView.findViewById(R.id.proxy_port); 1202 mProxyPortView.addTextChangedListener(this); 1203 mProxyExclusionListView = (TextView) mView.findViewById(R.id.proxy_exclusionlist); 1204 mProxyExclusionListView.addTextChangedListener(this); 1205 } 1206 if (config != null) { 1207 ProxyInfo proxyProperties = config.getHttpProxy(); 1208 if (proxyProperties != null) { 1209 mProxyHostView.setText(proxyProperties.getHost()); 1210 mProxyPortView.setText(Integer.toString(proxyProperties.getPort())); 1211 mProxyExclusionListView.setText(proxyProperties.getExclusionListAsString()); 1212 } 1213 } 1214 } else if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_PAC) { 1215 setVisibility(R.id.proxy_warning_limited_support, View.GONE); 1216 setVisibility(R.id.proxy_fields, View.GONE); 1217 setVisibility(R.id.proxy_pac_field, View.VISIBLE); 1218 1219 if (mProxyPacView == null) { 1220 mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac); 1221 mProxyPacView.addTextChangedListener(this); 1222 } 1223 if (config != null) { 1224 ProxyInfo proxyInfo = config.getHttpProxy(); 1225 if (proxyInfo != null) { 1226 mProxyPacView.setText(proxyInfo.getPacFileUrl().toString()); 1227 } 1228 } 1229 } else { 1230 setVisibility(R.id.proxy_warning_limited_support, View.GONE); 1231 setVisibility(R.id.proxy_fields, View.GONE); 1232 setVisibility(R.id.proxy_pac_field, View.GONE); 1233 } 1234 } 1235 1236 private void setVisibility(int id, int visibility) { 1237 final View v = mView.findViewById(id); 1238 if (v != null) { 1239 v.setVisibility(visibility); 1240 } 1241 } 1242 1243 @VisibleForTesting 1244 KeyStore getKeyStore() { 1245 return KeyStore.getInstance(); 1246 } 1247 1248 private void loadCertificates( 1249 Spinner spinner, 1250 String prefix, 1251 String noCertificateString, 1252 boolean showMultipleCerts, 1253 boolean showUsePreinstalledCertOption) { 1254 final Context context = mConfigUi.getContext(); 1255 1256 ArrayList<String> certs = new ArrayList<String>(); 1257 certs.add(mUnspecifiedCertString); 1258 if (showMultipleCerts) { 1259 certs.add(mMultipleCertSetString); 1260 } 1261 if (showUsePreinstalledCertOption) { 1262 certs.add(mUseSystemCertsString); 1263 } 1264 try { 1265 certs.addAll( 1266 Arrays.asList(getKeyStore().list(prefix, android.os.Process.WIFI_UID))); 1267 } catch (Exception e) { 1268 Log.e(TAG, "can't get the certificate list from KeyStore"); 1269 } 1270 certs.add(noCertificateString); 1271 1272 final ArrayAdapter<String> adapter = new ArrayAdapter<String>( 1273 context, android.R.layout.simple_spinner_item, 1274 certs.toArray(new String[certs.size()])); 1275 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 1276 spinner.setAdapter(adapter); 1277 } 1278 1279 private void setSelection(Spinner spinner, String value) { 1280 if (value != null) { 1281 @SuppressWarnings("unchecked") 1282 ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter(); 1283 for (int i = adapter.getCount() - 1; i >= 0; --i) { 1284 if (value.equals(adapter.getItem(i))) { 1285 spinner.setSelection(i); 1286 break; 1287 } 1288 } 1289 } 1290 } 1291 1292 public int getMode() { 1293 return mMode; 1294 } 1295 1296 @Override 1297 public void afterTextChanged(Editable s) { 1298 ThreadUtils.postOnMainThread(() -> { 1299 showWarningMessagesIfAppropriate(); 1300 enableSubmitIfAppropriate(); 1301 }); 1302 } 1303 1304 @Override 1305 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 1306 // work done in afterTextChanged 1307 } 1308 1309 @Override 1310 public void onTextChanged(CharSequence s, int start, int before, int count) { 1311 // work done in afterTextChanged 1312 } 1313 1314 @Override 1315 public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { 1316 if (textView == mPasswordView) { 1317 if (id == EditorInfo.IME_ACTION_DONE && isSubmittable()) { 1318 mConfigUi.dispatchSubmit(); 1319 return true; 1320 } 1321 } 1322 return false; 1323 } 1324 1325 @Override 1326 public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 1327 if (view == mPasswordView) { 1328 if (keyCode == KeyEvent.KEYCODE_ENTER && isSubmittable()) { 1329 mConfigUi.dispatchSubmit(); 1330 return true; 1331 } 1332 } 1333 return false; 1334 } 1335 1336 @Override 1337 public void onCheckedChanged(CompoundButton view, boolean isChecked) { 1338 if (view.getId() == R.id.show_password) { 1339 int pos = mPasswordView.getSelectionEnd(); 1340 mPasswordView.setInputType(InputType.TYPE_CLASS_TEXT 1341 | (isChecked ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 1342 : InputType.TYPE_TEXT_VARIATION_PASSWORD)); 1343 if (pos >= 0) { 1344 ((EditText) mPasswordView).setSelection(pos); 1345 } 1346 } else if (view.getId() == R.id.wifi_advanced_togglebox) { 1347 final View advancedToggle = mView.findViewById(R.id.wifi_advanced_toggle); 1348 final int toggleVisibility; 1349 final int stringID; 1350 if (isChecked) { 1351 toggleVisibility = View.VISIBLE; 1352 stringID = R.string.wifi_advanced_toggle_description_expanded; 1353 } else { 1354 toggleVisibility = View.GONE; 1355 stringID = R.string.wifi_advanced_toggle_description_collapsed; 1356 } 1357 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(toggleVisibility); 1358 advancedToggle.setContentDescription(mContext.getString(stringID)); 1359 } 1360 } 1361 1362 @Override 1363 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 1364 if (parent == mSecuritySpinner) { 1365 mAccessPointSecurity = position; 1366 showSecurityFields(); 1367 } else if (parent == mEapMethodSpinner || parent == mEapCaCertSpinner) { 1368 showSecurityFields(); 1369 } else if (parent == mPhase2Spinner 1370 && mEapMethodSpinner.getSelectedItemPosition() == WIFI_EAP_METHOD_PEAP) { 1371 showPeapFields(); 1372 } else if (parent == mProxySettingsSpinner) { 1373 showProxyFields(); 1374 } else if (parent == mHiddenSettingsSpinner) { 1375 mHiddenWarningView.setVisibility( 1376 position == NOT_HIDDEN_NETWORK 1377 ? View.GONE 1378 : View.VISIBLE); 1379 if (position == HIDDEN_NETWORK) { 1380 mDialogContainer.post(() -> { 1381 mDialogContainer.fullScroll(View.FOCUS_DOWN); 1382 }); 1383 } 1384 } else { 1385 showIpConfigFields(); 1386 } 1387 showWarningMessagesIfAppropriate(); 1388 enableSubmitIfAppropriate(); 1389 } 1390 1391 @Override 1392 public void onNothingSelected(AdapterView<?> parent) { 1393 // 1394 } 1395 1396 /** 1397 * Make the characters of the password visible if show_password is checked. 1398 */ 1399 public void updatePassword() { 1400 TextView passwdView = (TextView) mView.findViewById(R.id.password); 1401 passwdView.setInputType(InputType.TYPE_CLASS_TEXT 1402 | (((CheckBox) mView.findViewById(R.id.show_password)).isChecked() 1403 ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 1404 : InputType.TYPE_TEXT_VARIATION_PASSWORD)); 1405 } 1406 1407 public AccessPoint getAccessPoint() { 1408 return mAccessPoint; 1409 } 1410} 1411