Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
For #26329 Refactor the search widget to use the A-C common behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
iorgamgabriel committed Aug 18, 2022
1 parent 765c3e0 commit 5494021
Show file tree
Hide file tree
Showing 21 changed files with 70 additions and 815 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.feature.search.ext.waitForSelectedOrDefaultSearchEngine
import mozilla.components.feature.search.widget.BaseVoiceSearchActivity.Companion.SPEECH_PROCESSING
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.components.metrics.MetricsUtils
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.widget.VoiceSearchActivity.Companion.SPEECH_PROCESSING

/**
* The search widget has a microphone button to let users search with their voice.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
Expand Down Expand Up @@ -88,7 +87,6 @@ import org.mozilla.fenix.search.toolbar.SearchSelectorMenu
import org.mozilla.fenix.search.toolbar.SearchSelectorToolbarAction
import org.mozilla.fenix.search.toolbar.ToolbarView
import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.widget.VoiceSearchActivity

typealias SearchDialogFragmentStore = SearchFragmentStore

Expand Down Expand Up @@ -549,7 +547,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
}

override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
if (requestCode == VoiceSearchActivity.SPEECH_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
if (requestCode == SPEECH_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
intent?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)?.first()?.also {
toolbarView.view.edit.updateUrl(url = it, shouldHighlight = true)
interactor.onTextChanged(it)
Expand Down Expand Up @@ -790,7 +788,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
putExtra(RecognizerIntent.EXTRA_PROMPT, requireContext().getString(R.string.voice_search_explainer))
}
startActivityForResult(speechIntent, VoiceSearchActivity.SPEECH_REQUEST_CODE)
startActivityForResult(speechIntent, SPEECH_REQUEST_CODE)
}

private fun updateQrButton(searchFragmentState: SearchFragmentState) {
Expand Down Expand Up @@ -904,6 +902,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {

companion object {
private const val TAP_INCREASE_DPS = 8
const val SPEECH_REQUEST_CODE = 0
private const val QR_FRAGMENT_TAG = "MOZAC_QR_FRAGMENT"
private const val REQUEST_CODE_CAMERA_PERMISSIONS = 1
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.preference.CheckBoxPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import mozilla.components.feature.search.widget.AppSearchWidgetProvider.Companion.updateAllWidgets
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.getPreferenceKey
Expand Down Expand Up @@ -90,7 +91,7 @@ class SearchEngineFragment : PreferenceFragmentCompat() {
requireContext().settings().preferences.edit {
putBoolean(preference.key, newBooleanValue)
}
SearchWidgetProvider.updateAllWidgets(requireContext())
updateAllWidgets(requireContext(), SearchWidgetProvider::class.java)
return true
}
}
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/org/mozilla/fenix/utils/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,14 @@ class Settings(private val appContext: Context) : PreferencesHolder {
default = false
)

var shouldUpdateSearchWidget: Boolean
get() = preferences.getBoolean(appContext.getPreferenceKey(R.string.pref_key_update_search_widget), true)
set(value) {
preferences.edit()
.putBoolean(appContext.getPreferenceKey(R.string.pref_key_update_search_widget), value)
.apply()
}

var gridTabView by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_tab_view_grid),
default = true
Expand Down
112 changes: 16 additions & 96 deletions app/src/main/java/org/mozilla/fenix/widget/VoiceSearchActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,118 +4,38 @@

package org.mozilla.fenix.widget

import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import android.os.StrictMode
import android.speech.RecognizerIntent
import androidx.appcompat.app.AppCompatActivity
import mozilla.components.feature.search.widget.BaseVoiceSearchActivity
import mozilla.components.support.locale.LocaleManager
import mozilla.telemetry.glean.private.NoExtras
import org.mozilla.fenix.GleanMetrics.SearchWidget
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
import org.mozilla.fenix.ext.components
import java.util.Locale

/**
* Launches voice recognition then uses it to start a new web search.
* Implementation of voice search that is needed in search widget
*/
class VoiceSearchActivity : AppCompatActivity() {
class VoiceSearchActivity : BaseVoiceSearchActivity() {

/**
* Holds the intent that initially started this activity
* so that it can persist through the speech activity.
*/
private var previousIntent: Intent? = null

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelable(PREVIOUS_INTENT, previousIntent)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

if (Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).resolveActivity(packageManager) == null) {
finish()
return
}

// Retrieve the previous intent from the saved state
previousIntent = savedInstanceState?.get(PREVIOUS_INTENT) as Intent?
if (previousIntent.isForSpeechProcessing()) {
// Don't reopen the speech recognizer
return
}

// The intent property is nullable, but the rest of the code below assumes it is not.
val intent = intent?.let { Intent(intent) } ?: Intent()

if (intent.isForSpeechProcessing()) {
previousIntent = intent
displaySpeechRecognizer()
} else {
finish()
}
}

/**
* Displays a speech recognizer popup that listens for input from the user.
*/
@Suppress("DEPRECATION")
// https://github.com/mozilla-mobile/fenix/issues/19919
private fun displaySpeechRecognizer() {
val intentSpeech = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
putExtra(
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
)
putExtra(
RecognizerIntent.EXTRA_LANGUAGE,
components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
LocaleManager.getCurrentLocale(this@VoiceSearchActivity)
}
)
override fun getCurrentLocale(): Locale {
val locale = components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
LocaleManager.getCurrentLocale(this@VoiceSearchActivity)
?: LocaleManager.getSystemDefault()
}
SearchWidget.voiceButton.record(NoExtras())

startActivityForResult(intentSpeech, SPEECH_REQUEST_CODE)
return locale
}

@Suppress("DEPRECATION")
// https://github.com/mozilla-mobile/fenix/issues/19919
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)

if (requestCode == SPEECH_REQUEST_CODE && resultCode == RESULT_OK) {
val spokenText = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)?.first()
val context = this

previousIntent?.apply {
component = ComponentName(context, IntentReceiverActivity::class.java)
putExtra(SPEECH_PROCESSING, spokenText)
putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, true)
startActivity(this)
}
}

finish()
override fun onSpeechRecognitionEnded(spokenText: String) {
val intent = Intent(this, IntentReceiverActivity::class.java)
intent.putExtra(SPEECH_PROCESSING, spokenText)
intent.putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, true)
startActivity(intent)
}

/**
* Returns true if the [SPEECH_PROCESSING] extra is present and set to true.
* Returns false if the intent is null.
*/
private fun Intent?.isForSpeechProcessing(): Boolean =
this?.getBooleanExtra(SPEECH_PROCESSING, false) == true

companion object {
internal const val SPEECH_REQUEST_CODE = 0
internal const val PREVIOUS_INTENT = "org.mozilla.fenix.previous_intent"
/**
* In [VoiceSearchActivity] activity, used to store if the speech processing should start.
* In [IntentReceiverActivity] activity, used to store the search terms.
*/
const val SPEECH_PROCESSING = "speech_processing"
override fun onSpeechRecognitionStarted() {
SearchWidget.voiceButton.record(NoExtras())
}
}
Loading

0 comments on commit 5494021

Please sign in to comment.