Bug 1950205 - Add recent searches settings. r=android-reviewers,android-l10n-reviewers,delphine,gl

Differential Revision: https://phabricator.services.mozilla.com/D239774
This commit is contained in:
Roger Yang
2025-03-04 21:30:04 +00:00
parent 8c703a7db2
commit d184200301
15 changed files with 222 additions and 58 deletions

View File

@@ -50,8 +50,8 @@ private const val MAXIMUM_ALLOWED_SUGGESTIONS_LIMIT_REACHED =
* highest scored suggestion URL. * highest scored suggestion URL.
* @param showEditSuggestion optional parameter to specify if the suggestion should show the edit button. * @param showEditSuggestion optional parameter to specify if the suggestion should show the edit button.
* @param suggestionsHeader optional parameter to specify if the suggestion should have a header * @param suggestionsHeader optional parameter to specify if the suggestion should have a header
* @param showSuggestionsWhenEmpty optional parameter to specify if suggestions should be shown even * @param showSuggestionsOnlyWhenEmpty optional parameter to specify if suggestions should be shown
* when the input text is empty. * only when the input text is empty.
*/ */
class SearchTermSuggestionsProvider( class SearchTermSuggestionsProvider(
private val historyStorage: PlacesHistoryStorage, private val historyStorage: PlacesHistoryStorage,
@@ -63,7 +63,7 @@ class SearchTermSuggestionsProvider(
private val engine: Engine? = null, private val engine: Engine? = null,
private val showEditSuggestion: Boolean = true, private val showEditSuggestion: Boolean = true,
private val suggestionsHeader: String? = null, private val suggestionsHeader: String? = null,
private val showSuggestionsWhenEmpty: Boolean = false, private val showSuggestionsOnlyWhenEmpty: Boolean = false,
) : AwesomeBar.SuggestionProvider { ) : AwesomeBar.SuggestionProvider {
init { init {
if (maxNumberOfSuggestions > SEARCH_TERMS_MAXIMUM_ALLOWED_SUGGESTIONS_LIMIT) { if (maxNumberOfSuggestions > SEARCH_TERMS_MAXIMUM_ALLOWED_SUGGESTIONS_LIMIT) {
@@ -78,12 +78,13 @@ class SearchTermSuggestionsProvider(
} }
override suspend fun onInputChanged(text: String): List<AwesomeBar.Suggestion> = coroutineScope { override suspend fun onInputChanged(text: String): List<AwesomeBar.Suggestion> = coroutineScope {
val shouldReturnEmpty =
(text.isBlank() && !showSuggestionsOnlyWhenEmpty) ||
(text.isNotBlank() && showSuggestionsOnlyWhenEmpty)
if (shouldReturnEmpty) return@coroutineScope emptyList()
historyStorage.cancelReads(text) historyStorage.cancelReads(text)
if (!showSuggestionsWhenEmpty && text.isBlank()) {
return@coroutineScope emptyList()
}
val suggestions = withContext(this.coroutineContext) { val suggestions = withContext(this.coroutineContext) {
historyStorage.getHistoryMetadataSince(Long.MIN_VALUE) historyStorage.getHistoryMetadataSince(Long.MIN_VALUE)
.asSequence() .asSequence()

View File

@@ -78,7 +78,7 @@ class SearchTermSuggestionsProviderTest {
} }
@Test @Test
fun `GIVEN an empty input and should show suggestions when empty WHEN querying suggestions THEN return suggestions from configured history storage`() = runTest { fun `GIVEN only an empty input should show suggestions THEN return suggestions from configured history storage only when input is empty`() = runTest {
val searchEngineIcon: Bitmap = mock() val searchEngineIcon: Bitmap = mock()
val provider = SearchTermSuggestionsProvider( val provider = SearchTermSuggestionsProvider(
historyStorage = storage, historyStorage = storage,
@@ -86,10 +86,10 @@ class SearchTermSuggestionsProviderTest {
searchEngine = searchEngine, searchEngine = searchEngine,
icon = searchEngineIcon, icon = searchEngineIcon,
showEditSuggestion = true, showEditSuggestion = true,
showSuggestionsWhenEmpty = true, showSuggestionsOnlyWhenEmpty = true,
) )
val suggestions = provider.onInputChanged("") var suggestions = provider.onInputChanged("")
assertEquals(1, suggestions.size) assertEquals(1, suggestions.size)
assertEquals(provider, suggestions[0].provider) assertEquals(provider, suggestions[0].provider)
@@ -103,14 +103,56 @@ class SearchTermSuggestionsProviderTest {
assertNotNull(suggestions[0].onSuggestionClicked) assertNotNull(suggestions[0].onSuggestionClicked)
assertNull(suggestions[0].onChipClicked) assertNull(suggestions[0].onChipClicked)
assertEquals(Int.MAX_VALUE - 2, suggestions[0].score) assertEquals(Int.MAX_VALUE - 2, suggestions[0].score)
suggestions = provider.onInputChanged("fir")
assertEquals(0, suggestions.size)
}
@Test
fun `GIVEN only not empty input should show suggestions THEN return suggestions from configured history storage only when input is not empty`() = runTest {
val searchEngineIcon: Bitmap = mock()
val provider = SearchTermSuggestionsProvider(
historyStorage = storage,
searchUseCase = mock(),
searchEngine = searchEngine,
icon = searchEngineIcon,
showEditSuggestion = true,
)
var suggestions = provider.onInputChanged("")
assertEquals(0, suggestions.size)
suggestions = provider.onInputChanged("fir")
assertEquals(1, suggestions.size)
assertEquals(provider, suggestions[0].provider)
assertEquals(historyEntry.key.searchTerm, suggestions[0].title)
assertNull(suggestions[0].description)
assertEquals(historyEntry.key.searchTerm, suggestions[0].editSuggestion)
assertEquals(searchEngineIcon, suggestions[0].icon)
assertNull(suggestions[0].indicatorIcon)
assertTrue(suggestions[0].chips.isEmpty())
assertTrue(suggestions[0].flags.isEmpty())
assertNotNull(suggestions[0].onSuggestionClicked)
assertNull(suggestions[0].onChipClicked)
assertEquals(Int.MAX_VALUE - 2, suggestions[0].score)
} }
@Test @Test
fun `GIVEN an empty input WHEN querying suggestions THEN cleanup all read operations for the current query`() = runTest { fun `GIVEN an empty input AND should show empty query WHEN querying suggestions THEN do not cleanup read operations for the empty query`() = runTest {
val provider = SearchTermSuggestionsProvider(storage, mock(), searchEngine) val provider = SearchTermSuggestionsProvider(storage, mock(), searchEngine)
provider.onInputChanged("") provider.onInputChanged("")
verify(storage, never()).cancelReads()
verify(storage, never()).cancelReads("")
}
@Test
fun `GIVEN an empty input AND should show empty query WHEN querying suggestions THEN cleanup read operations for the empty query`() = runTest {
val provider = SearchTermSuggestionsProvider(storage, mock(), searchEngine, showSuggestionsOnlyWhenEmpty = true)
provider.onInputChanged("")
verify(storage, never()).cancelReads() verify(storage, never()).cancelReads()
verify(storage).cancelReads("") verify(storage).cancelReads("")
} }

View File

@@ -479,11 +479,11 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
observeClipboardState() observeClipboardState()
observeSuggestionProvidersState() observeSuggestionProvidersState()
val isPrivate = (requireActivity() as HomeActivity).browsingModeManager.mode.isPrivate val browsingMode = (requireActivity() as HomeActivity).browsingModeManager.mode
if ( if (view.context.settings().shouldShowTrendingOrRecentSearchSuggestions(
view.context.settings().shouldShowTrendingSearchSuggestions( browsingMode = browsingMode,
isPrivate, isTrendingSuggestionSupported = requireComponents.core.store.state.search
requireComponents.core.store.state.search.selectedOrDefaultSearchEngine, .selectedOrDefaultSearchEngine?.trendingUrl != null,
) && ( ) && (
store.state.query.isNotEmpty() || store.state.query.isNotEmpty() ||
FxNimbus.features.searchSuggestionsOnHomepage.value().enabled FxNimbus.features.searchSuggestionsOnHomepage.value().enabled

View File

@@ -299,7 +299,7 @@ class AwesomeBarView(
state: SearchProviderState, state: SearchProviderState,
): MutableSet<AwesomeBar.SuggestionProvider> { ): MutableSet<AwesomeBar.SuggestionProvider> {
val providersToAdd = mutableSetOf<AwesomeBar.SuggestionProvider>() val providersToAdd = mutableSetOf<AwesomeBar.SuggestionProvider>()
val isPrivate = activity.browsingModeManager.mode.isPrivate val browsingMode = activity.browsingModeManager.mode
when (state.searchEngineSource) { when (state.searchEngineSource) {
is SearchEngineSource.History -> { is SearchEngineSource.History -> {
@@ -314,11 +314,13 @@ class AwesomeBarView(
if (state.showSearchTermHistory) { if (state.showSearchTermHistory) {
getSearchTermSuggestionsProvider( getSearchTermSuggestionsProvider(
state.searchEngineSource, searchEngineSource = state.searchEngineSource,
activity.settings().shouldShowTrendingSearchSuggestions( )?.let { providersToAdd.add(it) }
isPrivate, }
state.searchEngineSource.searchEngine,
), if (activity.settings().shouldShowRecentSearchSuggestions) {
getRecentSearchSuggestionsProvider(
searchEngineSource = state.searchEngineSource,
)?.let { providersToAdd.add(it) } )?.let { providersToAdd.add(it) }
} }
@@ -407,8 +409,8 @@ class AwesomeBarView(
providersToAdd.add(searchEngineSuggestionProvider) providersToAdd.add(searchEngineSuggestionProvider)
if (activity.settings().shouldShowTrendingSearchSuggestions( if (activity.settings().shouldShowTrendingSearchSuggestions(
isPrivate, browsingMode = browsingMode,
state.searchEngineSource.searchEngine, isTrendingSuggestionSupported = state.searchEngineSource.searchEngine?.trendingUrl != null,
) )
) { ) {
providersToAdd.add(defaultTopSitesSuggestionProvider) providersToAdd.add(defaultTopSitesSuggestionProvider)
@@ -483,7 +485,6 @@ class AwesomeBarView(
@VisibleForTesting @VisibleForTesting
internal fun getSearchTermSuggestionsProvider( internal fun getSearchTermSuggestionsProvider(
searchEngineSource: SearchEngineSource, searchEngineSource: SearchEngineSource,
showSuggestionsWhenEmpty: Boolean = false,
): AwesomeBar.SuggestionProvider? { ): AwesomeBar.SuggestionProvider? {
val validSearchEngine = searchEngineSource.searchEngine ?: return null val validSearchEngine = searchEngineSource.searchEngine ?: return null
@@ -494,7 +495,23 @@ class AwesomeBarView(
icon = getDrawable(activity, R.drawable.ic_history)?.toBitmap(), icon = getDrawable(activity, R.drawable.ic_history)?.toBitmap(),
engine = engineForSpeculativeConnects, engine = engineForSpeculativeConnects,
suggestionsHeader = getSearchEngineSuggestionsHeader(searchEngineSource.searchEngine), suggestionsHeader = getSearchEngineSuggestionsHeader(searchEngineSource.searchEngine),
showSuggestionsWhenEmpty = showSuggestionsWhenEmpty, )
}
@VisibleForTesting
internal fun getRecentSearchSuggestionsProvider(
searchEngineSource: SearchEngineSource,
): AwesomeBar.SuggestionProvider? {
val validSearchEngine = searchEngineSource.searchEngine ?: return null
return SearchTermSuggestionsProvider(
historyStorage = components.core.historyStorage,
searchUseCase = historySearchTermUseCase,
searchEngine = validSearchEngine,
icon = getDrawable(activity, R.drawable.ic_history)?.toBitmap(),
engine = engineForSpeculativeConnects,
suggestionsHeader = activity.getString(R.string.recent_searches_header),
showSuggestionsOnlyWhenEmpty = true,
) )
} }

View File

@@ -127,6 +127,12 @@ class SecretSettingsFragment : PreferenceFragmentCompat() {
onPreferenceChangeListener = SharedPreferenceUpdater() onPreferenceChangeListener = SharedPreferenceUpdater()
} }
requirePreference<SwitchPreference>(R.string.pref_key_enable_recent_searches).apply {
isVisible = Config.channel.isNightlyOrDebug
isChecked = context.settings().isRecentSearchesVisible
onPreferenceChangeListener = SharedPreferenceUpdater()
}
requirePreference<SwitchPreference>(R.string.pref_key_enable_fxsuggest).apply { requirePreference<SwitchPreference>(R.string.pref_key_enable_fxsuggest).apply {
isVisible = FeatureFlags.FX_SUGGEST isVisible = FeatureFlags.FX_SUGGEST
isChecked = context.settings().enableFxSuggest isChecked = context.settings().enableFxSuggest

View File

@@ -46,6 +46,9 @@ class SearchEngineFragment : PreferenceFragmentCompat() {
requirePreference<CheckBoxPreference>(R.string.pref_key_show_trending_search_suggestions).apply { requirePreference<CheckBoxPreference>(R.string.pref_key_show_trending_search_suggestions).apply {
isVisible = context.settings().isTrendingSearchesVisible isVisible = context.settings().isTrendingSearchesVisible
} }
requirePreference<SwitchPreference>(R.string.pref_key_show_recent_search_suggestions).apply {
isVisible = context.settings().isRecentSearchesVisible
}
view?.hideKeyboard() view?.hideKeyboard()
} }
@@ -74,6 +77,9 @@ class SearchEngineFragment : PreferenceFragmentCompat() {
context.settings().shouldShowSearchSuggestions context.settings().shouldShowSearchSuggestions
} }
val recentSearchSuggestionsPreference =
requirePreference<SwitchPreference>(R.string.pref_key_show_recent_search_suggestions)
val autocompleteURLsPreference = val autocompleteURLsPreference =
requirePreference<SwitchPreference>(R.string.pref_key_enable_autocomplete_urls).apply { requirePreference<SwitchPreference>(R.string.pref_key_enable_autocomplete_urls).apply {
isChecked = context.settings().shouldAutocompleteInAwesomebar isChecked = context.settings().shouldAutocompleteInAwesomebar
@@ -134,6 +140,7 @@ class SearchEngineFragment : PreferenceFragmentCompat() {
showClipboardSuggestions.onPreferenceChangeListener = SharedPreferenceUpdater() showClipboardSuggestions.onPreferenceChangeListener = SharedPreferenceUpdater()
searchSuggestionsInPrivatePreference.onPreferenceChangeListener = SharedPreferenceUpdater() searchSuggestionsInPrivatePreference.onPreferenceChangeListener = SharedPreferenceUpdater()
trendingSearchSuggestionsPreference.onPreferenceChangeListener = SharedPreferenceUpdater() trendingSearchSuggestionsPreference.onPreferenceChangeListener = SharedPreferenceUpdater()
recentSearchSuggestionsPreference.onPreferenceChangeListener = SharedPreferenceUpdater()
showVoiceSearchPreference.onPreferenceChangeListener = object : Preference.OnPreferenceChangeListener { showVoiceSearchPreference.onPreferenceChangeListener = object : Preference.OnPreferenceChangeListener {
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
val newBooleanValue = newValue as? Boolean ?: return false val newBooleanValue = newValue as? Boolean ?: return false

View File

@@ -15,7 +15,6 @@ import android.view.accessibility.AccessibilityManager
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.annotation.VisibleForTesting.Companion.PRIVATE
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.concept.engine.Engine.HttpsOnlyMode import mozilla.components.concept.engine.Engine.HttpsOnlyMode
import mozilla.components.concept.engine.EngineSession.CookieBannerHandlingMode import mozilla.components.concept.engine.EngineSession.CookieBannerHandlingMode
import mozilla.components.feature.sitepermissions.SitePermissionsRules import mozilla.components.feature.sitepermissions.SitePermissionsRules
@@ -1119,11 +1118,39 @@ class Settings(private val appContext: Context) : PreferencesHolder {
) )
/** /**
* Returns true if trending searches should be shown to the user. * Returns true if trending search suggestions should be shown to the user.
*/ */
fun shouldShowTrendingSearchSuggestions(isPrivate: Boolean, searchEngine: SearchEngine?) = fun shouldShowTrendingSearchSuggestions(
trendingSearchSuggestionsEnabled && isTrendingSearchesVisible && browsingMode: BrowsingMode,
searchEngine?.trendingUrl != null && (!isPrivate || shouldShowSearchSuggestionsInPrivate) isTrendingSuggestionSupported: Boolean,
) =
trendingSearchSuggestionsEnabled && isTrendingSearchesVisible && isTrendingSuggestionSupported &&
(!browsingMode.isPrivate || shouldShowSearchSuggestionsInPrivate)
/**
* Indicates if the user have enabled recent search in the search suggestions setting preference.
*/
@VisibleForTesting
internal var recentSearchSuggestionsEnabled by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_show_recent_search_suggestions),
default = true,
)
/**
* Returns true if recent searches should be shown to the user.
*/
val shouldShowRecentSearchSuggestions: Boolean
get() = recentSearchSuggestionsEnabled && isRecentSearchesVisible
/**
* Returns true if trending searches or recent searches should be shown to the user.
*/
fun shouldShowTrendingOrRecentSearchSuggestions(
browsingMode: BrowsingMode,
isTrendingSuggestionSupported: Boolean,
) =
shouldShowTrendingSearchSuggestions(browsingMode, isTrendingSuggestionSupported) ||
shouldShowRecentSearchSuggestions
var showSearchSuggestionsInPrivateOnboardingFinished by booleanPreference( var showSearchSuggestionsInPrivateOnboardingFinished by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions_in_private_onboarding), appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions_in_private_onboarding),
@@ -1990,12 +2017,19 @@ class Settings(private val appContext: Context) : PreferencesHolder {
) )
/** /**
* Indicates if Trending Searches is enabled. * Indicates if Trending Search Suggestions are enabled.
*/ */
var isTrendingSearchesVisible by lazyFeatureFlagPreference( var isTrendingSearchesVisible by booleanPreference(
key = appContext.getPreferenceKey(R.string.pref_key_enable_trending_searches), key = appContext.getPreferenceKey(R.string.pref_key_enable_trending_searches),
default = { FxNimbus.features.trendingSearches.value().enabled }, default = FxNimbus.features.trendingSearches.value().enabled,
featureFlag = true, )
/**
* Indicates if Recent Search Suggestions are enabled.
*/
var isRecentSearchesVisible by booleanPreference(
key = appContext.getPreferenceKey(R.string.pref_key_enable_recent_searches),
default = FxNimbus.features.recentSearches.value().enabled,
) )
/** /**

View File

@@ -129,6 +129,7 @@
<string name="pref_key_show_search_suggestions_in_private" translatable="false">pref_key_show_search_suggestions_in_private</string> <string name="pref_key_show_search_suggestions_in_private" translatable="false">pref_key_show_search_suggestions_in_private</string>
<string name="pref_key_show_search_suggestions_in_private_onboarding" translatable="false">pref_key_show_search_suggestions_in_privateonboarding</string> <string name="pref_key_show_search_suggestions_in_private_onboarding" translatable="false">pref_key_show_search_suggestions_in_privateonboarding</string>
<string name="pref_key_show_trending_search_suggestions" translatable="false">pref_key_show_trending_search_suggestions</string> <string name="pref_key_show_trending_search_suggestions" translatable="false">pref_key_show_trending_search_suggestions</string>
<string name="pref_key_show_recent_search_suggestions" translatable="false">pref_key_show_recent_search_suggestions</string>
<string name="pref_key_show_voice_search" translatable="false">pref_key_show_voice_search</string> <string name="pref_key_show_voice_search" translatable="false">pref_key_show_voice_search</string>
<string name="pref_key_enable_autocomplete_urls" translatable="false">pref_key_enable_domain_autocomplete</string> <string name="pref_key_enable_autocomplete_urls" translatable="false">pref_key_enable_domain_autocomplete</string>
<string name="pref_key_show_sponsored_suggestions" translatable="false">pref_key_show_sponsored_suggestions</string> <string name="pref_key_show_sponsored_suggestions" translatable="false">pref_key_show_sponsored_suggestions</string>
@@ -403,6 +404,7 @@
<string name="pref_key_enable_homepage_as_new_tab" translatable="false">pref_key_enable_homepage_as_new_tab</string> <string name="pref_key_enable_homepage_as_new_tab" translatable="false">pref_key_enable_homepage_as_new_tab</string>
<string name="pref_key_enable_unified_trust_panel" translatable="false">pref_key_enable_unified_trust_panel</string> <string name="pref_key_enable_unified_trust_panel" translatable="false">pref_key_enable_unified_trust_panel</string>
<string name="pref_key_enable_trending_searches" translatable="false">pref_key_enable_trending_searches</string> <string name="pref_key_enable_trending_searches" translatable="false">pref_key_enable_trending_searches</string>
<string name="pref_key_enable_recent_searches" translatable="false">pref_key_enable_recent_searches</string>
<!-- Growth Data --> <!-- Growth Data -->
<string name="pref_key_growth_set_as_default" translatable="false">pref_key_growth_set_as_default</string> <string name="pref_key_growth_set_as_default" translatable="false">pref_key_growth_set_as_default</string>

View File

@@ -103,6 +103,8 @@
<string name="preferences_debug_settings_unified_trust_panel" translatable="false">Enable Unified Trust Panel</string> <string name="preferences_debug_settings_unified_trust_panel" translatable="false">Enable Unified Trust Panel</string>
<!-- Label for enabling Trending Searches --> <!-- Label for enabling Trending Searches -->
<string name="preferences_debug_settings_trending_searches" translatable="false">Enable Trending Searches</string> <string name="preferences_debug_settings_trending_searches" translatable="false">Enable Trending Searches</string>
<!-- Label for enabling Recent Searches -->
<string name="preferences_debug_settings_recent_searches" translatable="false">Enable Recent Searches</string>
<!-- Label for enabling the DNS over HTTPS settings --> <!-- Label for enabling the DNS over HTTPS settings -->
<string name="preferences_debug_settings_enable_doh_settings" translatable="false">Enable DNS over HTTPS settings</string> <string name="preferences_debug_settings_enable_doh_settings" translatable="false">Enable DNS over HTTPS settings</string>

View File

@@ -789,6 +789,8 @@
<string name="preferences_show_search_suggestions_in_private">Show in private sessions</string> <string name="preferences_show_search_suggestions_in_private">Show in private sessions</string>
<!-- Preference title for switch preference to show trending search suggestions --> <!-- Preference title for switch preference to show trending search suggestions -->
<string name="preferences_show_trending_search_suggestions">Show trending suggestions</string> <string name="preferences_show_trending_search_suggestions">Show trending suggestions</string>
<!-- Preference title for switch preference to show recent search suggestions -->
<string name="preferences_show_recent_search_suggestions">Show recent searches</string>
<!-- Preference title for switch preference to show a clipboard suggestion when searching --> <!-- Preference title for switch preference to show a clipboard suggestion when searching -->
<string name="preferences_show_clipboard_suggestions">Show clipboard suggestions</string> <string name="preferences_show_clipboard_suggestions">Show clipboard suggestions</string>
<!-- Preference title for switch preference to suggest browsing history when searching --> <!-- Preference title for switch preference to suggest browsing history when searching -->
@@ -2540,6 +2542,8 @@
<string name="google_search_engine_suggestion_header">Google Search</string> <string name="google_search_engine_suggestion_header">Google Search</string>
<!-- Title for search suggestions when the default search suggestion engine is anything other than Google. The first parameter is default search engine name. --> <!-- Title for search suggestions when the default search suggestion engine is anything other than Google. The first parameter is default search engine name. -->
<string name="other_default_search_engine_suggestion_header">%s search</string> <string name="other_default_search_engine_suggestion_header">%s search</string>
<!-- Title for recent search suggestions. -->
<string name="recent_searches_header">Recent Searches</string>
<!-- Default browser experiment --> <!-- Default browser experiment -->
<!-- Default browser card title --> <!-- Default browser card title -->

View File

@@ -44,6 +44,11 @@
android:layout="@layout/checkbox_left_preference" android:layout="@layout/checkbox_left_preference"
android:title="@string/preferences_show_trending_search_suggestions" android:title="@string/preferences_show_trending_search_suggestions"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<SwitchPreference
app:iconSpaceReserved="false"
android:defaultValue="true"
android:key="@string/pref_key_show_recent_search_suggestions"
android:title="@string/preferences_show_recent_search_suggestions" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

View File

@@ -72,6 +72,10 @@
android:key="@string/pref_key_enable_trending_searches" android:key="@string/pref_key_enable_trending_searches"
android:title="@string/preferences_debug_settings_trending_searches" android:title="@string/preferences_debug_settings_trending_searches"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<SwitchPreference
android:key="@string/pref_key_enable_recent_searches"
android:title="@string/preferences_debug_settings_recent_searches"
app:iconSpaceReserved="false" />
<SwitchPreference <SwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:key="@string/pref_key_enable_debug_drawer" android:key="@string/pref_key_enable_debug_drawer"

View File

@@ -1477,6 +1477,32 @@ class AwesomeBarViewTest {
assertEquals(0, result.filterIsInstance<TrendingSearchProvider>().size) assertEquals(0, result.filterIsInstance<TrendingSearchProvider>().size)
assertEquals(0, result.filterIsInstance<TopSitesSuggestionProvider>().size) assertEquals(0, result.filterIsInstance<TopSitesSuggestionProvider>().size)
} }
@Test
fun `GIVEN should show recent searches WHEN configuring providers THEN add the recent search suggestions provider`() {
every { activity.settings() } returns mockk(relaxed = true) {
every { shouldShowRecentSearchSuggestions } returns true
}
val state = getSearchProviderState(
searchEngineSource = SearchEngineSource.Default(mockk(relaxed = true)),
)
val result = awesomeBarView.getProvidersToAdd(state)
assertEquals(2, result.filterIsInstance<SearchTermSuggestionsProvider>().size)
}
@Test
fun `GIVEN should not show recent searches WHEN configuring providers THEN don't add the recent search suggestions provider`() {
every { activity.settings() } returns mockk(relaxed = true) {
every { shouldShowRecentSearchSuggestions } returns false
}
val state = getSearchProviderState(
searchEngineSource = SearchEngineSource.Default(mockk(relaxed = true)),
)
val result = awesomeBarView.getProvidersToAdd(state)
assertEquals(1, result.filterIsInstance<SearchTermSuggestionsProvider>().size)
}
} }
/** /**

View File

@@ -128,6 +128,11 @@ class SearchEngineFragmentTest {
every { testContext.components.core.store.state.search } returns mockk(relaxed = true) every { testContext.components.core.store.state.search } returns mockk(relaxed = true)
every { any<SearchState>().selectedOrDefaultSearchEngine } returns mockk(relaxed = true) every { any<SearchState>().selectedOrDefaultSearchEngine } returns mockk(relaxed = true)
} }
every {
fragment.findPreference<SwitchPreference>(testContext.getString(R.string.pref_key_show_recent_search_suggestions))
} returns mockk(relaxed = true) {
every { context } returns testContext
}
// Trigger the preferences setup. // Trigger the preferences setup.
fragment.onResume() fragment.onResume()

View File

@@ -6,10 +6,8 @@ package org.mozilla.fenix.utils
import android.content.Context import android.content.Context
import io.mockk.every import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.spyk import io.mockk.spyk
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.concept.engine.Engine.HttpsOnlyMode.DISABLED import mozilla.components.concept.engine.Engine.HttpsOnlyMode.DISABLED
import mozilla.components.concept.engine.Engine.HttpsOnlyMode.ENABLED import mozilla.components.concept.engine.Engine.HttpsOnlyMode.ENABLED
import mozilla.components.concept.engine.Engine.HttpsOnlyMode.ENABLED_PRIVATE_ONLY import mozilla.components.concept.engine.Engine.HttpsOnlyMode.ENABLED_PRIVATE_ONLY
@@ -1153,64 +1151,75 @@ class SettingsTest {
@Test @Test
fun `GIVEN trending searches is enabled, visible and search engine supports it THEN should show trending searches`() { fun `GIVEN trending searches is enabled, visible and search engine supports it THEN should show trending searches`() {
val settings = spyk(settings) val settings = spyk(settings)
val searchEngine: SearchEngine = mockk(relaxed = true)
every { settings.trendingSearchSuggestionsEnabled } returns true every { settings.trendingSearchSuggestionsEnabled } returns true
every { settings.isTrendingSearchesVisible } returns true every { settings.isTrendingSearchesVisible } returns true
every { settings.shouldShowSearchSuggestionsInPrivate } returns true every { settings.shouldShowSearchSuggestionsInPrivate } returns true
every { searchEngine.trendingUrl } returns "https://mozilla.org"
assertTrue(settings.shouldShowTrendingSearchSuggestions(true, searchEngine)) assertTrue(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Private, true))
assertTrue(settings.shouldShowTrendingSearchSuggestions(false, searchEngine)) assertTrue(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Normal, true))
every { settings.trendingSearchSuggestionsEnabled } returns false every { settings.trendingSearchSuggestionsEnabled } returns false
every { settings.isTrendingSearchesVisible } returns true every { settings.isTrendingSearchesVisible } returns true
every { settings.shouldShowSearchSuggestionsInPrivate } returns true every { settings.shouldShowSearchSuggestionsInPrivate } returns true
assertFalse(settings.shouldShowTrendingSearchSuggestions(true, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Private, true))
assertFalse(settings.shouldShowTrendingSearchSuggestions(false, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Normal, true))
every { settings.trendingSearchSuggestionsEnabled } returns true every { settings.trendingSearchSuggestionsEnabled } returns true
every { settings.isTrendingSearchesVisible } returns false every { settings.isTrendingSearchesVisible } returns false
every { settings.shouldShowSearchSuggestionsInPrivate } returns true every { settings.shouldShowSearchSuggestionsInPrivate } returns true
assertFalse(settings.shouldShowTrendingSearchSuggestions(true, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Private, true))
assertFalse(settings.shouldShowTrendingSearchSuggestions(false, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Normal, true))
every { settings.trendingSearchSuggestionsEnabled } returns false every { settings.trendingSearchSuggestionsEnabled } returns false
every { settings.isTrendingSearchesVisible } returns false every { settings.isTrendingSearchesVisible } returns false
every { settings.shouldShowSearchSuggestionsInPrivate } returns true every { settings.shouldShowSearchSuggestionsInPrivate } returns true
assertFalse(settings.shouldShowTrendingSearchSuggestions(true, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Private, true))
assertFalse(settings.shouldShowTrendingSearchSuggestions(false, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Normal, true))
} }
@Test @Test
fun `GIVEN search engine does not supports trending search THEN should not show trending searches`() { fun `GIVEN search engine does not supports trending search THEN should not show trending searches`() {
val settings = spyk(settings) val settings = spyk(settings)
val searchEngine: SearchEngine = mockk(relaxed = true)
every { settings.trendingSearchSuggestionsEnabled } returns true every { settings.trendingSearchSuggestionsEnabled } returns true
every { settings.isTrendingSearchesVisible } returns true every { settings.isTrendingSearchesVisible } returns true
every { settings.shouldShowSearchSuggestionsInPrivate } returns true every { settings.shouldShowSearchSuggestionsInPrivate } returns true
every { searchEngine.trendingUrl } returns null
assertFalse(settings.shouldShowTrendingSearchSuggestions(false, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Private, false))
assertFalse(settings.shouldShowTrendingSearchSuggestions(true, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Normal, false))
} }
@Test @Test
fun `GIVEN is private tab THEN should show trending searches only if allowed`() { fun `GIVEN is private tab THEN should show trending searches only if allowed`() {
val settings = spyk(settings) val settings = spyk(settings)
val searchEngine: SearchEngine = mockk(relaxed = true)
every { settings.trendingSearchSuggestionsEnabled } returns true every { settings.trendingSearchSuggestionsEnabled } returns true
every { settings.isTrendingSearchesVisible } returns true every { settings.isTrendingSearchesVisible } returns true
every { settings.shouldShowSearchSuggestionsInPrivate } returns true every { settings.shouldShowSearchSuggestionsInPrivate } returns true
every { searchEngine.trendingUrl } returns "abc"
assertTrue(settings.shouldShowTrendingSearchSuggestions(true, searchEngine)) assertTrue(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Private, true))
assertTrue(settings.shouldShowTrendingSearchSuggestions(false, searchEngine)) assertTrue(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Normal, true))
every { settings.shouldShowSearchSuggestionsInPrivate } returns false every { settings.shouldShowSearchSuggestionsInPrivate } returns false
assertFalse(settings.shouldShowTrendingSearchSuggestions(true, searchEngine)) assertFalse(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Private, true))
assertTrue(settings.shouldShowTrendingSearchSuggestions(false, searchEngine)) assertTrue(settings.shouldShowTrendingSearchSuggestions(BrowsingMode.Normal, true))
}
@Test
fun `GIVEN recent search is enable THEN should show recent searches only if recent search is visible`() {
val settings = spyk(settings)
every { settings.recentSearchSuggestionsEnabled } returns true
every { settings.isRecentSearchesVisible } returns true
assertTrue(settings.shouldShowRecentSearchSuggestions)
every { settings.isRecentSearchesVisible } returns false
every { settings.recentSearchSuggestionsEnabled } returns true
assertFalse(settings.shouldShowRecentSearchSuggestions)
every { settings.isRecentSearchesVisible } returns true
every { settings.recentSearchSuggestionsEnabled } returns false
assertFalse(settings.shouldShowRecentSearchSuggestions)
} }
} }