Commit 065cd806 authored by Vaclav Brozek's avatar Vaclav Brozek Committed by Commit Bot

[Android settings] Disable password export if there are no saved passwords

If the settings do not show any saved passwords, the export button in
the menu should still be present, but disabled.

Note that the existence of "blacklisted" entries, i.e., entries where
the user asked Chrome to never save a password, does not influence
the state of the menu item, because those entries are not exported.

Mocks: go chrome-pwd-export-mocks-android (currently slide 10,
Google-internal only)

General design:
https://docs.google.com/a/chromium.org/document/d/1miKr2x0PTNIKgt3RQeur51ICQ66uszlYAmFXJONbG_0/edit?usp=sharing

Bug: 788701
Change-Id: I1f5ad12eef9ef6ec1c9b0529c5b1ef16941c5298
Reviewed-on: https://chromium-review.googlesource.com/811186
Commit-Queue: Vaclav Brozek <vabr@chromium.org>
Reviewed-by: default avatarTheresa <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#522400}
parent 4d144970
......@@ -104,6 +104,13 @@ public class SavePasswordsPreferences
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.save_password_preferences_action_bar_menu, menu);
menu.findItem(R.id.export_passwords).setEnabled(false);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.export_passwords).setEnabled(!mNoPasswords);
super.onPrepareOptionsMenu(menu);
}
@Override
......
......@@ -5,14 +5,18 @@
package org.chromium.chrome.browser.preferences.password;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.Espresso;
......@@ -106,6 +110,30 @@ public class SavePasswordsPreferencesTest {
}
}
// Used to provide fake lists of stored passwords. Tests which need it can use setPasswordSource
// to instantiate it.
FakePasswordManagerHandler mHandler;
/**
* Helper to set up a fake source of displayed passwords.
* @param entry An entry to be added to saved passwords. Can be null.
*/
private void setPasswordSource(SavedPasswordEntry entry) throws Exception {
if (mHandler == null) {
mHandler = new FakePasswordManagerHandler(PasswordManagerHandlerProvider.getInstance());
}
ArrayList<SavedPasswordEntry> entries = new ArrayList<SavedPasswordEntry>();
if (entry != null) entries.add(entry);
mHandler.setSavedPasswords(entries);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
PasswordManagerHandlerProvider.getInstance().setPasswordManagerHandlerForTest(
mHandler);
}
});
}
/**
* Ensure that resetting of empty passwords list works.
*/
......@@ -243,6 +271,82 @@ public class SavePasswordsPreferencesTest {
});
}
/**
* Check that if there are no saved passwords, the export menu item is disabled.
*/
@Test
@SmallTest
@Feature({"Preferences"})
@EnableFeatures("password-export")
public void testExportMenuDisabled() throws Exception {
// Ensure there are no saved passwords reported to settings.
setPasswordSource(null);
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
Espresso.openActionBarOverflowOrOptionsMenu(
InstrumentationRegistry.getInstrumentation().getTargetContext());
// The text matches a text view, but the disabled entity is some wrapper two levels up in
// the view hierarchy, hence the two withParent matchers.
Espresso.onView(allOf(withText(R.string.save_password_preferences_export_action_title),
withParent(withParent(not(isEnabled())))))
.check(matches(isDisplayed()));
}
/**
* Check that if there are saved passwords, the export menu item is enabled.
*/
@Test
@SmallTest
@Feature({"Preferences"})
@EnableFeatures("password-export")
public void testExportMenuEnabled() throws Exception {
setPasswordSource(new SavedPasswordEntry("https://example.com", "test user", "password"));
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
Espresso.openActionBarOverflowOrOptionsMenu(
InstrumentationRegistry.getInstrumentation().getTargetContext());
// The text matches a text view, but the potentially disabled entity is some wrapper two
// levels up in the view hierarchy, hence the two withParent matchers.
Espresso.onView(allOf(withText(R.string.save_password_preferences_export_action_title),
withParent(withParent(isEnabled()))))
.check(matches(isDisplayed()));
}
/**
* Check that if "password-export" feature is not explicitly enabled, there is no menu item to
* export passwords.
* TODO(crbug.com/788701): Add the @DisableFeatures annotation once exporting gets enabled by
* default, and remove completely once the feature is gone.
*/
@Test
@SmallTest
@Feature({"Preferences"})
public void testExportMenuMissing() throws Exception {
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
final Preferences preferences =
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
// Ideally this would need the same matcher (Espresso.OVERFLOW_BUTTON_MATCHER) as used
// inside Espresso.openActionBarOverflowOrOptionsMenu(), but that is private to Espresso.
// Matching the overflow menu with the class name "OverflowMenuButton" won't work on
// obfuscated release builds, so matching the description remains. The
// OVERFLOW_BUTTON_MATCHER specifies the string directly, not via string resource, so this
// is also done below.
Espresso.onView(withContentDescription("More options")).check(doesNotExist());
}
/**
* Check that the export menu item is included and hidden behind the overflow menu. Check that
* the menu displays the warning before letting the user export passwords.
......@@ -252,6 +356,8 @@ public class SavePasswordsPreferencesTest {
@Feature({"Preferences"})
@EnableFeatures("password-export")
public void testExportMenuItem() throws Exception {
setPasswordSource(new SavedPasswordEntry("https://example.com", "test user", "password"));
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
ReauthenticationManager.OverrideState.AVAILABLE);
......@@ -280,6 +386,8 @@ public class SavePasswordsPreferencesTest {
@Feature({"Preferences"})
@EnableFeatures("password-export")
public void testExportMenuItemNoLock() throws Exception {
setPasswordSource(new SavedPasswordEntry("https://example.com", "test user", "password"));
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
ReauthenticationManager.OverrideState.UNAVAILABLE);
......@@ -304,18 +412,7 @@ public class SavePasswordsPreferencesTest {
@SmallTest
@Feature({"Preferences"})
public void testViewPasswordNoLock() throws Exception {
FakePasswordManagerHandler handler =
new FakePasswordManagerHandler(PasswordManagerHandlerProvider.getInstance());
ArrayList<SavedPasswordEntry> entries = new ArrayList<SavedPasswordEntry>();
entries.add(new SavedPasswordEntry("https://example.com", "test user", "password"));
handler.setSavedPasswords(entries);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
PasswordManagerHandlerProvider.getInstance().setPasswordManagerHandlerForTest(
handler);
}
});
setPasswordSource(new SavedPasswordEntry("https://example.com", "test user", "password"));
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
......@@ -332,8 +429,6 @@ public class SavePasswordsPreferencesTest {
Espresso.onView(withText(R.string.password_entry_editor_set_lock_screen))
.inRoot(withDecorView(isEnabled()))
.check(matches(isDisplayed()));
handler.setSavedPasswords(null);
}
/**
......@@ -343,18 +438,8 @@ public class SavePasswordsPreferencesTest {
@SmallTest
@Feature({"Preferences"})
public void testViewPassword() throws Exception {
FakePasswordManagerHandler handler =
new FakePasswordManagerHandler(PasswordManagerHandlerProvider.getInstance());
ArrayList<SavedPasswordEntry> entries = new ArrayList<SavedPasswordEntry>();
entries.add(new SavedPasswordEntry("https://example.com", "test user", "test password"));
handler.setSavedPasswords(entries);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
PasswordManagerHandlerProvider.getInstance().setPasswordManagerHandlerForTest(
handler);
}
});
setPasswordSource(
new SavedPasswordEntry("https://example.com", "test user", "test password"));
ReauthenticationManager.setApiOverride(ReauthenticationManager.OverrideState.AVAILABLE);
ReauthenticationManager.setScreenLockSetUpOverride(
......@@ -372,7 +457,5 @@ public class SavePasswordsPreferencesTest {
Espresso.onView(withContentDescription(R.string.password_entry_editor_view_stored_password))
.perform(click());
Espresso.onView(withText("test password")).check(matches(isDisplayed()));
handler.setSavedPasswords(null);
}
}
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