Commit 4a5f9167 authored by Friedrich Horschig's avatar Friedrich Horschig Committed by Commit Bot

[PwdCheckAndroid] Disable save button for empty passwords

With this CL, the save button is disabled while the new password is
empty. Additionally, it displays a brief error text to inform the user
about the required field.

Screenshots in the bug.

Bug: 1114720, 1092444
Change-Id: I0abb9582bdde093a69279a6887b74c0ddea68436
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2359995Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Commit-Queue: Friedrich [CET] <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799047}
parent 24721f06
...@@ -125,6 +125,7 @@ android_library("test_java") { ...@@ -125,6 +125,7 @@ android_library("test_java") {
"//third_party/android_deps:androidx_recyclerview_recyclerview_java", "//third_party/android_deps:androidx_recyclerview_recyclerview_java",
"//third_party/android_deps:androidx_test_runner_java", "//third_party/android_deps:androidx_test_runner_java",
"//third_party/android_deps:espresso_java", "//third_party/android_deps:espresso_java",
"//third_party/android_deps:material_design_java",
"//third_party/android_sdk:android_test_base_java", "//third_party/android_sdk:android_test_base_java",
"//third_party/hamcrest:hamcrest_java", "//third_party/hamcrest:hamcrest_java",
"//third_party/junit", "//third_party/junit",
...@@ -155,6 +156,9 @@ android_resources("java_resources") { ...@@ -155,6 +156,9 @@ android_resources("java_resources") {
"java/res/values-night/colors.xml", "java/res/values-night/colors.xml",
"java/res/values/colors.xml", "java/res/values/colors.xml",
] ]
deps = [ "//chrome/browser/ui/android/strings:ui_strings_grd" ] deps = [
"//chrome/browser/ui/android/strings:ui_strings_grd",
"//components/strings:components_strings_grd",
]
create_srcjar = false create_srcjar = false
} }
...@@ -21,6 +21,8 @@ import androidx.annotation.Nullable; ...@@ -21,6 +21,8 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceFragmentCompat;
import com.google.android.material.textfield.TextInputLayout;
import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.Supplier;
/** /**
...@@ -38,6 +40,8 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat { ...@@ -38,6 +40,8 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat {
private CompromisedCredential mCredential; private CompromisedCredential mCredential;
private EditText mPasswordText; private EditText mPasswordText;
private MenuItem mSaveButton;
private TextInputLayout mPasswordLabel;
/** /**
* Initializes the password check factory that allows to retrieve a {@link PasswordCheck} * Initializes the password check factory that allows to retrieve a {@link PasswordCheck}
...@@ -71,6 +75,7 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat { ...@@ -71,6 +75,7 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat {
EditText usernameText = (EditText) view.findViewById(R.id.username_edit); EditText usernameText = (EditText) view.findViewById(R.id.username_edit);
usernameText.setText(mCredential.getDisplayUsername()); usernameText.setText(mCredential.getDisplayUsername());
mPasswordLabel = (TextInputLayout) view.findViewById(R.id.password_label);
mPasswordText = (EditText) view.findViewById(R.id.password_edit); mPasswordText = (EditText) view.findViewById(R.id.password_edit);
mPasswordText.setText(mCredential.getPassword()); mPasswordText.setText(mCredential.getPassword());
mPasswordText.addTextChangedListener(new TextWatcher() { mPasswordText.addTextChangedListener(new TextWatcher() {
...@@ -83,17 +88,19 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat { ...@@ -83,17 +88,19 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat {
@Override @Override
public void afterTextChanged(Editable editable) { public void afterTextChanged(Editable editable) {
mNewPassword = mPasswordText.getText().toString(); mNewPassword = mPasswordText.getText().toString();
if (TextUtils.isEmpty(mNewPassword)) { checkSavingConditions(TextUtils.isEmpty(mNewPassword));
// TODO(crbug.com/1114720): setError on R.id.password_label.
}
} }
}); });
// Enforce that even the initial password (maybe from a saved instance) cannot be empty.
checkSavingConditions(TextUtils.isEmpty(mNewPassword));
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear(); // Remove help and feedback for this screen. menu.clear(); // Remove help and feedback for this screen.
inflater.inflate(R.menu.password_check_editor_action_bar_menu, menu); inflater.inflate(R.menu.password_check_editor_action_bar_menu, menu);
mSaveButton = menu.findItem(R.id.action_save_edited_password);
checkSavingConditions(mNewPassword.isEmpty()); // Enable the newly created save button.
// TODO(crbug.com/1092444): Make the back arrow an 'X'. // TODO(crbug.com/1092444): Make the back arrow an 'X'.
} }
...@@ -108,7 +115,7 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat { ...@@ -108,7 +115,7 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat {
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId(); int id = item.getItemId();
if (id == R.id.action_save_edited_password) { if (id == R.id.action_save_edited_password) {
if (!TextUtils.isEmpty(mNewPassword)) saveChanges(); saveChanges();
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
...@@ -144,4 +151,11 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat { ...@@ -144,4 +151,11 @@ public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat {
} }
return mCredential.getPassword(); return mCredential.getPassword();
} }
private void checkSavingConditions(boolean emptyPassword) {
if (mSaveButton != null) mSaveButton.setEnabled(!emptyPassword);
mPasswordLabel.setError(emptyPassword ? getContext().getString(
R.string.pref_edit_dialog_field_required_validation_message)
: "");
}
} }
...@@ -6,11 +6,14 @@ package org.chromium.chrome.browser.password_check; ...@@ -6,11 +6,14 @@ package org.chromium.chrome.browser.password_check;
import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.assertTrue;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
...@@ -25,8 +28,11 @@ import android.os.Bundle; ...@@ -25,8 +28,11 @@ import android.os.Bundle;
import android.text.InputType; import android.text.InputType;
import android.widget.EditText; import android.widget.EditText;
import androidx.annotation.StringRes;
import androidx.test.filters.MediumTest; import androidx.test.filters.MediumTest;
import com.google.android.material.textfield.TextInputLayout;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
...@@ -130,10 +136,29 @@ public class PasswordCheckEditViewTest { ...@@ -130,10 +136,29 @@ public class PasswordCheckEditViewTest {
verify(mPasswordCheck).updateCredential(eq(ANA), eq(newPassword)); verify(mPasswordCheck).updateCredential(eq(ANA), eq(newPassword));
} }
@Test
@MediumTest
public void testEmptyPasswordDisablesSaveButton() {
// Delete the password.
EditText password = mPasswordCheckEditView.getView().findViewById(R.id.password_edit);
runOnUiThreadBlocking(() -> password.setText(""));
onView(withId(R.id.action_save_edited_password)).check(matches(not(isEnabled())));
TextInputLayout passwordLabel =
mPasswordCheckEditView.getView().findViewById(R.id.password_label);
assertNotNull(passwordLabel.getError());
assertThat(passwordLabel.getError().toString(),
equalTo(getString(R.string.pref_edit_dialog_field_required_validation_message)));
}
private void setUpUiLaunchedFromSettings() { private void setUpUiLaunchedFromSettings() {
Bundle fragmentArgs = new Bundle(); Bundle fragmentArgs = new Bundle();
fragmentArgs.putParcelable(EXTRA_COMPROMISED_CREDENTIAL, ANA); fragmentArgs.putParcelable(EXTRA_COMPROMISED_CREDENTIAL, ANA);
mTestRule.startSettingsActivity(fragmentArgs); mTestRule.startSettingsActivity(fragmentArgs);
mPasswordCheckEditView = mTestRule.getFragment(); mPasswordCheckEditView = mTestRule.getFragment();
} }
private String getString(@StringRes int stringId) {
return mPasswordCheckEditView.getContext().getString(stringId);
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment