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