For #2395 - Properly takes you back to where you start authentication on completion
parent
12eabd5eb3
commit
f26c402f0a
|
@ -15,7 +15,7 @@ class Components(private val context: Context) {
|
||||||
val backgroundServices by lazy {
|
val backgroundServices by lazy {
|
||||||
BackgroundServices(context, core.historyStorage, core.bookmarksStorage, utils.notificationManager)
|
BackgroundServices(context, core.historyStorage, core.bookmarksStorage, utils.notificationManager)
|
||||||
}
|
}
|
||||||
val services by lazy { Services(backgroundServices.accountManager, useCases.tabsUseCases) }
|
val services by lazy { Services(backgroundServices.accountManager) }
|
||||||
val core by lazy { Core(context) }
|
val core by lazy { Core(context) }
|
||||||
val search by lazy { Search(context) }
|
val search by lazy { Search(context) }
|
||||||
val useCases by lazy { UseCases(context, core.sessionManager, core.engine.settings, search.searchEngineManager) }
|
val useCases by lazy { UseCases(context, core.sessionManager, core.engine.settings, search.searchEngineManager) }
|
||||||
|
|
|
@ -4,9 +4,8 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.components
|
package org.mozilla.fenix.components
|
||||||
|
|
||||||
import mozilla.components.feature.accounts.FirefoxAccountsAuthFeature
|
|
||||||
import mozilla.components.feature.tabs.TabsUseCases
|
|
||||||
import mozilla.components.service.fxa.manager.FxaAccountManager
|
import mozilla.components.service.fxa.manager.FxaAccountManager
|
||||||
|
import org.mozilla.fenix.components.features.FirefoxAccountsAuthFeature
|
||||||
import org.mozilla.fenix.test.Mockable
|
import org.mozilla.fenix.test.Mockable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,13 +13,11 @@ import org.mozilla.fenix.test.Mockable
|
||||||
*/
|
*/
|
||||||
@Mockable
|
@Mockable
|
||||||
class Services(
|
class Services(
|
||||||
private val accountManager: FxaAccountManager,
|
private val accountManager: FxaAccountManager
|
||||||
private val tabsUseCases: TabsUseCases
|
|
||||||
) {
|
) {
|
||||||
val accountsAuthFeature by lazy {
|
val accountsAuthFeature by lazy {
|
||||||
FirefoxAccountsAuthFeature(
|
FirefoxAccountsAuthFeature(
|
||||||
accountManager,
|
accountManager,
|
||||||
tabsUseCases,
|
|
||||||
redirectUrl = BackgroundServices.REDIRECT_URL
|
redirectUrl = BackgroundServices.REDIRECT_URL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.mozilla.fenix.components.features
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.components.concept.engine.EngineSession
|
||||||
|
import mozilla.components.concept.engine.request.RequestInterceptor
|
||||||
|
import mozilla.components.service.fxa.manager.FxaAccountManager
|
||||||
|
import org.mozilla.fenix.settings.SupportUtils
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class FirefoxAccountsAuthFeature(
|
||||||
|
private val accountManager: FxaAccountManager,
|
||||||
|
private val redirectUrl: String,
|
||||||
|
private val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
|
) {
|
||||||
|
fun beginAuthentication(context: Context) {
|
||||||
|
beginAuthenticationAsync(context) {
|
||||||
|
accountManager.beginAuthenticationAsync().await()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun beginPairingAuthentication(context: Context, pairingUrl: String) {
|
||||||
|
beginAuthenticationAsync(context) {
|
||||||
|
accountManager.beginAuthenticationAsync(pairingUrl).await()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun beginAuthenticationAsync(context: Context, beginAuthentication: suspend () -> String?) {
|
||||||
|
CoroutineScope(coroutineContext).launch {
|
||||||
|
// FIXME return a fallback URL provided by Config...
|
||||||
|
// https://github.com/mozilla-mobile/android-components/issues/2496
|
||||||
|
val authUrl = beginAuthentication() ?: "https://accounts.firefox.com/signin"
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// We may fail to obtain an authentication URL, for example due to transient network errors.
|
||||||
|
// If that happens, open up a fallback URL in order to present some kind of a "no network"
|
||||||
|
// UI to the user.
|
||||||
|
// It's possible that the underlying problem will go away by the time the tab actually
|
||||||
|
// loads, resulting in a confusing experience.
|
||||||
|
val intent = SupportUtils.createCustomTabIntent(context, authUrl)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val interceptor = object : RequestInterceptor {
|
||||||
|
override fun onLoadRequest(session: EngineSession, uri: String): RequestInterceptor.InterceptionResponse? {
|
||||||
|
if (uri.startsWith(redirectUrl)) {
|
||||||
|
val parsedUri = Uri.parse(uri)
|
||||||
|
val code = parsedUri.getQueryParameter("code")
|
||||||
|
|
||||||
|
if (code != null) {
|
||||||
|
val state = parsedUri.getQueryParameter("state") as String
|
||||||
|
|
||||||
|
// Notify the state machine about our success.
|
||||||
|
accountManager.finishAuthenticationAsync(code, state)
|
||||||
|
|
||||||
|
return RequestInterceptor.InterceptionResponse.Url(redirectUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -284,7 +284,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
|
||||||
.subscribe {
|
.subscribe {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SignInAction.ClickedSignIn -> {
|
is SignInAction.ClickedSignIn -> {
|
||||||
context?.components?.services?.accountsAuthFeature?.beginAuthentication()
|
context?.components?.services?.accountsAuthFeature?.beginAuthentication(requireContext())
|
||||||
(activity as HomeActivity).openToBrowser(BrowserDirection.FromBookmarks)
|
(activity as HomeActivity).openToBrowser(BrowserDirection.FromBookmarks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver
|
||||||
.subscribe {
|
.subscribe {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SignInAction.ClickedSignIn -> {
|
is SignInAction.ClickedSignIn -> {
|
||||||
requireComponents.services.accountsAuthFeature.beginAuthentication()
|
requireComponents.services.accountsAuthFeature.beginAuthentication(requireContext())
|
||||||
view?.let {
|
view?.let {
|
||||||
(activity as HomeActivity).openToBrowser(BrowserDirection.FromBookmarksFolderSelect)
|
(activity as HomeActivity).openToBrowser(BrowserDirection.FromBookmarksFolderSelect)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class AccountProblemFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
private fun getClickListenerForSignIn(): Preference.OnPreferenceClickListener {
|
private fun getClickListenerForSignIn(): Preference.OnPreferenceClickListener {
|
||||||
return Preference.OnPreferenceClickListener {
|
return Preference.OnPreferenceClickListener {
|
||||||
requireComponents.services.accountsAuthFeature.beginAuthentication()
|
requireComponents.services.accountsAuthFeature.beginAuthentication(requireContext())
|
||||||
// TODO The sign-in web content populates session history,
|
// TODO The sign-in web content populates session history,
|
||||||
// so pressing "back" after signing in won't take us back into the settings screen, but rather up the
|
// so pressing "back" after signing in won't take us back into the settings screen, but rather up the
|
||||||
// session history stack.
|
// session history stack.
|
||||||
|
|
|
@ -16,8 +16,6 @@ import androidx.navigation.fragment.NavHostFragment.findNavController
|
||||||
import mozilla.components.feature.qr.QrFeature
|
import mozilla.components.feature.qr.QrFeature
|
||||||
import mozilla.components.support.base.feature.BackHandler
|
import mozilla.components.support.base.feature.BackHandler
|
||||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||||
import org.mozilla.fenix.BrowserDirection
|
|
||||||
import org.mozilla.fenix.HomeActivity
|
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
|
|
||||||
|
@ -43,8 +41,12 @@ class PairFragment : Fragment(), BackHandler {
|
||||||
requestPermissions(permissions, REQUEST_CODE_CAMERA_PERMISSIONS)
|
requestPermissions(permissions, REQUEST_CODE_CAMERA_PERMISSIONS)
|
||||||
},
|
},
|
||||||
onScanResult = { pairingUrl ->
|
onScanResult = { pairingUrl ->
|
||||||
requireComponents.services.accountsAuthFeature.beginPairingAuthentication(pairingUrl)
|
requireComponents.services.accountsAuthFeature.beginPairingAuthentication(
|
||||||
(activity as HomeActivity).openToBrowser(BrowserDirection.FromPair)
|
requireContext(),
|
||||||
|
pairingUrl
|
||||||
|
)
|
||||||
|
findNavController(this@PairFragment)
|
||||||
|
.popBackStack(R.id.turnOnSyncFragment, false)
|
||||||
}),
|
}),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = view
|
view = view
|
||||||
|
@ -63,7 +65,8 @@ class PairFragment : Fragment(), BackHandler {
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean {
|
override fun onBackPressed(): Boolean {
|
||||||
qrFeature.onBackPressed()
|
qrFeature.onBackPressed()
|
||||||
findNavController(this@PairFragment).navigateUp()
|
findNavController(this@PairFragment)
|
||||||
|
.popBackStack(R.id.turnOnSyncFragment, false)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,20 @@ package org.mozilla.fenix.settings
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
|
import androidx.navigation.fragment.NavHostFragment.findNavController
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import org.mozilla.fenix.BrowserDirection
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
import org.mozilla.fenix.HomeActivity
|
import mozilla.components.concept.sync.OAuthAccount
|
||||||
|
import mozilla.components.concept.sync.Profile
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.getPreferenceKey
|
import org.mozilla.fenix.ext.getPreferenceKey
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
|
|
||||||
class TurnOnSyncFragment : PreferenceFragmentCompat() {
|
@SuppressWarnings("TooManyFunctions")
|
||||||
|
class TurnOnSyncFragment : PreferenceFragmentCompat(), AccountObserver {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
requireComponents.analytics.metrics.track(Event.SyncAuthOpened)
|
requireComponents.analytics.metrics.track(Event.SyncAuthOpened)
|
||||||
|
@ -30,6 +33,11 @@ class TurnOnSyncFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
if (requireComponents.backgroundServices.accountManager.authenticatedAccount() != null) {
|
||||||
|
findNavController(this).popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
requireComponents.backgroundServices.accountManager.register(this, owner = this)
|
||||||
(activity as AppCompatActivity).title = getString(R.string.preferences_sync)
|
(activity as AppCompatActivity).title = getString(R.string.preferences_sync)
|
||||||
(activity as AppCompatActivity).supportActionBar?.show()
|
(activity as AppCompatActivity).supportActionBar?.show()
|
||||||
}
|
}
|
||||||
|
@ -50,16 +58,13 @@ class TurnOnSyncFragment : PreferenceFragmentCompat() {
|
||||||
|
|
||||||
private fun getClickListenerForSignIn(): Preference.OnPreferenceClickListener {
|
private fun getClickListenerForSignIn(): Preference.OnPreferenceClickListener {
|
||||||
return Preference.OnPreferenceClickListener {
|
return Preference.OnPreferenceClickListener {
|
||||||
requireComponents.services.accountsAuthFeature.beginAuthentication()
|
requireComponents.services.accountsAuthFeature.beginAuthentication(requireContext())
|
||||||
// TODO The sign-in web content populates session history,
|
// TODO The sign-in web content populates session history,
|
||||||
// so pressing "back" after signing in won't take us back into the settings screen, but rather up the
|
// so pressing "back" after signing in won't take us back into the settings screen, but rather up the
|
||||||
// session history stack.
|
// session history stack.
|
||||||
// We could auto-close this tab once we get to the end of the authentication process?
|
// We could auto-close this tab once we get to the end of the authentication process?
|
||||||
// Via an interceptor, perhaps.
|
// Via an interceptor, perhaps.
|
||||||
requireComponents.analytics.metrics.track(Event.SyncAuthSignIn)
|
requireComponents.analytics.metrics.track(Event.SyncAuthSignIn)
|
||||||
view?.let {
|
|
||||||
(activity as HomeActivity).openToBrowser(BrowserDirection.FromTurnOnSync)
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,11 +72,8 @@ class TurnOnSyncFragment : PreferenceFragmentCompat() {
|
||||||
private fun getClickListenerForCreateAccount(): Preference.OnPreferenceClickListener {
|
private fun getClickListenerForCreateAccount(): Preference.OnPreferenceClickListener {
|
||||||
// Currently the same as sign in, as FxA handles this, however we want to emit a different telemetry event
|
// Currently the same as sign in, as FxA handles this, however we want to emit a different telemetry event
|
||||||
return Preference.OnPreferenceClickListener {
|
return Preference.OnPreferenceClickListener {
|
||||||
requireComponents.services.accountsAuthFeature.beginAuthentication()
|
requireComponents.services.accountsAuthFeature.beginAuthentication(requireContext())
|
||||||
requireComponents.analytics.metrics.track(Event.SyncAuthCreateAccount)
|
requireComponents.analytics.metrics.track(Event.SyncAuthCreateAccount)
|
||||||
view?.let {
|
|
||||||
(activity as HomeActivity).openToBrowser(BrowserDirection.FromTurnOnSync)
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,4 +87,14 @@ class TurnOnSyncFragment : PreferenceFragmentCompat() {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
override fun onAuthenticated(account: OAuthAccount) {
|
||||||
|
FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_SHORT)
|
||||||
|
.setText(requireContext().getString(R.string.sync_syncing_in_progress))
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationProblems() {}
|
||||||
|
override fun onError(error: Exception) {}
|
||||||
|
override fun onLoggedOut() {}
|
||||||
|
override fun onProfileUpdated(profile: Profile) {} }
|
||||||
|
|
Loading…
Reference in New Issue