1
0
Fork 0

Extract intent processors from HomeActivity (#4884)

master
Tiger Oakes 2019-08-22 14:31:40 -04:00 committed by Colin Lee
parent 4bd94f0f9b
commit 9f154dc3a0
12 changed files with 697 additions and 90 deletions

View File

@ -6,8 +6,6 @@ package org.mozilla.fenix
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.AttributeSet
import android.view.View
@ -28,7 +26,6 @@ import mozilla.components.browser.search.SearchEngine
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.EngineView
import mozilla.components.lib.crash.Crash
import mozilla.components.support.base.feature.BackHandler
import mozilla.components.support.ktx.kotlin.isUrl
import mozilla.components.support.ktx.kotlin.toNormalizedUrl
@ -44,6 +41,11 @@ import org.mozilla.fenix.components.metrics.SentryBreadcrumbsRecorder
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getRootView
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.home.intent.CrashReporterIntentProcessor
import org.mozilla.fenix.home.intent.DeepLinkIntentProcessor
import org.mozilla.fenix.home.intent.OpenBrowserIntentProcessor
import org.mozilla.fenix.home.intent.SpeechProcessingIntentProcessor
import org.mozilla.fenix.home.intent.StartSearchIntentProcessor
import org.mozilla.fenix.share.ShareFragment
import org.mozilla.fenix.theme.DefaultThemeManager
import org.mozilla.fenix.theme.ThemeManager
@ -61,6 +63,15 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
}
private val externalSourceIntentProcessors by lazy {
listOf(
SpeechProcessingIntentProcessor(this),
StartSearchIntentProcessor(components.analytics.metrics),
DeepLinkIntentProcessor(this),
OpenBrowserIntentProcessor(this, ::getIntentSessionId)
)
}
final override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -105,8 +116,10 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
*/
final override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
handleCrashIfNecessary(intent)
handleOpenedFromExternalSourceIfNecessary(intent)
intent ?: return
val intentProcessors = listOf(CrashReporterIntentProcessor()) + externalSourceIntentProcessors
intentProcessors.any { it.process(intent, navHost.navController, this.intent) }
}
/**
@ -162,86 +175,7 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
onBackPressed()
}
handleOpenedFromExternalSourceIfNecessary(intent)
}
private fun handleCrashIfNecessary(intent: Intent?) {
if (intent != null && Crash.isCrashIntent(intent)) {
openToCrashReporter(intent)
}
}
private fun openToCrashReporter(intent: Intent) {
val directions = NavGraphDirections.actionGlobalCrashReporter(intent)
navHost.navController.navigate(directions)
}
private fun handleOpenedFromExternalSourceIfNecessary(intent: Intent?) {
if (intent?.extras?.getBoolean(OPEN_TO_BROWSER_AND_LOAD) == true) {
this.intent.putExtra(OPEN_TO_BROWSER_AND_LOAD, false)
openToBrowserAndLoad(
intent.getStringExtra(
IntentReceiverActivity.SPEECH_PROCESSING
), true, BrowserDirection.FromGlobal, forceSearch = true
)
return
} else if (intent?.extras?.getBoolean(OPEN_TO_SEARCH) == true) {
this.intent.putExtra(OPEN_TO_SEARCH, false)
components.analytics.metrics.track(Event.SearchWidgetNewTabPressed)
navHost.navController.nav(null, NavGraphDirections.actionGlobalSearch(null, true))
return
} else if (intent?.scheme == "fenix") {
intent.data?.let { handleDeepLink(it) }
}
if (intent?.extras?.getBoolean(OPEN_TO_BROWSER) != true) return
this.intent.putExtra(OPEN_TO_BROWSER, false)
openToBrowser(BrowserDirection.FromGlobal, getIntentSessionId(intent.toSafeIntent()))
}
@SuppressWarnings("ComplexMethod")
private fun handleDeepLink(uri: Uri) {
val link = uri.host
// Handle links that require more than just simple navigation
when (link) {
"enable_private_browsing" -> {
navHost.navController.navigate(NavGraphDirections.actionGlobalHomeFragment())
browsingModeManager.mode = BrowsingMode.Private
}
"make_default_browser" -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { return }
val settingsIntent = Intent(
android.provider.Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS
)
startActivity(settingsIntent)
}
"open" -> {
uri.getQueryParameter("url")?.let {
load(
searchTermOrURL = it,
newTab = true,
engine = null,
forceSearch = false
)
navHost.navController.navigate(NavGraphDirections.actionGlobalBrowser(null))
}
}
}
val directions = when (link) {
"home" -> NavGraphDirections.actionGlobalHomeFragment()
"settings" -> NavGraphDirections.actionGlobalSettingsFragment()
"turn_on_sync" -> NavGraphDirections.actionGlobalTurnOnSync()
"settings_search_engine" -> NavGraphDirections.actionGlobalSearchEngineFragment()
"settings_accessibility" -> NavGraphDirections.actionGlobalAccessibilityFragment()
"settings_delete_browsing_data" -> NavGraphDirections.actionGlobalDeleteBrowsingDataFragment()
else -> return
}
navHost.navController.navigate(directions)
externalSourceIntentProcessors.any { it.process(intent, navHost.navController, this.intent) }
}
protected open fun getIntentSessionId(intent: SafeIntent): String? = null
@ -264,11 +198,7 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
sessionObserver = subscribeToSessions()
with(navHost.navController) {
if (currentDestination?.id == R.id.browserFragment || popBackStack(
R.id.browserFragment,
false
)
) return
if (currentDestination?.id == R.id.browserFragment || popBackStack(R.id.browserFragment, false)) return
}
@IdRes val fragmentId = if (from.fragmentId != 0) from.fragmentId else null

View File

@ -0,0 +1,31 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
import mozilla.components.lib.crash.Crash
import org.mozilla.fenix.NavGraphDirections
/**
* When the app crashes, the user has the option to report it.
* Reporting fires an intent to the main activity which is handled here.
*/
class CrashReporterIntentProcessor : HomeIntentProcessor {
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
return if (Crash.isCrashIntent(intent)) {
openToCrashReporter(intent, navController)
true
} else {
false
}
}
private fun openToCrashReporter(intent: Intent, navController: NavController) {
val directions = NavGraphDirections.actionGlobalCrashReporter(intent)
navController.navigate(directions)
}
}

View File

@ -0,0 +1,75 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.provider.Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS
import androidx.navigation.NavController
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
/**
* Deep links in the form of `fenix://host` open different parts of the app.
*/
class DeepLinkIntentProcessor(
private val activity: HomeActivity
) : HomeIntentProcessor {
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
return if (intent.scheme == "fenix") {
intent.data?.let { handleDeepLink(it, navController) }
true
} else {
false
}
}
private fun handleDeepLink(deepLink: Uri, navController: NavController) {
handleDeepLinkSideEffects(deepLink)
val directions = when (deepLink.host) {
"home", "enable_private_browsing" -> NavGraphDirections.actionGlobalHomeFragment()
"settings" -> NavGraphDirections.actionGlobalSettingsFragment()
"turn_on_sync" -> NavGraphDirections.actionGlobalTurnOnSync()
"settings_search_engine" -> NavGraphDirections.actionGlobalSearchEngineFragment()
"settings_accessibility" -> NavGraphDirections.actionGlobalAccessibilityFragment()
"settings_delete_browsing_data" -> NavGraphDirections.actionGlobalDeleteBrowsingDataFragment()
else -> return
}
navController.navigate(directions)
}
/**
* Handle links that require more than just simple navigation.
*/
private fun handleDeepLinkSideEffects(deepLink: Uri) {
when (deepLink.host) {
"enable_private_browsing" -> {
activity.browsingModeManager.mode = BrowsingMode.Private
}
"make_default_browser" -> {
if (SDK_INT >= Build.VERSION_CODES.N) {
val settingsIntent = Intent(ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
activity.startActivity(settingsIntent)
}
}
"open" -> {
deepLink.getQueryParameter("url")?.let { searchTermOrUrl ->
activity.openToBrowserAndLoad(
searchTermOrUrl,
newTab = true,
from = BrowserDirection.FromGlobal
)
}
}
}
}
}

View File

@ -0,0 +1,24 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
/**
* Processor for Android intents received in [org.mozilla.fenix.HomeActivity].
*/
interface HomeIntentProcessor {
/**
* Processes the given [intent]. May add properties to [out].
*
* @param intent The intent to process.
* @param navController Controller to navigate between fragments.
* @param out Intent to mutate.
* @return True if the intent was processed, otherwise false.
*/
fun process(intent: Intent, navController: NavController, out: Intent): Boolean
}

View File

@ -0,0 +1,33 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
import mozilla.components.support.utils.SafeIntent
import mozilla.components.support.utils.toSafeIntent
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
/**
* The [org.mozilla.fenix.IntentReceiverActivity] may set the [HomeActivity.OPEN_TO_BROWSER] flag
* when the browser should be opened in response to an intent.
*/
class OpenBrowserIntentProcessor(
private val activity: HomeActivity,
private val getIntentSessionId: (SafeIntent) -> String?
) : HomeIntentProcessor {
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
return if (intent.extras?.getBoolean(HomeActivity.OPEN_TO_BROWSER) == true) {
out.putExtra(HomeActivity.OPEN_TO_BROWSER, false)
activity.openToBrowser(BrowserDirection.FromGlobal, getIntentSessionId(intent.toSafeIntent()))
true
} else {
false
}
}
}

View File

@ -0,0 +1,35 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
/**
* The search widget has a microphone button to let users search with their voice.
* Once the search is complete then a new search should be started.
*/
class SpeechProcessingIntentProcessor(
private val activity: HomeActivity
) : HomeIntentProcessor {
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
return if (intent.extras?.getBoolean(HomeActivity.OPEN_TO_BROWSER_AND_LOAD) == true) {
out.putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, false)
activity.openToBrowserAndLoad(
searchTermOrURL = intent.getStringExtra(IntentReceiverActivity.SPEECH_PROCESSING).orEmpty(),
newTab = true,
from = BrowserDirection.FromGlobal,
forceSearch = true
)
true
} else {
false
}
}
}

View File

@ -0,0 +1,34 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.nav
/**
* When the search widget is tapped, Fenix should open to the search fragment.
*/
class StartSearchIntentProcessor(
private val metrics: MetricController
) : HomeIntentProcessor {
override fun process(intent: Intent, navController: NavController, out: Intent): Boolean {
return if (intent.extras?.getBoolean(HomeActivity.OPEN_TO_SEARCH) == true) {
out.putExtra(HomeActivity.OPEN_TO_SEARCH, false)
metrics.track(Event.SearchWidgetNewTabPressed)
val directions = NavGraphDirections.actionGlobalSearch(sessionId = null, showShortcutEnginePicker = true)
navController.nav(null, directions)
true
} else {
false
}
}
}

View File

@ -0,0 +1,48 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import android.os.Bundle
import androidx.navigation.NavController
import io.mockk.Called
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.TestApplication
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@ObsoleteCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class)
class CrashReporterIntentProcessorTest {
@Test
fun `do not process blank intents`() {
val navController: NavController = mockk()
val out: Intent = mockk()
CrashReporterIntentProcessor().process(Intent(), navController, out)
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `process crash intents`() {
val navController: NavController = mockk(relaxed = true)
val out: Intent = mockk()
val intent = Intent().apply {
putExtra("mozilla.components.lib.crash.CRASH", mockk<Bundle>())
}
CrashReporterIntentProcessor().process(intent, navController, out)
verify { navController.navigate(NavGraphDirections.actionGlobalCrashReporter(intent)) }
verify { out wasNot Called }
}
}

View File

@ -0,0 +1,156 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.core.net.toUri
import androidx.navigation.NavController
import io.mockk.Called
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.TestApplication
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@ObsoleteCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class)
class DeepLinkIntentProcessorTest {
private lateinit var activity: HomeActivity
private lateinit var navController: NavController
private lateinit var out: Intent
private lateinit var processor: DeepLinkIntentProcessor
@Before
fun setup() {
activity = mockk(relaxed = true)
navController = mockk(relaxed = true)
out = mockk()
processor = DeepLinkIntentProcessor(activity)
}
@Test
fun `do not process blank intents`() {
assertFalse(processor.process(Intent(), navController, out))
verify { activity wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `return true if scheme is fenix`() {
assertTrue(processor.process(testIntent("fenix://test"), navController, out))
verify { activity wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `process home deep link`() {
assertTrue(processor.process(testIntent("fenix://home"), navController, out))
verify { activity wasNot Called }
verify { navController.navigate(NavGraphDirections.actionGlobalHomeFragment()) }
verify { out wasNot Called }
}
@Test
fun `process settings deep link`() {
assertTrue(processor.process(testIntent("fenix://settings"), navController, out))
verify { activity wasNot Called }
verify { navController.navigate(NavGraphDirections.actionGlobalSettingsFragment()) }
verify { out wasNot Called }
}
@Test
fun `process turn_on_sync deep link`() {
assertTrue(processor.process(testIntent("fenix://turn_on_sync"), navController, out))
verify { activity wasNot Called }
verify { navController.navigate(NavGraphDirections.actionGlobalTurnOnSync()) }
verify { out wasNot Called }
}
@Test
fun `process settings_search_engine deep link`() {
assertTrue(processor.process(testIntent("fenix://settings_search_engine"), navController, out))
verify { activity wasNot Called }
verify { navController.navigate(NavGraphDirections.actionGlobalSearchEngineFragment()) }
verify { out wasNot Called }
}
@Test
fun `process settings_accessibility deep link`() {
assertTrue(processor.process(testIntent("fenix://settings_accessibility"), navController, out))
verify { activity wasNot Called }
verify { navController.navigate(NavGraphDirections.actionGlobalAccessibilityFragment()) }
verify { out wasNot Called }
}
@Test
fun `process settings_delete_browsing_data deep link`() {
assertTrue(processor.process(testIntent("fenix://settings_delete_browsing_data"), navController, out))
verify { activity wasNot Called }
verify { navController.navigate(NavGraphDirections.actionGlobalDeleteBrowsingDataFragment()) }
verify { out wasNot Called }
}
@Test
fun `process enable_private_browsing deep link`() {
assertTrue(processor.process(testIntent("fenix://enable_private_browsing"), navController, out))
verify { activity.browsingModeManager.mode = BrowsingMode.Private }
verify { navController.navigate(NavGraphDirections.actionGlobalHomeFragment()) }
verify { out wasNot Called }
}
@Test
fun `process open deep link`() {
assertTrue(processor.process(testIntent("fenix://open"), navController, out))
verify { activity wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
assertTrue(processor.process(testIntent("fenix://open?url=test"), navController, out))
verify {
activity.openToBrowserAndLoad(
"test",
newTab = true,
from = BrowserDirection.FromGlobal
)
}
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `process make_default_browser deep link`() {
assertTrue(processor.process(testIntent("fenix://make_default_browser"), navController, out))
verify { navController wasNot Called }
verify { out wasNot Called }
}
private fun testIntent(uri: String) = Intent("", uri.toUri())
}

View File

@ -0,0 +1,70 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
import io.mockk.Called
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.TestApplication
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@ObsoleteCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class)
class OpenBrowserIntentProcessorTest {
@Test
fun `do not process blank intents`() {
val activity: HomeActivity = mockk()
val navController: NavController = mockk()
val out: Intent = mockk()
val processor = OpenBrowserIntentProcessor(activity) { null }
processor.process(Intent(), navController, out)
verify { activity wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `do not process when open extra is false`() {
val activity: HomeActivity = mockk()
val navController: NavController = mockk()
val out: Intent = mockk()
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_BROWSER, false)
}
val processor = OpenBrowserIntentProcessor(activity) { null }
processor.process(intent, navController, out)
verify { activity wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `process when open extra is true`() {
val activity: HomeActivity = mockk(relaxed = true)
val navController: NavController = mockk()
val out: Intent = mockk(relaxed = true)
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_BROWSER, true)
}
val processor = OpenBrowserIntentProcessor(activity) { "session-id" }
processor.process(intent, navController, out)
verify { activity.openToBrowser(BrowserDirection.FromGlobal, "session-id") }
verify { navController wasNot Called }
verify { out.putExtra(HomeActivity.OPEN_TO_BROWSER, false) }
}
}

View File

@ -0,0 +1,98 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
import io.mockk.Called
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
import org.mozilla.fenix.TestApplication
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@ObsoleteCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class)
class SpeechProcessingIntentProcessorTest {
@Test
fun `do not process blank intents`() {
val activity: HomeActivity = mockk()
val navController: NavController = mockk()
val out: Intent = mockk()
val processor = SpeechProcessingIntentProcessor(activity)
processor.process(Intent(), navController, out)
verify { activity wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `do not process when open extra is false`() {
val activity: HomeActivity = mockk()
val navController: NavController = mockk()
val out: Intent = mockk()
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, false)
}
val processor = SpeechProcessingIntentProcessor(activity)
processor.process(intent, navController, out)
verify { activity wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `process when open extra is true`() {
val activity: HomeActivity = mockk(relaxed = true)
val navController: NavController = mockk()
val out: Intent = mockk(relaxed = true)
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, true)
}
val processor = SpeechProcessingIntentProcessor(activity)
processor.process(intent, navController, out)
verify {
activity.openToBrowserAndLoad(
searchTermOrURL = "",
newTab = true,
from = BrowserDirection.FromGlobal,
forceSearch = true
)
}
verify { navController wasNot Called }
verify { out.putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, false) }
}
@Test
fun `reads the speech processing extra`() {
val activity: HomeActivity = mockk(relaxed = true)
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_BROWSER_AND_LOAD, true)
putExtra(IntentReceiverActivity.SPEECH_PROCESSING, "hello world")
}
val processor = SpeechProcessingIntentProcessor(activity)
processor.process(intent, mockk(), mockk(relaxed = true))
verify {
activity.openToBrowserAndLoad(
searchTermOrURL = "hello world",
newTab = true,
from = BrowserDirection.FromGlobal,
forceSearch = true
)
}
}
}

View File

@ -0,0 +1,73 @@
/* 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/. */
package org.mozilla.fenix.home.intent
import android.content.Intent
import androidx.navigation.NavController
import io.mockk.Called
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ObsoleteCoroutinesApi
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.TestApplication
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@ObsoleteCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class)
class StartSearchIntentProcessorTest {
@Test
fun `do not process blank intents`() {
val metrics: MetricController = mockk()
val navController: NavController = mockk()
val out: Intent = mockk()
StartSearchIntentProcessor(metrics).process(Intent(), navController, out)
verify { metrics wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `do not process when search extra is false`() {
val metrics: MetricController = mockk()
val navController: NavController = mockk()
val out: Intent = mockk()
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_SEARCH, false)
}
StartSearchIntentProcessor(metrics).process(intent, navController, out)
verify { metrics wasNot Called }
verify { navController wasNot Called }
verify { out wasNot Called }
}
@Test
fun `process search intents`() {
val metrics: MetricController = mockk(relaxed = true)
val navController: NavController = mockk(relaxed = true)
val out: Intent = mockk(relaxed = true)
val intent = Intent().apply {
putExtra(HomeActivity.OPEN_TO_SEARCH, true)
}
StartSearchIntentProcessor(metrics).process(intent, navController, out)
verify { metrics.track(Event.SearchWidgetNewTabPressed) }
verify {
navController.navigate(
NavGraphDirections.actionGlobalSearch(sessionId = null, showShortcutEnginePicker = true)
)
}
verify { out.putExtra(HomeActivity.OPEN_TO_SEARCH, false) }
}
}