diff options
| author | 2024-04-11 06:53:32 +0000 | |
|---|---|---|
| committer | 2024-04-15 03:29:31 +0000 | |
| commit | 96b30a4b40a9388ae61758b27e207d44a3c0d3b8 (patch) | |
| tree | d45f278445645eb60fe4799b9d926ca7debee239 | |
| parent | 5d2120c82dbd4acc4a30e66fbeeb34c4b2b55694 (diff) | |
Fix Error Propagation and No Device Lock
Alongside the CL where we polish the UX to be updated with the mock, this CL aims to
finalize a specific edge case - the lack of a device credential. This is
done and also realizes a second goal - ensuring error propagation for
any non-cancellation based error, as per earlier product decisions.
Bug: 331826599
Bug: 333445754
Test: Video and build tests found in bug
Change-Id: I1015c4142703f3284bdf0e9bac78301ac1d6341a
5 files changed, 50 insertions, 20 deletions
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index 888777e81d65..36f6ad2f386d 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -30,6 +30,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel +import com.android.credentialmanager.common.BiometricError import com.android.credentialmanager.common.BiometricFlowType import com.android.credentialmanager.common.BiometricPromptState import com.android.credentialmanager.common.BiometricResult @@ -128,13 +129,22 @@ class CredentialSelectorViewModel( uiState = uiState.copy(providerActivityState = ProviderActivityState.PENDING) val entryIntent = entry.fillInIntent entryIntent?.putExtra(Constants.IS_AUTO_SELECTED_KEY, uiState.isAutoSelectFlow) - if (biometricState.biometricResult != null) { + if (biometricState.biometricResult != null || biometricState.biometricError != null) { if (uiState.isAutoSelectFlow) { Log.w(Constants.LOG_TAG, "Unexpected biometric result exists when " + "autoSelect is preferred.") } - entryIntent?.putExtra(Constants.BIOMETRIC_AUTH_TYPE, - biometricState.biometricResult.biometricAuthenticationResult.authenticationType) + // TODO(b/333445754) : Decide whether to propagate info on prompt launch + if (biometricState.biometricResult != null) { + entryIntent?.putExtra(Constants.BIOMETRIC_AUTH_RESULT, + biometricState.biometricResult.biometricAuthenticationResult + .authenticationType) + } else if (biometricState.biometricError != null){ + entryIntent?.putExtra(Constants.BIOMETRIC_AUTH_ERROR_CODE, + biometricState.biometricError.errorCode) + entryIntent?.putExtra(Constants.BIOMETRIC_AUTH_ERROR_MESSAGE, + biometricState.biometricError.errorMessage) + } } val intentSenderRequest = IntentSenderRequest.Builder(pendingIntent) .setFillInIntent(entryIntent).build() @@ -219,7 +229,8 @@ class CredentialSelectorViewModel( /**************************************************************************/ fun getFlowOnEntrySelected( entry: EntryInfo, - authResult: BiometricPrompt.AuthenticationResult? = null + authResult: BiometricPrompt.AuthenticationResult? = null, + authError: BiometricError? = null, ) { Log.d(Constants.LOG_TAG, "credential selected: {provider=${entry.providerId}" + ", key=${entry.entryKey}, subkey=${entry.entrySubkey}}") @@ -227,10 +238,11 @@ class CredentialSelectorViewModel( uiState.copy( selectedEntry = entry, providerActivityState = ProviderActivityState.READY_TO_LAUNCH, - biometricState = if (authResult == null) uiState.biometricState else uiState + biometricState = if (authResult == null && authError == null) + uiState.biometricState else if (authResult != null) uiState .biometricState.copy(biometricResult = BiometricResult( - biometricAuthenticationResult = authResult) - ) + biometricAuthenticationResult = authResult)) else uiState + .biometricState.copy(biometricError = authError) ) } else { credManRepo.onOptionSelected(entry.providerId, entry.entryKey, entry.entrySubkey) @@ -350,7 +362,8 @@ class CredentialSelectorViewModel( fun createFlowOnEntrySelected( selectedEntry: EntryInfo, - authResult: AuthenticationResult? = null + authResult: AuthenticationResult? = null, + authError: BiometricError? = null, ) { val providerId = selectedEntry.providerId val entryKey = selectedEntry.entryKey @@ -362,9 +375,11 @@ class CredentialSelectorViewModel( uiState = uiState.copy( selectedEntry = selectedEntry, providerActivityState = ProviderActivityState.READY_TO_LAUNCH, - biometricState = if (authResult == null) uiState.biometricState else uiState + biometricState = if (authResult == null && authError == null) + uiState.biometricState else if (authResult != null) uiState .biometricState.copy(biometricResult = BiometricResult( - biometricAuthenticationResult = authResult)) + biometricAuthenticationResult = authResult)) else uiState + .biometricState.copy(biometricError = authError) ) } else { credManRepo.onOptionSelected( diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt index be3e0437a83e..e088d3addaf2 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt @@ -76,6 +76,7 @@ data class BiometricDisplayInfo( */ data class BiometricState( val biometricResult: BiometricResult? = null, + val biometricError: BiometricError? = null, val biometricStatus: BiometricPromptState = BiometricPromptState.INACTIVE ) @@ -92,7 +93,7 @@ data class BiometricResult( */ data class BiometricError( val errorCode: Int, - val errString: CharSequence? = null + val errorMessage: CharSequence? = null ) /** @@ -113,7 +114,7 @@ fun runBiometricFlowForGet( biometricEntry: EntryInfo, context: Context, openMoreOptionsPage: () -> Unit, - sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit, + sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult?, BiometricError?) -> Unit, onCancelFlowAndFinish: () -> Unit, onIllegalStateAndFinish: (String) -> Unit, getBiometricPromptState: () -> BiometricPromptState, @@ -158,7 +159,7 @@ fun runBiometricFlowForCreate( biometricEntry: EntryInfo, context: Context, openMoreOptionsPage: () -> Unit, - sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit, + sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult?, BiometricError?) -> Unit, onCancelFlowAndFinish: () -> Unit, onIllegalStateAndFinish: (String) -> Unit, getBiometricPromptState: () -> BiometricPromptState, @@ -285,7 +286,7 @@ private fun removeDeviceCredential(requestAllowedAuthenticators: Int): Int { * Sets up the biometric authentication callback. */ private fun setupBiometricAuthenticationCallback( - sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit, + sendDataToProvider: (EntryInfo, BiometricPrompt.AuthenticationResult?, BiometricError?) -> Unit, selectedEntry: EntryInfo, onCancelFlowAndFinish: () -> Unit, onIllegalStateAndFinish: (String) -> Unit, @@ -301,7 +302,7 @@ private fun setupBiometricAuthenticationCallback( try { if (authResult != null) { onBiometricPromptStateChange(BiometricPromptState.COMPLETE) - sendDataToProvider(selectedEntry, authResult) + sendDataToProvider(selectedEntry, authResult, /*authError=*/null) } else { onIllegalStateAndFinish("The biometric flow succeeded but unexpectedly " + "returned a null value.") @@ -326,8 +327,10 @@ private fun setupBiometricAuthenticationCallback( // into the selector, parity applies to the selector's cancellation instead // of the provider's biometric prompt cancellation. onCancelFlowAndFinish() + } else { + sendDataToProvider(selectedEntry, /*authResult=*/null, /*authError=*/ + BiometricError(errorCode, errString)) } - // TODO(b/333445772) : Propagate to provider } override fun onAuthenticationFailed() { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt index 7e7a74fd3107..3c80113134b1 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt @@ -22,7 +22,9 @@ class Constants { const val BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS = "androidx.credentials.BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED" const val IS_AUTO_SELECTED_KEY = "IS_AUTO_SELECTED" - const val BIOMETRIC_AUTH_TYPE = "BIOMETRIC_AUTH_TYPE" - const val BIOMETRIC_AUTH_FAILURE = "BIOMETRIC_AUTH_FAILURE" + // TODO(b/333445772) : Qualify error codes fully for propagation + const val BIOMETRIC_AUTH_RESULT = "BIOMETRIC_AUTH_RESULT" + const val BIOMETRIC_AUTH_ERROR_CODE = "BIOMETRIC_AUTH_ERROR_CODE" + const val BIOMETRIC_AUTH_ERROR_MESSAGE = "BIOMETRIC_AUTH_ERROR_MESSAGE" } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt index 122b8964dc96..a0915d22b613 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt @@ -46,6 +46,7 @@ import androidx.core.graphics.drawable.toBitmap import com.android.compose.theme.LocalAndroidColorScheme import com.android.credentialmanager.CredentialSelectorViewModel import com.android.credentialmanager.R +import com.android.credentialmanager.common.BiometricError import com.android.credentialmanager.common.BiometricFlowType import com.android.credentialmanager.common.BiometricPromptState import com.android.credentialmanager.model.EntryInfo @@ -581,7 +582,11 @@ internal fun BiometricSelectionPage( onMoreOptionSelected: () -> Unit, requestDisplayInfo: RequestDisplayInfo, enabledProviderInfo: EnabledProviderInfo, - onBiometricEntrySelected: (EntryInfo, BiometricPrompt.AuthenticationResult) -> Unit, + onBiometricEntrySelected: ( + EntryInfo, + BiometricPrompt.AuthenticationResult?, + BiometricError? + ) -> Unit, onCancelFlowAndFinish: () -> Unit, onIllegalScreenStateAndFinish: (String) -> Unit, fallbackToOriginalFlow: (BiometricFlowType) -> Unit, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index 72b7814a791a..c1120bb356b7 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -52,6 +52,7 @@ import androidx.compose.ui.unit.dp import androidx.core.graphics.drawable.toBitmap import com.android.credentialmanager.CredentialSelectorViewModel import com.android.credentialmanager.R +import com.android.credentialmanager.common.BiometricError import com.android.credentialmanager.common.BiometricFlowType import com.android.credentialmanager.common.BiometricPromptState import com.android.credentialmanager.common.ProviderActivityState @@ -223,7 +224,11 @@ internal fun BiometricSelectionPage( requestDisplayInfo: RequestDisplayInfo, providerInfoList: List<ProviderInfo>, providerDisplayInfo: ProviderDisplayInfo, - onBiometricEntrySelected: (EntryInfo, BiometricPrompt.AuthenticationResult?) -> Unit, + onBiometricEntrySelected: ( + EntryInfo, + BiometricPrompt.AuthenticationResult?, + BiometricError? + ) -> Unit, fallbackToOriginalFlow: (BiometricFlowType) -> Unit, getBiometricPromptState: () -> BiometricPromptState, onBiometricPromptStateChange: (BiometricPromptState) -> Unit, |