parent
1afc0eacd8
commit
95ef312b1e
|
@ -11,32 +11,33 @@ import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.annotation.CallSuper
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import androidx.annotation.VisibleForTesting.PROTECTED
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavDestination
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.AppBarConfiguration
|
import androidx.navigation.ui.AppBarConfiguration
|
||||||
import androidx.navigation.ui.NavigationUI
|
import androidx.navigation.ui.NavigationUI
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import io.sentry.Sentry
|
|
||||||
import io.sentry.event.Breadcrumb
|
|
||||||
import io.sentry.event.BreadcrumbBuilder
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.browser.search.SearchEngine
|
import mozilla.components.browser.search.SearchEngine
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
import mozilla.components.browser.session.intent.EXTRA_SESSION_ID
|
|
||||||
import mozilla.components.concept.engine.EngineView
|
import mozilla.components.concept.engine.EngineView
|
||||||
import mozilla.components.lib.crash.Crash
|
import mozilla.components.lib.crash.Crash
|
||||||
import mozilla.components.support.base.feature.BackHandler
|
import mozilla.components.support.base.feature.BackHandler
|
||||||
import mozilla.components.support.ktx.kotlin.isUrl
|
import mozilla.components.support.ktx.kotlin.isUrl
|
||||||
import mozilla.components.support.ktx.kotlin.toNormalizedUrl
|
import mozilla.components.support.ktx.kotlin.toNormalizedUrl
|
||||||
import mozilla.components.support.utils.SafeIntent
|
import mozilla.components.support.utils.SafeIntent
|
||||||
|
import mozilla.components.support.utils.toSafeIntent
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.isSentryEnabled
|
import org.mozilla.fenix.components.isSentryEnabled
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.mozilla.fenix.components.metrics.SentryBreadcrumbsRecorder
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.getRootView
|
import org.mozilla.fenix.ext.getRootView
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
|
@ -45,93 +46,40 @@ import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
||||||
open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback {
|
open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback {
|
||||||
open val isCustomTab = false
|
|
||||||
private var sessionObserver: SessionManager.Observer? = null
|
|
||||||
|
|
||||||
lateinit var themeManager: ThemeManager
|
lateinit var themeManager: ThemeManager
|
||||||
|
lateinit var browsingModeManager: BrowsingModeManager
|
||||||
|
|
||||||
|
private var sessionObserver: SessionManager.Observer? = null
|
||||||
|
|
||||||
private val navHost by lazy {
|
private val navHost by lazy {
|
||||||
supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
|
supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
lateinit var browsingModeManager: BrowsingModeManager
|
final override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
private val onDestinationChangedListener =
|
|
||||||
NavController.OnDestinationChangedListener { _, dest, _ ->
|
|
||||||
val fragmentName = resources.getResourceEntryName(dest.id)
|
|
||||||
Sentry.getContext().recordBreadcrumb(
|
|
||||||
BreadcrumbBuilder()
|
|
||||||
.setCategory("DestinationChanged")
|
|
||||||
.setMessage("Changing to fragment $fragmentName, isCustomTab: $isCustomTab")
|
|
||||||
.setLevel(Breadcrumb.Level.INFO)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
components.publicSuffixList.prefetch()
|
components.publicSuffixList.prefetch()
|
||||||
browsingModeManager = createBrowsingModeManager()
|
setupThemeAndBrowsingMode()
|
||||||
themeManager = createThemeManager(browsingModeManager.mode)
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_home)
|
setContentView(R.layout.activity_home)
|
||||||
|
|
||||||
setupToolbarAndNavigation()
|
setupToolbarAndNavigation()
|
||||||
|
|
||||||
if (Settings.getInstance(this).isTelemetryEnabled && isSentryEnabled()) {
|
if (Settings.getInstance(this).isTelemetryEnabled) {
|
||||||
navHost.navController.addOnDestinationChangedListener(onDestinationChangedListener)
|
if (isSentryEnabled()) {
|
||||||
}
|
lifecycle.addObserver(SentryBreadcrumbsRecorder(navHost.navController, ::getSentryBreadcrumbMessage))
|
||||||
|
|
||||||
intent
|
|
||||||
?.let { SafeIntent(it) }
|
|
||||||
?.let {
|
|
||||||
when {
|
|
||||||
isCustomTab -> Event.OpenedApp.Source.CUSTOM_TAB
|
|
||||||
it.isLauncherIntent -> Event.OpenedApp.Source.APP_ICON
|
|
||||||
it.action == Intent.ACTION_VIEW -> Event.OpenedApp.Source.LINK
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?.also { components.analytics.metrics.track(Event.OpenedApp(it)) }
|
|
||||||
|
|
||||||
handleOpenedFromExternalSourceIfNecessary(intent)
|
intent
|
||||||
}
|
?.toSafeIntent()
|
||||||
|
?.let(::getIntentSource)
|
||||||
private fun setupToolbarAndNavigation() {
|
?.also { components.analytics.metrics.track(Event.OpenedApp(it)) }
|
||||||
// Add ids to this that we don't want to have a toolbar back button
|
|
||||||
val appBarConfiguration = AppBarConfiguration.Builder().build()
|
|
||||||
val navigationToolbar = findViewById<Toolbar>(R.id.navigationToolbar)
|
|
||||||
setSupportActionBar(navigationToolbar)
|
|
||||||
NavigationUI.setupWithNavController(
|
|
||||||
navigationToolbar,
|
|
||||||
navHost.navController,
|
|
||||||
appBarConfiguration
|
|
||||||
)
|
|
||||||
navigationToolbar.setNavigationOnClickListener {
|
|
||||||
onBackPressed()
|
|
||||||
}
|
}
|
||||||
supportActionBar?.hide()
|
supportActionBar?.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
@CallSuper
|
||||||
sessionObserver?.let { components.core.sessionManager.unregister(it) }
|
|
||||||
navHost.navController.removeOnDestinationChangedListener(onDestinationChangedListener)
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent?) {
|
|
||||||
super.onNewIntent(intent)
|
|
||||||
|
|
||||||
intent?.let {
|
|
||||||
if (Crash.isCrashIntent(it)) {
|
|
||||||
openToCrashReporter(it)
|
|
||||||
} else {
|
|
||||||
handleOpenedFromExternalSourceIfNecessary(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
@ -147,21 +95,29 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
/**
|
||||||
|
* Handles intents received when the activity is open.
|
||||||
|
*/
|
||||||
|
final override fun onNewIntent(intent: Intent?) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
handleCrashIfNecessary(intent)
|
||||||
|
handleOpenedFromExternalSourceIfNecessary(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides view inflation to inject a custom [EngineView] from [components].
|
||||||
|
*/
|
||||||
|
final override fun onCreateView(
|
||||||
parent: View?,
|
parent: View?,
|
||||||
name: String,
|
name: String,
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet
|
attrs: AttributeSet
|
||||||
): View? =
|
): View? = when (name) {
|
||||||
when (name) {
|
EngineView::class.java.name -> components.core.engine.createView(context, attrs).asView()
|
||||||
EngineView::class.java.name -> components.core.engine.createView(
|
else -> super.onCreateView(parent, name, context, attrs)
|
||||||
context,
|
}
|
||||||
attrs
|
|
||||||
).asView()
|
|
||||||
else -> super.onCreateView(parent, name, context, attrs)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed() {
|
final override fun onBackPressed() {
|
||||||
supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
|
supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach {
|
||||||
if (it is BackHandler && it.onBackPressed()) {
|
if (it is BackHandler && it.onBackPressed()) {
|
||||||
return
|
return
|
||||||
|
@ -170,6 +126,46 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun getSentryBreadcrumbMessage(destination: NavDestination): String {
|
||||||
|
val fragmentName = resources.getResourceEntryName(destination.id)
|
||||||
|
return "Changing to fragment $fragmentName, isCustomTab: false"
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = PROTECTED)
|
||||||
|
internal open fun getIntentSource(intent: SafeIntent): Event.OpenedApp.Source? {
|
||||||
|
return when {
|
||||||
|
intent.isLauncherIntent -> Event.OpenedApp.Source.APP_ICON
|
||||||
|
intent.action == Intent.ACTION_VIEW -> Event.OpenedApp.Source.LINK
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupThemeAndBrowsingMode() {
|
||||||
|
browsingModeManager = createBrowsingModeManager()
|
||||||
|
themeManager = createThemeManager()
|
||||||
|
themeManager.setActivityTheme(this)
|
||||||
|
themeManager.applyStatusBarTheme(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupToolbarAndNavigation() {
|
||||||
|
// Add ids to this that we don't want to have a toolbar back button
|
||||||
|
val appBarConfiguration = AppBarConfiguration.Builder().build()
|
||||||
|
val navigationToolbar = findViewById<Toolbar>(R.id.navigationToolbar)
|
||||||
|
setSupportActionBar(navigationToolbar)
|
||||||
|
NavigationUI.setupWithNavController(navigationToolbar, navHost.navController, appBarConfiguration)
|
||||||
|
navigationToolbar.setNavigationOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOpenedFromExternalSourceIfNecessary(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleCrashIfNecessary(intent: Intent?) {
|
||||||
|
if (intent != null && Crash.isCrashIntent(intent)) {
|
||||||
|
openToCrashReporter(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun openToCrashReporter(intent: Intent) {
|
private fun openToCrashReporter(intent: Intent) {
|
||||||
val directions = NavGraphDirections.actionGlobalCrashReporter(intent)
|
val directions = NavGraphDirections.actionGlobalCrashReporter(intent)
|
||||||
navHost.navController.navigate(directions)
|
navHost.navController.navigate(directions)
|
||||||
|
@ -196,13 +192,8 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
if (intent?.extras?.getBoolean(OPEN_TO_BROWSER) != true) return
|
if (intent?.extras?.getBoolean(OPEN_TO_BROWSER) != true) return
|
||||||
|
|
||||||
this.intent.putExtra(OPEN_TO_BROWSER, false)
|
this.intent.putExtra(OPEN_TO_BROWSER, false)
|
||||||
var customTabSessionId: String? = null
|
|
||||||
|
|
||||||
if (isCustomTab) {
|
openToBrowser(BrowserDirection.FromGlobal, getIntentSessionId(intent.toSafeIntent()))
|
||||||
customTabSessionId = SafeIntent(intent).getStringExtra(EXTRA_SESSION_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
openToBrowser(BrowserDirection.FromGlobal, customTabSessionId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ComplexMethod")
|
@SuppressWarnings("ComplexMethod")
|
||||||
|
@ -248,6 +239,8 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
navHost.navController.navigate(directions)
|
navHost.navController.navigate(directions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected open fun getIntentSessionId(intent: SafeIntent): String? = null
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
fun openToBrowserAndLoad(
|
fun openToBrowserAndLoad(
|
||||||
searchTermOrURL: String,
|
searchTermOrURL: String,
|
||||||
|
@ -312,18 +305,6 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val singleSessionObserver = object : Session.Observer {
|
|
||||||
var urlLoading: String? = null
|
|
||||||
|
|
||||||
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
|
||||||
if (loading) {
|
|
||||||
urlLoading = session.url
|
|
||||||
} else if (urlLoading != null && !session.private) {
|
|
||||||
components.analytics.metrics.track(Event.UriOpened)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateThemeForSession(session: Session) {
|
fun updateThemeForSession(session: Session) {
|
||||||
val sessionMode = BrowsingMode.fromBoolean(session.private)
|
val sessionMode = BrowsingMode.fromBoolean(session.private)
|
||||||
if (sessionMode != browsingModeManager.mode) {
|
if (sessionMode != browsingModeManager.mode) {
|
||||||
|
@ -331,31 +312,29 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createBrowsingModeManager(): BrowsingModeManager {
|
protected open fun createBrowsingModeManager(): BrowsingModeManager {
|
||||||
return if (isCustomTab) {
|
return DefaultBrowsingModeManager(Settings.getInstance(this)) { mode ->
|
||||||
CustomTabBrowsingModeManager()
|
themeManager.currentTheme = mode
|
||||||
} else {
|
|
||||||
DefaultBrowsingModeManager(Settings.getInstance(this)) { mode ->
|
|
||||||
themeManager.currentTheme = mode
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createThemeManager(currentTheme: BrowsingMode): ThemeManager {
|
protected open fun createThemeManager(): ThemeManager {
|
||||||
val themeManager = if (isCustomTab) {
|
return DefaultThemeManager(browsingModeManager.mode, this)
|
||||||
CustomTabThemeManager()
|
|
||||||
} else {
|
|
||||||
DefaultThemeManager(currentTheme) {
|
|
||||||
themeManager.setActivityTheme(this)
|
|
||||||
recreate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
themeManager.setActivityTheme(this)
|
|
||||||
themeManager.applyStatusBarTheme(this)
|
|
||||||
return themeManager
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("ComplexMethod")
|
||||||
private fun subscribeToSessions(): SessionManager.Observer {
|
private fun subscribeToSessions(): SessionManager.Observer {
|
||||||
|
val singleSessionObserver = object : Session.Observer {
|
||||||
|
var urlLoading: String? = null
|
||||||
|
|
||||||
|
override fun onLoadingStateChanged(session: Session, loading: Boolean) {
|
||||||
|
if (loading) {
|
||||||
|
urlLoading = session.url
|
||||||
|
} else if (urlLoading != null && !session.private) {
|
||||||
|
components.analytics.metrics.track(Event.UriOpened)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return object : SessionManager.Observer {
|
return object : SessionManager.Observer {
|
||||||
override fun onAllSessionsRemoved() {
|
override fun onAllSessionsRemoved() {
|
||||||
|
@ -381,7 +360,7 @@ open class HomeActivity : AppCompatActivity(), ShareFragment.TabsSharedCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTabsShared(tabsSize: Int) {
|
override fun onTabsShared(tabsSize: Int) {
|
||||||
this@HomeActivity.getRootView()?.let {
|
getRootView()?.let {
|
||||||
FenixSnackbar.make(it, Snackbar.LENGTH_SHORT).setText(
|
FenixSnackbar.make(it, Snackbar.LENGTH_SHORT).setText(
|
||||||
getString(
|
getString(
|
||||||
if (tabsSize == 1) R.string.sync_sent_tab_snackbar else
|
if (tabsSize == 1) R.string.sync_sent_tab_snackbar else
|
||||||
|
|
|
@ -101,13 +101,15 @@ abstract class ThemeManager {
|
||||||
|
|
||||||
class DefaultThemeManager(
|
class DefaultThemeManager(
|
||||||
currentTheme: BrowsingMode,
|
currentTheme: BrowsingMode,
|
||||||
private val onThemeChanged: (BrowsingMode) -> Unit
|
private val activity: Activity
|
||||||
) : ThemeManager() {
|
) : ThemeManager() {
|
||||||
override var currentTheme: BrowsingMode = currentTheme
|
override var currentTheme: BrowsingMode = currentTheme
|
||||||
set(value) {
|
set(value) {
|
||||||
if (currentTheme != value) {
|
if (currentTheme != value) {
|
||||||
field = value
|
field = value
|
||||||
onThemeChanged(value)
|
|
||||||
|
setActivityTheme(activity)
|
||||||
|
activity.recreate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/* 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.components.metrics
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleObserver
|
||||||
|
import androidx.lifecycle.OnLifecycleEvent
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavDestination
|
||||||
|
import io.sentry.Sentry
|
||||||
|
import io.sentry.event.Breadcrumb
|
||||||
|
import io.sentry.event.BreadcrumbBuilder
|
||||||
|
import org.mozilla.fenix.components.isSentryEnabled
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records breadcrumbs in Sentry when the fragment changes.
|
||||||
|
*
|
||||||
|
* Should be registered as a [LifecycleObserver] on an activity if telemetry is enabled.
|
||||||
|
* It will automatically be removed when the lifecycle owner is destroyed.
|
||||||
|
*/
|
||||||
|
class SentryBreadcrumbsRecorder(
|
||||||
|
private val navController: NavController,
|
||||||
|
private val getBreadcrumbMessage: (NavDestination) -> String
|
||||||
|
) : NavController.OnDestinationChangedListener, LifecycleObserver {
|
||||||
|
|
||||||
|
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
|
||||||
|
fun onCreate() {
|
||||||
|
if (isSentryEnabled()) {
|
||||||
|
navController.addOnDestinationChangedListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||||
|
fun onDestroy() {
|
||||||
|
navController.removeOnDestinationChangedListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the destination changes, record the new destination as a breadcrumb.
|
||||||
|
*/
|
||||||
|
override fun onDestinationChanged(
|
||||||
|
controller: NavController,
|
||||||
|
destination: NavDestination,
|
||||||
|
arguments: Bundle?
|
||||||
|
) {
|
||||||
|
Sentry.getContext().recordBreadcrumb(
|
||||||
|
BreadcrumbBuilder()
|
||||||
|
.setCategory("DestinationChanged")
|
||||||
|
.setMessage(getBreadcrumbMessage(destination))
|
||||||
|
.setLevel(Breadcrumb.Level.INFO)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package org.mozilla.fenix.customtabs
|
|
||||||
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
/* 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
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.customtabs
|
||||||
|
|
||||||
import mozilla.components.concept.sync.AccountObserver
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
import mozilla.components.concept.sync.OAuthAccount
|
import mozilla.components.concept.sync.OAuthAccount
|
||||||
|
|
|
@ -4,8 +4,25 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.customtabs
|
package org.mozilla.fenix.customtabs
|
||||||
|
|
||||||
|
import androidx.navigation.NavDestination
|
||||||
|
import mozilla.components.browser.session.intent.getSessionId
|
||||||
|
import mozilla.components.support.utils.SafeIntent
|
||||||
|
import org.mozilla.fenix.CustomTabBrowsingModeManager
|
||||||
|
import org.mozilla.fenix.CustomTabThemeManager
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
|
||||||
open class CustomTabActivity : HomeActivity() {
|
open class CustomTabActivity : HomeActivity() {
|
||||||
override val isCustomTab = true
|
final override fun getSentryBreadcrumbMessage(destination: NavDestination): String {
|
||||||
|
val fragmentName = resources.getResourceEntryName(destination.id)
|
||||||
|
return "Changing to fragment $fragmentName, isCustomTab: true"
|
||||||
|
}
|
||||||
|
|
||||||
|
final override fun getIntentSource(intent: SafeIntent) = Event.OpenedApp.Source.CUSTOM_TAB
|
||||||
|
|
||||||
|
final override fun getIntentSessionId(intent: SafeIntent) = intent.getSessionId()
|
||||||
|
|
||||||
|
final override fun createBrowsingModeManager() = CustomTabBrowsingModeManager()
|
||||||
|
|
||||||
|
final override fun createThemeManager() = CustomTabThemeManager()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import kotlinx.coroutines.ObsoleteCoroutinesApi
|
||||||
|
import mozilla.components.support.utils.toSafeIntent
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
|
@ObsoleteCoroutinesApi
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(application = TestApplication::class)
|
||||||
|
class HomeActivityTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getIntentSource() {
|
||||||
|
val activity = HomeActivity()
|
||||||
|
|
||||||
|
val launcherIntent = Intent(Intent.ACTION_MAIN).apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}.toSafeIntent()
|
||||||
|
assertEquals(Event.OpenedApp.Source.APP_ICON, activity.getIntentSource(launcherIntent))
|
||||||
|
|
||||||
|
val viewIntent = Intent(Intent.ACTION_VIEW).toSafeIntent()
|
||||||
|
assertEquals(Event.OpenedApp.Source.LINK, activity.getIntentSource(viewIntent))
|
||||||
|
|
||||||
|
val otherIntent = Intent().toSafeIntent()
|
||||||
|
assertNull(activity.getIntentSource(otherIntent))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* 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.customtabs
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import kotlinx.coroutines.ObsoleteCoroutinesApi
|
||||||
|
import mozilla.components.support.utils.toSafeIntent
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.TestApplication
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
|
@ObsoleteCoroutinesApi
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(application = TestApplication::class)
|
||||||
|
class CustomTabActivityTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getIntentSource() {
|
||||||
|
val activity = CustomTabActivity()
|
||||||
|
|
||||||
|
val launcherIntent = Intent(Intent.ACTION_MAIN).apply {
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}.toSafeIntent()
|
||||||
|
assertEquals(Event.OpenedApp.Source.CUSTOM_TAB, activity.getIntentSource(launcherIntent))
|
||||||
|
|
||||||
|
val viewIntent = Intent(Intent.ACTION_VIEW).toSafeIntent()
|
||||||
|
assertEquals(Event.OpenedApp.Source.CUSTOM_TAB, activity.getIntentSource(viewIntent))
|
||||||
|
|
||||||
|
val otherIntent = Intent().toSafeIntent()
|
||||||
|
assertEquals(Event.OpenedApp.Source.CUSTOM_TAB, activity.getIntentSource(otherIntent))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue