Commit 5709669f authored by Friedrich Horschig's avatar Friedrich Horschig Committed by Commit Bot

Reland "Clear password search on X and close it with back button"

This CL fixes what caused the revert in commit bed2f341.

(No TBRs because the original is quite old)

Original change's description:
> Revert "Clear password search on X and close it with back button"
> 
> This reverts commit dcb5b1f4.
> 
> Reason for revert:
> Regressed on some devices. Failure reason is not obvious enough for confident immediate fix.
> 
> Bug: 834676
> 
> Original change's description:
> > Clear password search on X and close it with back button
> > 
> > Right now, clicking the X button in the search will close it.
> > To start a new search, you have to open a new search.
> > That experience isn't very discoverable, so UX developed an improved
> > workflow - details in the bug.
> > 
> > The new flow needs these changes:
> > - the X button _only_ clears the query text field now
> > - the X button is _only_ available when a query was entered
> > - closing the search happens only via the "navigate up" button
> >   in the action bar.
> > - the three-dots overflow menu is hidden while a search is active
> >   (already the case on small screens - now large screens do the same)
> > 
> > Tests cover all of these cases.
> > 
> > Bug: 821755
> > Change-Id: Ieb2e16c096750d66874aa4c4999759629332491b
> > Reviewed-on: https://chromium-review.googlesource.com/966070
> > Reviewed-by: Theresa <twellington@chromium.org>
> > Commit-Queue: Friedrich Horschig <fhorschig@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#550955}
> 
> TBR=twellington@chromium.org,fhorschig@chromium.org
> 
> # Not skipping CQ checks because original CL landed > 1 day ago.
> 
> Bug: 821755
> Change-Id: I9035e5aed91dca19bcff94e195cf060ef61f2b29
> Reviewed-on: https://chromium-review.googlesource.com/1019150
> Reviewed-by: Friedrich Horschig <fhorschig@chromium.org>
> Commit-Queue: Friedrich Horschig <fhorschig@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#552101}

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: 834676, 821755, 864607
Change-Id: I7afbcd0022a84a10c13b89f7538f63105ab04e52
Reviewed-on: https://chromium-review.googlesource.com/1143204Reviewed-by: default avatarTheresa <twellington@chromium.org>
Commit-Queue: Friedrich Horschig <fhorschig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577136}
parent 97d5a240
......@@ -4,15 +4,19 @@
package org.chromium.chrome.browser.preferences;
import android.app.Activity;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.StrictMode;
import android.preference.PreferenceFragment;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.annotation.XmlRes;
import android.support.v7.content.res.AppCompatResources;
import android.support.v7.widget.ActionMenuView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import org.chromium.base.ApiCompatibilityUtils;
......@@ -70,4 +74,29 @@ public class PreferenceUtils {
PorterDuff.Mode.SRC_IN);
return icon;
}
/**
* A helper that is used to set the visibility of the overflow menu view in a given activity.
*
* @param activity The Activity containing the action bar with the menu.
* @param visibility The new visibility of the overflow menu view.
* @return True if the visibility could be set, false otherwise (e.g. because no menu exists).
*/
public static boolean setOverflowMenuVisibility(@Nullable Activity activity, int visibility) {
if (activity == null) return false;
ViewGroup actionBar = activity.findViewById(org.chromium.chrome.R.id.action_bar);
int i = actionBar.getChildCount();
ActionMenuView menuView = null;
while (i-- > 0) {
if (actionBar.getChildAt(i) instanceof ActionMenuView) {
menuView = (ActionMenuView) actionBar.getChildAt(i);
break;
}
}
if (menuView == null) return false;
View overflowButton = menuView.getChildAt(menuView.getChildCount() - 1);
if (overflowButton == null) return false;
overflowButton.setVisibility(visibility);
return true;
}
}
......@@ -238,6 +238,8 @@ public class Preferences extends AppCompatActivity implements OnPreferenceStartF
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Fragment activeFragment = getFragmentManager().findFragmentById(android.R.id.content);
if (activeFragment != null && activeFragment.onOptionsItemSelected(item)) return true;
if (item.getItemId() == android.R.id.home) {
finish();
return true;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.preferences;
import android.support.annotation.NonNull;
import android.support.v7.widget.SearchView;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.ImageView;
import javax.annotation.Nullable;
/**
* A helper class for applying the default search behavior to search items in Chromium settings.
*/
public class SearchUtils {
/**
* This interface allows to react to changed search queries when initialized with
* {@link SearchUtils#initializeSearchView(MenuItem, String, QueryChangeListener)}.
*/
public interface QueryChangeListener {
/**
* Called whenever the search query changes. This usually is immediately after a user types
* and doesn't wait for submission of the whole query.
* @param query Current query as entered by the user. Can be a partial query or empty.
*/
void onQueryTextChange(String query);
}
/**
* Initializes an Android default search item by setting listeners and default states of the
* search icon, box and close icon.
* @param searchItem The existing item that can trigger the search action view.
* @param initialQuery The query that the search field should be opened with.
* @param changeListener The listener to be notified when the user changes the query.
*/
public static void initializeSearchView(@NonNull MenuItem searchItem,
@Nullable String initialQuery, @NonNull QueryChangeListener changeListener) {
SearchView searchView = getSearchView(searchItem);
searchView.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN);
// Restore the search view if a query was recovered.
if (initialQuery != null) {
searchItem.expandActionView();
searchView.setIconified(false);
searchView.setQuery(initialQuery, false);
}
// Clicking the menu item hides the clear button and triggers search for an empty query.
searchItem.setOnMenuItemClickListener((MenuItem m) -> {
updateSearchClearButtonVisibility(searchItem, "");
changeListener.onQueryTextChange("");
return false; // Continue with the default action.
});
// Make the close button a clear button.
searchView.findViewById(org.chromium.chrome.R.id.search_close_btn)
.setOnClickListener((View v) -> {
searchView.setQuery("", false);
updateSearchClearButtonVisibility(searchItem, "");
changeListener.onQueryTextChange("");
});
// Ensure that a changed search view triggers the search - independent from use code path.
searchView.setOnSearchClickListener(view -> {
updateSearchClearButtonVisibility(searchItem, "");
changeListener.onQueryTextChange("");
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true; // Consume event.
}
@Override
public boolean onQueryTextChange(String query) {
// TODO(fhorschig) Exit early if a tracked query indicates no changes.
updateSearchClearButtonVisibility(searchItem, query);
changeListener.onQueryTextChange(query);
return true; // Consume event.
}
});
}
/**
* Handles an item in {@link android.support.v4.app.Fragment#onOptionsItemSelected(MenuItem)} if
* it is a search item and returns true. If it is not applicable, it returns false.
* @param selectedItem The user-selected menu item.
* @param searchItem The menu item known to contain the search view.
* @param query The current search query.
* @return Returns true if the item is a search item and could be handled. False otherwise.
*/
public static boolean handleSearchNavigation(
@NonNull MenuItem selectedItem, @NonNull MenuItem searchItem, @Nullable String query) {
if (selectedItem.getItemId() != android.R.id.home || query == null) return false;
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setQuery(null, false);
searchView.setIconified(true);
searchItem.collapseActionView();
return true;
}
/**
* Shorthand to easily access a search item's action view.
* @param searchItem The menu item containing search item.
* @return The search view associated with the menu item.
*/
public static SearchView getSearchView(MenuItem searchItem) {
return (SearchView) searchItem.getActionView();
}
private static void updateSearchClearButtonVisibility(MenuItem searchItem, String query) {
ImageView clearButton = findSearchClearButton(getSearchView(searchItem));
clearButton.setVisibility(query == null || query.equals("") ? View.GONE : View.VISIBLE);
}
private static ImageView findSearchClearButton(SearchView searchView) {
return searchView.findViewById(org.chromium.chrome.R.id.search_close_btn);
}
}
......@@ -7,9 +7,6 @@ package org.chromium.chrome.browser.preferences.password;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.preference.Preference;
......@@ -18,14 +15,13 @@ import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.VisibleForTesting;
......@@ -36,8 +32,10 @@ import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
import org.chromium.chrome.browser.preferences.ChromeBasePreference;
import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.preferences.PreferenceUtils;
import org.chromium.chrome.browser.preferences.Preferences;
import org.chromium.chrome.browser.preferences.PreferencesLauncher;
import org.chromium.chrome.browser.preferences.SearchUtils;
import org.chromium.chrome.browser.preferences.TextMessagePreference;
import org.chromium.ui.text.SpanApplier;
......@@ -84,6 +82,7 @@ public class SavePasswordsPreferences
private boolean mNoPasswordExceptions;
private MenuItem mHelpItem;
private MenuItem mSearchItem;
private String mSearchQuery;
private Preference mLinkPref;
......@@ -91,7 +90,7 @@ public class SavePasswordsPreferences
private ChromeBaseCheckBoxPreference mAutoSignInSwitch;
private TextMessagePreference mEmptyView;
private boolean mSearchRecorded;
private Menu mMenuForTesting;
private Menu mMenu;
/**
* For controlling the UX flow of exporting passwords.
......@@ -138,54 +137,19 @@ public class SavePasswordsPreferences
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
mMenuForTesting = menu;
mMenu = menu;
inflater.inflate(R.menu.save_password_preferences_action_bar_menu, menu);
menu.findItem(R.id.export_passwords).setVisible(ExportFlow.providesPasswordExport());
menu.findItem(R.id.export_passwords).setEnabled(false);
MenuItem searchItem = menu.findItem(R.id.menu_id_search);
searchItem.setVisible(providesPasswordSearch());
mSearchItem = menu.findItem(R.id.menu_id_search);
mSearchItem.setVisible(providesPasswordSearch());
if (providesPasswordSearch()) {
mHelpItem = menu.findItem(R.id.menu_id_general_help);
setUpSearchAction(searchItem);
}
}
/**
* Prepares the searchItem's icon and searchView. Sets up listeners to clicks and interactions
* with the searchItem or its searchView.
* @param searchItem the item containing the SearchView. Must not be null.
*/
private void setUpSearchAction(MenuItem searchItem) {
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN);
searchItem.setIcon(convertToPlainWhite(searchItem.getIcon()));
if (mSearchQuery != null) { // If a query was recovered, restore the search view.
searchItem.expandActionView();
searchView.setIconified(false);
searchView.setQuery(mSearchQuery, false);
}
searchItem.setOnMenuItemClickListener((MenuItem m) -> {
filterPasswords("");
return false; // Continue with the default action.
});
searchView.findViewById(R.id.search_close_btn).setOnClickListener((View v) -> {
searchView.setQuery(null, false);
searchView.setIconified(true);
filterPasswords(null); // Reset filter to bring back all preferences.
});
searchView.setOnSearchClickListener(view -> filterPasswords(""));
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true; // Continue with default action - nothing.
}
@Override
public boolean onQueryTextChange(String query) {
SearchUtils.initializeSearchView(mSearchItem, mSearchQuery, (query) -> {
maybeRecordTriggeredPasswordSearch(true);
return filterPasswords(query);
}
});
filterPasswords(query);
});
}
}
/**
......@@ -214,16 +178,23 @@ public class SavePasswordsPreferences
mExportFlow.startExporting();
return true;
}
if (SearchUtils.handleSearchNavigation(item, mSearchItem, mSearchQuery)) {
filterPasswords(null);
return true;
}
return super.onOptionsItemSelected(item);
}
private boolean filterPasswords(String query) {
private void filterPasswords(String query) {
mSearchQuery = query;
// Hide the help option. It's not useful during search but might be clicked by accident.
mHelpItem.setShowAsAction(mSearchQuery != null ? MenuItem.SHOW_AS_ACTION_NEVER
: MenuItem.SHOW_AS_ACTION_IF_ROOM);
if (mSearchQuery == null) {
mHelpItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
PreferenceUtils.setOverflowMenuVisibility(getActivity(), View.VISIBLE);
} else {
mHelpItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
PreferenceUtils.setOverflowMenuVisibility(getActivity(), View.GONE);
}
rebuildPasswordLists();
return false; // Query has been handled. Don't trigger default action of SearchView.
}
/**
......@@ -430,19 +401,6 @@ public class SavePasswordsPreferences
return true;
}
/**
* Convert a given icon to a plain white version by applying the MATRIX_TRANSFORM_TO_WHITE color
* filter. The resulting drawable will be brighter than a usual grayscale conversion.
*
* For grayscale conversion, use the function ColorMatrix#setSaturation(0) instead.
* @param icon The drawable to be converted.
* @return Returns the bright white version of the passed drawable.
*/
private static Drawable convertToPlainWhite(Drawable icon) {
icon.mutate().setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
return icon;
}
private void createSavePasswordsSwitch() {
if (mSearchQuery != null) {
return; // Don't create this option when the preferences are filtered for passwords.
......@@ -530,6 +488,11 @@ public class SavePasswordsPreferences
@VisibleForTesting
Menu getMenuForTesting() {
return mMenuForTesting;
return mMenu;
}
@VisibleForTesting
Toolbar getToolbarForTesting() {
return getActivity().findViewById(R.id.action_bar);
}
}
......@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.preferences.website;
import static org.chromium.chrome.browser.preferences.SearchUtils.handleSearchNavigation;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Build;
......@@ -15,9 +17,7 @@ import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.SearchView;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.format.Formatter;
......@@ -29,7 +29,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
......@@ -51,6 +50,7 @@ import org.chromium.chrome.browser.preferences.ManagedPreferencesUtils;
import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.preferences.PreferenceUtils;
import org.chromium.chrome.browser.preferences.ProtectedContentResetCredentialConfirmDialogFragment;
import org.chromium.chrome.browser.preferences.SearchUtils;
import org.chromium.chrome.browser.preferences.website.Website.StoredDataClearedCallback;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.ui.widget.Toast;
......@@ -80,14 +80,14 @@ public class SingleCategoryPreferences extends PreferenceFragment
// The view to show when the list is empty.
private TextView mEmptyView;
// The view for searching the list of items.
private SearchView mSearchView;
// The item for searching the list of items.
private MenuItem mSearchItem;
// The clear button displayed in the Storage view.
private Button mClearButton;
// The Site Settings Category we are showing.
private SiteSettingsCategory mCategory;
// If not blank, represents a substring to use to search for site names.
private String mSearch = "";
private String mSearch;
// Whether to group by allowed/blocked list.
private boolean mGroupByAllowBlock;
// Whether the Blocked list should be shown expanded.
......@@ -327,26 +327,11 @@ public class SingleCategoryPreferences extends PreferenceFragment
menu.clear();
inflater.inflate(R.menu.website_preferences_menu, menu);
MenuItem searchItem = menu.findItem(R.id.search);
mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
mSearchView.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN);
SearchView.OnQueryTextListener queryTextListener =
new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String query) {
if (query.equals(mSearch)) return true;
mSearch = query;
getInfoForOrigins();
return true;
}
};
mSearchView.setOnQueryTextListener(queryTextListener);
mSearchItem = menu.findItem(R.id.search);
SearchUtils.initializeSearchView(mSearchItem, mSearch, (query) -> {
mSearch = query;
getInfoForOrigins();
});
if (mCategory.showSites(SiteSettingsCategory.Type.PROTECTED_MEDIA)) {
// Add a menu item to reset protected media identifier device credentials.
......@@ -380,6 +365,11 @@ public class SingleCategoryPreferences extends PreferenceFragment
getActivity(), getString(helpContextResId), Profile.getLastUsedProfile(), null);
return true;
}
if (handleSearchNavigation(item, mSearchItem, mSearch)) {
mSearch = null;
getInfoForOrigins();
return true;
}
return false;
}
......@@ -392,11 +382,11 @@ public class SingleCategoryPreferences extends PreferenceFragment
return false;
}
if (!mSearch.isEmpty()) {
if (mSearch != null) {
// Clear out any lingering searches, so that the full list is shown
// when coming back to this page.
mSearch = "";
mSearchView.setQuery("", false);
mSearch = null;
SearchUtils.getSearchView(mSearchItem).setQuery("", false);
}
if (preference instanceof WebsitePreference) {
......@@ -605,7 +595,7 @@ public class SingleCategoryPreferences extends PreferenceFragment
// Find origins matching the current search.
for (Website site : sites) {
if (mSearch.isEmpty() || site.getTitle().contains(mSearch)) {
if (mSearch == null || mSearch.isEmpty() || site.getTitle().contains(mSearch)) {
websites.add(new WebsitePreference(getActivity(), site, mCategory));
}
}
......
......@@ -1089,6 +1089,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/preferences/ProtectedContentResetCredentialConfirmDialogFragment.java",
"java/src/org/chromium/chrome/browser/preferences/SearchEngineAdapter.java",
"java/src/org/chromium/chrome/browser/preferences/SearchEnginePreference.java",
"java/src/org/chromium/chrome/browser/preferences/SearchUtils.java",
"java/src/org/chromium/chrome/browser/preferences/SeekBarLinkedCheckBoxPreference.java",
"java/src/org/chromium/chrome/browser/preferences/SeekBarPreference.java",
"java/src/org/chromium/chrome/browser/preferences/SigninExpandablePreferenceGroup.java",
......
......@@ -39,6 +39,9 @@ import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.hamcrest.Matchers.startsWith;
import static org.chromium.chrome.test.util.ViewUtils.VIEW_GONE;
import static org.chromium.chrome.test.util.ViewUtils.VIEW_INVISIBLE;
import static org.chromium.chrome.test.util.ViewUtils.VIEW_NULL;
import static org.chromium.chrome.test.util.ViewUtils.waitForView;
import android.app.Activity;
......@@ -1596,7 +1599,8 @@ public class SavePasswordsPreferencesTest {
// Trigger the search, close it and wait for UI to be restored.
Espresso.onView(withSearchMenuIdOrText()).perform(click());
Espresso.onView(withId(R.id.search_close_btn)).perform(click());
Espresso.onView(withContentDescription(R.string.abc_action_bar_up_description))
.perform(click());
Espresso.onView(isRoot()).check(
(root, e)
-> waitForView(
......@@ -1737,7 +1741,9 @@ public class SavePasswordsPreferencesTest {
Espresso.onView(withText(R.string.section_saved_passwords_exceptions))
.check(doesNotExist());
Espresso.onView(withId(R.id.search_close_btn)).perform(click()); // Close search view.
Espresso.onView(withContentDescription(R.string.abc_action_bar_up_description))
.perform(click());
InstrumentationRegistry.getInstrumentation().waitForIdleSync(); // Close search view.
Espresso.onView(withText(R.string.section_saved_passwords_exceptions)).perform(scrollTo());
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
......@@ -1754,17 +1760,43 @@ public class SavePasswordsPreferencesTest {
@EnableFeatures(ChromeFeatureList.PASSWORD_SEARCH)
public void testSearchIconClickedHidesGeneralPrefs() throws Exception {
setPasswordSource(ZEUS_ON_EARTH);
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
final SavePasswordsPreferences prefs =
(SavePasswordsPreferences) PreferencesTest
.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName())
.getFragmentForTest();
final AtomicReference<Boolean> menuInitiallyVisible = new AtomicReference<>();
ThreadUtils.runOnUiThreadBlocking(
()
-> menuInitiallyVisible.set(
prefs.getToolbarForTesting().isOverflowMenuShowing()));
Espresso.onView(withText(R.string.passwords_auto_signin_title))
.check(matches(isDisplayed()));
Espresso.onView(withText(startsWith("View and manage"))).check(matches(isDisplayed()));
if (menuInitiallyVisible.get()) { // Check overflow menu only on large screens that have it.
Espresso.onView(withContentDescription(R.string.abc_action_menu_overflow_description))
.check(matches(isDisplayed()));
}
Espresso.onView(withSearchMenuIdOrText()).perform(click());
Espresso.onView(withText(R.string.passwords_auto_signin_title)).check(doesNotExist());
Espresso.onView(withText(startsWith("View and manage"))).check(doesNotExist());
Espresso.onView(isRoot()).check(
(root, e)
-> waitForView((ViewGroup) root,
withContentDescription(
R.string.abc_action_menu_overflow_description),
VIEW_INVISIBLE | VIEW_GONE | VIEW_NULL));
Espresso.onView(withContentDescription(R.string.abc_action_bar_up_description))
.perform(click());
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
if (menuInitiallyVisible.get()) { // If the overflow menu was there, it should be restored.
Espresso.onView(withContentDescription(R.string.abc_action_menu_overflow_description))
.check(matches(isDisplayed()));
}
}
/**
......@@ -1786,13 +1818,47 @@ public class SavePasswordsPreferencesTest {
Espresso.onView(withText(R.string.passwords_auto_signin_title)).check(doesNotExist());
Espresso.onView(withText(startsWith("View and manage"))).check(doesNotExist());
Espresso.pressBack(); // Close keyboard.
Espresso.onView(withContentDescription(R.string.abc_action_bar_up_description))
.perform(click());
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
Espresso.onView(withId(R.id.search_close_btn)).perform(click());
Espresso.onView(withText(R.string.passwords_auto_signin_title))
.check(matches(isDisplayed()));
Espresso.onView(withText(startsWith("View and manage"))).check(matches(isDisplayed()));
Espresso.onView(withId(R.id.menu_id_search)).check(matches(isDisplayed()));
}
/**
* Check that clearing the search also hides the clear button.
*/
@Test
@SmallTest
@Feature({"Preferences"})
@EnableFeatures(ChromeFeatureList.PASSWORD_SEARCH)
public void testSearchViewCloseIconExistsOnlyToClearQueries() throws Exception {
setPasswordSourceWithMultipleEntries(GREEK_GODS);
PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
SavePasswordsPreferences.class.getName());
// Trigger search which shouldn't have the button yet.
Espresso.onView(withSearchMenuIdOrText()).perform(click());
Espresso.onView(isRoot()).check(
(root, e)
-> waitForView((ViewGroup) root, withId(R.id.search_close_btn),
VIEW_INVISIBLE | VIEW_GONE | VIEW_NULL));
// Type something and see the button appear.
Espresso.onView(withId(R.id.search_src_text))
// Trigger search which shouldn't have the button yet.
.perform(click(), typeText("Zeu"), closeSoftKeyboard());
Espresso.onView(withId(R.id.search_close_btn)).check(matches(isDisplayed()));
// Clear the search which should hide the button again.
Espresso.onView(withId(R.id.search_close_btn)).perform(click()); // Clear search.
Espresso.onView(isRoot()).check(
(root, e)
-> waitForView((ViewGroup) root, withId(R.id.search_close_btn),
VIEW_INVISIBLE | VIEW_GONE | VIEW_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