Commit bceb07a0 authored by ekager's avatar ekager Committed by Emily Kager
Browse files

For #12312 - Disable settings that navigate while authenticating

parent 3e617245
Loading
Loading
Loading
Loading
+40 −13
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.preference.Preference
@@ -31,6 +32,7 @@ import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.service.fxa.SyncEngine
import mozilla.components.service.fxa.manager.SyncEnginesStorage
import org.mozilla.fenix.R
import org.mozilla.fenix.addons.runIfFragmentIsAttached
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.requireComponents
@@ -39,7 +41,7 @@ import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.settings.SharedPreferenceUpdater
import org.mozilla.fenix.settings.requirePreference
import java.util.concurrent.Executors
import java.util.concurrent.Executor

@Suppress("TooManyFunctions", "LargeClass")
class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {
@@ -48,7 +50,7 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {
    private lateinit var biometricPromptCallback: BiometricPrompt.AuthenticationCallback

    @TargetApi(M)
    private val executor = Executors.newSingleThreadExecutor()
    private lateinit var executor: Executor

    @TargetApi(M)
    private lateinit var biometricPrompt: BiometricPrompt
@@ -60,6 +62,28 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {
        setPreferencesFromResource(R.xml.logins_preferences, rootKey)
    }

    /**
     * There is a bug where while the biometric prompt is showing, you were able to quickly navigate
     * so we are disabling the settings that navigate while authenticating.
     * https://github.com/mozilla-mobile/fenix/issues/12312
     */
    private fun togglePrefsEnabledWhileAuthenticating(enabled: Boolean) {
        requirePreference<Preference>(R.string.pref_key_password_sync_logins).isEnabled = enabled
        requirePreference<Preference>(R.string.pref_key_save_logins_settings).isEnabled = enabled
        requirePreference<Preference>(R.string.pref_key_saved_logins).isEnabled = enabled
    }

    private fun navigateToSavedLogins() {
        runIfFragmentIsAttached {
            viewLifecycleOwner.lifecycleScope.launch(Main) {
                // Workaround for likely biometric library bug
                // https://github.com/mozilla-mobile/fenix/issues/8438
                delay(SHORT_DELAY_MS)
                navigateToSavedLoginsFragment()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

@@ -67,23 +91,22 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {

            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                Log.e(LOG_TAG, "onAuthenticationError $errString")
                togglePrefsEnabledWhileAuthenticating(enabled = true)
            }

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                Log.d(LOG_TAG, "onAuthenticationSucceeded")
                viewLifecycleOwner.lifecycleScope.launch(Main) {
                    // Workaround for likely biometric library bug
                    // https://github.com/mozilla-mobile/fenix/issues/8438
                    delay(SHORT_DELAY_MS)
                    navigateToSavedLoginsFragment()
                }
                navigateToSavedLogins()
            }

            override fun onAuthenticationFailed() {
                Log.e(LOG_TAG, "onAuthenticationFailed")
                togglePrefsEnabledWhileAuthenticating(enabled = true)
            }
        }

        executor = ContextCompat.getMainExecutor(requireContext())

        biometricPrompt = BiometricPrompt(this, executor, biometricPromptCallback)

        promptInfo = BiometricPrompt.PromptInfo.Builder()
@@ -122,6 +145,7 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {

        requirePreference<Preference>(R.string.pref_key_saved_logins).setOnPreferenceClickListener {
            if (Build.VERSION.SDK_INT >= M && isHardwareAvailable && hasBiometricEnrolled) {
                togglePrefsEnabledWhileAuthenticating(enabled = false)
                biometricPrompt.authenticate(promptInfo)
            } else {
                verifyPinOrShowSetupWarning()
@@ -148,7 +172,7 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {

    override fun onAuthenticationProblems() = updateSyncPreferenceNeedsReauth()

    val isHardwareAvailable: Boolean by lazy {
    private val isHardwareAvailable: Boolean by lazy {
        if (Build.VERSION.SDK_INT >= M) {
            context?.let {
                val bm = BiometricManager.from(it)
@@ -161,7 +185,7 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {
        }
    }

    val hasBiometricEnrolled: Boolean by lazy {
    private val hasBiometricEnrolled: Boolean by lazy {
        if (Build.VERSION.SDK_INT >= M) {
            context?.let {
                val bm = BiometricManager.from(it)
@@ -252,7 +276,8 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {
            getString(R.string.logins_biometric_prompt_message_pin),
            getString(R.string.logins_biometric_prompt_message)
        )
        startActivityForResult(intent,
        startActivityForResult(
            intent,
            PIN_REQUEST
        )
    }
@@ -267,7 +292,8 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {

    private fun navigateToSavedLoginsFragment() {
        context?.components?.analytics?.metrics?.track(Event.OpenLogins)
        val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToLoginsListFragment()
        val directions =
            SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToLoginsListFragment()
        findNavController().navigate(directions)
    }

@@ -283,7 +309,8 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver {
    }

    private fun navigateToTurnOnSyncFragment() {
        val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment()
        val directions =
            SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment()
        findNavController().navigate(directions)
    }