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
This commit is contained in:
Qinmei Du
2022-10-20 14:09:26 +00:00
parent d50e446877
commit 4b2efe93ff
4 changed files with 103 additions and 37 deletions

View File

@@ -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,
)
}

View File

@@ -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,

View File

@@ -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<ProviderInfo>,
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(),

View File

@@ -30,7 +30,8 @@ import com.android.credentialmanager.common.ResultState
data class CreatePasskeyUiState(
val providers: List<ProviderInfo>,
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,
)
}
}