Loading app/src/main/java/org/mozilla/fenix/settings/logins/SavedLoginsAuthFragment.kt +40 −13 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 { Loading @@ -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 Loading @@ -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) Loading @@ -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() Loading Loading @@ -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() Loading @@ -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) Loading @@ -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) Loading Loading @@ -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 ) } Loading @@ -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) } Loading @@ -283,7 +309,8 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver { } private fun navigateToTurnOnSyncFragment() { val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() findNavController().navigate(directions) } Loading Loading
app/src/main/java/org/mozilla/fenix/settings/logins/SavedLoginsAuthFragment.kt +40 −13 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 { Loading @@ -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 Loading @@ -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) Loading @@ -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() Loading Loading @@ -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() Loading @@ -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) Loading @@ -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) Loading Loading @@ -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 ) } Loading @@ -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) } Loading @@ -283,7 +309,8 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat(), AccountObserver { } private fun navigateToTurnOnSyncFragment() { val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() findNavController().navigate(directions) } Loading