Issue #24299: Add history to the search engine menu

pull/543/head
Roger Yang 2 years ago committed by mergify[bot]
parent 9e8ee28e40
commit 7f29461c75

@ -8,14 +8,18 @@ import android.content.Context
import android.content.res.Configuration
import android.os.Build
import android.os.StrictMode
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient
import mozilla.components.browser.engine.gecko.permission.GeckoSitePermissionsStorage
import mozilla.components.browser.icons.BrowserIcons
import mozilla.components.browser.session.storage.SessionStorage
import mozilla.components.browser.state.engine.EngineMiddleware
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.SearchState
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
@ -39,6 +43,7 @@ import mozilla.components.feature.pwa.WebAppShortcutManager
import mozilla.components.feature.readerview.ReaderViewMiddleware
import mozilla.components.feature.recentlyclosed.RecentlyClosedMiddleware
import mozilla.components.feature.recentlyclosed.RecentlyClosedTabsStorage
import mozilla.components.feature.search.ext.createApplicationSearchEngine
import mozilla.components.feature.search.middleware.AdsTelemetryMiddleware
import mozilla.components.feature.search.middleware.SearchMiddleware
import mozilla.components.feature.search.region.RegionMiddleware
@ -189,6 +194,17 @@ class Core(
}
}
val applicationSearchEngines: List<SearchEngine> by lazyMonitored {
listOf(
createApplicationSearchEngine(
id = HISTORY_SEARCH_ENGINE_ID,
name = context.getString(R.string.library_history),
url = "",
icon = getDrawable(context, R.drawable.ic_history_search)?.toBitmap()!!,
)
)
}
/**
* The [BrowserStore] holds the global [BrowserState].
*/
@ -217,6 +233,15 @@ class Core(
)
BrowserStore(
initialState = BrowserState(
search = SearchState(
applicationSearchEngines = if (context.settings().showUnifiedSearchFeature) {
applicationSearchEngines
} else {
emptyList()
},
)
),
middleware = middlewareList + EngineMiddleware.create(
engine,
// We are disabling automatic suspending of engine sessions under memory pressure.
@ -477,5 +502,11 @@ class Core(
private const val RECENTLY_CLOSED_MAX = 10
const val HISTORY_METADATA_MAX_AGE_IN_MS = 14 * 24 * 60 * 60 * 1000 // 14 days
private const val CONTILE_MAX_CACHE_AGE = 60L // 60 minutes
const val HISTORY_SEARCH_ENGINE_ID = "history_search_engine_id"
// Maximum number of suggestions returned from the history search engine source.
const val METADATA_HISTORY_SUGGESTION_LIMIT = 100
// Maximum number of suggestions returned from shortcut search engine.
const val METADATA_SHORTCUT_SUGGESTION_LIMIT = 20
}
}

@ -9,6 +9,7 @@ import mozilla.components.feature.awesomebar.provider.CombinedHistorySuggestionP
import mozilla.components.feature.session.SessionUseCases
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.Core.Companion.METADATA_SHORTCUT_SUGGESTION_LIMIT
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.library.history.HistorySearchFragmentState
@ -47,7 +48,7 @@ class AwesomeBarView(
loadUrlUseCase = loadUrlUseCase,
icons = components.core.icons,
engine = engineForSpeculativeConnects,
maxNumberOfSuggestions = METADATA_SUGGESTION_LIMIT,
maxNumberOfSuggestions = METADATA_SHORTCUT_SUGGESTION_LIMIT,
showEditSuggestion = false,
)
@ -57,9 +58,4 @@ class AwesomeBarView(
fun update(state: HistorySearchFragmentState) {
view.onInputChanged(state.query)
}
companion object {
// Maximum number of suggestions returned from the history metadata storage.
const val METADATA_SUGGESTION_LIMIT = 100
}
}

@ -23,6 +23,7 @@ import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.SearchShortcuts
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Core
import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.crashes.CrashListActivity
import org.mozilla.fenix.ext.navigateSafe
@ -69,6 +70,11 @@ class SearchDialogController(
) : SearchController {
override fun handleUrlCommitted(url: String, fromHomeScreen: Boolean) {
// Do not load URL if application search engine is selected.
if (fragmentStore.state.searchEngineSource.searchEngine?.type == SearchEngine.Type.APPLICATION) {
return
}
when (url) {
"about:crashes" -> {
// The list of past crashes can be accessed via "settings > about", but desktop and
@ -190,9 +196,22 @@ class SearchDialogController(
override fun handleSearchShortcutEngineSelected(searchEngine: SearchEngine) {
focusToolbar()
fragmentStore.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine))
when {
searchEngine.type == SearchEngine.Type.APPLICATION && searchEngine.id == Core.HISTORY_SEARCH_ENGINE_ID -> {
fragmentStore.dispatch(SearchFragmentAction.SearchHistoryEngineSelected(searchEngine))
}
searchEngine == store.state.search.selectedOrDefaultSearchEngine -> {
fragmentStore.dispatch(SearchFragmentAction.SearchDefaultEngineSelected(searchEngine, settings))
}
else -> {
fragmentStore.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine, settings))
}
}
val engine = when (searchEngine.type) {
SearchEngine.Type.CUSTOM -> "custom"
SearchEngine.Type.APPLICATION -> "application"
else -> searchEngine.name
}
SearchShortcuts.selected.record(SearchShortcuts.SelectedExtra(engine))

@ -16,6 +16,7 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.utils.Settings
/**
* The [Store] for holding the [SearchFragmentState] and applying [SearchFragmentAction]s.
@ -33,12 +34,28 @@ class SearchFragmentStore(
sealed class SearchEngineSource {
abstract val searchEngine: SearchEngine?
/**
* No search engine
*/
object None : SearchEngineSource() {
override val searchEngine: SearchEngine? = null
}
/**
* Search engine set as default
*/
data class Default(override val searchEngine: SearchEngine) : SearchEngineSource()
/**
* Search engine for quick search
* This is for any search engine that is not the user selected default.
*/
data class Shortcut(override val searchEngine: SearchEngine) : SearchEngineSource()
/**
* Search engine for history
*/
data class History(override val searchEngine: SearchEngine) : SearchEngineSource()
}
/**
@ -60,6 +77,8 @@ sealed class SearchEngineSource {
* @property showClipboardSuggestions Whether or not to show clipboard suggestion in the AwesomeBar
* @property showHistorySuggestions Whether or not to show history suggestions in the AwesomeBar
* @property showBookmarkSuggestions Whether or not to show the bookmark suggestion in the AwesomeBar
* @property showSyncedTabsSuggestions Whether or not to show the synced tabs suggestion in the AwesomeBar
* @property showSessionSuggestions Whether or not to show the session suggestion in the AwesomeBar
* @property pastedText The text pasted from the long press toolbar menu
* @property clipboardHasUrl Indicates if the clipboard contains an URL.
*/
@ -78,6 +97,7 @@ data class SearchFragmentState(
val showHistorySuggestions: Boolean,
val showBookmarkSuggestions: Boolean,
val showSyncedTabsSuggestions: Boolean,
val showSessionSuggestions: Boolean,
val tabId: String?,
val pastedText: String? = null,
val searchAccessPoint: MetricsUtils.Source,
@ -119,6 +139,7 @@ fun createInitialSearchFragmentState(
showHistorySuggestions = settings.shouldShowHistorySuggestions,
showBookmarkSuggestions = settings.shouldShowBookmarkSuggestions,
showSyncedTabsSuggestions = settings.shouldShowSyncedTabsSuggestions,
showSessionSuggestions = true,
tabId = tabId,
pastedText = pastedText,
searchAccessPoint = searchAccessPoint
@ -129,11 +150,44 @@ fun createInitialSearchFragmentState(
* Actions to dispatch through the `SearchStore` to modify `SearchState` through the reducer.
*/
sealed class SearchFragmentAction : Action {
/**
* Action to enable or disable search suggestions.
*/
data class SetShowSearchSuggestions(val show: Boolean) : SearchFragmentAction()
data class SearchShortcutEngineSelected(val engine: SearchEngine) : SearchFragmentAction()
/**
* Action when default search engine is selected.
*/
data class SearchDefaultEngineSelected(val engine: SearchEngine, val settings: Settings) : SearchFragmentAction()
/**
* Action when shortcut search engine is selected.
*/
data class SearchShortcutEngineSelected(val engine: SearchEngine, val settings: Settings) : SearchFragmentAction()
/**
* Action when history search engine is selected.
*/
data class SearchHistoryEngineSelected(val engine: SearchEngine) : SearchFragmentAction()
/**
* Action when search engine picker is selected.
*/
data class ShowSearchShortcutEnginePicker(val show: Boolean) : SearchFragmentAction()
/**
* Action when allow search suggestion in private mode hint is tapped.
*/
data class AllowSearchSuggestionsInPrivateModePrompt(val show: Boolean) : SearchFragmentAction()
/**
* Action when query is updated.
*/
data class UpdateQuery(val query: String) : SearchFragmentAction()
/**
* Action when updating clipboard URL.
*/
data class UpdateClipboardHasUrl(val hasUrl: Boolean) : SearchFragmentAction()
/**
@ -145,12 +199,56 @@ sealed class SearchFragmentAction : Action {
/**
* The SearchState Reducer.
*/
@Suppress("LongMethod")
private fun searchStateReducer(state: SearchFragmentState, action: SearchFragmentAction): SearchFragmentState {
return when (action) {
is SearchFragmentAction.SearchDefaultEngineSelected ->
state.copy(
searchEngineSource = SearchEngineSource.Default(action.engine),
showSearchSuggestions = true,
showSearchShortcuts = action.settings.shouldShowSearchShortcuts,
showClipboardSuggestions = action.settings.shouldShowClipboardSuggestions,
showHistorySuggestions = action.settings.shouldShowHistorySuggestions,
showBookmarkSuggestions = action.settings.shouldShowBookmarkSuggestions,
showSyncedTabsSuggestions = action.settings.shouldShowSyncedTabsSuggestions,
showSessionSuggestions = true,
)
is SearchFragmentAction.SearchShortcutEngineSelected ->
state.copy(
searchEngineSource = SearchEngineSource.Shortcut(action.engine),
showSearchShortcuts = false
showSearchSuggestions = true,
showSearchShortcuts = when (action.settings.showUnifiedSearchFeature) {
true -> false
false -> action.settings.shouldShowSearchShortcuts
},
showClipboardSuggestions = action.settings.shouldShowClipboardSuggestions,
showHistorySuggestions = when (action.settings.showUnifiedSearchFeature) {
true -> false
false -> action.settings.shouldShowHistorySuggestions
},
showBookmarkSuggestions = when (action.settings.showUnifiedSearchFeature) {
true -> false
false -> action.settings.shouldShowBookmarkSuggestions
},
showSyncedTabsSuggestions = when (action.settings.showUnifiedSearchFeature) {
true -> false
false -> action.settings.shouldShowSyncedTabsSuggestions
},
showSessionSuggestions = when (action.settings.showUnifiedSearchFeature) {
true -> false
false -> true
},
)
is SearchFragmentAction.SearchHistoryEngineSelected ->
state.copy(
searchEngineSource = SearchEngineSource.History(action.engine),
showSearchSuggestions = false,
showSearchShortcuts = false,
showClipboardSuggestions = false,
showHistorySuggestions = true,
showBookmarkSuggestions = false,
showSyncedTabsSuggestions = false,
showSessionSuggestions = false,
)
is SearchFragmentAction.ShowSearchShortcutEnginePicker ->
state.copy(showSearchShortcuts = action.show && state.areShortcutsAvailable)
@ -167,11 +265,14 @@ private fun searchStateReducer(state: SearchFragmentState, action: SearchFragmen
showSearchShortcuts = state.url.isEmpty() &&
state.showSearchShortcutsSetting &&
action.search.searchEngines.size > 1,
searchEngineSource = if (state.searchEngineSource !is SearchEngineSource.Shortcut) {
action.search.selectedOrDefaultSearchEngine?.let { SearchEngineSource.Default(it) }
?: SearchEngineSource.None
} else {
state.searchEngineSource
searchEngineSource = when (state.searchEngineSource) {
is SearchEngineSource.Shortcut, is SearchEngineSource.History -> {
state.searchEngineSource
}
else -> {
action.search.selectedOrDefaultSearchEngine?.let { SearchEngineSource.Default(it) }
?: SearchEngineSource.None
}
}
)
}

@ -28,6 +28,8 @@ import mozilla.components.support.ktx.android.content.getColorFromAttr
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.Core.Companion.METADATA_HISTORY_SUGGESTION_LIMIT
import org.mozilla.fenix.components.Core.Companion.METADATA_SHORTCUT_SUGGESTION_LIMIT
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.search.SearchEngineSource
@ -53,7 +55,6 @@ class AwesomeBarView(
private val defaultSearchActionProvider: SearchActionProvider
private val searchEngineSuggestionProvider: SearchEngineSuggestionProvider
private val searchSuggestionProviderMap: MutableMap<SearchEngine, List<AwesomeBar.SuggestionProvider>>
private var providersInUse = mutableSetOf<AwesomeBar.SuggestionProvider>()
private val loadUrlUseCase = object : SessionUseCases.LoadUrlUseCase {
override fun invoke(
@ -213,33 +214,15 @@ class AwesomeBarView(
fun updateSuggestionProvidersVisibility(
state: SearchProviderState
) {
view.removeAllProviders()
if (state.showSearchShortcuts) {
handleDisplayShortcutsProviders()
return
}
val providersToAdd = getProvidersToAdd(state)
val providersToRemove = getProvidersToRemove(state)
performProviderListChanges(providersToAdd, providersToRemove)
}
private fun performProviderListChanges(
providersToAdd: MutableSet<AwesomeBar.SuggestionProvider>,
providersToRemove: MutableSet<AwesomeBar.SuggestionProvider>
) {
for (provider in providersToAdd) {
if (providersInUse.find { it.id == provider.id } == null) {
providersInUse.add(provider)
view.addProviders(provider)
}
}
for (provider in providersToRemove) {
if (providersInUse.find { it.id == provider.id } != null) {
providersInUse.remove(provider)
view.removeProviders(provider)
}
for (provider in getProvidersToAdd(state)) {
view.addProviders(provider)
}
}
@ -249,6 +232,17 @@ class AwesomeBarView(
): MutableSet<AwesomeBar.SuggestionProvider> {
val providersToAdd = mutableSetOf<AwesomeBar.SuggestionProvider>()
when (state.searchEngineSource) {
is SearchEngineSource.History -> {
combinedHistoryProvider.setMaxNumberOfSuggestions(METADATA_HISTORY_SUGGESTION_LIMIT)
historyStorageProvider.setMaxNumberOfSuggestions(METADATA_HISTORY_SUGGESTION_LIMIT)
}
else -> {
combinedHistoryProvider.setMaxNumberOfSuggestions(METADATA_SUGGESTION_LIMIT)
historyStorageProvider.setMaxNumberOfSuggestions(METADATA_SUGGESTION_LIMIT)
}
}
if (state.showHistorySuggestions) {
if (activity.settings().historyMetadataUIFeature) {
providersToAdd.add(combinedHistoryProvider)
@ -269,45 +263,15 @@ class AwesomeBarView(
providersToAdd.add(syncedTabsStorageSuggestionProvider)
}
if (activity.browsingModeManager.mode == BrowsingMode.Normal) {
if (activity.browsingModeManager.mode == BrowsingMode.Normal && state.showSessionSuggestions) {
providersToAdd.add(sessionProvider)
}
providersToAdd.add(searchEngineSuggestionProvider)
return providersToAdd
}
private fun getProvidersToRemove(state: SearchProviderState): MutableSet<AwesomeBar.SuggestionProvider> {
val providersToRemove = mutableSetOf<AwesomeBar.SuggestionProvider>()
providersToRemove.add(shortcutsEnginePickerProvider)
if (!state.showHistorySuggestions) {
if (activity.settings().historyMetadataUIFeature) {
providersToRemove.add(combinedHistoryProvider)
} else {
providersToRemove.add(historyStorageProvider)
}
}
if (!state.showBookmarkSuggestions) {
providersToRemove.add(bookmarksStorageSuggestionProvider)
if (!activity.settings().showUnifiedSearchFeature) {
providersToAdd.add(searchEngineSuggestionProvider)
}
if (!state.showSearchSuggestions) {
providersToRemove.addAll(getSelectedSearchSuggestionProvider(state))
}
if (!state.showSyncedTabsSuggestions) {
providersToRemove.add(syncedTabsStorageSuggestionProvider)
}
if (activity.browsingModeManager.mode == BrowsingMode.Private) {
providersToRemove.add(sessionProvider)
}
return providersToRemove
return providersToAdd
}
private fun getSelectedSearchSuggestionProvider(state: SearchProviderState): List<AwesomeBar.SuggestionProvider> {
@ -319,14 +283,12 @@ class AwesomeBarView(
is SearchEngineSource.Shortcut -> getSuggestionProviderForEngine(
state.searchEngineSource.searchEngine
)
is SearchEngineSource.History -> emptyList()
is SearchEngineSource.None -> emptyList()
}
}
private fun handleDisplayShortcutsProviders() {
view.removeAllProviders()
providersInUse.clear()
providersInUse.add(shortcutsEnginePickerProvider)
view.addProviders(shortcutsEnginePickerProvider)
}
@ -355,7 +317,11 @@ class AwesomeBarView(
engine,
shortcutSearchUseCase,
components.core.client,
limit = 3,
limit = if (activity.settings().showUnifiedSearchFeature) {
METADATA_SHORTCUT_SUGGESTION_LIMIT
} else {
METADATA_SUGGESTION_LIMIT
},
mode = SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS,
icon = searchBitmap,
engine = engineForSpeculativeConnects,
@ -375,11 +341,12 @@ class AwesomeBarView(
val showBookmarkSuggestions: Boolean,
val showSearchSuggestions: Boolean,
val showSyncedTabsSuggestions: Boolean,
val showSessionSuggestions: Boolean,
val searchEngineSource: SearchEngineSource
)
companion object {
// Maximum number of suggestions returned from the history metadata storage.
// Maximum number of suggestions returned.
const val METADATA_SUGGESTION_LIMIT = 3
}
}
@ -390,5 +357,6 @@ fun SearchFragmentState.toSearchProviderState() = AwesomeBarView.SearchProviderS
showBookmarkSuggestions,
showSearchSuggestions,
showSyncedTabsSuggestions,
showSessionSuggestions,
searchEngineSource
)

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:name="path"
android:fillColor="#FFFFFF"
android:pathData="M 2 0 L 22 0 C 22.53 0 23.039 0.211 23.414 0.586 C 23.789 0.961 24 1.47 24 2 L 24 22 C 24 22.53 23.789 23.039 23.414 23.414 C 23.039 23.789 22.53 24 22 24 L 2 24 C 1.47 24 0.961 23.789 0.586 23.414 C 0.211 23.039 0 22.53 0 22 L 0 2 C 0 1.47 0.211 0.961 0.586 0.586 C 0.961 0.211 1.47 0 2 0"
android:strokeWidth="1" />
<path
android:fillColor="#000000"
android:pathData="M11.974 21.5c-5.238 0-9.5-4.262-9.5-9.5s4.262-9.5 9.5-9.5 9.5 4.262 9.5 9.5-4.262 9.5-9.5 9.5zm0-17.5c-4.411 0-8 3.589-8 8s3.589 8 8 8 8-3.589 8-8-3.589-8-8-8z" />
<path
android:fillColor="#000000"
android:pathData="M15.414 14.948a0.748 0.748 0 0 1-0.385-0.106l-3.664-2.198L11 12V7.75a0.75 0.75 0 0 1 1.5 0v3.825l3.3 1.979a0.75 0.75 0 0 1-0.386 1.394z" />
</vector>

@ -14,7 +14,7 @@
android:layout_height="28dp"
android:layout_marginTop="14dp"
android:layout_marginHorizontal="8dp"
app:cardBackgroundColor="?attr/layer2"
app:cardBackgroundColor="@color/photonWhite"
app:cardCornerRadius="4dp"
app:cardElevation="0dp">
@ -43,6 +43,7 @@
android:layout_height="6dp"
android:importantForAccessibility="no"
app:srcCompat="@drawable/ic_chevron_down_6"
app:tint="@color/photonBlack"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />

@ -44,7 +44,7 @@
<!-- Label for enabling the Task Continuity feature -->
<string name="preferences_debug_settings_task_continuity" translatable="false">Enable Task Continuity</string>
<!-- Label for enabling the Unified Search feature -->
<string name="preferences_debug_settings_unified_search" translatable="false">Enable Unified Search</string>
<string name="preferences_debug_settings_unified_search" translatable="false">Enable Unified Search (requires restart)</string>
<!-- A secret menu option in the tabs tray for making a tab inactive for testing. -->
<string name="inactive_tabs_menu_item">Make inactive</string>

@ -43,6 +43,7 @@ import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.SearchShortcuts
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Core
import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.search.SearchDialogFragmentDirections.Companion.actionGlobalAddonsManagementFragment
@ -76,6 +77,7 @@ class SearchDialogControllerTest {
)
every { store.state.tabId } returns "test-tab-id"
every { store.state.searchEngineSource.searchEngine } returns searchEngine
every { searchEngine.type } returns SearchEngine.Type.BUNDLED
every { navController.currentDestination } returns mockk {
every { id } returns R.id.searchDialogFragment
}
@ -139,6 +141,31 @@ class SearchDialogControllerTest {
}
}
@Test
fun `WHEN the search engine is added by the application THEN do not load URL`() {
every { searchEngine.type } returns SearchEngine.Type.APPLICATION
val searchTerm = "Firefox"
var dismissDialogInvoked = false
createController(
dismissDialog = {
dismissDialogInvoked = true
}
).handleUrlCommitted(searchTerm)
verify(exactly = 0) {
activity.openToBrowserAndLoad(
searchTermOrURL = any(),
newTab = any(),
from = any(),
engine = any()
)
}
assertFalse(dismissDialogInvoked)
}
@Test
fun handleCrashesUrlCommitted() {
val url = "about:crashes"
@ -319,7 +346,7 @@ class SearchDialogControllerTest {
).handleSearchShortcutEngineSelected(searchEngine)
assertTrue(focusToolbarInvoked)
verify { store.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine)) }
verify { store.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine, settings)) }
assertTrue(SearchShortcuts.selected.testHasValue())
val recordedEvents = SearchShortcuts.selected.testGetValue()
@ -330,6 +357,31 @@ class SearchDialogControllerTest {
assertEquals(searchEngine.name, eventExtra["engine"])
}
@Test
fun `WHEN history search engine is selected THEN dispatch correct action`() {
val searchEngine: SearchEngine = mockk(relaxed = true)
every { searchEngine.type } returns SearchEngine.Type.APPLICATION
every { searchEngine.id } returns Core.HISTORY_SEARCH_ENGINE_ID
var focusToolbarInvoked = false
createController(
focusToolbar = {
focusToolbarInvoked = true
}
).handleSearchShortcutEngineSelected(searchEngine)
assertTrue(focusToolbarInvoked)
verify { store.dispatch(SearchFragmentAction.SearchHistoryEngineSelected(searchEngine)) }
assertTrue(SearchShortcuts.selected.testHasValue())
val recordedEvents = SearchShortcuts.selected.testGetValue()
assertEquals(1, recordedEvents.size)
val eventExtra = recordedEvents.single().extra
assertNotNull(eventExtra)
assertTrue(eventExtra!!.containsKey("engine"))
assertEquals("application", eventExtra["engine"])
}
@Test
fun handleClickSearchEngineSettings() {
val directions: NavDirections = actionGlobalSearchEngineFragment()

@ -23,6 +23,7 @@ import org.junit.Assert.assertNotSame
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
@ -68,6 +69,7 @@ class SearchFragmentStoreTest {
showHistorySuggestions = false,
showBookmarkSuggestions = false,
showSyncedTabsSuggestions = false,
showSessionSuggestions = true,
tabId = null,
pastedText = "pastedText",
searchAccessPoint = MetricsUtils.Source.ACTION
@ -126,6 +128,7 @@ class SearchFragmentStoreTest {
showHistorySuggestions = false,
showBookmarkSuggestions = false,
showSyncedTabsSuggestions = false,
showSessionSuggestions = true,
tabId = "tabId",
pastedText = "",
searchAccessPoint = MetricsUtils.Source.SHORTCUT
@ -156,12 +159,22 @@ class SearchFragmentStoreTest {
val initialState = emptyDefaultState()
val store = SearchFragmentStore(initialState)
store.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine)).join()
store.dispatch(SearchFragmentAction.SearchShortcutEngineSelected(searchEngine, settings)).join()
assertNotSame(initialState, store.state)
assertEquals(SearchEngineSource.Shortcut(searchEngine), store.state.searchEngineSource)
assertEquals(false, store.state.showSearchShortcuts)
}
@Test
fun `WHEN history engine selected action dispatched THEN update search engine source`() = runTest {
val initialState = emptyDefaultState()
val store = SearchFragmentStore(initialState)
store.dispatch(SearchFragmentAction.SearchHistoryEngineSelected(searchEngine)).join()
assertNotSame(initialState, store.state)
assertEquals(SearchEngineSource.History(searchEngine), store.state.searchEngineSource)
}
@Test
fun showSearchShortcutEnginePicker() = runTest {
val initialState = emptyDefaultState()
@ -213,6 +226,7 @@ class SearchFragmentStoreTest {
}
@Test
@Ignore("Flaky, needs investigation: https://github.com/mozilla-mobile/fenix/issues/25170")
fun `Updating SearchFragmentState from SearchState`() = runTest {
val store = SearchFragmentStore(
emptyDefaultState(
@ -270,6 +284,7 @@ class SearchFragmentStoreTest {
}
@Test
@Ignore("Flaky, needs investigation: https://github.com/mozilla-mobile/fenix/issues/25170")
fun `Updating SearchFragmentState from SearchState - shortcuts disabled`() = runTest {
val store = SearchFragmentStore(
emptyDefaultState(
@ -347,6 +362,7 @@ class SearchFragmentStoreTest {
showHistorySuggestions = false,
showBookmarkSuggestions = false,
showSyncedTabsSuggestions = false,
showSessionSuggestions = false,
searchAccessPoint = MetricsUtils.Source.NONE
)
}

@ -57,6 +57,7 @@ class ToolbarViewTest {
showHistorySuggestions = false,
showBookmarkSuggestions = false,
showSyncedTabsSuggestions = false,
showSessionSuggestions = false,
searchAccessPoint = MetricsUtils.Source.NONE
)

@ -361,15 +361,6 @@
<ID>UndocumentedPublicClass:SearchEngineMenu.kt$SearchEngineMenu$Item</ID>
<ID>UndocumentedPublicClass:SearchEngineMenu.kt$SearchEngineMenu.Item$Delete : Item</ID>
<ID>UndocumentedPublicClass:SearchEngineMenu.kt$SearchEngineMenu.Item$Edit : Item</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchEngineSource$Default : SearchEngineSource</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchEngineSource$None : SearchEngineSource</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchEngineSource$Shortcut : SearchEngineSource</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchFragmentAction$AllowSearchSuggestionsInPrivateModePrompt : SearchFragmentAction</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchFragmentAction$SearchShortcutEngineSelected : SearchFragmentAction</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchFragmentAction$SetShowSearchSuggestions : SearchFragmentAction</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchFragmentAction$ShowSearchShortcutEnginePicker : SearchFragmentAction</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchFragmentAction$UpdateClipboardHasUrl : SearchFragmentAction</ID>
<ID>UndocumentedPublicClass:SearchFragmentStore.kt$SearchFragmentAction$UpdateQuery : SearchFragmentAction</ID>
<ID>UndocumentedPublicClass:SearchStringValidator.kt$SearchStringValidator</ID>
<ID>UndocumentedPublicClass:SearchStringValidator.kt$SearchStringValidator$Result</ID>
<ID>UndocumentedPublicClass:SearchWidgetProvider.kt$SearchWidgetProvider : AppWidgetProvider</ID>

Loading…
Cancel
Save