Loading packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +25 −10 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() Loading Loading @@ -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}}") Loading @@ -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) Loading Loading @@ -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 Loading @@ -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( Loading packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt +9 −6 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ data class BiometricDisplayInfo( */ data class BiometricState( val biometricResult: BiometricResult? = null, val biometricError: BiometricError? = null, val biometricStatus: BiometricPromptState = BiometricPromptState.INACTIVE ) Loading @@ -92,7 +93,7 @@ data class BiometricResult( */ data class BiometricError( val errorCode: Int, val errString: CharSequence? = null val errorMessage: CharSequence? = null ) /** Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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, Loading @@ -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.") Loading @@ -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() { Loading packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt +4 −2 Original line number Diff line number Diff line Loading @@ -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" } } packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading
packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +25 −10 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() Loading Loading @@ -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}}") Loading @@ -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) Loading Loading @@ -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 Loading @@ -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( Loading
packages/CredentialManager/src/com/android/credentialmanager/common/BiometricHandler.kt +9 −6 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ data class BiometricDisplayInfo( */ data class BiometricState( val biometricResult: BiometricResult? = null, val biometricError: BiometricError? = null, val biometricStatus: BiometricPromptState = BiometricPromptState.INACTIVE ) Loading @@ -92,7 +93,7 @@ data class BiometricResult( */ data class BiometricError( val errorCode: Int, val errString: CharSequence? = null val errorMessage: CharSequence? = null ) /** Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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, Loading @@ -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.") Loading @@ -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() { Loading
packages/CredentialManager/src/com/android/credentialmanager/common/Constants.kt +4 −2 Original line number Diff line number Diff line Loading @@ -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" } }
packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading
packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +6 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading