1
0
Fork 0

For #2395 - Properly takes you back to where you start authentication on completion

master
Jeff Boek 2019-06-04 15:57:24 -07:00
parent 12eabd5eb3
commit f26c402f0a
8 changed files with 106 additions and 27 deletions

View File

@ -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) }

View File

@ -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
) )
} }

View File

@ -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
}
}
}

View File

@ -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)
} }
} }

View File

@ -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)
} }

View File

@ -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.

View File

@ -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
} }

View File

@ -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) {} }