fix: better prompt variable management #2105

This commit is contained in:
J-Jamet
2025-08-13 18:27:51 +02:00
parent 04bcc6631c
commit da0f02e536
2 changed files with 34 additions and 30 deletions

View File

@@ -133,10 +133,12 @@ class DeviceUnlockFragment: Fragment() {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
mDeviceUnlockViewModel.uiState.collect { uiState -> mDeviceUnlockViewModel.uiState.collect { uiState ->
// Change mode // Change mode
toggleDeviceCredentialMode(uiState.deviceUnlockMode) toggleDeviceCredentialMode(
uiState.newDeviceUnlockMode,
uiState.deviceUnlockModeChange
)
// Prompt // Prompt
manageDeviceCredentialPrompt( manageDeviceCredentialPrompt(
uiState.cryptoPrompt,
uiState.cryptoPromptState uiState.cryptoPromptState
) )
// Advanced menu // Advanced menu
@@ -162,36 +164,32 @@ class DeviceUnlockFragment: Fragment() {
mBiometricPrompt?.cancelAuthentication() mBiometricPrompt?.cancelAuthentication()
} }
private var currentCredentialMode = DeviceUnlockMode.BIOMETRIC_UNAVAILABLE private fun toggleDeviceCredentialMode(deviceUnlockMode: DeviceUnlockMode, modeChanged: Boolean) {
private fun toggleDeviceCredentialMode(deviceUnlockMode: DeviceUnlockMode) { if (modeChanged) {
if (currentCredentialMode == deviceUnlockMode) { try {
return when (deviceUnlockMode) {
} DeviceUnlockMode.BIOMETRIC_UNAVAILABLE -> setNotAvailableMode()
currentCredentialMode = deviceUnlockMode DeviceUnlockMode.BIOMETRIC_SECURITY_UPDATE_REQUIRED -> setSecurityUpdateRequiredMode()
try { DeviceUnlockMode.DEVICE_CREDENTIAL_OR_BIOMETRIC_NOT_CONFIGURED -> setNotConfiguredMode()
when (deviceUnlockMode) { DeviceUnlockMode.KEY_MANAGER_UNAVAILABLE -> setKeyManagerNotAvailableMode()
DeviceUnlockMode.BIOMETRIC_UNAVAILABLE -> setNotAvailableMode() DeviceUnlockMode.WAIT_CREDENTIAL -> setWaitCredentialMode()
DeviceUnlockMode.BIOMETRIC_SECURITY_UPDATE_REQUIRED -> setSecurityUpdateRequiredMode() DeviceUnlockMode.STORE_CREDENTIAL -> setStoreCredentialMode()
DeviceUnlockMode.DEVICE_CREDENTIAL_OR_BIOMETRIC_NOT_CONFIGURED -> setNotConfiguredMode() DeviceUnlockMode.EXTRACT_CREDENTIAL -> setExtractCredentialMode()
DeviceUnlockMode.KEY_MANAGER_UNAVAILABLE -> setKeyManagerNotAvailableMode() }
DeviceUnlockMode.WAIT_CREDENTIAL -> setWaitCredentialMode() } catch (e: Exception) {
DeviceUnlockMode.STORE_CREDENTIAL -> setStoreCredentialMode() mDeviceUnlockViewModel.setException(e)
DeviceUnlockMode.EXTRACT_CREDENTIAL -> setExtractCredentialMode()
} }
} catch (e: Exception) {
mDeviceUnlockViewModel.setException(e)
} }
} }
private fun manageDeviceCredentialPrompt( private fun manageDeviceCredentialPrompt(
cryptoPrompt: DeviceUnlockCryptoPrompt?,
state: DeviceUnlockPromptMode state: DeviceUnlockPromptMode
) { ) {
cryptoPrompt?.let { mDeviceUnlockViewModel.cryptoPrompt?.let { prompt ->
when (state) { when (state) {
DeviceUnlockPromptMode.IDLE -> {} DeviceUnlockPromptMode.IDLE -> {}
DeviceUnlockPromptMode.SHOW -> { DeviceUnlockPromptMode.SHOW -> {
openPrompt(cryptoPrompt) openPrompt(prompt)
mDeviceUnlockViewModel.promptShown() mDeviceUnlockViewModel.promptShown()
} }
DeviceUnlockPromptMode.CLOSE -> { DeviceUnlockPromptMode.CLOSE -> {

View File

@@ -34,6 +34,9 @@ class DeviceUnlockViewModel(application: Application): AndroidViewModel(applicat
private var deviceUnlockManager: DeviceUnlockManager? = null private var deviceUnlockManager: DeviceUnlockManager? = null
private var databaseUri: Uri? = null private var databaseUri: Uri? = null
private var deviceUnlockMode = DeviceUnlockMode.BIOMETRIC_UNAVAILABLE
var cryptoPrompt: DeviceUnlockCryptoPrompt? = null
// TODO Retrieve credential storage from app database // TODO Retrieve credential storage from app database
var credentialDatabaseStorage: CredentialStorage = CredentialStorage.DEFAULT var credentialDatabaseStorage: CredentialStorage = CredentialStorage.DEFAULT
@@ -91,7 +94,7 @@ class DeviceUnlockViewModel(application: Application): AndroidViewModel(applicat
} }
private fun isModeChanging(newMode: DeviceUnlockMode): Boolean { private fun isModeChanging(newMode: DeviceUnlockMode): Boolean {
return _uiState.value.deviceUnlockMode != newMode return deviceUnlockMode != newMode
} }
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
@@ -165,7 +168,7 @@ class DeviceUnlockViewModel(application: Application): AndroidViewModel(applicat
fun onAuthenticationSucceeded( fun onAuthenticationSucceeded(
activityResult: ActivityResult activityResult: ActivityResult
) { ) {
uiState.value.cryptoPrompt?.let { prompt -> cryptoPrompt?.let { prompt ->
when (prompt.type) { when (prompt.type) {
DeviceUnlockCryptoPromptType.CREDENTIAL_ENCRYPTION -> DeviceUnlockCryptoPromptType.CREDENTIAL_ENCRYPTION ->
retrieveCredentialForEncryption( prompt.cipher) retrieveCredentialForEncryption( prompt.cipher)
@@ -179,7 +182,7 @@ class DeviceUnlockViewModel(application: Application): AndroidViewModel(applicat
fun onAuthenticationSucceeded( fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult result: BiometricPrompt.AuthenticationResult
) { ) {
uiState.value.cryptoPrompt?.type?.let { type -> cryptoPrompt?.type?.let { type ->
when (type) { when (type) {
DeviceUnlockCryptoPromptType.CREDENTIAL_ENCRYPTION -> DeviceUnlockCryptoPromptType.CREDENTIAL_ENCRYPTION ->
retrieveCredentialForEncryption(result.cryptoObject?.cipher) retrieveCredentialForEncryption(result.cryptoObject?.cipher)
@@ -299,9 +302,9 @@ class DeviceUnlockViewModel(application: Application): AndroidViewModel(applicat
cryptoPrompt: DeviceUnlockCryptoPrompt, cryptoPrompt: DeviceUnlockCryptoPrompt,
autoOpen: Boolean = false autoOpen: Boolean = false
) { ) {
this@DeviceUnlockViewModel.cryptoPrompt = cryptoPrompt
_uiState.update { currentState -> _uiState.update { currentState ->
currentState.copy( currentState.copy(
cryptoPrompt = cryptoPrompt,
cryptoPromptState = if ( cryptoPromptState = if (
autoOpen autoOpen
&& PreferencesUtil.isAdvancedUnlockPromptAutoOpenEnable(getApplication())) && PreferencesUtil.isAdvancedUnlockPromptAutoOpenEnable(getApplication()))
@@ -374,10 +377,13 @@ class DeviceUnlockViewModel(application: Application): AndroidViewModel(applicat
@RequiresApi(Build.VERSION_CODES.M) @RequiresApi(Build.VERSION_CODES.M)
private fun changeMode(deviceUnlockMode: DeviceUnlockMode) { private fun changeMode(deviceUnlockMode: DeviceUnlockMode) {
val modeChanged = this.deviceUnlockMode == deviceUnlockMode
this.deviceUnlockMode = deviceUnlockMode
cipherDatabaseAction.containsCipherDatabase(databaseUri) { containsCipher -> cipherDatabaseAction.containsCipherDatabase(databaseUri) { containsCipher ->
_uiState.update { currentState -> _uiState.update { currentState ->
currentState.copy( currentState.copy(
deviceUnlockMode = deviceUnlockMode, newDeviceUnlockMode = deviceUnlockMode,
deviceUnlockModeChange = modeChanged,
allowAdvancedUnlockMenu = containsCipher allowAdvancedUnlockMenu = containsCipher
&& deviceUnlockMode != DeviceUnlockMode.BIOMETRIC_UNAVAILABLE && deviceUnlockMode != DeviceUnlockMode.BIOMETRIC_UNAVAILABLE
&& deviceUnlockMode != DeviceUnlockMode.KEY_MANAGER_UNAVAILABLE && deviceUnlockMode != DeviceUnlockMode.KEY_MANAGER_UNAVAILABLE
@@ -409,9 +415,9 @@ class DeviceUnlockViewModel(application: Application): AndroidViewModel(applicat
} }
fun biometricPromptClosed() { fun biometricPromptClosed() {
cryptoPrompt = null
_uiState.update { currentState -> _uiState.update { currentState ->
currentState.copy( currentState.copy(
cryptoPrompt = null,
cryptoPromptState = DeviceUnlockPromptMode.IDLE cryptoPromptState = DeviceUnlockPromptMode.IDLE
) )
} }
@@ -437,12 +443,12 @@ enum class DeviceUnlockPromptMode {
} }
data class DeviceUnlockState( data class DeviceUnlockState(
val deviceUnlockMode: DeviceUnlockMode = DeviceUnlockMode.BIOMETRIC_UNAVAILABLE, val newDeviceUnlockMode: DeviceUnlockMode = DeviceUnlockMode.BIOMETRIC_UNAVAILABLE,
val deviceUnlockModeChange: Boolean = true,
val allowAdvancedUnlockMenu: Boolean = false, val allowAdvancedUnlockMenu: Boolean = false,
val credentialRequiredCipher: Cipher? = null, val credentialRequiredCipher: Cipher? = null,
val cipherEncryptDatabase: CipherEncryptDatabase? = null, val cipherEncryptDatabase: CipherEncryptDatabase? = null,
val cipherDecryptDatabase: CipherDecryptDatabase? = null, val cipherDecryptDatabase: CipherDecryptDatabase? = null,
val cryptoPrompt: DeviceUnlockCryptoPrompt? = null,
val cryptoPromptState: DeviceUnlockPromptMode = DeviceUnlockPromptMode.IDLE, val cryptoPromptState: DeviceUnlockPromptMode = DeviceUnlockPromptMode.IDLE,
val autoOpenPrompt: Boolean = false, val autoOpenPrompt: Boolean = false,
val exception: Exception? = null val exception: Exception? = null