1 /* 2 * Copyright (C) 2019 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.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.res.Resources; 23 import android.net.InetAddresses; 24 import android.net.IpConfiguration; 25 import android.net.IpConfiguration.IpAssignment; 26 import android.net.IpConfiguration.ProxySettings; 27 import android.net.LinkAddress; 28 import android.net.ProxyInfo; 29 import android.net.StaticIpConfiguration; 30 import android.net.Uri; 31 import android.net.wifi.WifiConfiguration; 32 import android.net.wifi.WifiEnterpriseConfig; 33 import android.net.wifi.WifiEnterpriseConfig.Eap; 34 import android.net.wifi.WifiEnterpriseConfig.Phase2; 35 import android.net.wifi.WifiManager; 36 import android.os.IBinder; 37 import android.security.keystore.KeyProperties; 38 import android.telephony.SubscriptionInfo; 39 import android.telephony.SubscriptionManager; 40 import android.text.Editable; 41 import android.text.InputType; 42 import android.text.SpannableString; 43 import android.text.TextUtils; 44 import android.text.TextWatcher; 45 import android.util.ArrayMap; 46 import android.util.Log; 47 import android.view.KeyEvent; 48 import android.view.View; 49 import android.view.View.AccessibilityDelegate; 50 import android.view.ViewGroup; 51 import android.view.accessibility.AccessibilityEvent; 52 import android.view.accessibility.AccessibilityNodeInfo; 53 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 54 import android.view.inputmethod.EditorInfo; 55 import android.view.inputmethod.InputMethodManager; 56 import android.widget.AdapterView; 57 import android.widget.ArrayAdapter; 58 import android.widget.Button; 59 import android.widget.CheckBox; 60 import android.widget.CompoundButton; 61 import android.widget.CompoundButton.OnCheckedChangeListener; 62 import android.widget.EditText; 63 import android.widget.ImageButton; 64 import android.widget.LinearLayout; 65 import android.widget.Spinner; 66 import android.widget.TextView; 67 68 import androidx.annotation.Nullable; 69 import androidx.annotation.VisibleForTesting; 70 71 import com.android.net.module.util.NetUtils; 72 import com.android.net.module.util.ProxyUtils; 73 import com.android.settings.ProxySelector; 74 import com.android.settings.R; 75 import com.android.settings.network.SubscriptionUtil; 76 import com.android.settings.utils.AndroidKeystoreAliasLoader; 77 import com.android.settings.wifi.details2.WifiPrivacyPreferenceController; 78 import com.android.settings.wifi.details2.WifiPrivacyPreferenceController2; 79 import com.android.settings.wifi.dpp.WifiDppUtils; 80 import com.android.settingslib.Utils; 81 import com.android.settingslib.utils.ThreadUtils; 82 import com.android.wifi.flags.Flags; 83 import com.android.wifitrackerlib.WifiEntry; 84 import com.android.wifitrackerlib.WifiEntry.ConnectedInfo; 85 86 import java.net.Inet4Address; 87 import java.net.InetAddress; 88 import java.util.ArrayList; 89 import java.util.Arrays; 90 import java.util.Collection; 91 import java.util.Collections; 92 import java.util.Iterator; 93 import java.util.List; 94 import java.util.stream.Collectors; 95 96 /** 97 * The class for allowing UIs like {@link WifiDialog2} and {@link WifiConfigUiBase2} to 98 * share the logic for controlling buttons, text fields, etc. 99 */ 100 public class WifiConfigController2 implements TextWatcher, 101 AdapterView.OnItemSelectedListener, OnCheckedChangeListener, 102 TextView.OnEditorActionListener, View.OnKeyListener { 103 private static final String TAG = "WifiConfigController2"; 104 @VisibleForTesting 105 static final String DEFAULT_ANONYMOUS_ID = "anonymous"; 106 107 private static final String SYSTEM_CA_STORE_PATH = "/system/etc/security/cacerts"; 108 109 private final WifiConfigUiBase2 mConfigUi; 110 private final View mView; 111 private final WifiEntry mWifiEntry; 112 113 /* This value comes from "wifi_ip_settings" resource array */ 114 private static final int DHCP = 0; 115 private static final int STATIC_IP = 1; 116 117 /* Constants used for referring to the hidden state of a network. */ 118 public static final int HIDDEN_NETWORK = 1; 119 public static final int NOT_HIDDEN_NETWORK = 0; 120 121 /* These values come from "wifi_proxy_settings" resource array */ 122 public static final int PROXY_NONE = 0; 123 public static final int PROXY_STATIC = 1; 124 public static final int PROXY_PAC = 2; 125 126 /* These values come from "wifi_eap_method" resource array */ 127 public static final int WIFI_EAP_METHOD_PEAP = 0; 128 public static final int WIFI_EAP_METHOD_TLS = 1; 129 public static final int WIFI_EAP_METHOD_TTLS = 2; 130 public static final int WIFI_EAP_METHOD_PWD = 3; 131 public static final int WIFI_EAP_METHOD_SIM = 4; 132 public static final int WIFI_EAP_METHOD_AKA = 5; 133 public static final int WIFI_EAP_METHOD_AKA_PRIME = 6; 134 135 /* These values come from "wifi_peap_phase2_entries" resource array */ 136 public static final int WIFI_PEAP_PHASE2_MSCHAPV2 = 0; 137 public static final int WIFI_PEAP_PHASE2_GTC = 1; 138 public static final int WIFI_PEAP_PHASE2_SIM = 2; 139 public static final int WIFI_PEAP_PHASE2_AKA = 3; 140 public static final int WIFI_PEAP_PHASE2_AKA_PRIME = 4; 141 142 /* These values come from "wifi_ttls_phase2_entries" resource array */ 143 public static final int WIFI_TTLS_PHASE2_PAP = 0; 144 public static final int WIFI_TTLS_PHASE2_MSCHAP = 1; 145 public static final int WIFI_TTLS_PHASE2_MSCHAPV2 = 2; 146 public static final int WIFI_TTLS_PHASE2_GTC = 3; 147 148 private static final String UNDESIRED_CERTIFICATE_MACRANDSECRET = "MacRandSecret"; 149 private static final String UNDESIRED_CERTIFICATE_MACRANDSAPSECRET = "MacRandSapSecret"; 150 @VisibleForTesting 151 static final String[] UNDESIRED_CERTIFICATES = { 152 UNDESIRED_CERTIFICATE_MACRANDSECRET, 153 UNDESIRED_CERTIFICATE_MACRANDSAPSECRET 154 }; 155 156 /* These values are for install certificate */ 157 private static final String ACTION_INSTALL_CERTS = "android.credentials.INSTALL"; 158 private static final String PACKAGE_INSTALL_CERTS = "com.android.certinstaller"; 159 private static final String CLASS_INSTALL_CERTS = "com.android.certinstaller.CertInstallerMain"; 160 private static final String KEY_INSTALL_CERTIFICATE = "certificate_install_usage"; 161 private static final String INSTALL_CERTIFICATE_VALUE = "wifi"; 162 163 protected int REQUEST_INSTALL_CERTS = 1; 164 165 /* Phase2 methods supported by PEAP are limited */ 166 private ArrayAdapter<CharSequence> mPhase2PeapAdapter; 167 /* Phase2 methods supported by TTLS are limited */ 168 private ArrayAdapter<CharSequence> mPhase2TtlsAdapter; 169 170 // e.g. WifiEntry.SECURITY_NONE 171 @VisibleForTesting 172 int mWifiEntrySecurity; 173 private TextView mPasswordView; 174 private ImageButton mSsidScanButton; 175 176 private String mUnspecifiedCertString; 177 private String mMultipleCertSetString; 178 private String mUseSystemCertsString; 179 private String mTrustOnFirstUse; 180 private String mDoNotProvideEapUserCertString; 181 @VisibleForTesting String mInstallCertsString; 182 183 private Spinner mSecuritySpinner; 184 @VisibleForTesting Spinner mEapMethodSpinner; 185 private int mLastShownEapMethod; 186 @VisibleForTesting Spinner mEapSimSpinner; // For EAP-SIM, EAP-AKA and EAP-AKA-PRIME. 187 @VisibleForTesting Spinner mEapCaCertSpinner; 188 private Spinner mEapMinTlsVerSpinner; 189 private Spinner mEapOcspSpinner; 190 private TextView mEapDomainView; 191 private Spinner mPhase2Spinner; 192 // Associated with mPhase2Spinner, one of mPhase2TtlsAdapter or mPhase2PeapAdapter 193 private ArrayAdapter<CharSequence> mPhase2Adapter; 194 private Spinner mEapUserCertSpinner; 195 private TextView mEapIdentityView; 196 @VisibleForTesting 197 TextView mEapAnonymousView; 198 199 private Spinner mIpSettingsSpinner; 200 private TextView mIpAddressView; 201 private TextView mGatewayView; 202 private TextView mNetworkPrefixLengthView; 203 private TextView mDns1View; 204 private TextView mDns2View; 205 206 private Spinner mProxySettingsSpinner; 207 @Nullable 208 private Spinner mMeteredSettingsSpinner; 209 private Spinner mHiddenSettingsSpinner; 210 @Nullable 211 private Spinner mPrivacySettingsSpinner; 212 @Nullable 213 private Spinner mDhcpSettingsSpinner; 214 private TextView mHiddenWarningView; 215 private TextView mProxyHostView; 216 private TextView mProxyPortView; 217 private TextView mProxyExclusionListView; 218 private TextView mProxyPacView; 219 private CheckBox mSharedCheckBox; 220 221 private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED; 222 private ProxySettings mProxySettings = ProxySettings.UNASSIGNED; 223 private ProxyInfo mHttpProxy = null; 224 private StaticIpConfiguration mStaticIpConfiguration = null; 225 226 private String[] mLevels; 227 private final int mMode; 228 private final boolean mHideMeteredAndPrivacy; 229 private final WifiManager mWifiManager; 230 private final AndroidKeystoreAliasLoader mAndroidKeystoreAliasLoader; 231 private TextView mSsidView; 232 233 private final Context mContext; 234 235 @VisibleForTesting 236 Integer[] mSecurityInPosition; 237 238 private boolean mIsTrustOnFirstUseSupported; 239 240 private final ArrayMap<Integer, SubscriptionInfo> mActiveSubscriptionInfos = new ArrayMap<>(); 241 WifiConfigController2(WifiConfigUiBase2 parent, View view, WifiEntry wifiEntry, int mode)242 public WifiConfigController2(WifiConfigUiBase2 parent, View view, WifiEntry wifiEntry, 243 int mode) { 244 this(parent, view, wifiEntry, mode, false); 245 } 246 WifiConfigController2(WifiConfigUiBase2 parent, View view, WifiEntry wifiEntry, int mode, boolean hideMeteredAndPrivacy)247 public WifiConfigController2(WifiConfigUiBase2 parent, View view, WifiEntry wifiEntry, 248 int mode, boolean hideMeteredAndPrivacy) { 249 this(parent, view, wifiEntry, mode, hideMeteredAndPrivacy, 250 parent.getContext().getSystemService(WifiManager.class), 251 new AndroidKeystoreAliasLoader(KeyProperties.NAMESPACE_WIFI)); 252 } 253 254 @VisibleForTesting WifiConfigController2(WifiConfigUiBase2 parent, View view, WifiEntry wifiEntry, int mode, boolean hideMeteredAndPrivacy, WifiManager wifiManager, AndroidKeystoreAliasLoader androidKeystoreAliasLoader)255 public WifiConfigController2(WifiConfigUiBase2 parent, View view, WifiEntry wifiEntry, 256 int mode, boolean hideMeteredAndPrivacy, WifiManager wifiManager, 257 AndroidKeystoreAliasLoader androidKeystoreAliasLoader) { 258 mConfigUi = parent; 259 mView = view; 260 mWifiEntry = wifiEntry; 261 mMode = mode; 262 mHideMeteredAndPrivacy = hideMeteredAndPrivacy; 263 mContext = mConfigUi.getContext(); 264 mWifiManager = wifiManager; 265 mAndroidKeystoreAliasLoader = androidKeystoreAliasLoader; 266 initWifiConfigController2(wifiEntry); 267 } 268 initWifiConfigController2(WifiEntry wifiEntry)269 private void initWifiConfigController2(WifiEntry wifiEntry) { 270 mWifiEntrySecurity = (wifiEntry == null) ? WifiEntry.SECURITY_NONE : 271 wifiEntry.getSecurity(); 272 mIsTrustOnFirstUseSupported = mWifiManager.isTrustOnFirstUseSupported(); 273 274 final Resources res = mContext.getResources(); 275 276 mLevels = res.getStringArray(R.array.wifi_signal); 277 if (Utils.isWifiOnly(mContext) || !mContext.getResources().getBoolean( 278 com.android.internal.R.bool.config_eap_sim_based_auth_supported)) { 279 mPhase2PeapAdapter = getSpinnerAdapter(R.array.wifi_peap_phase2_entries); 280 } else { 281 mPhase2PeapAdapter = getSpinnerAdapterWithEapMethodsTts( 282 R.array.wifi_peap_phase2_entries_with_sim_auth); 283 } 284 285 mPhase2TtlsAdapter = getSpinnerAdapter(R.array.wifi_ttls_phase2_entries); 286 287 mUnspecifiedCertString = mContext.getString(R.string.wifi_unspecified); 288 mMultipleCertSetString = mContext.getString(R.string.wifi_multiple_cert_added); 289 mUseSystemCertsString = mContext.getString(R.string.wifi_use_system_certs); 290 mTrustOnFirstUse = mContext.getString(R.string.wifi_trust_on_first_use); 291 mDoNotProvideEapUserCertString = 292 mContext.getString(R.string.wifi_do_not_provide_eap_user_cert); 293 mInstallCertsString = mContext.getString(R.string.wifi_install_credentials); 294 295 if (Flags.androidVWifiApi() && mWifiEntrySecurity == WifiEntry.SECURITY_WEP) { 296 LinearLayout wepWarningLayout = 297 (LinearLayout) mView.findViewById(R.id.wep_warning_layout); 298 wepWarningLayout.setVisibility(View.VISIBLE); 299 } 300 301 mSsidScanButton = (ImageButton) mView.findViewById(R.id.ssid_scanner_button); 302 mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings); 303 mIpSettingsSpinner.setOnItemSelectedListener(this); 304 mProxySettingsSpinner = (Spinner) mView.findViewById(R.id.proxy_settings); 305 mProxySettingsSpinner.setOnItemSelectedListener(this); 306 mSharedCheckBox = (CheckBox) mView.findViewById(R.id.shared); 307 if (!mHideMeteredAndPrivacy) { 308 mMeteredSettingsSpinner = mView.findViewById(R.id.metered_settings); 309 mView.findViewById(R.id.metered_settings_fields).setVisibility(View.VISIBLE); 310 } 311 mHiddenSettingsSpinner = mView.findViewById(R.id.hidden_settings); 312 if (!mHideMeteredAndPrivacy && mWifiManager.isConnectedMacRandomizationSupported()) { 313 mPrivacySettingsSpinner = mView.findViewById(R.id.privacy_settings); 314 if (Flags.androidVWifiApi()) { 315 mDhcpSettingsSpinner = mView.findViewById(R.id.dhcp_settings); 316 } 317 mView.findViewById(R.id.privacy_settings_fields).setVisibility(View.VISIBLE); 318 } 319 mHiddenSettingsSpinner.setOnItemSelectedListener(this); 320 mHiddenWarningView = mView.findViewById(R.id.hidden_settings_warning); 321 mHiddenWarningView.setVisibility( 322 mHiddenSettingsSpinner.getSelectedItemPosition() == NOT_HIDDEN_NETWORK 323 ? View.GONE 324 : View.VISIBLE); 325 mSecurityInPosition = new Integer[WifiEntry.NUM_SECURITY_TYPES]; 326 327 if (mWifiEntry == null) { // new network 328 configureSecuritySpinner(); 329 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save)); 330 } else { 331 mConfigUi.setTitle(mWifiEntry.getTitle()); 332 333 ViewGroup group = (ViewGroup) mView.findViewById(R.id.info); 334 335 boolean showAdvancedFields = false; 336 if (mWifiEntry.isSaved()) { 337 WifiConfiguration config = mWifiEntry.getWifiConfiguration(); 338 if (mMeteredSettingsSpinner != null) { 339 mMeteredSettingsSpinner.setSelection(config.meteredOverride); 340 } 341 mHiddenSettingsSpinner.setSelection(config.hiddenSSID 342 ? HIDDEN_NETWORK 343 : NOT_HIDDEN_NETWORK); 344 345 if (mPrivacySettingsSpinner != null) { 346 final int prefMacValue = WifiPrivacyPreferenceController2 347 .translateMacRandomizedValueToPrefValue(config.macRandomizationSetting); 348 mPrivacySettingsSpinner.setSelection(prefMacValue); 349 } 350 351 if (mDhcpSettingsSpinner != null) { 352 final int prefDhcpValue = WifiPrivacyPreferenceController.Companion 353 .translateSendDhcpHostnameEnabledToPrefValue( 354 config.isSendDhcpHostnameEnabled()); 355 mDhcpSettingsSpinner.setSelection(prefDhcpValue); 356 } 357 358 if (config.getIpConfiguration().getIpAssignment() == IpAssignment.STATIC) { 359 mIpSettingsSpinner.setSelection(STATIC_IP); 360 showAdvancedFields = true; 361 // Display IP address. 362 StaticIpConfiguration staticConfig = config.getIpConfiguration() 363 .getStaticIpConfiguration(); 364 if (staticConfig != null && staticConfig.getIpAddress() != null) { 365 addRow(group, R.string.wifi_ip_address, 366 staticConfig.getIpAddress().getAddress().getHostAddress()); 367 } 368 } else { 369 mIpSettingsSpinner.setSelection(DHCP); 370 } 371 372 mSharedCheckBox.setEnabled(config.shared); 373 if (!config.shared) { 374 showAdvancedFields = true; 375 } 376 377 ProxySettings proxySettings = config.getIpConfiguration().getProxySettings(); 378 if (proxySettings == ProxySettings.STATIC) { 379 mProxySettingsSpinner.setSelection(PROXY_STATIC); 380 showAdvancedFields = true; 381 } else if (proxySettings == ProxySettings.PAC) { 382 mProxySettingsSpinner.setSelection(PROXY_PAC); 383 showAdvancedFields = true; 384 } else { 385 mProxySettingsSpinner.setSelection(PROXY_NONE); 386 } 387 if (config != null && config.isPasspoint()) { 388 addRow(group, R.string.passpoint_label, 389 String.format(mContext.getString(R.string.passpoint_content), 390 config.providerFriendlyName)); 391 } 392 } 393 394 if ((!mWifiEntry.isSaved() 395 && mWifiEntry.getConnectedState() != WifiEntry.CONNECTED_STATE_CONNECTED 396 && !mWifiEntry.isSubscription()) 397 || mMode != WifiConfigUiBase2.MODE_VIEW) { 398 showSecurityFields(/* refreshEapMethods */ true, /* refreshCertificates */ true); 399 showIpConfigFields(); 400 showProxyFields(); 401 final CheckBox advancedTogglebox = 402 (CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox); 403 if (!showAdvancedFields) { 404 // Need to show Advanced Option button. 405 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE); 406 advancedTogglebox.setOnCheckedChangeListener(this); 407 advancedTogglebox.setChecked(showAdvancedFields); 408 setAdvancedOptionAccessibilityString(); 409 } 410 mView.findViewById(R.id.wifi_advanced_fields) 411 .setVisibility(showAdvancedFields ? View.VISIBLE : View.GONE); 412 } 413 414 if (mMode == WifiConfigUiBase2.MODE_MODIFY) { 415 mConfigUi.setSubmitButton(res.getString(R.string.wifi_save)); 416 } else if (mMode == WifiConfigUiBase2.MODE_CONNECT) { 417 mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect)); 418 } else { 419 final String signalLevel = getSignalString(); 420 421 if (mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED 422 && signalLevel != null) { 423 mConfigUi.setSubmitButton(res.getString(R.string.wifi_connect)); 424 } else { 425 if (signalLevel != null) { 426 addRow(group, R.string.wifi_signal, signalLevel); 427 } 428 429 final ConnectedInfo info = mWifiEntry.getConnectedInfo(); 430 if (info != null && info.linkSpeedMbps >= 0) { 431 addRow(group, R.string.wifi_speed, String.format( 432 res.getString(R.string.link_speed), info.linkSpeedMbps)); 433 } 434 435 if (info != null && info.frequencyMhz != WifiEntry.FREQUENCY_UNKNOWN) { 436 final int frequency = info.frequencyMhz; 437 String band = null; 438 439 if (frequency >= WifiEntry.MIN_FREQ_24GHZ 440 && frequency < WifiEntry.MAX_FREQ_24GHZ) { 441 band = res.getString(R.string.wifi_band_24ghz); 442 } else if (frequency >= WifiEntry.MIN_FREQ_5GHZ 443 && frequency < WifiEntry.MAX_FREQ_5GHZ) { 444 band = res.getString(R.string.wifi_band_5ghz); 445 } else if (frequency >= WifiEntry.MIN_FREQ_6GHZ 446 && frequency < WifiEntry.MAX_FREQ_6GHZ) { 447 band = res.getString(R.string.wifi_band_6ghz); 448 } else { 449 Log.e(TAG, "Unexpected frequency " + frequency); 450 } 451 if (band != null) { 452 addRow(group, R.string.wifi_frequency, band); 453 } 454 } 455 456 addRow(group, R.string.wifi_security, 457 mWifiEntry.getSecurityString(false /* concise */)); 458 mView.findViewById(R.id.ip_fields).setVisibility(View.GONE); 459 } 460 if (mWifiEntry.isSaved() 461 || mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED 462 || mWifiEntry.isSubscription()) { 463 mConfigUi.setForgetButton(res.getString(R.string.wifi_forget)); 464 } 465 } 466 467 mSsidScanButton.setVisibility(View.GONE); 468 } 469 mSharedCheckBox.setVisibility(View.GONE); 470 471 mConfigUi.setCancelButton(res.getString(R.string.wifi_cancel)); 472 if (mConfigUi.getSubmitButton() != null) { 473 enableSubmitIfAppropriate(); 474 } 475 476 // After done view show and hide, request focus 477 mView.findViewById(R.id.l_wifidialog).requestFocus(); 478 } 479 addRow(ViewGroup group, int name, String value)480 private void addRow(ViewGroup group, int name, String value) { 481 View row = mConfigUi.getLayoutInflater().inflate(R.layout.wifi_dialog_row, group, false); 482 ((TextView) row.findViewById(R.id.name)).setText(name); 483 ((TextView) row.findViewById(R.id.value)).setText(value); 484 group.addView(row); 485 } 486 487 @VisibleForTesting getSignalString()488 String getSignalString() { 489 if (mWifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) { 490 return null; 491 } 492 final int level = mWifiEntry.getLevel(); 493 494 return (level > -1 && level < mLevels.length) ? mLevels[level] : null; 495 } 496 hideForgetButton()497 void hideForgetButton() { 498 Button forget = mConfigUi.getForgetButton(); 499 if (forget == null) return; 500 501 forget.setVisibility(View.GONE); 502 } 503 hideSubmitButton()504 void hideSubmitButton() { 505 Button submit = mConfigUi.getSubmitButton(); 506 if (submit == null) return; 507 508 submit.setVisibility(View.GONE); 509 } 510 511 /* show submit button if password, ip and proxy settings are valid */ enableSubmitIfAppropriate()512 void enableSubmitIfAppropriate() { 513 Button submit = mConfigUi.getSubmitButton(); 514 if (submit == null) return; 515 516 submit.setEnabled(isSubmittable()); 517 } 518 isValidPsk(String password)519 boolean isValidPsk(String password) { 520 if (password.length() == 64 && password.matches("[0-9A-Fa-f]{64}")) { 521 return true; 522 } else if (password.length() >= 8 && password.length() <= 63) { 523 return true; 524 } 525 return false; 526 } 527 isValidSaePassword(String password)528 boolean isValidSaePassword(String password) { 529 if (password.length() >= 1 && password.length() <= 128) { 530 return true; 531 } 532 return false; 533 } 534 isSubmittable()535 boolean isSubmittable() { 536 boolean enabled = false; 537 boolean passwordInvalid = false; 538 if (mPasswordView != null 539 && ((mWifiEntrySecurity == WifiEntry.SECURITY_WEP 540 && mPasswordView.length() == 0) 541 || (mWifiEntrySecurity == WifiEntry.SECURITY_PSK 542 && !isValidPsk(mPasswordView.getText().toString())) 543 || (mWifiEntrySecurity == WifiEntry.SECURITY_SAE 544 && !isValidSaePassword(mPasswordView.getText().toString())))) { 545 passwordInvalid = true; 546 } 547 if ((mSsidView != null && mSsidView.length() == 0) 548 // If WifiEntry is not saved, apply passwordInvalid check 549 || ((mWifiEntry == null || !mWifiEntry.isSaved()) && passwordInvalid 550 // If WifiEntry is saved (modifying network) and password is changed, apply 551 // Invalid password check 552 || mWifiEntry != null && mWifiEntry.isSaved() && passwordInvalid 553 && mPasswordView.length() > 0)) { 554 enabled = false; 555 } else { 556 enabled = ipAndProxyFieldsAreValid(); 557 } 558 if ((mWifiEntrySecurity == WifiEntry.SECURITY_EAP 559 || mWifiEntrySecurity == WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE 560 || mWifiEntrySecurity == WifiEntry.SECURITY_EAP_SUITE_B) 561 && mEapCaCertSpinner != null 562 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) { 563 String caCertSelection = (String) mEapCaCertSpinner.getSelectedItem(); 564 if (caCertSelection.equals(mUnspecifiedCertString)) { 565 // Disallow submit if the user has not selected a CA certificate for an EAP network 566 // configuration. 567 enabled = false; 568 } else if (mEapDomainView != null 569 && mView.findViewById(R.id.l_domain).getVisibility() != View.GONE 570 && TextUtils.isEmpty(mEapDomainView.getText().toString())) { 571 // Disallow submit if the user chooses to use a certificate for EAP server 572 // validation, but does not provide a domain. 573 enabled = false; 574 } 575 } 576 if ((mWifiEntrySecurity == WifiEntry.SECURITY_EAP 577 || mWifiEntrySecurity == WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE 578 || mWifiEntrySecurity == WifiEntry.SECURITY_EAP_SUITE_B) 579 && mEapUserCertSpinner != null 580 && mView.findViewById(R.id.l_user_cert).getVisibility() != View.GONE 581 && mEapUserCertSpinner.getSelectedItem().equals(mUnspecifiedCertString)) { 582 // Disallow submit if the user has not selected a user certificate for an EAP network 583 // configuration. 584 enabled = false; 585 } 586 return enabled; 587 } 588 showWarningMessagesIfAppropriate()589 void showWarningMessagesIfAppropriate() { 590 mView.findViewById(R.id.no_user_cert_warning).setVisibility(View.GONE); 591 mView.findViewById(R.id.no_domain_warning).setVisibility(View.GONE); 592 mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.GONE); 593 594 if (mSsidView != null) { 595 final String ssid = mSsidView.getText().toString(); 596 if (WifiUtils.isSSIDTooLong(ssid)) { 597 mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE); 598 } 599 } 600 if (mEapCaCertSpinner != null 601 && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) { 602 if (mEapDomainView != null 603 && mView.findViewById(R.id.l_domain).getVisibility() != View.GONE 604 && TextUtils.isEmpty(mEapDomainView.getText().toString())) { 605 // Display warning if user chooses to use a certificate without restricting the 606 // server domain that these certificates can be used to validate. 607 mView.findViewById(R.id.no_domain_warning).setVisibility(View.VISIBLE); 608 } 609 } 610 611 if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_SUITE_B 612 && mEapMethodSpinner.getSelectedItemPosition() == WIFI_EAP_METHOD_TLS) { 613 String userCertSelection = (String) mEapUserCertSpinner.getSelectedItem(); 614 if (userCertSelection.equals(mUnspecifiedCertString)) { 615 mView.findViewById(R.id.no_user_cert_warning).setVisibility(View.VISIBLE); 616 } 617 } 618 } 619 620 /** 621 * @return {@link WifiConfiguration} from mWifiEntry and UI edit result. 622 */ getConfig()623 public WifiConfiguration getConfig() { 624 if (mMode == WifiConfigUiBase2.MODE_VIEW) { 625 return null; 626 } 627 628 WifiConfiguration config; 629 if (mWifiEntry == null) { 630 config = new WifiConfiguration(); 631 config.SSID = "\"" + mSsidView.getText().toString() + "\""; 632 // If the user adds a network manually, assume that it is hidden. 633 config.hiddenSSID = mHiddenSettingsSpinner.getSelectedItemPosition() == HIDDEN_NETWORK; 634 } else if (mWifiEntry.isSaved()) { 635 config = new WifiConfiguration(mWifiEntry.getWifiConfiguration()); 636 } else { 637 config = new WifiConfiguration(); 638 config.SSID = "\"" + mWifiEntry.getTitle() + "\""; 639 } 640 641 config.shared = mSharedCheckBox.isChecked(); 642 643 switch (mWifiEntrySecurity) { 644 case WifiEntry.SECURITY_NONE: 645 if (mWifiEntry == null || !mWifiEntry.isSaved()) { 646 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); 647 } 648 break; 649 650 case WifiEntry.SECURITY_WEP: 651 if (mWifiEntry == null || !mWifiEntry.isSaved()) { 652 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP); 653 } 654 if (mPasswordView.length() != 0) { 655 int length = mPasswordView.length(); 656 String password = mPasswordView.getText().toString(); 657 // WEP-40, WEP-104, and 256-bit WEP (WEP-232?) 658 if ((length == 10 || length == 26 || length == 58) 659 && password.matches("[0-9A-Fa-f]*")) { 660 config.wepKeys[0] = password; 661 } else { 662 config.wepKeys[0] = '"' + password + '"'; 663 } 664 } 665 break; 666 667 case WifiEntry.SECURITY_PSK: 668 if (mWifiEntry == null || !mWifiEntry.isSaved()) { 669 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); 670 } 671 if (mPasswordView.length() != 0) { 672 String password = mPasswordView.getText().toString(); 673 if (password.matches("[0-9A-Fa-f]{64}")) { 674 config.preSharedKey = password; 675 } else { 676 config.preSharedKey = '"' + password + '"'; 677 } 678 } 679 break; 680 681 case WifiEntry.SECURITY_EAP: 682 case WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE: 683 case WifiEntry.SECURITY_EAP_SUITE_B: 684 if (mWifiEntry == null || !mWifiEntry.isSaved()) { 685 if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_SUITE_B) { 686 // allowedSuiteBCiphers will be set according to certificate type 687 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B); 688 } else if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE) { 689 config.setSecurityParams( 690 WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE); 691 } else { 692 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP); 693 } 694 } 695 config.enterpriseConfig = new WifiEnterpriseConfig(); 696 int eapMethod = mEapMethodSpinner.getSelectedItemPosition(); 697 int phase2Method = mPhase2Spinner.getSelectedItemPosition(); 698 config.enterpriseConfig.setEapMethod(eapMethod); 699 switch (eapMethod) { 700 case Eap.PEAP: 701 // PEAP supports limited phase2 values 702 // Map the index from the mPhase2PeapAdapter to the one used 703 // by the API which has the full list of PEAP methods. 704 switch(phase2Method) { 705 case WIFI_PEAP_PHASE2_MSCHAPV2: 706 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2); 707 break; 708 case WIFI_PEAP_PHASE2_GTC: 709 config.enterpriseConfig.setPhase2Method(Phase2.GTC); 710 break; 711 case WIFI_PEAP_PHASE2_SIM: 712 config.enterpriseConfig.setPhase2Method(Phase2.SIM); 713 break; 714 case WIFI_PEAP_PHASE2_AKA: 715 config.enterpriseConfig.setPhase2Method(Phase2.AKA); 716 break; 717 case WIFI_PEAP_PHASE2_AKA_PRIME: 718 config.enterpriseConfig.setPhase2Method(Phase2.AKA_PRIME); 719 break; 720 default: 721 Log.e(TAG, "Unknown phase2 method" + phase2Method); 722 break; 723 } 724 break; 725 case Eap.TTLS: 726 // The default index from mPhase2TtlsAdapter maps to the API 727 switch(phase2Method) { 728 case WIFI_TTLS_PHASE2_PAP: 729 config.enterpriseConfig.setPhase2Method(Phase2.PAP); 730 break; 731 case WIFI_TTLS_PHASE2_MSCHAP: 732 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAP); 733 break; 734 case WIFI_TTLS_PHASE2_MSCHAPV2: 735 config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2); 736 break; 737 case WIFI_TTLS_PHASE2_GTC: 738 config.enterpriseConfig.setPhase2Method(Phase2.GTC); 739 break; 740 default: 741 Log.e(TAG, "Unknown phase2 method" + phase2Method); 742 break; 743 } 744 break; 745 default: 746 break; 747 } 748 749 if (config.enterpriseConfig.isAuthenticationSimBased() 750 && mActiveSubscriptionInfos.size() > 0) { 751 config.carrierId = mActiveSubscriptionInfos 752 .valueAt(mEapSimSpinner.getSelectedItemPosition()).getCarrierId(); 753 } 754 755 String caCert = (String) mEapCaCertSpinner.getSelectedItem(); 756 config.enterpriseConfig.setCaCertificateAliases(null); 757 config.enterpriseConfig.setCaPath(null); 758 config.enterpriseConfig.setDomainSuffixMatch(mEapDomainView.getText().toString()); 759 if (caCert.equals(mUnspecifiedCertString)) { 760 // ca_cert already set to null, so do nothing. 761 } else if (mIsTrustOnFirstUseSupported && caCert.equals(mTrustOnFirstUse)) { 762 config.enterpriseConfig.enableTrustOnFirstUse(true); 763 } else if (caCert.equals(mUseSystemCertsString)) { 764 config.enterpriseConfig.setCaPath(SYSTEM_CA_STORE_PATH); 765 } else if (caCert.equals(mMultipleCertSetString)) { 766 if (mWifiEntry != null) { 767 if (!mWifiEntry.isSaved()) { 768 Log.e(TAG, "Multiple certs can only be set " 769 + "when editing saved network"); 770 } 771 config.enterpriseConfig.setCaCertificateAliases( 772 mWifiEntry.getWifiConfiguration() 773 .enterpriseConfig 774 .getCaCertificateAliases()); 775 } 776 } else { 777 config.enterpriseConfig.setCaCertificateAliases(new String[] {caCert}); 778 } 779 780 // ca_cert or ca_path should not both be non-null, since we only intend to let 781 // the use either their own certificate, or the system certificates, not both. 782 // The variable that is not used must explicitly be set to null, so that a 783 // previously-set value on a saved configuration will be erased on an update. 784 if (config.enterpriseConfig.getCaCertificateAliases() != null 785 && config.enterpriseConfig.getCaPath() != null) { 786 Log.e(TAG, "ca_cert (" 787 + Arrays.toString(config.enterpriseConfig.getCaCertificateAliases()) 788 + ") and ca_path (" 789 + config.enterpriseConfig.getCaPath() 790 + ") should not both be non-null"); 791 } 792 793 // Only set certificate option if there is a valid CA certificate. 794 if (caCert.equals(mUnspecifiedCertString)) { 795 config.enterpriseConfig.setOcsp(WifiEnterpriseConfig.OCSP_NONE); 796 config.enterpriseConfig.setMinimumTlsVersion(WifiEnterpriseConfig.TLS_V1_0); 797 } else { 798 config.enterpriseConfig.setOcsp(mEapOcspSpinner.getSelectedItemPosition()); 799 config.enterpriseConfig.setMinimumTlsVersion( 800 mEapMinTlsVerSpinner.getSelectedItemPosition()); 801 } 802 803 String clientCert = (String) mEapUserCertSpinner.getSelectedItem(); 804 if (clientCert.equals(mUnspecifiedCertString) 805 || clientCert.equals(mDoNotProvideEapUserCertString)) { 806 // Note: |clientCert| should not be able to take the value |unspecifiedCert|, 807 // since we prevent such configurations from being saved. 808 clientCert = ""; 809 } 810 config.enterpriseConfig.setClientCertificateAlias(clientCert); 811 if (eapMethod == Eap.SIM || eapMethod == Eap.AKA || eapMethod == Eap.AKA_PRIME) { 812 config.enterpriseConfig.setIdentity(""); 813 config.enterpriseConfig.setAnonymousIdentity(""); 814 } else if (eapMethod == Eap.PWD) { 815 config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString()); 816 config.enterpriseConfig.setAnonymousIdentity(""); 817 } else { 818 config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString()); 819 config.enterpriseConfig.setAnonymousIdentity( 820 mEapAnonymousView.getText().toString()); 821 } 822 823 if (mPasswordView.isShown()) { 824 // For security reasons, a previous password is not displayed to user. 825 // Update only if it has been changed. 826 if (mPasswordView.length() > 0) { 827 config.enterpriseConfig.setPassword(mPasswordView.getText().toString()); 828 } 829 } else { 830 // clear password 831 config.enterpriseConfig.setPassword(mPasswordView.getText().toString()); 832 } 833 break; 834 case WifiEntry.SECURITY_SAE: 835 if (mWifiEntry == null || !mWifiEntry.isSaved()) { 836 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); 837 } 838 if (mPasswordView.length() != 0) { 839 String password = mPasswordView.getText().toString(); 840 config.preSharedKey = '"' + password + '"'; 841 } 842 break; 843 844 case WifiEntry.SECURITY_OWE: 845 if (mWifiEntry == null || !mWifiEntry.isSaved()) { 846 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); 847 } 848 break; 849 850 default: 851 return null; 852 } 853 854 final IpConfiguration ipConfig = new IpConfiguration(); 855 ipConfig.setIpAssignment(mIpAssignment); 856 ipConfig.setProxySettings(mProxySettings); 857 ipConfig.setStaticIpConfiguration(mStaticIpConfiguration); 858 ipConfig.setHttpProxy(mHttpProxy); 859 config.setIpConfiguration(ipConfig); 860 if (mMeteredSettingsSpinner != null) { 861 config.meteredOverride = mMeteredSettingsSpinner.getSelectedItemPosition(); 862 } 863 864 if (mPrivacySettingsSpinner != null) { 865 config.macRandomizationSetting = WifiPrivacyPreferenceController2 866 .translatePrefValueToMacRandomizedValue(mPrivacySettingsSpinner 867 .getSelectedItemPosition()); 868 } 869 870 if (mDhcpSettingsSpinner != null) { 871 config.setSendDhcpHostnameEnabled(WifiPrivacyPreferenceController.Companion 872 .translatePrefValueToSendDhcpHostnameEnabled(mDhcpSettingsSpinner 873 .getSelectedItemPosition())); 874 } 875 876 return config; 877 } 878 ipAndProxyFieldsAreValid()879 private boolean ipAndProxyFieldsAreValid() { 880 mIpAssignment = 881 (mIpSettingsSpinner != null 882 && mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) 883 ? IpAssignment.STATIC 884 : IpAssignment.DHCP; 885 886 if (mIpAssignment == IpAssignment.STATIC) { 887 mStaticIpConfiguration = new StaticIpConfiguration(); 888 int result = validateIpConfigFields(mStaticIpConfiguration); 889 if (result != 0) { 890 return false; 891 } 892 } 893 894 final int selectedPosition = mProxySettingsSpinner.getSelectedItemPosition(); 895 mProxySettings = ProxySettings.NONE; 896 mHttpProxy = null; 897 if (selectedPosition == PROXY_STATIC && mProxyHostView != null) { 898 mProxySettings = ProxySettings.STATIC; 899 String host = mProxyHostView.getText().toString(); 900 String portStr = mProxyPortView.getText().toString(); 901 String exclusionList = mProxyExclusionListView.getText().toString(); 902 int port = 0; 903 int result = 0; 904 try { 905 port = Integer.parseInt(portStr); 906 result = ProxySelector.validate(host, portStr, exclusionList); 907 } catch (NumberFormatException e) { 908 result = R.string.proxy_error_invalid_port; 909 } 910 if (result == 0) { 911 mHttpProxy = ProxyInfo.buildDirectProxy( 912 host, port, Arrays.asList(exclusionList.split(","))); 913 } else { 914 return false; 915 } 916 } else if (selectedPosition == PROXY_PAC && mProxyPacView != null) { 917 mProxySettings = ProxySettings.PAC; 918 CharSequence uriSequence = mProxyPacView.getText(); 919 if (TextUtils.isEmpty(uriSequence)) { 920 return false; 921 } 922 Uri uri = Uri.parse(uriSequence.toString()); 923 if (uri == null) { 924 return false; 925 } 926 mHttpProxy = ProxyInfo.buildPacProxy(uri); 927 } 928 return true; 929 } 930 getIPv4Address(String text)931 private Inet4Address getIPv4Address(String text) { 932 try { 933 return (Inet4Address) InetAddresses.parseNumericAddress(text); 934 } catch (IllegalArgumentException | ClassCastException e) { 935 return null; 936 } 937 } 938 validateIpConfigFields(StaticIpConfiguration staticIpConfiguration)939 private int validateIpConfigFields(StaticIpConfiguration staticIpConfiguration) { 940 if (mIpAddressView == null) return 0; 941 942 String ipAddr = mIpAddressView.getText().toString(); 943 if (TextUtils.isEmpty(ipAddr)) return R.string.wifi_ip_settings_invalid_ip_address; 944 945 Inet4Address inetAddr = getIPv4Address(ipAddr); 946 if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) { 947 return R.string.wifi_ip_settings_invalid_ip_address; 948 } 949 950 // Copy all fields into the builder first and set desired value later with builder. 951 final StaticIpConfiguration.Builder staticIPBuilder = new StaticIpConfiguration.Builder() 952 .setDnsServers(staticIpConfiguration.getDnsServers()) 953 .setDomains(staticIpConfiguration.getDomains()) 954 .setGateway(staticIpConfiguration.getGateway()) 955 .setIpAddress(staticIpConfiguration.getIpAddress()); 956 try { 957 int networkPrefixLength = -1; 958 try { 959 networkPrefixLength = 960 Integer.parseInt(mNetworkPrefixLengthView.getText().toString()); 961 if (networkPrefixLength < 0 || networkPrefixLength > 32) { 962 return R.string.wifi_ip_settings_invalid_network_prefix_length; 963 } 964 staticIPBuilder.setIpAddress(new LinkAddress(inetAddr, networkPrefixLength)); 965 } catch (NumberFormatException e) { 966 // Set the hint as default after user types in ip address 967 mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString( 968 com.android.settingslib.R.string.wifi_network_prefix_length_hint)); 969 } catch (IllegalArgumentException e) { 970 return R.string.wifi_ip_settings_invalid_ip_address; 971 } 972 973 String gateway = mGatewayView.getText().toString(); 974 if (TextUtils.isEmpty(gateway)) { 975 try { 976 //Extract a default gateway from IP address 977 InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength); 978 byte[] addr = netPart.getAddress(); 979 addr[addr.length - 1] = 1; 980 mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress()); 981 } catch (RuntimeException ee) { 982 } catch (java.net.UnknownHostException u) { 983 } 984 } else { 985 InetAddress gatewayAddr = getIPv4Address(gateway); 986 if (gatewayAddr == null) { 987 return R.string.wifi_ip_settings_invalid_gateway; 988 } 989 if (gatewayAddr.isMulticastAddress()) { 990 return R.string.wifi_ip_settings_invalid_gateway; 991 } 992 staticIPBuilder.setGateway(gatewayAddr); 993 } 994 995 String dns = mDns1View.getText().toString(); 996 InetAddress dnsAddr = null; 997 final ArrayList<InetAddress> dnsServers = new ArrayList<>(); 998 999 if (TextUtils.isEmpty(dns)) { 1000 //If everything else is valid, provide hint as a default option 1001 mDns1View.setText(mConfigUi.getContext().getString( 1002 com.android.settingslib.R.string.wifi_dns1_hint)); 1003 } else { 1004 dnsAddr = getIPv4Address(dns); 1005 if (dnsAddr == null) { 1006 return R.string.wifi_ip_settings_invalid_dns; 1007 } 1008 dnsServers.add(dnsAddr); 1009 } 1010 1011 if (mDns2View.length() > 0) { 1012 dns = mDns2View.getText().toString(); 1013 dnsAddr = getIPv4Address(dns); 1014 if (dnsAddr == null) { 1015 return R.string.wifi_ip_settings_invalid_dns; 1016 } 1017 dnsServers.add(dnsAddr); 1018 } 1019 staticIPBuilder.setDnsServers(dnsServers); 1020 return 0; 1021 } finally { 1022 // Caller of this method may rely on staticIpConfiguration, so build the final result 1023 // at the end of the method. 1024 mStaticIpConfiguration = staticIPBuilder.build(); 1025 } 1026 } 1027 showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates)1028 protected void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) { 1029 if (mWifiEntrySecurity == WifiEntry.SECURITY_NONE 1030 || mWifiEntrySecurity == WifiEntry.SECURITY_OWE) { 1031 mView.findViewById(R.id.security_fields).setVisibility(View.GONE); 1032 return; 1033 } 1034 mView.findViewById(R.id.security_fields).setVisibility(View.VISIBLE); 1035 1036 if (mPasswordView == null) { 1037 mPasswordView = (TextView) mView.findViewById(R.id.password); 1038 mPasswordView.addTextChangedListener(this); 1039 mPasswordView.setOnEditorActionListener(this); 1040 mPasswordView.setOnKeyListener(this); 1041 ((CheckBox) mView.findViewById(R.id.show_password)) 1042 .setOnCheckedChangeListener(this); 1043 1044 if (mWifiEntry != null && mWifiEntry.isSaved()) { 1045 mPasswordView.setHint(R.string.wifi_unchanged); 1046 } 1047 } 1048 1049 if (mWifiEntrySecurity != WifiEntry.SECURITY_EAP 1050 && mWifiEntrySecurity != WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE 1051 && mWifiEntrySecurity != WifiEntry.SECURITY_EAP_SUITE_B) { 1052 mView.findViewById(R.id.eap).setVisibility(View.GONE); 1053 return; 1054 } 1055 mView.findViewById(R.id.eap).setVisibility(View.VISIBLE); 1056 1057 // TODO (b/140541213): Maybe we can remove initiateEnterpriseNetworkUi by moving code block 1058 boolean initiateEnterpriseNetworkUi = false; 1059 if (mEapMethodSpinner == null) { 1060 initiateEnterpriseNetworkUi = true; 1061 mEapMethodSpinner = (Spinner) mView.findViewById(R.id.method); 1062 mEapMethodSpinner.setOnItemSelectedListener(this); 1063 mEapSimSpinner = (Spinner) mView.findViewById(R.id.sim); 1064 mPhase2Spinner = (Spinner) mView.findViewById(R.id.phase2); 1065 mPhase2Spinner.setOnItemSelectedListener(this); 1066 mEapCaCertSpinner = (Spinner) mView.findViewById(R.id.ca_cert); 1067 mEapCaCertSpinner.setOnItemSelectedListener(this); 1068 mEapMinTlsVerSpinner = getEapMinTlsVerSpinner(mWifiManager.isTlsV13Supported()); 1069 1070 mEapOcspSpinner = (Spinner) mView.findViewById(R.id.ocsp); 1071 mEapDomainView = (TextView) mView.findViewById(R.id.domain); 1072 mEapDomainView.addTextChangedListener(this); 1073 mEapUserCertSpinner = (Spinner) mView.findViewById(R.id.user_cert); 1074 mEapUserCertSpinner.setOnItemSelectedListener(this); 1075 mEapIdentityView = (TextView) mView.findViewById(R.id.identity); 1076 mEapAnonymousView = (TextView) mView.findViewById(R.id.anonymous); 1077 1078 setAccessibilityDelegateForSecuritySpinners(); 1079 } 1080 1081 if (refreshEapMethods) { 1082 ArrayAdapter<CharSequence> eapMethodSpinnerAdapter; 1083 if (mWifiEntrySecurity == WifiEntry.SECURITY_EAP_SUITE_B) { 1084 eapMethodSpinnerAdapter = getSpinnerAdapter(R.array.wifi_eap_method); 1085 mEapMethodSpinner.setAdapter(eapMethodSpinnerAdapter); 1086 // WAP3-Enterprise 192-bit only allows EAP method TLS 1087 mEapMethodSpinner.setSelection(Eap.TLS); 1088 mEapMethodSpinner.setEnabled(false); 1089 } else if (Utils.isWifiOnly(mContext) || !mContext.getResources().getBoolean( 1090 com.android.internal.R.bool.config_eap_sim_based_auth_supported)) { 1091 eapMethodSpinnerAdapter = getSpinnerAdapter(R.array.eap_method_without_sim_auth); 1092 mEapMethodSpinner.setAdapter(eapMethodSpinnerAdapter); 1093 mEapMethodSpinner.setEnabled(true); 1094 } else { 1095 eapMethodSpinnerAdapter = getSpinnerAdapterWithEapMethodsTts( 1096 R.array.wifi_eap_method); 1097 mEapMethodSpinner.setAdapter(eapMethodSpinnerAdapter); 1098 mEapMethodSpinner.setEnabled(true); 1099 } 1100 } 1101 1102 if (refreshCertificates) { 1103 loadSims(); 1104 1105 loadCertificates( 1106 mEapCaCertSpinner, 1107 mAndroidKeystoreAliasLoader.getCaCertAliases(), 1108 null /* noCertificateString */, 1109 false /* showMultipleCerts */, 1110 true /* showUsePreinstalledCertOption */); 1111 loadCertificates( 1112 mEapUserCertSpinner, 1113 mAndroidKeystoreAliasLoader.getKeyCertAliases(), 1114 mDoNotProvideEapUserCertString, 1115 false /* showMultipleCerts */, 1116 false /* showUsePreinstalledCertOption */); 1117 1118 setSelection(mEapCaCertSpinner, mUnspecifiedCertString); 1119 } 1120 1121 // Modifying an existing network 1122 if (initiateEnterpriseNetworkUi && mWifiEntry != null && mWifiEntry.isSaved()) { 1123 final WifiConfiguration wifiConfig = mWifiEntry.getWifiConfiguration(); 1124 final WifiEnterpriseConfig enterpriseConfig = wifiConfig.enterpriseConfig; 1125 final int eapMethod = enterpriseConfig.getEapMethod(); 1126 final int phase2Method = enterpriseConfig.getPhase2Method(); 1127 mEapMethodSpinner.setSelection(eapMethod); 1128 mLastShownEapMethod = eapMethod; 1129 showEapFieldsByMethod(eapMethod); 1130 switch (eapMethod) { 1131 case Eap.PEAP: 1132 switch (phase2Method) { 1133 case Phase2.MSCHAPV2: 1134 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_MSCHAPV2); 1135 break; 1136 case Phase2.GTC: 1137 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_GTC); 1138 break; 1139 case Phase2.SIM: 1140 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_SIM); 1141 break; 1142 case Phase2.AKA: 1143 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_AKA); 1144 break; 1145 case Phase2.AKA_PRIME: 1146 mPhase2Spinner.setSelection(WIFI_PEAP_PHASE2_AKA_PRIME); 1147 break; 1148 default: 1149 Log.e(TAG, "Invalid phase 2 method " + phase2Method); 1150 break; 1151 } 1152 break; 1153 case Eap.TTLS: 1154 switch (phase2Method) { 1155 case Phase2.PAP: 1156 mPhase2Spinner.setSelection(WIFI_TTLS_PHASE2_PAP); 1157 break; 1158 case Phase2.MSCHAP: 1159 mPhase2Spinner.setSelection(WIFI_TTLS_PHASE2_MSCHAP); 1160 break; 1161 case Phase2.MSCHAPV2: 1162 mPhase2Spinner.setSelection(WIFI_TTLS_PHASE2_MSCHAPV2); 1163 break; 1164 case Phase2.GTC: 1165 mPhase2Spinner.setSelection(WIFI_TTLS_PHASE2_GTC); 1166 break; 1167 default: 1168 Log.e(TAG, "Invalid phase 2 method " + phase2Method); 1169 break; 1170 } 1171 break; 1172 default: 1173 break; 1174 } 1175 1176 if (enterpriseConfig.isAuthenticationSimBased()) { 1177 int index = mActiveSubscriptionInfos.indexOfKey(wifiConfig.carrierId); 1178 if (index > -1) { 1179 mEapSimSpinner.setSelection(index); 1180 } 1181 } 1182 1183 if (!TextUtils.isEmpty(enterpriseConfig.getCaPath())) { 1184 setSelection(mEapCaCertSpinner, mUseSystemCertsString); 1185 } else { 1186 String[] caCerts = enterpriseConfig.getCaCertificateAliases(); 1187 if (caCerts == null) { 1188 if (mIsTrustOnFirstUseSupported 1189 && enterpriseConfig.isTrustOnFirstUseEnabled()) { 1190 setSelection(mEapCaCertSpinner, mTrustOnFirstUse); 1191 } else { 1192 setSelection(mEapCaCertSpinner, mUnspecifiedCertString); 1193 } 1194 } else if (caCerts.length == 1) { 1195 setSelection(mEapCaCertSpinner, caCerts[0]); 1196 } else { 1197 // Reload the cert spinner with an extra "multiple certificates added" item. 1198 loadCertificates( 1199 mEapCaCertSpinner, 1200 mAndroidKeystoreAliasLoader.getCaCertAliases(), 1201 null /* noCertificateString */, 1202 true /* showMultipleCerts */, 1203 true /* showUsePreinstalledCertOption */); 1204 setSelection(mEapCaCertSpinner, mMultipleCertSetString); 1205 } 1206 } 1207 mEapMinTlsVerSpinner.setSelection(enterpriseConfig.getMinimumTlsVersion()); 1208 mEapOcspSpinner.setSelection(enterpriseConfig.getOcsp()); 1209 mEapDomainView.setText(enterpriseConfig.getDomainSuffixMatch()); 1210 String userCert = enterpriseConfig.getClientCertificateAlias(); 1211 if (TextUtils.isEmpty(userCert)) { 1212 setSelection(mEapUserCertSpinner, mDoNotProvideEapUserCertString); 1213 } else { 1214 setSelection(mEapUserCertSpinner, userCert); 1215 } 1216 mEapIdentityView.setText(enterpriseConfig.getIdentity()); 1217 mEapAnonymousView.setText(enterpriseConfig.getAnonymousIdentity()); 1218 } else { 1219 showEapFieldsByMethod(mEapMethodSpinner.getSelectedItemPosition()); 1220 } 1221 } 1222 setAccessibilityDelegateForSecuritySpinners()1223 private void setAccessibilityDelegateForSecuritySpinners() { 1224 final AccessibilityDelegate selectedEventBlocker = new AccessibilityDelegate() { 1225 @Override 1226 public void sendAccessibilityEvent(View host, int eventType) { 1227 if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED) { 1228 // Ignore TYPE_VIEW_SELECTED or there will be multiple Spinner selected 1229 // information for WifiController2#showSecurityFields. 1230 return; 1231 } 1232 super.sendAccessibilityEvent(host, eventType); 1233 } 1234 }; 1235 1236 mEapMethodSpinner.setAccessibilityDelegate(selectedEventBlocker); 1237 mPhase2Spinner.setAccessibilityDelegate(selectedEventBlocker); 1238 mEapCaCertSpinner.setAccessibilityDelegate(selectedEventBlocker); 1239 mEapMinTlsVerSpinner.setAccessibilityDelegate(selectedEventBlocker); 1240 mEapOcspSpinner.setAccessibilityDelegate(selectedEventBlocker); 1241 mEapUserCertSpinner.setAccessibilityDelegate(selectedEventBlocker); 1242 } 1243 1244 /** 1245 * EAP-PWD valid fields include 1246 * identity 1247 * password 1248 * EAP-PEAP valid fields include 1249 * phase2: MSCHAPV2, GTC, SIM, AKA, AKA' 1250 * ca_cert 1251 * identity 1252 * anonymous_identity 1253 * password (not required for SIM, AKA, AKA') 1254 * EAP-TLS valid fields include 1255 * user_cert 1256 * ca_cert 1257 * domain 1258 * identity 1259 * EAP-TTLS valid fields include 1260 * phase2: PAP, MSCHAP, MSCHAPV2, GTC 1261 * ca_cert 1262 * identity 1263 * anonymous_identity 1264 * password 1265 */ showEapFieldsByMethod(int eapMethod)1266 private void showEapFieldsByMethod(int eapMethod) { 1267 // Common defaults 1268 mView.findViewById(R.id.l_method).setVisibility(View.VISIBLE); 1269 mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE); 1270 mView.findViewById(R.id.l_domain).setVisibility(View.VISIBLE); 1271 1272 // Defaults for most of the EAP methods and over-riden by 1273 // by certain EAP methods 1274 mView.findViewById(R.id.l_ca_cert).setVisibility(View.VISIBLE); 1275 if (mWifiManager.isTlsMinimumVersionSupported()) { 1276 mView.findViewById(R.id.l_min_tls_ver).setVisibility(View.VISIBLE); 1277 } 1278 mView.findViewById(R.id.l_ocsp).setVisibility(View.VISIBLE); 1279 mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE); 1280 mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE); 1281 mView.findViewById(R.id.l_sim).setVisibility(View.VISIBLE); 1282 1283 Context context = mConfigUi.getContext(); 1284 switch (eapMethod) { 1285 case WIFI_EAP_METHOD_PWD: 1286 setPhase2Invisible(); 1287 setCaCertInvisible(); 1288 setMinTlsVerInvisible(); 1289 setOcspInvisible(); 1290 setDomainInvisible(); 1291 setAnonymousIdentInvisible(); 1292 setUserCertInvisible(); 1293 mView.findViewById(R.id.l_sim).setVisibility(View.GONE); 1294 break; 1295 case WIFI_EAP_METHOD_TLS: 1296 mView.findViewById(R.id.l_user_cert).setVisibility(View.VISIBLE); 1297 setPhase2Invisible(); 1298 setAnonymousIdentInvisible(); 1299 setPasswordInvisible(); 1300 mView.findViewById(R.id.l_sim).setVisibility(View.GONE); 1301 break; 1302 case WIFI_EAP_METHOD_PEAP: 1303 // Reset adapter if needed 1304 if (mPhase2Adapter != mPhase2PeapAdapter) { 1305 mPhase2Adapter = mPhase2PeapAdapter; 1306 mPhase2Spinner.setAdapter(mPhase2Adapter); 1307 } 1308 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE); 1309 setAnonymousIdVisible(); 1310 showPeapFields(); 1311 setUserCertInvisible(); 1312 break; 1313 case WIFI_EAP_METHOD_TTLS: 1314 // Reset adapter if needed 1315 if (mPhase2Adapter != mPhase2TtlsAdapter) { 1316 mPhase2Adapter = mPhase2TtlsAdapter; 1317 mPhase2Spinner.setAdapter(mPhase2Adapter); 1318 } 1319 mView.findViewById(R.id.l_phase2).setVisibility(View.VISIBLE); 1320 setAnonymousIdVisible(); 1321 setUserCertInvisible(); 1322 mView.findViewById(R.id.l_sim).setVisibility(View.GONE); 1323 break; 1324 case WIFI_EAP_METHOD_SIM: 1325 case WIFI_EAP_METHOD_AKA: 1326 case WIFI_EAP_METHOD_AKA_PRIME: 1327 setPhase2Invisible(); 1328 setAnonymousIdentInvisible(); 1329 setCaCertInvisible(); 1330 setMinTlsVerInvisible(); 1331 setOcspInvisible(); 1332 setDomainInvisible(); 1333 setUserCertInvisible(); 1334 setPasswordInvisible(); 1335 setIdentityInvisible(); 1336 break; 1337 } 1338 1339 if (mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) { 1340 String eapCertSelection = (String) mEapCaCertSpinner.getSelectedItem(); 1341 if (eapCertSelection.equals(mUnspecifiedCertString) 1342 || (mIsTrustOnFirstUseSupported 1343 && eapCertSelection.equals(mTrustOnFirstUse))) { 1344 setMinTlsVerInvisible(); 1345 // Domain suffix matching is not relevant if the user hasn't chosen a CA 1346 // certificate yet, or chooses not to validate the EAP server. 1347 setDomainInvisible(); 1348 // Ocsp is an additional validation step for a server certifidate. 1349 // This field is not relevant if the user hasn't chosen a valid 1350 // CA certificate yet. 1351 setOcspInvisible(); 1352 } 1353 } 1354 } 1355 showPeapFields()1356 private void showPeapFields() { 1357 int phase2Method = mPhase2Spinner.getSelectedItemPosition(); 1358 if (phase2Method == WIFI_PEAP_PHASE2_SIM || phase2Method == WIFI_PEAP_PHASE2_AKA 1359 || phase2Method == WIFI_PEAP_PHASE2_AKA_PRIME) { 1360 mEapIdentityView.setText(""); 1361 mView.findViewById(R.id.l_identity).setVisibility(View.GONE); 1362 setPasswordInvisible(); 1363 mView.findViewById(R.id.l_sim).setVisibility(View.VISIBLE); 1364 } else { 1365 mView.findViewById(R.id.l_identity).setVisibility(View.VISIBLE); 1366 mView.findViewById(R.id.password_layout).setVisibility(View.VISIBLE); 1367 mView.findViewById(R.id.show_password_layout).setVisibility(View.VISIBLE); 1368 mView.findViewById(R.id.l_sim).setVisibility(View.GONE); 1369 } 1370 } 1371 setIdentityInvisible()1372 private void setIdentityInvisible() { 1373 mView.findViewById(R.id.l_identity).setVisibility(View.GONE); 1374 } 1375 setPhase2Invisible()1376 private void setPhase2Invisible() { 1377 mView.findViewById(R.id.l_phase2).setVisibility(View.GONE); 1378 } 1379 setCaCertInvisible()1380 private void setCaCertInvisible() { 1381 mView.findViewById(R.id.l_ca_cert).setVisibility(View.GONE); 1382 setSelection(mEapCaCertSpinner, mUnspecifiedCertString); 1383 } 1384 setMinTlsVerInvisible()1385 private void setMinTlsVerInvisible() { 1386 mView.findViewById(R.id.l_min_tls_ver).setVisibility(View.GONE); 1387 mEapMinTlsVerSpinner.setSelection(WifiEnterpriseConfig.TLS_V1_0); 1388 } 1389 setOcspInvisible()1390 private void setOcspInvisible() { 1391 mView.findViewById(R.id.l_ocsp).setVisibility(View.GONE); 1392 mEapOcspSpinner.setSelection(WifiEnterpriseConfig.OCSP_NONE); 1393 } 1394 setDomainInvisible()1395 private void setDomainInvisible() { 1396 mView.findViewById(R.id.l_domain).setVisibility(View.GONE); 1397 mEapDomainView.setText(""); 1398 } 1399 setUserCertInvisible()1400 private void setUserCertInvisible() { 1401 mView.findViewById(R.id.l_user_cert).setVisibility(View.GONE); 1402 setSelection(mEapUserCertSpinner, mUnspecifiedCertString); 1403 } 1404 setAnonymousIdentInvisible()1405 private void setAnonymousIdentInvisible() { 1406 mView.findViewById(R.id.l_anonymous).setVisibility(View.GONE); 1407 mEapAnonymousView.setText(""); 1408 } 1409 1410 @VisibleForTesting setAnonymousIdVisible()1411 void setAnonymousIdVisible() { 1412 View view = mView.findViewById(R.id.l_anonymous); 1413 if (view.getVisibility() == View.VISIBLE) { 1414 return; 1415 } 1416 view.setVisibility(View.VISIBLE); 1417 mEapAnonymousView.setText(DEFAULT_ANONYMOUS_ID); 1418 } 1419 setPasswordInvisible()1420 private void setPasswordInvisible() { 1421 mPasswordView.setText(""); 1422 mView.findViewById(R.id.password_layout).setVisibility(View.GONE); 1423 mView.findViewById(R.id.show_password_layout).setVisibility(View.GONE); 1424 } 1425 setEapMethodInvisible()1426 private void setEapMethodInvisible() { 1427 mView.findViewById(R.id.eap).setVisibility(View.GONE); 1428 } 1429 showIpConfigFields()1430 private void showIpConfigFields() { 1431 WifiConfiguration config = null; 1432 1433 mView.findViewById(R.id.ip_fields).setVisibility(View.VISIBLE); 1434 1435 if (mWifiEntry != null && mWifiEntry.isSaved()) { 1436 config = mWifiEntry.getWifiConfiguration(); 1437 } 1438 1439 if (mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) { 1440 mView.findViewById(R.id.staticip).setVisibility(View.VISIBLE); 1441 if (mIpAddressView == null) { 1442 mIpAddressView = (TextView) mView.findViewById(R.id.ipaddress); 1443 mIpAddressView.addTextChangedListener(this); 1444 mGatewayView = (TextView) mView.findViewById(R.id.gateway); 1445 mGatewayView.addTextChangedListener(getIpConfigFieldsTextWatcher(mGatewayView)); 1446 mNetworkPrefixLengthView = (TextView) mView.findViewById( 1447 R.id.network_prefix_length); 1448 mNetworkPrefixLengthView.addTextChangedListener( 1449 getIpConfigFieldsTextWatcher(mNetworkPrefixLengthView)); 1450 mDns1View = (TextView) mView.findViewById(R.id.dns1); 1451 mDns1View.addTextChangedListener(getIpConfigFieldsTextWatcher(mDns1View)); 1452 mDns2View = (TextView) mView.findViewById(R.id.dns2); 1453 mDns2View.addTextChangedListener(this); 1454 } 1455 if (config != null) { 1456 StaticIpConfiguration staticConfig = config.getIpConfiguration() 1457 .getStaticIpConfiguration(); 1458 if (staticConfig != null) { 1459 if (staticConfig.getIpAddress() != null) { 1460 mIpAddressView.setText( 1461 staticConfig.getIpAddress().getAddress().getHostAddress()); 1462 mNetworkPrefixLengthView.setText(Integer.toString( 1463 staticConfig.getIpAddress().getPrefixLength())); 1464 } 1465 1466 if (staticConfig.getGateway() != null) { 1467 mGatewayView.setText(staticConfig.getGateway().getHostAddress()); 1468 } 1469 1470 Iterator<InetAddress> dnsIterator = staticConfig.getDnsServers().iterator(); 1471 if (dnsIterator.hasNext()) { 1472 mDns1View.setText(dnsIterator.next().getHostAddress()); 1473 } 1474 if (dnsIterator.hasNext()) { 1475 mDns2View.setText(dnsIterator.next().getHostAddress()); 1476 } 1477 } 1478 } 1479 } else { 1480 mView.findViewById(R.id.staticip).setVisibility(View.GONE); 1481 } 1482 } 1483 showProxyFields()1484 private void showProxyFields() { 1485 WifiConfiguration config = null; 1486 1487 mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE); 1488 1489 if (mWifiEntry != null && mWifiEntry.isSaved()) { 1490 config = mWifiEntry.getWifiConfiguration(); 1491 } 1492 1493 if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) { 1494 setVisibility(R.id.proxy_warning_limited_support, View.VISIBLE); 1495 setVisibility(R.id.proxy_fields, View.VISIBLE); 1496 setVisibility(R.id.proxy_pac_field, View.GONE); 1497 if (mProxyHostView == null) { 1498 mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname); 1499 mProxyHostView.addTextChangedListener(this); 1500 mProxyPortView = (TextView) mView.findViewById(R.id.proxy_port); 1501 mProxyPortView.addTextChangedListener(this); 1502 mProxyExclusionListView = (TextView) mView.findViewById(R.id.proxy_exclusionlist); 1503 mProxyExclusionListView.addTextChangedListener(this); 1504 } 1505 if (config != null) { 1506 ProxyInfo proxyProperties = config.getHttpProxy(); 1507 if (proxyProperties != null) { 1508 mProxyHostView.setText(proxyProperties.getHost()); 1509 mProxyPortView.setText(Integer.toString(proxyProperties.getPort())); 1510 mProxyExclusionListView.setText( 1511 ProxyUtils.exclusionListAsString(proxyProperties.getExclusionList())); 1512 } 1513 } 1514 } else if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_PAC) { 1515 setVisibility(R.id.proxy_warning_limited_support, View.GONE); 1516 setVisibility(R.id.proxy_fields, View.GONE); 1517 setVisibility(R.id.proxy_pac_field, View.VISIBLE); 1518 1519 if (mProxyPacView == null) { 1520 mProxyPacView = (TextView) mView.findViewById(R.id.proxy_pac); 1521 mProxyPacView.addTextChangedListener(this); 1522 } 1523 if (config != null) { 1524 ProxyInfo proxyInfo = config.getHttpProxy(); 1525 if (proxyInfo != null) { 1526 mProxyPacView.setText(proxyInfo.getPacFileUrl().toString()); 1527 } 1528 } 1529 } else { 1530 setVisibility(R.id.proxy_warning_limited_support, View.GONE); 1531 setVisibility(R.id.proxy_fields, View.GONE); 1532 setVisibility(R.id.proxy_pac_field, View.GONE); 1533 } 1534 } 1535 setVisibility(int id, int visibility)1536 private void setVisibility(int id, int visibility) { 1537 final View v = mView.findViewById(id); 1538 if (v != null) { 1539 v.setVisibility(visibility); 1540 } 1541 } 1542 1543 @VisibleForTesting loadSims()1544 void loadSims() { 1545 List<SubscriptionInfo> activeSubscriptionInfos = mContext 1546 .getSystemService(SubscriptionManager.class).getActiveSubscriptionInfoList(); 1547 if (activeSubscriptionInfos == null) { 1548 activeSubscriptionInfos = Collections.EMPTY_LIST; 1549 } 1550 mActiveSubscriptionInfos.clear(); 1551 1552 // Shows disabled 'No SIM' when there is no active subscription. 1553 if (activeSubscriptionInfos.isEmpty()) { 1554 final String[] noSim = new String[]{mContext.getString(R.string.wifi_no_sim_card)}; 1555 mEapSimSpinner.setAdapter(getSpinnerAdapter(noSim)); 1556 mEapSimSpinner.setSelection(0 /* position */); 1557 mEapSimSpinner.setEnabled(false); 1558 return; 1559 } 1560 1561 // Shows display name of each active subscription. 1562 ArrayMap<Integer, CharSequence> displayNames = new ArrayMap<>(); 1563 int defaultDataSubscriptionId = SubscriptionManager.getDefaultDataSubscriptionId(); 1564 for (SubscriptionInfo activeSubInfo : activeSubscriptionInfos) { 1565 // If multiple SIMs have the same carrier id, only the first or default data SIM is 1566 // displayed. 1567 if (displayNames.containsKey(activeSubInfo.getCarrierId()) 1568 && defaultDataSubscriptionId != activeSubInfo.getSubscriptionId()) { 1569 continue; 1570 } 1571 displayNames.put(activeSubInfo.getCarrierId(), 1572 SubscriptionUtil.getUniqueSubscriptionDisplayName(activeSubInfo, mContext)); 1573 mActiveSubscriptionInfos.put(activeSubInfo.getCarrierId(), activeSubInfo); 1574 } 1575 mEapSimSpinner.setAdapter( 1576 getSpinnerAdapter(displayNames.values().toArray(new String[displayNames.size()]))); 1577 mEapSimSpinner.setSelection(0 /* position */); 1578 if (displayNames.size() == 1) { 1579 mEapSimSpinner.setEnabled(false); 1580 } 1581 } 1582 1583 @VisibleForTesting loadCertificates( Spinner spinner, Collection<String> choices, String noCertificateString, boolean showMultipleCerts, boolean showUsePreinstalledCertOption)1584 void loadCertificates( 1585 Spinner spinner, 1586 Collection<String> choices, 1587 String noCertificateString, 1588 boolean showMultipleCerts, 1589 boolean showUsePreinstalledCertOption) { 1590 final Context context = mConfigUi.getContext(); 1591 1592 ArrayList<String> certs = new ArrayList<String>(); 1593 certs.add(mUnspecifiedCertString); 1594 if (showMultipleCerts) { 1595 certs.add(mMultipleCertSetString); 1596 } 1597 if (showUsePreinstalledCertOption) { 1598 certs.add(mUseSystemCertsString); 1599 if (mIsTrustOnFirstUseSupported) { 1600 certs.add(mTrustOnFirstUse); 1601 } 1602 certs.add(mInstallCertsString); 1603 } 1604 1605 if (choices != null && choices.size() != 0) { 1606 certs.addAll(choices.stream() 1607 .filter(certificateName -> { 1608 for (String undesired : UNDESIRED_CERTIFICATES) { 1609 if (certificateName.startsWith(undesired)) { 1610 return false; 1611 } 1612 } 1613 return true; 1614 }).collect(Collectors.toList())); 1615 } 1616 1617 if (!TextUtils.isEmpty(noCertificateString) 1618 && mWifiEntrySecurity != WifiEntry.SECURITY_EAP_SUITE_B) { 1619 certs.add(noCertificateString); 1620 } 1621 1622 // If there is only mUnspecifiedCertString and one item to select, only shows the item 1623 if (certs.size() == 2) { 1624 certs.remove(mUnspecifiedCertString); 1625 spinner.setEnabled(false); 1626 } else { 1627 spinner.setEnabled(true); 1628 } 1629 1630 final ArrayAdapter<CharSequence> adapter = getSpinnerAdapter( 1631 certs.toArray(new String[certs.size()])); 1632 spinner.setAdapter(adapter); 1633 } 1634 setSelection(Spinner spinner, String value)1635 private void setSelection(Spinner spinner, String value) { 1636 if (value != null) { 1637 @SuppressWarnings("unchecked") 1638 ArrayAdapter<String> adapter = (ArrayAdapter<String>) spinner.getAdapter(); 1639 for (int i = adapter.getCount() - 1; i >= 0; --i) { 1640 if (value.equals(adapter.getItem(i))) { 1641 spinner.setSelection(i); 1642 break; 1643 } 1644 } 1645 } 1646 } 1647 getMode()1648 public int getMode() { 1649 return mMode; 1650 } 1651 1652 @Override afterTextChanged(Editable s)1653 public void afterTextChanged(Editable s) { 1654 ThreadUtils.postOnMainThread(() -> { 1655 showWarningMessagesIfAppropriate(); 1656 enableSubmitIfAppropriate(); 1657 }); 1658 } 1659 1660 @Override beforeTextChanged(CharSequence s, int start, int count, int after)1661 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 1662 // work done in afterTextChanged 1663 } 1664 1665 @Override onTextChanged(CharSequence s, int start, int before, int count)1666 public void onTextChanged(CharSequence s, int start, int before, int count) { 1667 // work done in afterTextChanged 1668 } 1669 1670 /* TODO: Add more test cases for this TextWatcher b/186368002 1671 * This TextWatcher is for IP config fields (Gateway/Network Prefix Length/DNS1) to prevent 1672 * to rewrite the value in these columns that the user wanted to change after they saved. 1673 * When afterTextChanged we will check the text is empty or not then set the Hint for user. 1674 */ getIpConfigFieldsTextWatcher(final TextView view)1675 private TextWatcher getIpConfigFieldsTextWatcher(final TextView view) { 1676 return new TextWatcher() { 1677 @Override 1678 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 1679 // work done in afterTextChanged 1680 } 1681 1682 @Override 1683 public void onTextChanged(CharSequence s, int start, int before, int count) { 1684 // work done in afterTextChanged 1685 } 1686 1687 @Override 1688 public void afterTextChanged(Editable s) { 1689 if (s.length() == 0) { 1690 if (view.getId() == R.id.gateway) { 1691 mGatewayView.setHint(com.android.settingslib.R.string.wifi_gateway_hint); 1692 } else if (view.getId() == R.id.network_prefix_length) { 1693 mNetworkPrefixLengthView.setHint( 1694 com.android.settingslib.R.string.wifi_network_prefix_length_hint); 1695 } else if (view.getId() == R.id.dns1) { 1696 mDns1View.setHint(com.android.settingslib.R.string.wifi_dns1_hint); 1697 } 1698 Button submit = mConfigUi.getSubmitButton(); 1699 if (submit == null) return; 1700 1701 submit.setEnabled(false); 1702 } else { 1703 ThreadUtils.postOnMainThread(() -> { 1704 showWarningMessagesIfAppropriate(); 1705 enableSubmitIfAppropriate(); 1706 }); 1707 } 1708 } 1709 }; 1710 } 1711 1712 @Override 1713 public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { 1714 if (textView == mPasswordView) { 1715 if (id == EditorInfo.IME_ACTION_DONE && isSubmittable()) { 1716 mConfigUi.dispatchSubmit(); 1717 return true; 1718 } 1719 } 1720 return false; 1721 } 1722 1723 @Override 1724 public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 1725 if (view == mPasswordView) { 1726 if (keyCode == KeyEvent.KEYCODE_ENTER && isSubmittable()) { 1727 mConfigUi.dispatchSubmit(); 1728 return true; 1729 } 1730 } 1731 return false; 1732 } 1733 1734 @Override 1735 public void onCheckedChanged(CompoundButton view, boolean isChecked) { 1736 if (view.getId() == R.id.show_password) { 1737 int pos = mPasswordView.getSelectionEnd(); 1738 mPasswordView.setInputType(InputType.TYPE_CLASS_TEXT 1739 | (isChecked ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 1740 : InputType.TYPE_TEXT_VARIATION_PASSWORD)); 1741 if (pos >= 0) { 1742 ((EditText) mPasswordView).setSelection(pos); 1743 } 1744 } else if (view.getId() == R.id.wifi_advanced_togglebox) { 1745 // Hide the SoftKeyboard temporary to let user can see most of the expanded items. 1746 hideSoftKeyboard(mView.getWindowToken()); 1747 view.setVisibility(View.GONE); 1748 mView.findViewById(R.id.wifi_advanced_fields).setVisibility(View.VISIBLE); 1749 } 1750 } 1751 1752 @Override 1753 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 1754 if (parent == mSecuritySpinner) { 1755 // Convert menu position to actual Wi-Fi security type 1756 mWifiEntrySecurity = mSecurityInPosition[position]; 1757 showSecurityFields(/* refreshEapMethods */ true, /* refreshCertificates */ true); 1758 1759 if (WifiDppUtils.isSupportEnrolleeQrCodeScanner(mContext, mWifiEntrySecurity)) { 1760 mSsidScanButton.setVisibility(View.VISIBLE); 1761 } else { 1762 mSsidScanButton.setVisibility(View.GONE); 1763 } 1764 } else if (parent == mEapMethodSpinner) { 1765 final int selectedItemPosition = mEapMethodSpinner.getSelectedItemPosition(); 1766 if (mLastShownEapMethod != selectedItemPosition) { 1767 mLastShownEapMethod = selectedItemPosition; 1768 showSecurityFields(/* refreshEapMethods */false, /* refreshCertificates */ true); 1769 } 1770 } else if (parent == mEapCaCertSpinner) { 1771 String selectedItem = parent.getItemAtPosition(position).toString(); 1772 if (selectedItem.equals(mInstallCertsString)) { 1773 startActivityForInstallCerts(); 1774 } 1775 showSecurityFields(/* refreshEapMethods */ false, /* refreshCertificates */ false); 1776 } else if (parent == mPhase2Spinner 1777 && mEapMethodSpinner.getSelectedItemPosition() == WIFI_EAP_METHOD_PEAP) { 1778 showPeapFields(); 1779 } else if (parent == mProxySettingsSpinner) { 1780 showProxyFields(); 1781 } else if (parent == mHiddenSettingsSpinner) { 1782 mHiddenWarningView.setVisibility(position == NOT_HIDDEN_NETWORK 1783 ? View.GONE : View.VISIBLE); 1784 } else { 1785 showIpConfigFields(); 1786 } 1787 showWarningMessagesIfAppropriate(); 1788 enableSubmitIfAppropriate(); 1789 } 1790 1791 @Override 1792 public void onNothingSelected(AdapterView<?> parent) { 1793 // 1794 } 1795 1796 /** 1797 * Start the install page for user to install the existing certificate. 1798 */ 1799 private void startActivityForInstallCerts() { 1800 Intent intent = new Intent(ACTION_INSTALL_CERTS); 1801 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1802 intent.setComponent(new ComponentName(PACKAGE_INSTALL_CERTS, CLASS_INSTALL_CERTS)); 1803 intent.putExtra(KEY_INSTALL_CERTIFICATE, INSTALL_CERTIFICATE_VALUE); 1804 1805 mContext.startActivity(intent); 1806 } 1807 1808 /** 1809 * Make the characters of the password visible if show_password is checked. 1810 */ 1811 public void updatePassword() { 1812 TextView passwdView = (TextView) mView.findViewById(R.id.password); 1813 passwdView.setInputType(InputType.TYPE_CLASS_TEXT 1814 | (((CheckBox) mView.findViewById(R.id.show_password)).isChecked() 1815 ? InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 1816 : InputType.TYPE_TEXT_VARIATION_PASSWORD)); 1817 } 1818 1819 public WifiEntry getWifiEntry() { 1820 return mWifiEntry; 1821 } 1822 1823 private void configureSecuritySpinner() { 1824 mConfigUi.setTitle(R.string.wifi_add_network); 1825 1826 mSsidView = (TextView) mView.findViewById(R.id.ssid); 1827 mSsidView.addTextChangedListener(this); 1828 mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security)); 1829 mSecuritySpinner.setOnItemSelectedListener(this); 1830 1831 ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(mContext, 1832 android.R.layout.simple_spinner_item, android.R.id.text1); 1833 spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 1834 mSecuritySpinner.setAdapter(spinnerAdapter); 1835 int idx = 0; 1836 1837 // Populate the Wi-Fi security spinner with the various supported key management types 1838 spinnerAdapter.add(mContext.getString(com.android.settingslib.R.string.wifi_security_none)); 1839 mSecurityInPosition[idx++] = WifiEntry.SECURITY_NONE; 1840 if (mWifiManager.isEnhancedOpenSupported()) { 1841 spinnerAdapter.add(mContext.getString( 1842 com.android.settingslib.R.string.wifi_security_owe)); 1843 mSecurityInPosition[idx++] = WifiEntry.SECURITY_OWE; 1844 } 1845 spinnerAdapter.add(mContext.getString(com.android.settingslib.R.string.wifi_security_wep)); 1846 mSecurityInPosition[idx++] = WifiEntry.SECURITY_WEP; 1847 spinnerAdapter.add(mContext.getString( 1848 com.android.settingslib.R.string.wifi_security_wpa_wpa2)); 1849 mSecurityInPosition[idx++] = WifiEntry.SECURITY_PSK; 1850 if (mWifiManager.isWpa3SaeSupported()) { 1851 spinnerAdapter.add(mContext.getString( 1852 com.android.settingslib.R.string.wifi_security_sae)); 1853 mSecurityInPosition[idx++] = WifiEntry.SECURITY_SAE; 1854 spinnerAdapter.add(mContext.getString( 1855 com.android.settingslib.R.string.wifi_security_eap_wpa_wpa2)); 1856 mSecurityInPosition[idx++] = WifiEntry.SECURITY_EAP; 1857 spinnerAdapter.add(mContext.getString( 1858 com.android.settingslib.R.string.wifi_security_eap_wpa3)); 1859 mSecurityInPosition[idx++] = WifiEntry.SECURITY_EAP_WPA3_ENTERPRISE; 1860 } else { 1861 spinnerAdapter.add(mContext.getString( 1862 com.android.settingslib.R.string.wifi_security_eap)); 1863 mSecurityInPosition[idx++] = WifiEntry.SECURITY_EAP; 1864 } 1865 if (mWifiManager.isWpa3SuiteBSupported()) { 1866 spinnerAdapter.add(mContext.getString( 1867 com.android.settingslib.R.string.wifi_security_eap_suiteb)); 1868 mSecurityInPosition[idx++] = WifiEntry.SECURITY_EAP_SUITE_B; 1869 } 1870 1871 spinnerAdapter.notifyDataSetChanged(); 1872 1873 mView.findViewById(R.id.type).setVisibility(View.VISIBLE); 1874 1875 showIpConfigFields(); 1876 showProxyFields(); 1877 mView.findViewById(R.id.wifi_advanced_toggle).setVisibility(View.VISIBLE); 1878 // Hidden option can be changed only when the user adds a network manually. 1879 mView.findViewById(R.id.hidden_settings_field).setVisibility(View.VISIBLE); 1880 ((CheckBox) mView.findViewById(R.id.wifi_advanced_togglebox)) 1881 .setOnCheckedChangeListener(this); 1882 // Set correct accessibility strings. 1883 setAdvancedOptionAccessibilityString(); 1884 } 1885 1886 /** 1887 * For each target string in {@code targetStringArray} try to find if it appears in {@code 1888 * originalStringArray}, if found then use the corresponding string, which have the same index 1889 * of the target string in {@code replacementStringArray}, to replace it. And finally return the 1890 * whole new string array back to caller. 1891 */ 1892 @VisibleForTesting 1893 CharSequence[] findAndReplaceTargetStrings(CharSequence[] originalStringArray, 1894 CharSequence[] targetStringArray, CharSequence[] replacementStringArray) { 1895 // The length of the targetStringArray and replacementStringArray should be the same, each 1896 // item in the targetStringArray should have a 1:1 mapping to replacementStringArray, so 1897 // just return the original string if the lengths are different. 1898 if (targetStringArray.length != replacementStringArray.length) { 1899 return originalStringArray; 1900 } 1901 1902 final CharSequence[] returnEntries = new CharSequence[originalStringArray.length]; 1903 for (int i = 0; i < originalStringArray.length; i++) { 1904 returnEntries[i] = originalStringArray[i]; 1905 for (int j = 0; j < targetStringArray.length; j++) { 1906 if (TextUtils.equals(originalStringArray[i], targetStringArray[j])) { 1907 returnEntries[i] = replacementStringArray[j]; 1908 } 1909 } 1910 } 1911 return returnEntries; 1912 } 1913 1914 private ArrayAdapter<CharSequence> getSpinnerAdapter( 1915 int contentStringArrayResId) { 1916 return getSpinnerAdapter( 1917 mContext.getResources().getStringArray(contentStringArrayResId)); 1918 } 1919 1920 @VisibleForTesting 1921 ArrayAdapter<CharSequence> getSpinnerAdapter( 1922 String[] contentStringArray) { 1923 ArrayAdapter<CharSequence> spinnerAdapter = new ArrayAdapter<>(mContext, 1924 android.R.layout.simple_spinner_item, contentStringArray); 1925 spinnerAdapter.setDropDownViewResource( 1926 android.R.layout.simple_spinner_dropdown_item); 1927 return spinnerAdapter; 1928 } 1929 1930 /** 1931 * This function is to span the TTS strings to each EAP method items in the 1932 * spinner to have detail TTS content for the TTS engine usage. 1933 */ 1934 private ArrayAdapter<CharSequence> getSpinnerAdapterWithEapMethodsTts( 1935 int contentStringArrayResId) { 1936 final Resources res = mContext.getResources(); 1937 CharSequence[] sourceStrings = res.getStringArray( 1938 contentStringArrayResId); 1939 CharSequence[] targetStrings = res.getStringArray( 1940 R.array.wifi_eap_method_target_strings); 1941 CharSequence[] ttsStrings = res.getStringArray( 1942 R.array.wifi_eap_method_tts_strings); 1943 1944 // Replace the target strings with tts strings and save all in a new array. 1945 final CharSequence[] newTtsSourceStrings = findAndReplaceTargetStrings( 1946 sourceStrings, targetStrings, ttsStrings); 1947 1948 // Build new TtsSpan text arrays for TalkBack. 1949 final CharSequence[] accessibilityArray = createAccessibleEntries( 1950 sourceStrings, newTtsSourceStrings); 1951 1952 // Return a new ArrayAdapter with the new TalkBack array. 1953 ArrayAdapter<CharSequence> spinnerAdapter = new ArrayAdapter<>( 1954 mContext, android.R.layout.simple_spinner_item, accessibilityArray); 1955 spinnerAdapter.setDropDownViewResource( 1956 android.R.layout.simple_spinner_dropdown_item); 1957 return spinnerAdapter; 1958 } 1959 1960 private SpannableString[] createAccessibleEntries(CharSequence[] entries, 1961 CharSequence[] contentDescriptions) { 1962 final SpannableString[] accessibleEntries = new SpannableString[entries.length]; 1963 for (int i = 0; i < entries.length; i++) { 1964 accessibleEntries[i] = com.android.settings.Utils.createAccessibleSequence(entries[i], 1965 contentDescriptions[i].toString()); 1966 } 1967 return accessibleEntries; 1968 } 1969 1970 private void hideSoftKeyboard(IBinder windowToken) { 1971 final InputMethodManager inputMethodManager = mContext.getSystemService( 1972 InputMethodManager.class); 1973 inputMethodManager.hideSoftInputFromWindow(windowToken, 0 /* flags */); 1974 } 1975 1976 private void setAdvancedOptionAccessibilityString() { 1977 final CheckBox advancedToggleBox = mView.findViewById(R.id.wifi_advanced_togglebox); 1978 advancedToggleBox.setAccessibilityDelegate(new AccessibilityDelegate() { 1979 @Override 1980 public void onInitializeAccessibilityNodeInfo( 1981 View v, AccessibilityNodeInfo info) { 1982 super.onInitializeAccessibilityNodeInfo(v, info); 1983 // To let TalkBack don't pronounce checked/unchecked. 1984 info.setCheckable(false /* checkable */); 1985 // To let TalkBack don't pronounce CheckBox. 1986 info.setClassName(null /* className */); 1987 // Customize TalkBack's pronunciation which been appended to "Double-tap to". 1988 final AccessibilityAction customClick = new AccessibilityAction( 1989 AccessibilityNodeInfo.ACTION_CLICK, 1990 mContext.getString(R.string.wifi_advanced_toggle_description_collapsed)); 1991 info.addAction(customClick); 1992 } 1993 }); 1994 } 1995 1996 @VisibleForTesting 1997 Spinner getEapMinTlsVerSpinner(boolean isTlsV13Supported) { 1998 Spinner spinner = mView.findViewById(R.id.min_tls_ver); 1999 String[] stringArray = mContext.getResources().getStringArray(R.array.wifi_eap_tls_ver); 2000 if (!isTlsV13Supported) { 2001 Log.w(TAG, "Wi-Fi Enterprise TLS v1.3 is not supported on this device"); 2002 List<String> list = new ArrayList<>(Arrays.asList(stringArray)); 2003 list.remove(WifiEnterpriseConfig.TLS_V1_3); 2004 stringArray = list.toArray(new String[0]); 2005 } 2006 spinner.setAdapter(getSpinnerAdapter(stringArray)); 2007 return spinner; 2008 } 2009 } 2010