• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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