diff --git a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 7a92205f8..7c538047b 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -33,7 +33,6 @@ import mozilla.components.browser.session.Session import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.runWithSessionIdOrSelected import mozilla.components.concept.engine.prompt.ShareData -import mozilla.components.feature.accounts.FxaCapability import mozilla.components.feature.accounts.FxaWebChannelFeature import mozilla.components.feature.app.links.AppLinksFeature import mozilla.components.feature.contextmenu.ContextMenuCandidate @@ -482,7 +481,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session view.swipeRefresh.setOnChildScrollUpCallback { _, _ -> true } } - @Suppress("ConstantConditionIf") + // @Suppress("ConstantConditionIf") + /* if (!FeatureFlags.asFeatureWebChannelsDisabled) { webchannelIntegration.set( feature = FxaWebChannelFeature( @@ -499,6 +499,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session ) } + */ + initializeEngineView(toolbarHeight) } } diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt index 118e0adcf..2b97ade35 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragment.kt @@ -5,17 +5,22 @@ package org.mozilla.fenix.search import android.Manifest +import android.app.Activity.RESULT_OK import android.content.Context import android.content.DialogInterface +import android.content.Intent import android.graphics.Typeface.BOLD import android.graphics.Typeface.ITALIC import android.os.Bundle +import android.speech.RecognizerIntent +import android.speech.RecognizerIntent.EXTRA_RESULTS import android.text.style.StyleSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.ViewStub import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -25,6 +30,7 @@ import kotlinx.android.synthetic.main.fragment_search.* import kotlinx.android.synthetic.main.fragment_search.view.* import kotlinx.android.synthetic.main.search_suggestions_onboarding.view.* import kotlinx.coroutines.ExperimentalCoroutinesApi +import mozilla.components.browser.toolbar.BrowserToolbar import mozilla.components.concept.storage.HistoryStorage import mozilla.components.feature.qr.QrFeature import mozilla.components.lib.state.ext.consumeFrom @@ -47,6 +53,7 @@ import org.mozilla.fenix.ext.settings import org.mozilla.fenix.search.awesomebar.AwesomeBarView import org.mozilla.fenix.search.toolbar.ToolbarView import org.mozilla.fenix.settings.SupportUtils +import org.mozilla.fenix.widget.VoiceSearchActivity.Companion.SPEECH_REQUEST_CODE @Suppress("TooManyFunctions", "LargeClass") class SearchFragment : Fragment(), UserInteractionHandler { @@ -127,6 +134,14 @@ class SearchFragment : Fragment(), UserInteractionHandler { requireComponents.core.engine ) + toolbarView.view.addEditAction( + BrowserToolbar.Button( + ContextCompat.getDrawable(requireContext(), R.drawable.ic_microphone)!!, + requireContext().getString(R.string.voice_search_content_description), + visible = { requireContext().settings().shouldShowVoiceSearch }, + listener = ::launchVoiceSearch + ) + ) val urlView = toolbarView.view .findViewById(R.id.mozac_browser_toolbar_edit_url_view) urlView?.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO @@ -136,6 +151,14 @@ class SearchFragment : Fragment(), UserInteractionHandler { return view } + private fun launchVoiceSearch() { + val speechIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply { + putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM) + putExtra(RecognizerIntent.EXTRA_PROMPT, requireContext().getString(R.string.voice_search_explainer)) + } + startActivityForResult(speechIntent, SPEECH_REQUEST_CODE) + } + private fun clearToolbarFocus() { toolbarView.view.clearFocus() } @@ -274,7 +297,7 @@ class SearchFragment : Fragment(), UserInteractionHandler { } if (!permissionDidUpdate) { - toolbarView.view.requestFocus() + toolbarView.view.edit.focus() } updateClipboardSuggestion( @@ -286,6 +309,16 @@ class SearchFragment : Fragment(), UserInteractionHandler { hideToolbar() } + override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { + if (requestCode == 0 && resultCode == RESULT_OK) { + intent?.getStringArrayListExtra(EXTRA_RESULTS)?.first()?.also { + toolbarView.view.edit.updateUrl(url = it, shouldHighlight = true) + searchInteractor.onTextChanged(it) + toolbarView.view.edit.focus() + } + } + } + override fun onPause() { super.onPause() toolbarView.view.clearFocus() @@ -295,6 +328,7 @@ class SearchFragment : Fragment(), UserInteractionHandler { // Note: Actual navigation happens in `handleEditingCancelled` in SearchController return when { qrFeature.onBackPressed() -> { + toolbarView.view.edit.focus() view?.search_scan_button?.isChecked = false toolbarView.view.requestFocus() } diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt index 7893054c9..3b2b7ebfa 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt @@ -60,6 +60,11 @@ class SearchEngineFragment : PreferenceFragmentCompat() { val searchEngineListPreference = findPreference(getPreferenceKey(R.string.pref_key_search_engine_list)) + val showVoiceSearchPreference = + findPreference(getPreferenceKey(R.string.pref_key_show_voice_search))?.apply { + isChecked = context.settings().shouldShowVoiceSearch + } + searchEngineListPreference?.reload(requireContext()) searchSuggestionsPreference?.onPreferenceChangeListener = SharedPreferenceUpdater() showSearchShortcuts?.onPreferenceChangeListener = SharedPreferenceUpdater() @@ -67,6 +72,7 @@ class SearchEngineFragment : PreferenceFragmentCompat() { showBookmarkSuggestions?.onPreferenceChangeListener = SharedPreferenceUpdater() showClipboardSuggestions?.onPreferenceChangeListener = SharedPreferenceUpdater() searchSuggestionsInPrivatePreference?.onPreferenceChangeListener = SharedPreferenceUpdater() + showVoiceSearchPreference?.onPreferenceChangeListener = SharedPreferenceUpdater() searchSuggestionsPreference?.setOnPreferenceClickListener { if (!searchSuggestionsPreference.isChecked) { diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index 0e1744ce0..af0ba9b53 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -545,6 +545,11 @@ class Settings private constructor( } } + var shouldShowVoiceSearch by booleanPreference( + appContext.getPreferenceKey(R.string.pref_key_show_voice_search), + default = true + ) + var shouldPromptToSaveLogins by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_save_logins), default = true diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 378287639..40ddb391d 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -87,6 +87,7 @@ pref_key_search_bookmarks pref_key_show_search_suggestions_in_private pref_key_show_search_suggestions_in_privateonboarding + pref_key_show_voice_search diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8075b4f30..7301dde35 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -248,6 +248,8 @@ Show search shortcuts Show search suggestions + + Show voice search Show in private sessions @@ -1360,4 +1362,8 @@ Edit Password required + + Voice search + + Speak now diff --git a/app/src/main/res/xml/search_preferences.xml b/app/src/main/res/xml/search_preferences.xml index c8b707d5c..7a2e6e285 100644 --- a/app/src/main/res/xml/search_preferences.xml +++ b/app/src/main/res/xml/search_preferences.xml @@ -51,6 +51,12 @@ android:title="@string/preferences_show_search_suggestions" app:iconSpaceReserved="false" app:allowDividerAbove="false"/> +