summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/CredentialManager/res/values/strings.xml1
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt12
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt9
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt107
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt63
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt7
6 files changed, 118 insertions, 81 deletions
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 114de89ce82a..887a369093dd 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -6,6 +6,7 @@
<string name="string_more_options">More options</string>
<string name="string_create_in_another_place">Create in another place</string>
<string name="string_save_to_another_place">Save to another place</string>
+ <string name="string_use_another_device">Use another device</string>
<string name="string_no_thanks">No thanks</string>
<string name="passkey_creation_intro_title">A simple way to sign in safely</string>
<string name="passkey_creation_intro_body">Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more</string>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index a6e64cefedcb..232d681fd209 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -149,8 +149,8 @@ class CredentialManagerRepo(
if (providerInfo.isDefault) {hasDefault = true; defaultProvider = providerInfo} }
// TODO: covert from real requestInfo for create passkey
var requestDisplayInfo = RequestDisplayInfo(
- "Elisa Beckett",
"beckett-bakert@gmail.com",
+ "Elisa Beckett",
TYPE_PUBLIC_KEY_CREDENTIAL,
"tribank")
val createCredentialRequest = requestInfo.createCredentialRequest
@@ -165,8 +165,12 @@ class CredentialManagerRepo(
return CreateCredentialUiState(
enabledProviders = providerEnabledList,
disabledProviders = providerDisabledList,
- if (hasDefault)
- {CreateScreenState.CREATION_OPTION_SELECTION} else {CreateScreenState.PASSKEY_INTRO},
+ // TODO: Add the screen when defaultProvider has no createOption but
+ // there's remoteInfo under other providers
+ if (!hasDefault || defaultProvider.createOptions.isEmpty()) {
+ if (requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL)
+ {CreateScreenState.PASSKEY_INTRO} else {CreateScreenState.PROVIDER_SELECTION}
+ } else {CreateScreenState.CREATION_OPTION_SELECTION},
requestDisplayInfo,
if (hasDefault) {
ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
@@ -439,7 +443,7 @@ class CredentialManagerRepo(
return RequestInfo.newCreateRequestInfo(
Binder(),
CreateCredentialRequest(
- TYPE_PASSWORD_CREDENTIAL,
+ TYPE_PUBLIC_KEY_CREDENTIAL,
data
),
/*isFirstUsage=*/false,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 830bc7a11bda..1c74743ab481 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -193,9 +193,10 @@ class CreateFlowUtils {
icon = pkgInfo.applicationInfo.loadIcon(packageManager)!!,
name = it.providerFlattenedComponentName,
displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
- createOptions = toCreationOptionInfoList(it.saveEntries, context),
+ createOptions = toCreationOptionInfoList(
+ it.providerFlattenedComponentName, it.saveEntries, context),
isDefault = it.isDefaultProvider,
- remoteEntry = toRemoteInfo(it.remoteEntry),
+ remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
)
}
}
@@ -219,6 +220,7 @@ class CreateFlowUtils {
}
private fun toCreationOptionInfoList(
+ providerId: String,
creationEntries: List<Entry>,
context: Context,
): List<CreateOptionInfo> {
@@ -227,6 +229,7 @@ class CreateFlowUtils {
return@map CreateOptionInfo(
// TODO: remove fallbacks
+ providerId = providerId,
entryKey = it.key,
entrySubkey = it.subkey,
pendingIntent = it.pendingIntent,
@@ -245,11 +248,13 @@ class CreateFlowUtils {
}
private fun toRemoteInfo(
+ providerId: String,
remoteEntry: Entry?,
): RemoteInfo? {
// TODO: should also call fromSlice after getting the official jetpack code.
return if (remoteEntry != null) {
RemoteInfo(
+ providerId = providerId,
entryKey = remoteEntry.key,
entrySubkey = remoteEntry.subkey,
pendingIntent = remoteEntry.pendingIntent,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 3a277a638e93..7574feed2132 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -55,8 +55,11 @@ fun CreateCredentialScreen(
viewModel: CreateCredentialViewModel,
providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
) {
- val primaryEntryCallback: () -> Unit = {
- viewModel.onPrimaryCreateOptionInfoSelected(providerActivityLauncher)
+ val selectEntryCallback: (EntryInfo) -> Unit = {
+ viewModel.onEntrySelected(it, providerActivityLauncher)
+ }
+ val confirmEntryCallback: () -> Unit = {
+ viewModel.onConfirmCreationSelected(providerActivityLauncher)
}
val state = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Expanded,
@@ -78,23 +81,23 @@ fun CreateCredentialScreen(
)
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
requestDisplayInfo = uiState.requestDisplayInfo,
+ enabledProviderList = uiState.enabledProviders,
providerInfo = uiState.activeEntry?.activeProvider!!,
createOptionInfo = uiState.activeEntry.activeEntryInfo as CreateOptionInfo,
- onOptionSelected = primaryEntryCallback,
- onConfirm = primaryEntryCallback,
+ onOptionSelected = selectEntryCallback,
+ onConfirm = confirmEntryCallback,
onCancel = viewModel::onCancel,
- multiProvider = uiState.enabledProviders.size > 1,
- onMoreOptionsSelected = viewModel::onMoreOptionsSelected
+ onMoreOptionsSelected = viewModel::onMoreOptionsSelected,
)
CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
- requestDisplayInfo = uiState.requestDisplayInfo,
- enabledProviderList = uiState.enabledProviders,
- disabledProviderList = uiState.disabledProviders,
- onBackButtonSelected = viewModel::onBackButtonSelected,
- onOptionSelected = viewModel::onMoreOptionsRowSelected,
- onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected,
- onRemoteEntrySelected = viewModel::onRemoteEntrySelected
- )
+ requestDisplayInfo = uiState.requestDisplayInfo,
+ enabledProviderList = uiState.enabledProviders,
+ disabledProviderList = uiState.disabledProviders,
+ onBackButtonSelected = viewModel::onBackButtonSelected,
+ onOptionSelected = viewModel::onMoreOptionsRowSelected,
+ onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected,
+ onRemoteEntrySelected = selectEntryCallback,
+ )
CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
providerInfo = uiState.activeEntry?.activeProvider!!,
onDefaultOrNotSelected = viewModel::onDefaultOrNotSelected
@@ -234,7 +237,7 @@ fun MoreOptionsSelectionCard(
onBackButtonSelected: () -> Unit,
onOptionSelected: (ActiveEntry) -> Unit,
onDisabledPasswordManagerSelected: () -> Unit,
- onRemoteEntrySelected: () -> Unit,
+ onRemoteEntrySelected: (EntryInfo) -> Unit,
) {
Card() {
Column() {
@@ -292,17 +295,15 @@ fun MoreOptionsSelectionCard(
)
}
}
- var hasRemoteInfo = false
+ // TODO: handle the error situation that if multiple remoteInfos exists
enabledProviderList.forEach {
if (it.remoteEntry != null) {
- hasRemoteInfo = true
- }
- }
- if (hasRemoteInfo) {
- item {
- RemoteEntryRow(
- onRemoteEntrySelected = onRemoteEntrySelected,
- )
+ item {
+ RemoteEntryRow(
+ remoteInfo = it.remoteEntry!!,
+ onRemoteEntrySelected = onRemoteEntrySelected,
+ )
+ }
}
}
}
@@ -388,12 +389,12 @@ fun ProviderRow(providerInfo: ProviderInfo, onProviderSelected: (String) -> Unit
@Composable
fun CreationSelectionCard(
requestDisplayInfo: RequestDisplayInfo,
- providerInfo: ProviderInfo,
+ enabledProviderList: List<EnabledProviderInfo>,
+ providerInfo: EnabledProviderInfo,
createOptionInfo: CreateOptionInfo,
- onOptionSelected: () -> Unit,
+ onOptionSelected: (EntryInfo) -> Unit,
onConfirm: () -> Unit,
onCancel: () -> Unit,
- multiProvider: Boolean,
onMoreOptionsSelected: () -> Unit,
) {
Card() {
@@ -442,19 +443,16 @@ fun CreationSelectionCard(
.padding(horizontal = 24.dp)
.align(alignment = Alignment.CenterHorizontally),
) {
- LazyColumn(
- verticalArrangement = Arrangement.spacedBy(2.dp)
- ) {
- item {
- PrimaryCreateOptionRow(
- requestDisplayInfo = requestDisplayInfo,
- createOptionInfo = createOptionInfo,
- onOptionSelected = onOptionSelected
- )
- }
- }
+ PrimaryCreateOptionRow(
+ requestDisplayInfo = requestDisplayInfo,
+ createOptionInfo = createOptionInfo,
+ onOptionSelected = onOptionSelected
+ )
}
- if (multiProvider) {
+ var createOptionsSize = 0
+ enabledProviderList.forEach{
+ enabledProvider -> createOptionsSize += enabledProvider.createOptions.size}
+ if (createOptionsSize > 1) {
TextButton(
onClick = onMoreOptionsSelected,
modifier = Modifier
@@ -469,6 +467,26 @@ fun CreationSelectionCard(
textAlign = TextAlign.Center,
)
}
+ } else if (
+ requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL
+ ) {
+ // TODO: handle the error situation that if multiple remoteInfos exists
+ enabledProviderList.forEach { enabledProvider ->
+ if (enabledProvider.remoteEntry != null) {
+ TextButton(
+ onClick = {
+ onOptionSelected(enabledProvider.remoteEntry!!) },
+ modifier = Modifier
+ .padding(horizontal = 24.dp)
+ .align(alignment = Alignment.CenterHorizontally)
+ ) {
+ Text(
+ text = stringResource(R.string.string_use_another_device),
+ textAlign = TextAlign.Center,
+ )
+ }
+ }
+ }
}
Divider(
thickness = 24.dp,
@@ -501,10 +519,10 @@ fun CreationSelectionCard(
fun PrimaryCreateOptionRow(
requestDisplayInfo: RequestDisplayInfo,
createOptionInfo: CreateOptionInfo,
- onOptionSelected: () -> Unit
+ onOptionSelected: (EntryInfo) -> Unit
) {
Entry(
- onClick = onOptionSelected,
+ onClick = {onOptionSelected(createOptionInfo)},
icon = {
Image(modifier = Modifier.size(32.dp).padding(start = 10.dp),
bitmap = createOptionInfo.credentialTypeIcon.toBitmap().asImageBitmap(),
@@ -527,7 +545,7 @@ fun PrimaryCreateOptionRow(
)
} else {
Text(
- text = requestDisplayInfo.subtitle,
+ text = requestDisplayInfo.title,
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.padding(top = 16.dp, bottom = 16.dp)
)
@@ -640,10 +658,11 @@ fun MoreOptionsDisabledProvidersRow(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RemoteEntryRow(
- onRemoteEntrySelected: () -> Unit,
+ remoteInfo: RemoteInfo,
+ onRemoteEntrySelected: (RemoteInfo) -> Unit,
) {
Entry(
- onClick = onRemoteEntrySelected,
+ onClick = {onRemoteEntrySelected(remoteInfo)},
icon = {
Icon(
painter = painterResource(R.drawable.ic_other_devices),
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
index 093c88f1c020..a90f4da3cae6 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
@@ -37,6 +37,7 @@ data class CreateCredentialUiState(
val currentScreenState: CreateScreenState,
val requestDisplayInfo: RequestDisplayInfo,
val activeEntry: ActiveEntry? = null,
+ val selectedEntry: EntryInfo? = null,
)
class CreateCredentialViewModel(
@@ -109,10 +110,6 @@ class CreateCredentialViewModel(
// TODO: Complete this function
}
- fun onRemoteEntrySelected() {
- // TODO: Complete this function
- }
-
fun onCancel() {
CredentialManagerRepo.getInstance().onCancel()
dialogResult.value = DialogResult(ResultState.CANCELED)
@@ -125,46 +122,54 @@ class CreateCredentialViewModel(
// TODO: implement the if choose as default or not logic later
}
- fun onPrimaryCreateOptionInfoSelected(
+ fun onEntrySelected(
+ selectedEntry: EntryInfo,
+ launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
+ ) {
+ val providerId = selectedEntry.providerId
+ val entryKey = selectedEntry.entryKey
+ val entrySubkey = selectedEntry.entrySubkey
+ Log.d(
+ "Account Selector", "Option selected for entry: " +
+ " {provider=$providerId, key=$entryKey, subkey=$entrySubkey")
+ if (selectedEntry.pendingIntent != null) {
+ uiState = uiState.copy(selectedEntry = selectedEntry)
+ val intentSenderRequest = IntentSenderRequest.Builder(selectedEntry.pendingIntent)
+ .setFillInIntent(selectedEntry.fillInIntent).build()
+ launcher.launch(intentSenderRequest)
+ } else {
+ CredentialManagerRepo.getInstance().onOptionSelected(
+ providerId,
+ entryKey,
+ entrySubkey
+ )
+ dialogResult.value = DialogResult(
+ ResultState.COMPLETE,
+ )
+ }
+ }
+
+ fun onConfirmCreationSelected(
launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
) {
val selectedEntry = uiState.activeEntry?.activeEntryInfo
if (selectedEntry != null) {
- val entryKey = selectedEntry.entryKey
- val entrySubkey = selectedEntry.entrySubkey
- Log.d(
- "Account Selector",
- "Option selected for creation: " +
- "{key = $entryKey, subkey = $entrySubkey}"
- )
- if (selectedEntry.pendingIntent != null) {
- val intentSenderRequest = IntentSenderRequest.Builder(selectedEntry.pendingIntent)
- .setFillInIntent(selectedEntry.fillInIntent).build()
- launcher.launch(intentSenderRequest)
- } else {
- CredentialManagerRepo.getInstance().onOptionSelected(
- uiState.activeEntry?.activeProvider!!.name,
- entryKey,
- entrySubkey
- )
- dialogResult.value = DialogResult(
- ResultState.COMPLETE,
- )
- }
+ onEntrySelected(selectedEntry, launcher)
} else {
+ Log.w("Account Selector",
+ "Illegal state: confirm is pressed but activeEntry isn't set.")
dialogResult.value = DialogResult(
ResultState.COMPLETE,
)
- TODO("Gracefully handle illegal state.")
}
}
fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) {
- val entry = uiState.activeEntry?.activeEntryInfo
+ val entry = uiState.selectedEntry
val resultCode = providerActivityResult.resultCode
val resultData = providerActivityResult.data
- val providerId = uiState.activeEntry?.activeProvider!!.name
if (entry != null) {
+ val providerId = entry.providerId
Log.d("Account Selector", "Got provider activity result: {provider=" +
"$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
"resultCode=$resultCode, resultData=$resultData}"
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 753dc3c63bc7..e27db43768a0 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -42,6 +42,7 @@ class DisabledProviderInfo(
) : ProviderInfo(icon, name, displayName)
open class EntryInfo (
+ val providerId: String,
val entryKey: String,
val entrySubkey: String,
val pendingIntent: PendingIntent?,
@@ -49,6 +50,7 @@ open class EntryInfo (
)
class CreateOptionInfo(
+ providerId: String,
entryKey: String,
entrySubkey: String,
pendingIntent: PendingIntent?,
@@ -60,14 +62,15 @@ class CreateOptionInfo(
val passkeyCount: Int?,
val totalCredentialCount: Int?,
val lastUsedTimeMillis: Long?,
-) : EntryInfo(entryKey, entrySubkey, pendingIntent, fillInIntent)
+) : EntryInfo(providerId, entryKey, entrySubkey, pendingIntent, fillInIntent)
class RemoteInfo(
+ providerId: String,
entryKey: String,
entrySubkey: String,
pendingIntent: PendingIntent?,
fillInIntent: Intent?,
-) : EntryInfo(entryKey, entrySubkey, pendingIntent, fillInIntent)
+) : EntryInfo(providerId, entryKey, entrySubkey, pendingIntent, fillInIntent)
data class RequestDisplayInfo(
val title: String,