1
0
Fork 0

For #13037 - Use email to sign in to fxa if device has no camera

App can be installed on devices with no camera modules. Like Android TV boxes.
Will skip presenting the option to sign in by scanning a qr code in this case
and default to login with email and password.
master
Mugurell 2020-07-31 18:04:15 +03:00
parent 0f0aee5e97
commit ab2ea8e682
4 changed files with 70 additions and 6 deletions

View File

@ -25,6 +25,7 @@ import mozilla.components.concept.sync.AccountObserver
import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.AuthType
import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.concept.sync.Profile import mozilla.components.concept.sync.Profile
import mozilla.components.support.ktx.android.content.hasCamera
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.Config import org.mozilla.fenix.Config
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
@ -188,7 +189,16 @@ class SettingsFragment : PreferenceFragmentCompat() {
val directions: NavDirections? = when (preference.key) { val directions: NavDirections? = when (preference.key) {
resources.getString(R.string.pref_key_sign_in) -> { resources.getString(R.string.pref_key_sign_in) -> {
SettingsFragmentDirections.actionSettingsFragmentToTurnOnSyncFragment() // App can be installed on devices with no camera modules. Like Android TV boxes.
// Let's skip presenting the option to sign in by scanning a qr code in this case
// and default to login with email and password.
if (requireContext().hasCamera()) {
SettingsFragmentDirections.actionSettingsFragmentToTurnOnSyncFragment()
} else {
requireComponents.services.accountsAuthFeature.beginAuthentication(requireContext())
requireComponents.analytics.metrics.track(Event.SyncAuthUseEmail)
null
}
} }
resources.getString(R.string.pref_key_search_settings) -> { resources.getString(R.string.pref_key_search_settings) -> {
SettingsFragmentDirections.actionSettingsFragmentToSearchEngineFragment() SettingsFragmentDirections.actionSettingsFragmentToSearchEngineFragment()

View File

@ -4,16 +4,21 @@
package org.mozilla.fenix.settings.logins package org.mozilla.fenix.settings.logins
import android.content.Context
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.preference.Preference import androidx.preference.Preference
import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AccountObserver
import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.AuthType
import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.feature.accounts.FirefoxAccountsAuthFeature
import mozilla.components.service.fxa.SyncEngine import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.manager.SyncEnginesStorage import mozilla.components.service.fxa.manager.SyncEnginesStorage
import mozilla.components.support.ktx.android.content.hasCamera
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections
/** /**
@ -23,7 +28,9 @@ class SyncLoginsPreferenceView(
private val syncLoginsPreference: Preference, private val syncLoginsPreference: Preference,
lifecycleOwner: LifecycleOwner, lifecycleOwner: LifecycleOwner,
accountManager: FxaAccountManager, accountManager: FxaAccountManager,
private val navController: NavController private val navController: NavController,
private val accountsAuthFeature: FirefoxAccountsAuthFeature,
private val metrics: MetricController
) { ) {
init { init {
@ -68,7 +75,15 @@ class SyncLoginsPreferenceView(
syncLoginsPreference.apply { syncLoginsPreference.apply {
summary = context.getString(R.string.preferences_passwords_sync_logins_sign_in) summary = context.getString(R.string.preferences_passwords_sync_logins_sign_in)
setOnPreferenceClickListener { setOnPreferenceClickListener {
navigateToTurnOnSyncFragment() // App can be installed on devices with no camera modules. Like Android TV boxes.
// Let's skip presenting the option to sign in by scanning a qr code in this case
// and default to login with email and password.
if (context.hasCamera()) {
navigateToTurnOnSyncFragment()
} else {
navigateToPairWithEmail(context)
}
true true
} }
} }
@ -102,4 +117,9 @@ class SyncLoginsPreferenceView(
val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment()
navController.navigate(directions) navController.navigate(directions)
} }
private fun navigateToPairWithEmail(context: Context) {
accountsAuthFeature.beginAuthentication(context)
metrics.track(Event.SyncAuthUseEmail)
}
} }

View File

@ -145,7 +145,9 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat() {
requirePreference(R.string.pref_key_password_sync_logins), requirePreference(R.string.pref_key_password_sync_logins),
lifecycleOwner = viewLifecycleOwner, lifecycleOwner = viewLifecycleOwner,
accountManager = requireComponents.backgroundServices.accountManager, accountManager = requireComponents.backgroundServices.accountManager,
navController = findNavController() navController = findNavController(),
accountsAuthFeature = requireComponents.services.accountsAuthFeature,
metrics = requireComponents.analytics.metrics
) )
togglePrefsEnabledWhileAuthenticating(enabled = true) togglePrefsEnabledWhileAuthenticating(enabled = true)

View File

@ -12,18 +12,24 @@ import io.mockk.impl.annotations.MockK
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkConstructor import io.mockk.mockkConstructor
import io.mockk.mockkStatic
import io.mockk.slot import io.mockk.slot
import io.mockk.unmockkConstructor import io.mockk.unmockkConstructor
import io.mockk.unmockkStatic
import io.mockk.verify import io.mockk.verify
import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AccountObserver
import mozilla.components.feature.accounts.FirefoxAccountsAuthFeature
import mozilla.components.service.fxa.SyncEngine import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.manager.SyncEnginesStorage import mozilla.components.service.fxa.manager.SyncEnginesStorage
import mozilla.components.support.ktx.android.content.hasCamera
import org.junit.After import org.junit.After
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections
class SyncLoginsPreferenceViewTest { class SyncLoginsPreferenceViewTest {
@ -32,6 +38,8 @@ class SyncLoginsPreferenceViewTest {
@MockK private lateinit var lifecycleOwner: LifecycleOwner @MockK private lateinit var lifecycleOwner: LifecycleOwner
@MockK private lateinit var accountManager: FxaAccountManager @MockK private lateinit var accountManager: FxaAccountManager
@MockK(relaxed = true) private lateinit var navController: NavController @MockK(relaxed = true) private lateinit var navController: NavController
@MockK(relaxed = true) private lateinit var accountsAuthFeature: FirefoxAccountsAuthFeature
@MockK(relaxed = true) private lateinit var metrics: MetricController
private lateinit var accountObserver: CapturingSlot<AccountObserver> private lateinit var accountObserver: CapturingSlot<AccountObserver>
private lateinit var clickListener: CapturingSlot<Preference.OnPreferenceClickListener> private lateinit var clickListener: CapturingSlot<Preference.OnPreferenceClickListener>
@ -87,9 +95,11 @@ class SyncLoginsPreferenceViewTest {
} }
@Test @Test
fun `needs login if account does not exist`() { fun `needs login if account does not exist and device has camera`() {
every { accountManager.authenticatedAccount() } returns null every { accountManager.authenticatedAccount() } returns null
every { accountManager.accountNeedsReauth() } returns false every { accountManager.accountNeedsReauth() } returns false
mockkStatic("mozilla.components.support.ktx.android.content.ContextKt")
every { any<Context>().hasCamera() } returns true
createView() createView()
verify { syncLoginsPreference.summary = "Sign in to Sync" } verify { syncLoginsPreference.summary = "Sign in to Sync" }
@ -100,6 +110,26 @@ class SyncLoginsPreferenceViewTest {
SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment()
) )
} }
unmockkStatic("mozilla.components.support.ktx.android.content.ContextKt")
}
@Test
fun `needs login if account does not exist and device does not have camera`() {
every { accountManager.authenticatedAccount() } returns null
every { accountManager.accountNeedsReauth() } returns false
createView()
mockkStatic("mozilla.components.support.ktx.android.content.ContextKt")
every { any<Context>().hasCamera() } returns false
verify { syncLoginsPreference.summary = "Sign in to Sync" }
assertTrue(clickListener.captured.onPreferenceClick(syncLoginsPreference))
verify {
accountsAuthFeature.beginAuthentication(any())
metrics.track(Event.SyncAuthUseEmail)
}
unmockkStatic("mozilla.components.support.ktx.android.content.ContextKt")
} }
@Test @Test
@ -141,6 +171,8 @@ class SyncLoginsPreferenceViewTest {
syncLoginsPreference, syncLoginsPreference,
lifecycleOwner, lifecycleOwner,
accountManager, accountManager,
navController navController,
accountsAuthFeature,
metrics
) )
} }