From d44941bd00921fb92e5e27576077a14b7cec38f6 Mon Sep 17 00:00:00 2001 From: Weng Su Date: Wed, 19 Feb 2025 12:15:13 +0800 Subject: [PATCH] Fixed accessibility issues in Wi-Fi SSID view - Keep the Save button enabled at all times - Show "Enter the SSID" to remind the user Bug: 386897596 Flag: EXEMPT bugfix Test: Manual testing atest SettingsUnitTests:AddNetworkFragmentTest atest WifiConfigController2Test Change-Id: I6cc6b197864511ee2c1c92affc67698b1761f11d --- res/layout/wifi_network_config.xml | 38 ++++++----- .../settings/wifi/AddNetworkFragment.java | 3 + .../settings/wifi/WifiConfigController2.java | 38 ++++++----- .../settings/wifi/utils/SsidInputGroup.kt | 34 ++++++++++ .../settings/wifi/utils/TextInputGroup.kt | 68 +++++++++++++++++++ .../wifi/WifiConfigController2Test.java | 27 +++++--- 6 files changed, 167 insertions(+), 41 deletions(-) create mode 100644 src/com/android/settings/wifi/utils/SsidInputGroup.kt create mode 100644 src/com/android/settings/wifi/utils/TextInputGroup.kt diff --git a/res/layout/wifi_network_config.xml b/res/layout/wifi_network_config.xml index dbd3e673913..d3680b19c30 100644 --- a/res/layout/wifi_network_config.xml +++ b/res/layout/wifi_network_config.xml @@ -16,11 +16,13 @@ + android:paddingBottom="8dip" + android:theme="@style/Theme.AppCompat.DayNight"> - - - + + + + 0)) { + if ((mWifiEntry == null || !mWifiEntry.isSaved()) && passwordInvalid) { + // If WifiEntry is not saved, apply passwordInvalid check + enabled = false; + } else if (mWifiEntry != null && mWifiEntry.isSaved() && passwordInvalid + && mPasswordView.length() > 0) { + // If WifiEntry is saved (modifying network) and password is changed, apply + // Invalid password check enabled = false; } else { enabled = ipAndProxyFieldsAreValid(); @@ -586,16 +588,21 @@ public class WifiConfigController2 implements TextWatcher, return enabled; } + boolean canFinish() { + if (!mSsidInputGroup.validate()) { + Log.w(TAG, "Can't finish because SSID is invalid!"); + return false; + } + return true; + } + void showWarningMessagesIfAppropriate() { mView.findViewById(R.id.no_user_cert_warning).setVisibility(View.GONE); mView.findViewById(R.id.no_domain_warning).setVisibility(View.GONE); mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.GONE); - if (mSsidView != null) { - final String ssid = mSsidView.getText().toString(); - if (WifiUtils.isSSIDTooLong(ssid)) { - mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE); - } + if (WifiUtils.isSSIDTooLong(mSsidInputGroup.getText())) { + mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE); } if (mEapCaCertSpinner != null && mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) { @@ -628,7 +635,7 @@ public class WifiConfigController2 implements TextWatcher, WifiConfiguration config; if (mWifiEntry == null) { config = new WifiConfiguration(); - config.SSID = "\"" + mSsidView.getText().toString() + "\""; + config.SSID = "\"" + mSsidInputGroup.getText() + "\""; // If the user adds a network manually, assume that it is hidden. config.hiddenSSID = mHiddenSettingsSpinner.getSelectedItemPosition() == HIDDEN_NETWORK; } else if (mWifiEntry.isSaved()) { @@ -1823,8 +1830,7 @@ public class WifiConfigController2 implements TextWatcher, private void configureSecuritySpinner() { mConfigUi.setTitle(R.string.wifi_add_network); - mSsidView = (TextView) mView.findViewById(R.id.ssid); - mSsidView.addTextChangedListener(this); + mSsidInputGroup.addTextChangedListener(this); mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security)); mSecuritySpinner.setOnItemSelectedListener(this); diff --git a/src/com/android/settings/wifi/utils/SsidInputGroup.kt b/src/com/android/settings/wifi/utils/SsidInputGroup.kt new file mode 100644 index 00000000000..5d8f8d418e3 --- /dev/null +++ b/src/com/android/settings/wifi/utils/SsidInputGroup.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi.utils + +import android.content.Context +import android.view.View +import com.android.settings.R + +/** TextInputGroup for Wi-Fi SSID. */ +class SsidInputGroup(private val context: Context, view: View, layoutId: Int, editTextId: Int) : + TextInputGroup(view, layoutId, editTextId) { + + fun validate(): Boolean { + if (getText().isEmpty()) { + setError(context.getString(R.string.wifi_ssid_hint)) + return false + } + return true + } +} diff --git a/src/com/android/settings/wifi/utils/TextInputGroup.kt b/src/com/android/settings/wifi/utils/TextInputGroup.kt new file mode 100644 index 00000000000..8006dad3bc4 --- /dev/null +++ b/src/com/android/settings/wifi/utils/TextInputGroup.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi.utils + +import android.text.Editable +import android.text.TextWatcher +import android.view.View +import android.widget.EditText +import com.google.android.material.textfield.TextInputLayout + +/** A widget that wraps the relationship work between a TextInputLayout and an EditText. */ +open class TextInputGroup( + private val view: View, + private val layoutId: Int, + private val editTextId: Int, +) { + + private val View.layout: TextInputLayout? + get() = findViewById(layoutId) + + private val View.editText: EditText? + get() = findViewById(editTextId) + + private val textWatcher = + object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + + override fun afterTextChanged(s: Editable?) { + view.layout?.isErrorEnabled = false + } + } + + init { + addTextChangedListener(textWatcher) + } + + fun addTextChangedListener(watcher: TextWatcher) { + view.editText?.addTextChangedListener(watcher) + } + + fun getText(): String { + return view.editText?.text?.toString() ?: "" + } + + fun setText(text: String) { + view.editText?.setText(text) + } + + fun setError(errorMessage: String?) { + view.layout?.apply { error = errorMessage } + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java index d985ee5b9d3..99b3acc0db2 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java @@ -193,15 +193,6 @@ public class WifiConfigController2Test { .isEqualTo(View.GONE); } - @Test - public void isSubmittable_noSSID_shouldReturnFalse() { - createController(mWifiEntry, WifiConfigUiBase2.MODE_CONNECT, false); - final TextView ssid = mView.findViewById(R.id.ssid); - assertThat(ssid).isNotNull(); - ssid.setText(""); - assertThat(mController.isSubmittable()).isFalse(); - } - @Test public void isSubmittable_longPsk_shouldReturnFalse() { createController(mWifiEntry, WifiConfigUiBase2.MODE_CONNECT, false); @@ -1048,6 +1039,24 @@ public class WifiConfigController2Test { verify(mController.mEapAnonymousView, never()).setText(any(String.class)); } + @Test + public void canFinish_ssidIsEmpty_returnFalse() { + createController(null, WifiConfigUiBase2.MODE_CONNECT, false); + TextView ssid = mView.findViewById(R.id.ssid); + ssid.setText(""); + + assertThat(mController.canFinish()).isFalse(); + } + + @Test + public void canFinish_ssidIsGood_returnTrue() { + createController(null, WifiConfigUiBase2.MODE_CONNECT, false); + TextView ssid = mView.findViewById(R.id.ssid); + ssid.setText(GOOD_SSID); + + assertThat(mController.canFinish()).isTrue(); + } + private void setUpModifyingSavedCertificateConfigController(String savedCaCertificate, String savedUserCertificate) { final WifiConfiguration mockWifiConfig = spy(new WifiConfiguration());