You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/main/java/org/mozilla/fenix/settings/biometric/BiometricPromptPreferenceFr...

121 lines
4.1 KiB
Kotlin

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.settings.biometric
import android.app.Activity.RESULT_OK
import android.app.KeyguardManager
import android.content.Context
import android.content.Intent
import android.view.View
import androidx.core.content.getSystemService
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.settings.requirePreference
/**
* Helper for creating and implementing the [BiometricPromptFeature]. Currently used
* for logins and credit cards.
*/
abstract class BiometricPromptPreferenceFragment : PreferenceFragmentCompat() {
private val biometricPromptFeature = ViewBoundFeatureWrapper<BiometricPromptFeature>()
/**
* Gets the string to be used for [BiometricPromptFeature.requestAuthentication] prompting to
* unlock the device.
*/
abstract fun unlockMessage(): String
/**
* Navigate when authentication is successful.
*/
abstract fun navigateOnSuccess()
/**
* Shows a dialog warning to set up a pin/password when the device is not secured. This is
* only used when BiometricPrompt is unavailable on the device.
*/
abstract fun showPinDialogWarning(context: Context)
/**
* Toggle preferences to enable or disable navigation during authentication flows.
*
* @param prefList a list of [Preference]s to toggle.
* @param enabled whether or not the preferences should be enabled.
*/
fun togglePrefsEnabled(prefList: List<Int>, enabled: Boolean) {
for (preference in prefList) {
requirePreference<Preference>(preference).isEnabled = enabled
}
}
/**
* Creates a prompt to verify the device's pin/password and start activity based on the result.
* This is only used when BiometricPrompt is unavailable on the device.
*/
@Suppress("Deprecation")
abstract fun showPinVerification(manager: KeyguardManager)
/**
* Sets the biometric prompt feature.
*
* @param view the view that the prompt will be associate with.
* @param prefList a list of [Preference]s to toggle.
*/
fun setBiometricPrompt(view: View, prefList: List<Int>) {
biometricPromptFeature.set(
feature = BiometricPromptFeature(
context = requireContext(),
fragment = this,
onAuthFailure = {
togglePrefsEnabled(prefList, true)
},
onAuthSuccess = ::navigateOnSuccess
),
owner = this,
view = view
)
}
/**
* Use [BiometricPromptFeature] or [KeyguardManager] to confirm device security.
*
* @param prefList a list of [Preference]s to disable while authentication is happening.
*/
fun verifyCredentialsOrShowSetupWarning(context: Context, prefList: List<Int>) {
// Use the BiometricPrompt if available
if (BiometricPromptFeature.canUseFeature(context)) {
togglePrefsEnabled(prefList, false)
biometricPromptFeature.get()?.requestAuthentication(unlockMessage())
return
}
// Fallback to prompting for password with the KeyguardManager
val manager = context.getSystemService<KeyguardManager>()
if (manager?.isKeyguardSecure == true) {
showPinVerification(manager)
} else {
// Warn that the device has not been secured
if (context.settings().shouldShowSecurityPinWarning) {
showPinDialogWarning(context)
} else {
navigateOnSuccess()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == PIN_REQUEST && resultCode == RESULT_OK) {
navigateOnSuccess()
}
}
companion object {
const val PIN_REQUEST = 303
}
}