From 4b2efe93ff2b2ced52ea64742f0850641d9b7470 Mon Sep 17 00:00:00 2001 From: Qinmei Du Date: Thu, 20 Oct 2022 14:09:26 +0000 Subject: Change the create a passkey screen to show the username/displayName from request rather than showing all createOptions under this provider and change the logic after it got selected screenshot: https://screenshot.googleplex.com/4UARFE3ZpgVtEeD Test: deployed locally Bug: 253157211 Change-Id: Ia622a2c66eaadc268e7c37e5b2c9e348bd6502fb --- .../credentialmanager/CredentialManagerRepo.kt | 4 ++ .../credentialmanager/createflow/CreateModel.kt | 15 ++++ .../createflow/CreatePasskeyComponents.kt | 81 +++++++++++++++------- .../createflow/CreatePasskeyViewModel.kt | 40 +++++++---- 4 files changed, 103 insertions(+), 37 deletions(-) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index ec0c5b708abe..93eaeb315bfb 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -32,6 +32,7 @@ import android.os.Bundle import android.os.ResultReceiver import com.android.credentialmanager.createflow.CreatePasskeyUiState import com.android.credentialmanager.createflow.CreateScreenState +import com.android.credentialmanager.createflow.RequestDisplayInfo import com.android.credentialmanager.getflow.GetCredentialUiState import com.android.credentialmanager.getflow.GetScreenState @@ -95,9 +96,12 @@ class CredentialManagerRepo( fun createPasskeyInitialUiState(): CreatePasskeyUiState { val providerList = CreateFlowUtils.toProviderList(providerList, context) + val requestDisplayInfo = RequestDisplayInfo( + "Elisa Beckett", "beckett-bakert@gmail.com", "TYPE_CREATE") return CreatePasskeyUiState( providers = providerList, currentScreenState = CreateScreenState.PASSKEY_INTRO, + requestDisplayInfo, ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt index 19820d6cd98c..e291cc206691 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt @@ -34,6 +34,21 @@ data class CreateOptionInfo( val usageData: String ) +data class RequestDisplayInfo( + val userName: String, + val displayName: String, + val type: String, +) + +/** + * This is initialized to be the most recent used. Can then be changed if + * user selects a different entry on the more option page. + */ +data class ActiveEntry ( + val activeProvider: ProviderInfo, + val activeCreateOptionInfo: CreateOptionInfo, +) + /** The name of the current screen. */ enum class CreateScreenState { PASSKEY_INTRO, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt index 82fce9f7a98d..fbbc3ac20e33 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt @@ -70,21 +70,21 @@ fun CreatePasskeyScreen( onProviderSelected = {viewModel.onProviderSelected(it)} ) CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard( - providerInfo = uiState.selectedProvider!!, - onOptionSelected = {viewModel.onCreateOptionSelected(it)}, + requestDisplayInfo = uiState.requestDisplayInfo, + providerInfo = uiState.activeEntry?.activeProvider!!, + onOptionSelected = {viewModel.onPrimaryCreateOptionInfoSelected()}, onCancel = {viewModel.onCancel()}, multiProvider = uiState.providers.size > 1, - onMoreOptionsSelected = {viewModel.onMoreOptionsSelected(it)} + onMoreOptionsSelected = {viewModel.onMoreOptionsSelected()} ) CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard( - providerInfo = uiState.selectedProvider!!, providerList = uiState.providers, - onBackButtonSelected = {viewModel.onBackButtonSelected(it)}, + onBackButtonSelected = {viewModel.onBackButtonSelected()}, onOptionSelected = {viewModel.onMoreOptionsRowSelected(it)} ) CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard( - providerInfo = uiState.selectedProvider!!, - onDefaultOrNotSelected = {viewModel.onDefaultOrNotSelected(it)} + providerInfo = uiState.activeEntry?.activeProvider!!, + onDefaultOrNotSelected = {viewModel.onDefaultOrNotSelected()} ) } }, @@ -218,10 +218,9 @@ fun ProviderSelectionCard( @ExperimentalMaterialApi @Composable fun MoreOptionsSelectionCard( - providerInfo: ProviderInfo, providerList: List, - onBackButtonSelected: (String) -> Unit, - onOptionSelected: (String) -> Unit + onBackButtonSelected: () -> Unit, + onOptionSelected: (ActiveEntry) -> Unit ) { Card( backgroundColor = lightBackgroundColor, @@ -235,7 +234,7 @@ fun MoreOptionsSelectionCard( elevation = 0.dp, navigationIcon = { - IconButton(onClick = { onBackButtonSelected(providerInfo.name) }) { + IconButton(onClick = onBackButtonSelected) { Icon(Icons.Filled.ArrowBack, "backIcon" ) } @@ -264,9 +263,12 @@ fun MoreOptionsSelectionCard( providerList.forEach { providerInfo -> providerInfo.createOptions.forEach { createOptionInfo -> item { - MoreOptionsInfoRow(providerInfo = providerInfo, + MoreOptionsInfoRow( + providerInfo = providerInfo, createOptionInfo = createOptionInfo, - onOptionSelected = onOptionSelected) + onOptionSelected = { + onOptionSelected(ActiveEntry(providerInfo, createOptionInfo)) + }) } } } @@ -285,7 +287,7 @@ fun MoreOptionsSelectionCard( @Composable fun MoreOptionsRowIntroCard( providerInfo: ProviderInfo, - onDefaultOrNotSelected: (String) -> Unit, + onDefaultOrNotSelected: () -> Unit, ) { Card( backgroundColor = lightBackgroundColor, @@ -302,11 +304,11 @@ fun MoreOptionsRowIntroCard( ) { CancelButton( stringResource(R.string.use_once), - onclick = { onDefaultOrNotSelected(providerInfo.name) } + onclick = onDefaultOrNotSelected ) ConfirmButton( stringResource(R.string.set_as_default), - onclick = { onDefaultOrNotSelected(providerInfo.name) } + onclick = onDefaultOrNotSelected ) } Divider( @@ -388,11 +390,12 @@ fun NavigationButton( @ExperimentalMaterialApi @Composable fun CreationSelectionCard( + requestDisplayInfo: RequestDisplayInfo, providerInfo: ProviderInfo, - onOptionSelected: (Int) -> Unit, + onOptionSelected: () -> Unit, onCancel: () -> Unit, multiProvider: Boolean, - onMoreOptionsSelected: (String) -> Unit, + onMoreOptionsSelected: () -> Unit, ) { Card( backgroundColor = lightBackgroundColor, @@ -427,14 +430,13 @@ fun CreationSelectionCard( LazyColumn( verticalArrangement = Arrangement.spacedBy(2.dp) ) { - providerInfo.createOptions.forEach { item { - CreateOptionRow(createOptionInfo = it, onOptionSelected = onOptionSelected) + PrimaryCreateOptionRow(requestDisplayInfo = requestDisplayInfo, + onOptionSelected = onOptionSelected) } - } if (multiProvider) { item { - MoreOptionsRow(onSelect = { onMoreOptionsSelected(providerInfo.name) }) + MoreOptionsRow(onSelect = onMoreOptionsSelected) } } } @@ -492,16 +494,47 @@ fun CreateOptionRow(createOptionInfo: CreateOptionInfo, onOptionSelected: (Int) } } +@ExperimentalMaterialApi +@Composable +fun PrimaryCreateOptionRow( + requestDisplayInfo: RequestDisplayInfo, + onOptionSelected: () -> Unit +) { + Chip( + modifier = Modifier.fillMaxWidth(), + onClick = {onOptionSelected()}, + // TODO: Add an icon generated by provider according to requestDisplayInfo type + colors = ChipDefaults.chipColors( + backgroundColor = Grey100, + leadingIconContentColor = Grey100 + ), + shape = Shapes.large + ) { + Column() { + Text( + text = requestDisplayInfo.userName, + style = Typography.h6, + modifier = Modifier.padding(top = 16.dp) + ) + Text( + text = requestDisplayInfo.displayName, + style = Typography.body2, + modifier = Modifier.padding(bottom = 16.dp) + ) + } + } +} + @ExperimentalMaterialApi @Composable fun MoreOptionsInfoRow( providerInfo: ProviderInfo, createOptionInfo: CreateOptionInfo, - onOptionSelected: (String) -> Unit + onOptionSelected: () -> Unit ) { Chip( modifier = Modifier.fillMaxWidth(), - onClick = { onOptionSelected(providerInfo.name) }, + onClick = onOptionSelected, leadingIcon = { Image(modifier = Modifier.size(24.dp, 24.dp).padding(start = 10.dp), bitmap = createOptionInfo.icon.toBitmap().asImageBitmap(), diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt index ff44e2ee1b06..38486e2c7d74 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyViewModel.kt @@ -30,7 +30,8 @@ import com.android.credentialmanager.common.ResultState data class CreatePasskeyUiState( val providers: List, val currentScreenState: CreateScreenState, - val selectedProvider: ProviderInfo? = null, + val requestDisplayInfo: RequestDisplayInfo, + val activeEntry: ActiveEntry? = null, ) class CreatePasskeyViewModel( @@ -56,7 +57,8 @@ class CreatePasskeyViewModel( } else if (uiState.providers.size == 1){ uiState = uiState.copy( currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION, - selectedProvider = uiState.providers.first() + activeEntry = ActiveEntry(uiState.providers.first(), + uiState.providers.first().createOptions.first()) ) } else { throw java.lang.IllegalStateException("Empty provider list.") @@ -66,14 +68,15 @@ class CreatePasskeyViewModel( fun onProviderSelected(providerName: String) { uiState = uiState.copy( currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION, - selectedProvider = getProviderInfoByName(providerName) + activeEntry = ActiveEntry(getProviderInfoByName(providerName), + getProviderInfoByName(providerName).createOptions.first()) ) } fun onCreateOptionSelected(createOptionId: Int) { Log.d("Account Selector", "Option selected for creation: $createOptionId") CredentialManagerRepo.getInstance().onOptionSelected( - uiState.selectedProvider!!.name, + uiState.activeEntry?.activeProvider!!.name, createOptionId ) dialogResult.value = DialogResult( @@ -87,24 +90,22 @@ class CreatePasskeyViewModel( } } - fun onMoreOptionsSelected(providerName: String) { + fun onMoreOptionsSelected() { uiState = uiState.copy( - currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION, - selectedProvider = getProviderInfoByName(providerName) + currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION, ) } - fun onBackButtonSelected(providerName: String) { + fun onBackButtonSelected() { uiState = uiState.copy( currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION, - selectedProvider = getProviderInfoByName(providerName) ) } - fun onMoreOptionsRowSelected(providerName: String) { + fun onMoreOptionsRowSelected(activeEntry: ActiveEntry) { uiState = uiState.copy( currentScreenState = CreateScreenState.MORE_OPTIONS_ROW_INTRO, - selectedProvider = getProviderInfoByName(providerName) + activeEntry = activeEntry ) } @@ -113,11 +114,24 @@ class CreatePasskeyViewModel( dialogResult.value = DialogResult(ResultState.CANCELED) } - fun onDefaultOrNotSelected(providerName: String) { + fun onDefaultOrNotSelected() { uiState = uiState.copy( currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION, - selectedProvider = getProviderInfoByName(providerName) ) // TODO: implement the if choose as default or not logic later } + + fun onPrimaryCreateOptionInfoSelected() { + var createOptionId = uiState.activeEntry?.activeCreateOptionInfo?.id + Log.d("Account Selector", "Option selected for creation: $createOptionId") + if (createOptionId != null) { + CredentialManagerRepo.getInstance().onOptionSelected( + uiState.activeEntry?.activeProvider!!.name, + createOptionId + ) + } + dialogResult.value = DialogResult( + ResultState.COMPLETE, + ) + } } -- cgit v1.2.3-59-g8ed1b