For #24618 - Add Fenix own ServiceWorkerSupport

This replaces the default implementation from Android-Components to add the
functionality to first navigate to the browser fragment before responding to
service workers' requests of opening new tabs.

This will register itself when the main activity is created and unregister
itself when that activity is destroyed to support requests even when the
activity is in background but prevent any leaks.
pull/543/head
Mugurell 2 years ago committed by mergify[bot]
parent 4d0b79192d
commit 5383d3ed63

@ -504,7 +504,6 @@ dependencies {
implementation Deps.mozilla_feature_webcompat
implementation Deps.mozilla_feature_webnotifications
implementation Deps.mozilla_feature_webcompat_reporter
implementation Deps.mozilla_feature_serviceworker
implementation Deps.mozilla_service_pocket
implementation Deps.mozilla_service_contile

@ -36,7 +36,6 @@ import mozilla.components.feature.addons.update.GlobalAddonDependencyProvider
import mozilla.components.feature.autofill.AutofillUseCases
import mozilla.components.feature.search.ext.buildSearchUrl
import mozilla.components.feature.search.ext.waitForSelectedOrDefaultSearchEngine
import mozilla.components.feature.serviceworker.ServiceWorkerSupport
import mozilla.components.feature.top.sites.TopSitesProviderConfig
import mozilla.components.lib.crash.CrashReporter
import mozilla.components.service.fxa.manager.SyncEnginesStorage
@ -196,10 +195,6 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
setupLeakCanary()
startMetricsIfEnabled()
ServiceWorkerSupport.install(
components.core.engine,
components.useCases.tabsUseCases.addTab
)
setupPush()
visibilityLifecycleCallback = VisibilityLifecycleCallback(getSystemService())

@ -160,6 +160,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
WebExtensionPopupFeature(components.core.store, ::openPopup)
}
private val serviceWorkerSupport by lazy {
ServiceWorkerSupportFeature(this)
}
private var inflater: LayoutInflater? = null
private val navHost by lazy {
@ -264,7 +268,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
}
supportActionBar?.hide()
lifecycle.addObservers(webExtensionPopupFeature)
lifecycle.addObservers(webExtensionPopupFeature, serviceWorkerSupport)
if (shouldAddToRecentsScreen(intent)) {
intent.removeExtra(START_IN_RECENTS_SCREEN)

@ -0,0 +1,47 @@
/* 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 androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import mozilla.components.browser.state.state.SessionState
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.EngineSession.LoadUrlFlags
import mozilla.components.concept.engine.serviceworker.ServiceWorkerDelegate
import org.mozilla.fenix.ext.components
/**
* Fenix own version of the `ServiceWorkerSupportFeature` from Android-Components
* which adds the ability to navigate to the browser before opening a new tab.
*
* Will automatically register callbacks for service workers requests and cleanup when [homeActivity] is destroyed.
*
* @param homeActivity [HomeActivity] used for navigating to browser or accessing various app components.
*/
class ServiceWorkerSupportFeature(
private val homeActivity: HomeActivity
) : ServiceWorkerDelegate, DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
homeActivity.components.core.engine.unregisterServiceWorkerDelegate()
}
override fun onCreate(owner: LifecycleOwner) {
homeActivity.components.core.engine.registerServiceWorkerDelegate(this)
}
override fun addNewTab(engineSession: EngineSession): Boolean {
with(homeActivity) {
openToBrowser(BrowserDirection.FromHome)
components.useCases.tabsUseCases.addTab(
flags = LoadUrlFlags.external(),
engineSession = engineSession,
source = SessionState.Source.Internal.None
)
}
return true
}
}

@ -0,0 +1,103 @@
/* 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.Context
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkStatic
import io.mockk.verify
import io.mockk.verifyOrder
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.state.state.SessionState.Source.Internal.None
import mozilla.components.concept.engine.EngineSession.LoadUrlFlags
import mozilla.components.feature.tabs.TabsUseCases.AddNewTabUseCase
import mozilla.components.support.test.eq
import org.junit.After
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.BrowserDirection.FromHome
import org.mozilla.fenix.ext.components
@RunWith(AndroidJUnit4::class)
class ServiceWorkerSupportTest {
@Before
fun setup() {
// Needed to mock the response of the "Context.components" extension property.
mockkStatic("org.mozilla.fenix.ext.ContextKt")
}
@After
fun teardown() {
unmockkStatic("org.mozilla.fenix.ext.ContextKt")
}
@Test
fun `GIVEN the feature is registered for lifecycle events WHEN the owner is created THEN register itself as a service worker delegate`() {
val engine: GeckoEngine = mockk(relaxed = true)
every { any<Context>().components.core.engine } returns engine
val feature = ServiceWorkerSupportFeature(mockk(relaxed = true))
feature.onCreate(mockk())
verify { engine.registerServiceWorkerDelegate(feature) }
}
@Test
fun `GIVEN the feature is registered for lifecycle events WHEN the owner is destroyed THEN unregister itself as a service worker delegate`() {
val engine: GeckoEngine = mockk(relaxed = true)
every { any<Context>().components.core.engine } returns engine
val feature = ServiceWorkerSupportFeature(mockk(relaxed = true))
feature.onDestroy(mockk())
verify { engine.unregisterServiceWorkerDelegate() }
}
@Test
fun `WHEN a new tab is requested THEN navigate to browser then add a new tab`() {
val addNewTabUseCase: AddNewTabUseCase = mockk(relaxed = true)
every { any<Context>().components.useCases.tabsUseCases.addTab } returns addNewTabUseCase
val activity: HomeActivity = mockk(relaxed = true)
val feature = ServiceWorkerSupportFeature(activity)
feature.addNewTab(mockk())
verifyOrder {
activity.openToBrowser(FromHome)
addNewTabUseCase(
url = eq("about:blank"),
selectTab = eq(true), // default
startLoading = eq(true), // default
parentId = eq(null), // default
flags = eq(LoadUrlFlags.external()),
contextId = eq(null), // default
engineSession = any(),
source = eq(None),
searchTerms = eq(""), // default
private = eq(false), // default
historyMetadata = eq(null) // default
)
}
}
@Test
fun `WHEN a new tab is requested THEN return true`() {
val addNewTabUseCase: AddNewTabUseCase = mockk(relaxed = true)
every { any<Context>().components.useCases.tabsUseCases.addTab } returns addNewTabUseCase
val activity: HomeActivity = mockk(relaxed = true)
val feature = ServiceWorkerSupportFeature(activity)
val result = feature.addNewTab(mockk())
assertTrue(result)
}
}

@ -135,7 +135,6 @@ object Deps {
const val mozilla_feature_webcompat = "org.mozilla.components:feature-webcompat:${Versions.mozilla_android_components}"
const val mozilla_feature_webnotifications = "org.mozilla.components:feature-webnotifications:${Versions.mozilla_android_components}"
const val mozilla_feature_webcompat_reporter = "org.mozilla.components:feature-webcompat-reporter:${Versions.mozilla_android_components}"
const val mozilla_feature_serviceworker = "org.mozilla.components:feature-serviceworker:${Versions.mozilla_android_components}"
const val mozilla_service_pocket = "org.mozilla.components:service-pocket:${Versions.mozilla_android_components}"
const val mozilla_service_contile =

Loading…
Cancel
Save