Bug 1831497 - [a11y] Dictate correct hint when selecting engine

In order for talkback to correctly dictate the hint for a newly
selected search engine in the search toolbar, it required setting
it when updating the content description of the toolbar.
Previously, when updating the content description, it was using
the previous search engine hint.
fenix/115.2.0
DreVla 1 year ago committed by mergify[bot]
parent d5cb470591
commit 934e3371bf

@ -79,6 +79,7 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Core.Companion.BOOKMARKS_SEARCH_ENGINE_ID
import org.mozilla.fenix.components.Core.Companion.HISTORY_SEARCH_ENGINE_ID
import org.mozilla.fenix.components.Core.Companion.TABS_SEARCH_ENGINE_ID
import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.databinding.FragmentSearchDialogBinding
import org.mozilla.fenix.databinding.SearchSuggestionsHintBinding
@ -106,8 +107,10 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
@VisibleForTesting internal lateinit var interactor: SearchDialogInteractor
private lateinit var store: SearchDialogFragmentStore
private lateinit var toolbarView: ToolbarView
private lateinit var inlineAutocompleteEditText: InlineAutocompleteEditText
@VisibleForTesting internal lateinit var toolbarView: ToolbarView
@VisibleForTesting internal lateinit var inlineAutocompleteEditText: InlineAutocompleteEditText
private lateinit var awesomeBarView: AwesomeBarView
private lateinit var startForResult: ActivityResultLauncher<Intent>
@ -478,7 +481,10 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
consumeFrom(store) {
updateSearchSuggestionsHintVisibility(it)
updateToolbarContentDescription(it.searchEngineSource)
updateToolbarContentDescription(
it.searchEngineSource.searchEngine,
it.searchEngineSource.searchEngine == it.defaultEngine,
)
toolbarView.update(it)
awesomeBarView.update(it)
@ -949,10 +955,35 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
}
}
private fun updateToolbarContentDescription(source: SearchEngineSource) {
source.searchEngine?.let { engine ->
toolbarView.view.contentDescription = engine.name + ", " + inlineAutocompleteEditText.hint
// investigate when engine is null
@VisibleForTesting
internal fun updateToolbarContentDescription(
engine: SearchEngine?,
selectedOrDefaultSearchEngine: Boolean,
) {
val hint = when (engine?.type) {
null -> requireContext().getString(R.string.search_hint)
SearchEngine.Type.APPLICATION ->
when (engine.id) {
HISTORY_SEARCH_ENGINE_ID -> requireContext().getString(R.string.history_search_hint)
BOOKMARKS_SEARCH_ENGINE_ID -> requireContext().getString(R.string.bookmark_search_hint)
TABS_SEARCH_ENGINE_ID -> requireContext().getString(R.string.tab_search_hint)
else -> requireContext().getString(R.string.application_search_hint)
}
else -> {
if (!engine.isGeneral) {
requireContext().getString(R.string.application_search_hint)
} else {
if (selectedOrDefaultSearchEngine) {
requireContext().getString(R.string.search_hint)
} else {
requireContext().getString(R.string.search_hint_general_engine)
}
}
}
}
inlineAutocompleteEditText.hint = hint
toolbarView.view.contentDescription = engine?.name + ", " + hint
inlineAutocompleteEditText.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
}

@ -10,7 +10,6 @@ import android.graphics.drawable.BitmapDrawable
import androidx.annotation.VisibleForTesting
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.toolbar.Toolbar
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
@ -19,7 +18,6 @@ import mozilla.components.support.ktx.android.content.res.resolveAttribute
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.Core
import org.mozilla.fenix.search.SearchEngineSource
import org.mozilla.fenix.search.SearchFragmentState
import org.mozilla.fenix.utils.Settings
@ -160,28 +158,6 @@ class ToolbarView(
val searchEngine = searchState.searchEngineSource.searchEngine
view.edit.hint = when (searchEngine?.type) {
null -> context.getString(R.string.search_hint)
SearchEngine.Type.APPLICATION ->
when (searchEngine.id) {
Core.HISTORY_SEARCH_ENGINE_ID -> context.getString(R.string.history_search_hint)
Core.BOOKMARKS_SEARCH_ENGINE_ID -> context.getString(R.string.bookmark_search_hint)
Core.TABS_SEARCH_ENGINE_ID -> context.getString(R.string.tab_search_hint)
else -> context.getString(R.string.application_search_hint)
}
else -> {
if (!searchEngine.isGeneral) {
context.getString(R.string.application_search_hint)
} else {
if (searchEngine == searchState.defaultEngine) {
context.getString(R.string.search_hint)
} else {
context.getString(R.string.search_hint_general_engine)
}
}
}
}
if (!settings.showUnifiedSearchFeature && searchEngine != null) {
val iconSize =
context.resources.getDimensionPixelSize(R.dimen.preference_icon_drawable_size)

@ -18,16 +18,18 @@ import io.mockk.spyk
import io.mockk.verify
import mozilla.components.browser.domains.autocomplete.BaseDomainAutocompleteProvider
import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.state.state.SearchState
import mozilla.components.browser.state.state.searchEngines
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.browser.toolbar.edit.EditToolbar
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.toolbar.Toolbar
import mozilla.components.feature.awesomebar.provider.SessionAutocompleteProvider
import mozilla.components.feature.syncedtabs.SyncedTabsAutocompleteProvider
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.ui.autocomplete.InlineAutocompleteEditText
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
@ -41,8 +43,10 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.Core
import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.search.SearchDialogFragment
import org.mozilla.fenix.search.SearchEngineSource
import org.mozilla.fenix.search.SearchFragmentState
import org.mozilla.fenix.utils.Settings
@ -53,7 +57,6 @@ class ToolbarViewTest {
@MockK(relaxed = true)
private lateinit var interactor: ToolbarInteractor
@MockK private lateinit var engine: Engine
private lateinit var context: Context
private lateinit var toolbar: BrowserToolbar
private val defaultState: SearchFragmentState = SearchFragmentState(
@ -213,142 +216,220 @@ class ToolbarViewTest {
fun `WHEN the default general search engine is selected THEN show text for default engine`() {
val toolbarView = buildToolbarView(false)
val defaultEngine = buildSearchEngine(SearchEngine.Type.BUNDLED, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint)
val expectedContentDescription = defaultEngine.name + ", " + context.getString(R.string.search_hint)
toolbarView.update(
defaultState.copy(
defaultEngine = defaultEngine,
searchEngineSource = SearchEngineSource.Default(defaultEngine),
),
)
every { fragment.requireContext().getString(R.string.search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns defaultEngine.id
every { searchState.searchEngines } returns listOf(defaultEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
assertEquals(context.getString(R.string.search_hint), toolbarView.view.edit.hint)
fragment.updateToolbarContentDescription(defaultEngine, true)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a general search engine is selected THEN show text for general engine`() {
fun `WHEN a general search engine is selected THEN show hint for general engine`() {
val toolbarView = buildToolbarView(false)
val generalEngine = buildSearchEngine(SearchEngine.Type.BUNDLED, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint_general_engine)
val expectedContentDescription = generalEngine.name + ", " + context.getString(R.string.search_hint_general_engine)
toolbarView.update(
defaultState.copy(
searchEngineSource = SearchEngineSource.Shortcut(generalEngine),
),
)
every { fragment.requireContext().getString(R.string.search_hint_general_engine) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns generalEngine.id
every { searchState.searchEngines } returns listOf(generalEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(generalEngine, false)
assertEquals(context.getString(R.string.search_hint_general_engine), toolbarView.view.edit.hint)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a topic specific search engine is selected THEN show text for topic specific engine`() {
fun `WHEN a topic specific search engine is selected THEN show hint for topic specific engine`() {
val toolbarView = buildToolbarView(false)
val topicSpecificEngine = buildSearchEngine(SearchEngine.Type.BUNDLED, false)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.application_search_hint)
val expectedContentDescription = topicSpecificEngine.name + ", " + context.getString(R.string.application_search_hint)
toolbarView.update(
defaultState.copy(
searchEngineSource = SearchEngineSource.Shortcut(topicSpecificEngine),
),
)
every { fragment.requireContext().getString(R.string.application_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns topicSpecificEngine.id
every { searchState.searchEngines } returns listOf(topicSpecificEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
assertEquals(context.getString(R.string.application_search_hint), toolbarView.view.edit.hint)
fragment.updateToolbarContentDescription(topicSpecificEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN the default additional general search engine is selected THEN show text for default engine`() {
fun `WHEN the default additional general search engine is selected THEN show hint for default engine`() {
val toolbarView = buildToolbarView(false)
val defaultEngine = buildSearchEngine(SearchEngine.Type.BUNDLED_ADDITIONAL, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint)
val expectedContentDescription = defaultEngine.name + ", " + context.getString(R.string.search_hint)
toolbarView.update(
defaultState.copy(
defaultEngine = defaultEngine,
searchEngineSource = SearchEngineSource.Default(defaultEngine),
),
)
every { fragment.requireContext().getString(R.string.search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns defaultEngine.id
every { searchState.searchEngines } returns listOf(defaultEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(defaultEngine, true)
assertEquals(context.getString(R.string.search_hint), toolbarView.view.edit.hint)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a general additional search engine is selected THEN show text for general engine`() {
fun `WHEN a general additional search engine is selected THEN show hint for general engine`() {
val toolbarView = buildToolbarView(false)
val generalEngine = buildSearchEngine(SearchEngine.Type.BUNDLED_ADDITIONAL, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint_general_engine)
val expectedContentDescription = generalEngine.name + ", " + context.getString(R.string.search_hint_general_engine)
toolbarView.update(
defaultState.copy(
searchEngineSource = SearchEngineSource.Shortcut(generalEngine),
),
)
every { fragment.requireContext().getString(R.string.search_hint_general_engine) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns generalEngine.id
every { searchState.searchEngines } returns listOf(generalEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(generalEngine, false)
assertEquals(context.getString(R.string.search_hint_general_engine), toolbarView.view.edit.hint)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN the default custom search engine is selected THEN show text for default engine`() {
fun `WHEN the default custom search engine is selected THEN show hint for default engine`() {
val toolbarView = buildToolbarView(false)
val customEngine = buildSearchEngine(SearchEngine.Type.CUSTOM, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint)
val expectedContentDescription = customEngine.name + ", " + context.getString(R.string.search_hint)
toolbarView.update(
defaultState.copy(
defaultEngine = customEngine,
searchEngineSource = SearchEngineSource.Default(customEngine),
),
)
every { fragment.requireContext().getString(R.string.search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns customEngine.id
every { searchState.searchEngines } returns listOf(customEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
assertEquals(context.getString(R.string.search_hint), toolbarView.view.edit.hint)
fragment.updateToolbarContentDescription(customEngine, true)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN a custom search engine is selected THEN show text for general engine`() {
fun `WHEN a custom search engine is selected THEN show hint for general engine`() {
val toolbarView = buildToolbarView(false)
val customEngine = buildSearchEngine(SearchEngine.Type.CUSTOM, true)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.search_hint_general_engine)
val expectedContentDescription = customEngine.name + ", " + context.getString(R.string.search_hint_general_engine)
toolbarView.update(
defaultState.copy(
searchEngineSource = SearchEngineSource.Shortcut(customEngine),
),
)
every { fragment.requireContext().getString(R.string.search_hint_general_engine) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns customEngine.id
every { searchState.searchEngines } returns listOf(customEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(customEngine, false)
assertEquals(context.getString(R.string.search_hint_general_engine), toolbarView.view.edit.hint)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN history is selected as engine THEN show text specific for history`() {
fun `WHEN history is selected as engine THEN show hint specific for history`() {
val toolbarView = buildToolbarView(false)
val historyEngine = buildSearchEngine(SearchEngine.Type.APPLICATION, false, Core.HISTORY_SEARCH_ENGINE_ID)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.history_search_hint)
val expectedContentDescription = historyEngine.name + ", " + context.getString(R.string.history_search_hint)
toolbarView.update(
defaultState.copy(
searchEngineSource = SearchEngineSource.Shortcut(historyEngine),
),
)
every { fragment.requireContext().getString(R.string.history_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns historyEngine.id
every { searchState.searchEngines } returns listOf(historyEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
assertEquals(context.getString(R.string.history_search_hint), toolbarView.view.edit.hint)
fragment.updateToolbarContentDescription(historyEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN bookmarks is selected as engine THEN show text specific for bookmarks`() {
fun `WHEN bookmarks is selected as engine THEN show hint specific for bookmarks`() {
val toolbarView = buildToolbarView(false)
val bookmarksEngine = buildSearchEngine(SearchEngine.Type.APPLICATION, false, Core.BOOKMARKS_SEARCH_ENGINE_ID)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.bookmark_search_hint)
val expectedContentDescription = bookmarksEngine.name + ", " + context.getString(R.string.bookmark_search_hint)
toolbarView.update(
defaultState.copy(
searchEngineSource = SearchEngineSource.Shortcut(bookmarksEngine),
),
)
every { fragment.requireContext().getString(R.string.bookmark_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns bookmarksEngine.id
every { searchState.searchEngines } returns listOf(bookmarksEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(bookmarksEngine, false)
assertEquals(context.getString(R.string.bookmark_search_hint), toolbarView.view.edit.hint)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test
fun `WHEN tabs is selected as engine THEN show text specific for tabs`() {
fun `WHEN tabs is selected as engine THEN show hint specific for tabs`() {
val toolbarView = buildToolbarView(false)
val tabsEngine = buildSearchEngine(SearchEngine.Type.APPLICATION, false, Core.TABS_SEARCH_ENGINE_ID)
toolbarView.update(
defaultState.copy(
searchEngineSource = SearchEngineSource.Shortcut(tabsEngine),
),
)
assertEquals(context.getString(R.string.tab_search_hint), toolbarView.view.edit.hint)
val fragment = spyk(SearchDialogFragment())
fragment.inlineAutocompleteEditText = InlineAutocompleteEditText(context)
val searchState = mockk<SearchState>()
val expectedHint = context.getString(R.string.tab_search_hint)
val expectedContentDescription = tabsEngine.name + ", " + context.getString(R.string.tab_search_hint)
every { fragment.requireContext().getString(R.string.tab_search_hint) } returns expectedHint
every { searchState.userSelectedSearchEngineId } returns tabsEngine.id
every { searchState.searchEngines } returns listOf(tabsEngine)
every { fragment.toolbarView } returns toolbarView
every { fragment.requireComponents.core.store.state.search } returns searchState
fragment.updateToolbarContentDescription(tabsEngine, false)
assertEquals(expectedHint, fragment.inlineAutocompleteEditText.hint)
assertEquals(expectedContentDescription, toolbarView.view.contentDescription)
}
@Test

Loading…
Cancel
Save