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
parent
0f0aee5e97
commit
ab2ea8e682
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue