Source code
Revision control
Copy as Markdown
Other Tools
/* 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
package org.mozilla.fenix
import android.content.Intent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import mozilla.components.feature.session.SessionFeature
import mozilla.components.feature.tabs.CustomTabsUseCases
import mozilla.components.lib.state.helpers.AbstractBinding
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.components.appstate.AppState
/**
* A binding for observing [AppState.openInFirefoxRequested] in the [AppStore] and opening the tab in the browser.
*
* @param activity The [HomeActivity] used to switch to the actual browser.
* @param appStore The [AppStore] used to observe [AppState.openInFirefoxRequested].
* @param customTabSessionId Optional custom tab session ID if navigating from a custom tab or null if the selected
* session should be used.
* @param customTabsUseCases The [CustomTabsUseCases] used to turn the session into a regular tab and select it.
* @param openInFenixIntent The [Intent] used to open the tab in the browser.
* @param sessionFeature The [SessionFeature] used to release the session from the EngineView.
* @param mainDispatcher The [CoroutineDispatcher] on which the state observation and updates will occur. Defaults to
* [Dispatchers.Main].
*/
class OpenInFirefoxBinding(
private val activity: HomeActivity,
private val appStore: AppStore,
private val customTabSessionId: String?,
private val customTabsUseCases: CustomTabsUseCases,
private val openInFenixIntent: Intent,
private val sessionFeature: ViewBoundFeatureWrapper<SessionFeature>,
mainDispatcher: CoroutineDispatcher = Dispatchers.Main,
) : AbstractBinding<AppState>(appStore, mainDispatcher) {
override suspend fun onState(flow: Flow<AppState>) {
flow
.map { state -> state.openInFirefoxRequested }
.distinctUntilChanged()
.collect { state ->
when (state) {
true -> {
customTabSessionId?.let {
// Stop the SessionFeature from updating the EngineView and let it release the session
// from the EngineView so that it can immediately be rendered by a different view once
// we switch to the actual browser.
sessionFeature.get()?.release()
// Turn this Session into a regular tab and then select it
customTabsUseCases.migrate(customTabSessionId, select = true)
// Switch to the actual browser which should now display our new selected session
activity.startActivity(
openInFenixIntent.apply {
// We never want to launch the browser in the same task as the external app
// activity. So we force a new task here. IntentReceiverActivity will do the
// right thing and take care of routing to an already existing browser and avoid
// cloning a new one.
flags = flags or Intent.FLAG_ACTIVITY_NEW_TASK
}
)
// Close this activity (and the task) since it is no longer displaying any session
activity.finishAndRemoveTask()
appStore.dispatch(AppAction.OpenInFirefoxFinished)
}
}
false -> Unit
}
}
}
}