summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/CredentialManager/AndroidManifest.xml9
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt4
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt35
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt60
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt102
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt14
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt181
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt18
8 files changed, 100 insertions, 323 deletions
diff --git a/packages/CredentialManager/AndroidManifest.xml b/packages/CredentialManager/AndroidManifest.xml
index 8724d69258ed..4161601e2317 100644
--- a/packages/CredentialManager/AndroidManifest.xml
+++ b/packages/CredentialManager/AndroidManifest.xml
@@ -42,15 +42,6 @@
android:excludeFromRecents="true"
android:theme="@style/Theme.CredentialSelector">
</activity>
-
- <receiver
- android:name=".CredentialProviderReceiver"
- android:exported="true"
- android:permission="android.permission.LAUNCH_CREDENTIAL_SELECTOR">
- <intent-filter>
- <action android:name="android.credentials.ui.action.CREDMAN_ENABLED_PROVIDERS_UPDATED"/>
- </intent-filter>
- </receiver>
</application>
</manifest>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index a9bee039264e..693e76731834 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -107,7 +107,6 @@ class CredentialManagerRepo(
initialUiState = when (requestInfo?.type) {
RequestInfo.TYPE_CREATE -> {
- val defaultProviderIdSetByUser = userConfigRepo.getDefaultProviderId()
val isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
val providerEnableListUiState = getCreateProviderEnableListInitialUiState()
val providerDisableListUiState = getCreateProviderDisableListInitialUiState()
@@ -119,7 +118,8 @@ class CredentialManagerRepo(
disabledProviders = providerDisableListUiState,
defaultProviderIdPreferredByApp =
requestDisplayInfoUiState.appPreferredDefaultProviderId,
- defaultProviderIdSetByUser = defaultProviderIdSetByUser,
+ defaultProviderIdsSetByUser =
+ requestDisplayInfoUiState.userSetDefaultProviderIds,
requestDisplayInfo = requestDisplayInfoUiState,
isOnPasskeyIntroStateAlready = false,
isPasskeyFirstUse = isPasskeyFirstUse,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt
deleted file mode 100644
index ee8cffed7f7d..000000000000
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialProviderReceiver.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.credentialmanager
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.util.Log
-import com.android.credentialmanager.common.Constants
-
-
-class CredentialProviderReceiver : BroadcastReceiver() {
-
- override fun onReceive(context: Context?, intent: Intent?) {
- Log.d(Constants.LOG_TAG, "Received intent in CredentialProviderReceiver")
-
- val sharedPreferences = context?.getSharedPreferences(context?.packageName,
- Context.MODE_PRIVATE)
- sharedPreferences?.edit()?.remove(UserConfigRepo.DEFAULT_PROVIDER)?.commit()
- }
-} \ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 8b74d766a152..de679895eedb 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -255,7 +255,8 @@ class CredentialSelectorViewModel(
disabledProviders = prevUiState.disabledProviders,
defaultProviderIdPreferredByApp =
prevUiState.requestDisplayInfo.appPreferredDefaultProviderId,
- defaultProviderIdSetByUser = userConfigRepo.getDefaultProviderId(),
+ defaultProviderIdsSetByUser =
+ prevUiState.requestDisplayInfo.userSetDefaultProviderIds,
requestDisplayInfo = prevUiState.requestDisplayInfo,
isOnPasskeyIntroStateAlready = true,
isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
@@ -269,28 +270,10 @@ class CredentialSelectorViewModel(
userConfigRepo.setIsPasskeyFirstUse(false)
}
- fun createFlowOnMoreOptionsSelectedOnProviderSelection() {
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
- isFromProviderSelection = true
- )
- )
- }
-
fun createFlowOnMoreOptionsSelectedOnCreationSelection() {
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
currentScreenState = CreateScreenState.MORE_OPTIONS_SELECTION,
- isFromProviderSelection = false
- )
- )
- }
-
- fun createFlowOnBackProviderSelectionButtonSelected() {
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.PROVIDER_SELECTION,
)
)
}
@@ -315,7 +298,10 @@ class CredentialSelectorViewModel(
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
currentScreenState =
- if (activeEntry.activeProvider.id == userConfigRepo.getDefaultProviderId() ||
+ if (uiState.createCredentialUiState?.requestDisplayInfo?.userSetDefaultProviderIds
+ ?.contains(activeEntry.activeProvider.id) ?: true ||
+ !(uiState.createCredentialUiState?.foundCandidateFromUserDefaultProvider
+ ?: false) ||
!TextUtils.isEmpty(uiState.createCredentialUiState?.requestDisplayInfo
?.appPreferredDefaultProviderId))
CreateScreenState.CREATION_OPTION_SELECTION
@@ -325,18 +311,7 @@ class CredentialSelectorViewModel(
)
}
- fun createFlowOnEntrySelectedFromFirstUseScreen(activeEntry: ActiveEntry) {
- val providerId = activeEntry.activeProvider.id
- createFlowOnDefaultChanged(providerId)
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- activeEntry = activeEntry
- )
- )
- }
-
- fun createFlowOnDisabledProvidersSelected() {
+ fun createFlowOnLaunchSettings() {
credManRepo.onSettingLaunchCancel()
uiState = uiState.copy(dialogState = DialogState.CANCELED_FOR_SETTINGS)
}
@@ -349,16 +324,6 @@ class CredentialSelectorViewModel(
)
}
- fun createFlowOnChangeDefaultSelected() {
- uiState = uiState.copy(
- createCredentialUiState = uiState.createCredentialUiState?.copy(
- currentScreenState = CreateScreenState.CREATION_OPTION_SELECTION,
- )
- )
- val providerId = uiState.createCredentialUiState?.activeEntry?.activeProvider?.id
- createFlowOnDefaultChanged(providerId)
- }
-
fun createFlowOnUseOnceSelected() {
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
@@ -367,17 +332,6 @@ class CredentialSelectorViewModel(
)
}
- fun createFlowOnDefaultChanged(providerId: String?) {
- if (providerId != null) {
- Log.d(
- Constants.LOG_TAG, "Default provider changed to: " +
- " {provider=$providerId")
- userConfigRepo.setDefaultProvider(providerId)
- } else {
- Log.w(Constants.LOG_TAG, "Null provider is being changed")
- }
- }
-
fun createFlowOnEntrySelected(selectedEntry: BaseEntry) {
val providerId = selectedEntry.providerId
val entryKey = selectedEntry.entryKey
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 57035d426654..00c2f1a63ed4 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -61,6 +61,7 @@ import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PublicKeyCredentialEntry
import androidx.credentials.provider.RemoteEntry
import org.json.JSONObject
+import java.time.Instant
// TODO: remove all !! checks
fun getAppLabel(
@@ -420,7 +421,7 @@ class CreateFlowUtils {
id = it.providerFlattenedComponentName,
displayName = providerLabel,
icon = providerIcon,
- createOptions = toCreationOptionInfoList(
+ sortedCreateOptions = toSortedCreationOptionInfoList(
it.providerFlattenedComponentName, it.saveEntries, context
),
remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
@@ -483,6 +484,7 @@ class CreateFlowUtils {
context.getDrawable(R.drawable.ic_password_24) ?: return null,
preferImmediatelyAvailableCredentials = false,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
+ userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
is CreatePublicKeyCredentialRequest -> {
newRequestDisplayInfoFromPasskeyJson(
@@ -492,6 +494,7 @@ class CreateFlowUtils {
preferImmediatelyAvailableCredentials =
createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
+ userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
}
is CreateCustomCredentialRequest -> {
@@ -508,6 +511,7 @@ class CreateFlowUtils {
?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null,
preferImmediatelyAvailableCredentials = false,
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
+ userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
)
}
else -> null
@@ -518,13 +522,13 @@ class CreateFlowUtils {
enabledProviders: List<EnabledProviderInfo>,
disabledProviders: List<DisabledProviderInfo>?,
defaultProviderIdPreferredByApp: String?,
- defaultProviderIdSetByUser: String?,
+ defaultProviderIdsSetByUser: Set<String>,
requestDisplayInfo: RequestDisplayInfo,
isOnPasskeyIntroStateAlready: Boolean,
isPasskeyFirstUse: Boolean,
): CreateCredentialUiState? {
- var lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo? = null
var remoteEntry: RemoteInfo? = null
+ var remoteEntryProvider: EnabledProviderInfo? = null
var defaultProviderPreferredByApp: EnabledProviderInfo? = null
var defaultProviderSetByUser: EnabledProviderInfo? = null
var createOptionsPairs:
@@ -535,14 +539,24 @@ class CreateFlowUtils {
defaultProviderPreferredByApp = enabledProvider
}
}
- if (defaultProviderIdSetByUser != null) {
- if (enabledProvider.id == defaultProviderIdSetByUser) {
+ if (enabledProvider.sortedCreateOptions.isNotEmpty() &&
+ defaultProviderIdsSetByUser.contains(enabledProvider.id)) {
+ if (defaultProviderSetByUser == null) {
defaultProviderSetByUser = enabledProvider
+ } else {
+ val newLastUsedTime = enabledProvider.sortedCreateOptions.firstOrNull()
+ ?.lastUsedTime
+ val curLastUsedTime = defaultProviderSetByUser?.sortedCreateOptions
+ ?.firstOrNull()?.lastUsedTime ?: Instant.MIN
+ if (newLastUsedTime != null) {
+ if (curLastUsedTime == null || newLastUsedTime > curLastUsedTime) {
+ defaultProviderSetByUser = enabledProvider
+ }
+ }
}
}
- if (enabledProvider.createOptions.isNotEmpty()) {
- lastSeenProviderWithNonEmptyCreateOptions = enabledProvider
- enabledProvider.createOptions.forEach {
+ if (enabledProvider.sortedCreateOptions.isNotEmpty()) {
+ enabledProvider.sortedCreateOptions.forEach {
createOptionsPairs.add(Pair(it, enabledProvider))
}
}
@@ -554,6 +568,7 @@ class CreateFlowUtils {
return null
}
remoteEntry = currRemoteEntry
+ remoteEntryProvider = enabledProvider
}
}
val defaultProvider = defaultProviderPreferredByApp ?: defaultProviderSetByUser
@@ -561,27 +576,26 @@ class CreateFlowUtils {
createOptionSize = createOptionsPairs.size,
isOnPasskeyIntroStateAlready = isOnPasskeyIntroStateAlready,
requestDisplayInfo = requestDisplayInfo,
- defaultProvider = defaultProvider,
remoteEntry = remoteEntry,
isPasskeyFirstUse = isPasskeyFirstUse
) ?: return null
+ val sortedCreateOptionsPairs = createOptionsPairs.sortedWith(
+ compareByDescending { it.first.lastUsedTime }
+ )
return CreateCredentialUiState(
enabledProviders = enabledProviders,
disabledProviders = disabledProviders,
currentScreenState = initialScreenState,
requestDisplayInfo = requestDisplayInfo,
- sortedCreateOptionsPairs = createOptionsPairs.sortedWith(
- compareByDescending { it.first.lastUsedTime }
- ),
- hasDefaultProvider = defaultProvider != null,
+ sortedCreateOptionsPairs = sortedCreateOptionsPairs,
activeEntry = toActiveEntry(
- /*defaultProvider=*/defaultProvider,
- /*createOptionSize=*/createOptionsPairs.size,
- /*lastSeenProviderWithNonEmptyCreateOptions=*/
- lastSeenProviderWithNonEmptyCreateOptions,
- /*remoteEntry=*/remoteEntry
+ defaultProvider = defaultProvider,
+ sortedCreateOptionsPairs = sortedCreateOptionsPairs,
+ remoteEntry = remoteEntry,
+ remoteEntryProvider = remoteEntryProvider,
),
remoteEntry = remoteEntry,
+ foundCandidateFromUserDefaultProvider = defaultProviderSetByUser != null,
)
}
@@ -589,59 +603,43 @@ class CreateFlowUtils {
createOptionSize: Int,
isOnPasskeyIntroStateAlready: Boolean,
requestDisplayInfo: RequestDisplayInfo,
- defaultProvider: EnabledProviderInfo?,
remoteEntry: RemoteInfo?,
isPasskeyFirstUse: Boolean,
): CreateScreenState? {
- return if (isPasskeyFirstUse && requestDisplayInfo.type ==
- CredentialType.PASSKEY && !isOnPasskeyIntroStateAlready) {
+ return if (isPasskeyFirstUse && requestDisplayInfo.type == CredentialType.PASSKEY &&
+ !isOnPasskeyIntroStateAlready) {
CreateScreenState.PASSKEY_INTRO
- } else if ((defaultProvider == null || defaultProvider.createOptions.isEmpty()) &&
- createOptionSize > 1) {
- CreateScreenState.PROVIDER_SELECTION
- } else if (((defaultProvider == null || defaultProvider.createOptions.isEmpty()) &&
- createOptionSize == 1) || (defaultProvider != null &&
- defaultProvider.createOptions.isNotEmpty())) {
- CreateScreenState.CREATION_OPTION_SELECTION
} else if (createOptionSize == 0 && remoteEntry != null) {
CreateScreenState.EXTERNAL_ONLY_SELECTION
} else {
- Log.d(
- Constants.LOG_TAG,
- "Unexpected failure: the screen state failed to instantiate" +
- " because the provider list is empty."
- )
- null
+ CreateScreenState.CREATION_OPTION_SELECTION
}
}
private fun toActiveEntry(
defaultProvider: EnabledProviderInfo?,
- createOptionSize: Int,
- lastSeenProviderWithNonEmptyCreateOptions: EnabledProviderInfo?,
+ sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
remoteEntry: RemoteInfo?,
+ remoteEntryProvider: EnabledProviderInfo?,
): ActiveEntry? {
return if (
- defaultProvider != null && defaultProvider.createOptions.isEmpty() &&
- remoteEntry != null
- ) {
- ActiveEntry(defaultProvider, remoteEntry)
- } else if (
- defaultProvider != null && defaultProvider.createOptions.isNotEmpty()
+ sortedCreateOptionsPairs.isEmpty() && remoteEntry != null &&
+ remoteEntryProvider != null
) {
- ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
- } else if (createOptionSize == 1) {
- ActiveEntry(
- lastSeenProviderWithNonEmptyCreateOptions!!,
- lastSeenProviderWithNonEmptyCreateOptions.createOptions.first()
- )
+ ActiveEntry(remoteEntryProvider, remoteEntry)
+ } else if (defaultProvider != null &&
+ defaultProvider.sortedCreateOptions.isNotEmpty()) {
+ ActiveEntry(defaultProvider, defaultProvider.sortedCreateOptions.first())
+ } else if (sortedCreateOptionsPairs.isNotEmpty()) {
+ val (topEntry, topEntryProvider) = sortedCreateOptionsPairs.first()
+ ActiveEntry(topEntryProvider, topEntry)
} else null
}
/**
* Note: caller required handle empty list due to parsing error.
*/
- private fun toCreationOptionInfoList(
+ private fun toSortedCreationOptionInfoList(
providerId: String,
creationEntries: List<Entry>,
context: Context,
@@ -664,7 +662,9 @@ class CreateFlowUtils {
footerDescription = createEntry.description?.toString()
))
}
- return result
+ return result.sortedWith(
+ compareByDescending { it.lastUsedTime }
+ )
}
private fun toRemoteInfo(
@@ -690,6 +690,7 @@ class CreateFlowUtils {
context: Context,
preferImmediatelyAvailableCredentials: Boolean,
appPreferredDefaultProviderId: String?,
+ userSetDefaultProviderIds: Set<String>,
): RequestDisplayInfo? {
val json = JSONObject(requestJson)
var passkeyUsername = ""
@@ -711,6 +712,7 @@ class CreateFlowUtils {
context.getDrawable(R.drawable.ic_passkey_24) ?: return null,
preferImmediatelyAvailableCredentials,
appPreferredDefaultProviderId,
+ userSetDefaultProviderIds,
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt
index a17f2c88abcd..bfcca4970a71 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/UserConfigRepo.kt
@@ -23,15 +23,6 @@ class UserConfigRepo(context: Context) {
val sharedPreferences: SharedPreferences = context.getSharedPreferences(
context.packageName, Context.MODE_PRIVATE)
- fun setDefaultProvider(
- providerId: String
- ) {
- sharedPreferences.edit().apply {
- putString(DEFAULT_PROVIDER, providerId)
- apply()
- }
- }
-
fun setIsPasskeyFirstUse(
isFirstUse: Boolean
) {
@@ -41,16 +32,11 @@ class UserConfigRepo(context: Context) {
}
}
- fun getDefaultProviderId(): String? {
- return sharedPreferences.getString(DEFAULT_PROVIDER, null)
- }
-
fun getIsPasskeyFirstUse(): Boolean {
return sharedPreferences.getBoolean(IS_PASSKEY_FIRST_USE, true)
}
companion object {
- const val DEFAULT_PROVIDER = "default_provider"
// This first use value only applies to passkeys, not related with if generally
// credential manager is first use or not
const val IS_PASSKEY_FIRST_USE = "is_passkey_first_use"
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 9d871ed75494..dfa517b118b3 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -88,27 +88,11 @@ fun CreateCredentialScreen(
onLearnMore = viewModel::createFlowOnLearnMore,
onLog = { viewModel.logUiEvent(it) },
)
- CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
- requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
- disabledProviderList = createCredentialUiState
- .disabledProviders,
- sortedCreateOptionsPairs =
- createCredentialUiState.sortedCreateOptionsPairs,
- hasRemoteEntry = createCredentialUiState.remoteEntry != null,
- onOptionSelected =
- viewModel::createFlowOnEntrySelectedFromFirstUseScreen,
- onDisabledProvidersSelected =
- viewModel::createFlowOnDisabledProvidersSelected,
- onMoreOptionsSelected =
- viewModel::createFlowOnMoreOptionsSelectedOnProviderSelection,
- onLog = { viewModel.logUiEvent(it) },
- )
CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
providerInfo = createCredentialUiState
.activeEntry?.activeProvider!!,
- hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
createOptionInfo =
createCredentialUiState.activeEntry.activeEntryInfo
as CreateOptionInfo,
@@ -121,21 +105,15 @@ fun CreateCredentialScreen(
CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
requestDisplayInfo = createCredentialUiState.requestDisplayInfo,
enabledProviderList = createCredentialUiState.enabledProviders,
- disabledProviderList = createCredentialUiState
- .disabledProviders,
+ disabledProviderList = createCredentialUiState.disabledProviders,
sortedCreateOptionsPairs =
createCredentialUiState.sortedCreateOptionsPairs,
- hasDefaultProvider = createCredentialUiState.hasDefaultProvider,
- isFromProviderSelection =
- createCredentialUiState.isFromProviderSelection!!,
- onBackProviderSelectionButtonSelected =
- viewModel::createFlowOnBackProviderSelectionButtonSelected,
onBackCreationSelectionButtonSelected =
viewModel::createFlowOnBackCreationSelectionButtonSelected,
onOptionSelected =
viewModel::createFlowOnEntrySelectedFromMoreOptionScreen,
onDisabledProvidersSelected =
- viewModel::createFlowOnDisabledProvidersSelected,
+ viewModel::createFlowOnLaunchSettings,
onRemoteEntrySelected = viewModel::createFlowOnEntrySelected,
onLog = { viewModel.logUiEvent(it) },
)
@@ -144,11 +122,11 @@ fun CreateCredentialScreen(
viewModel.onIllegalUiState("Expect active entry to be non-null" +
" upon default provider dialog.")
} else {
- DefaultProviderConfirmationCard(
+ NonDefaultUsageConfirmationCard(
selectedEntry = createCredentialUiState.activeEntry,
onIllegalScreenState = viewModel::onIllegalUiState,
- onChangeDefaultSelected =
- viewModel::createFlowOnChangeDefaultSelected,
+ onLaunchSettings =
+ viewModel::createFlowOnLaunchSettings,
onUseOnceSelected = viewModel::createFlowOnUseOnceSelected,
onLog = { viewModel.logUiEvent(it) },
)
@@ -263,94 +241,11 @@ fun PasskeyIntroCard(
}
@Composable
-fun ProviderSelectionCard(
- requestDisplayInfo: RequestDisplayInfo,
- disabledProviderList: List<DisabledProviderInfo>?,
- sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- hasRemoteEntry: Boolean,
- onOptionSelected: (ActiveEntry) -> Unit,
- onDisabledProvidersSelected: () -> Unit,
- onMoreOptionsSelected: () -> Unit,
- onLog: @Composable (UiEventEnum) -> Unit,
-) {
- SheetContainerCard {
- item { HeadlineIcon(bitmap = requestDisplayInfo.typeIcon.toBitmap().asImageBitmap()) }
- item { Divider(thickness = 16.dp, color = Color.Transparent) }
- item {
- HeadlineText(
- text = stringResource(
- R.string.choose_provider_title,
- when (requestDisplayInfo.type) {
- CredentialType.PASSKEY ->
- stringResource(R.string.passkeys)
- CredentialType.PASSWORD ->
- stringResource(R.string.passwords)
- CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info)
- }
- )
- )
- }
- item { Divider(thickness = 24.dp, color = Color.Transparent) }
-
- item {
- Row(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
- BodyMediumText(text = stringResource(R.string.choose_provider_body))
- }
- }
- item { Divider(thickness = 16.dp, color = Color.Transparent) }
- item {
- CredentialContainerCard {
- Column(
- verticalArrangement = Arrangement.spacedBy(2.dp)
- ) {
- sortedCreateOptionsPairs.forEach { entry ->
- MoreOptionsInfoRow(
- requestDisplayInfo = requestDisplayInfo,
- providerInfo = entry.second,
- createOptionInfo = entry.first,
- onOptionSelected = {
- onOptionSelected(
- ActiveEntry(
- entry.second,
- entry.first
- )
- )
- }
- )
- }
- MoreOptionsDisabledProvidersRow(
- disabledProviders = disabledProviderList,
- onDisabledProvidersSelected = onDisabledProvidersSelected,
- )
- }
- }
- }
- if (hasRemoteEntry) {
- item { Divider(thickness = 24.dp, color = Color.Transparent) }
- item {
- CtaButtonRow(
- leftButton = {
- ActionButton(
- stringResource(R.string.string_more_options),
- onMoreOptionsSelected
- )
- }
- )
- }
- }
- }
- onLog(CreateCredentialEvent.CREDMAN_CREATE_CRED_PROVIDER_SELECTION)
-}
-
-@Composable
fun MoreOptionsSelectionCard(
requestDisplayInfo: RequestDisplayInfo,
enabledProviderList: List<EnabledProviderInfo>,
disabledProviderList: List<DisabledProviderInfo>?,
sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- hasDefaultProvider: Boolean,
- isFromProviderSelection: Boolean,
- onBackProviderSelectionButtonSelected: () -> Unit,
onBackCreationSelectionButtonSelected: () -> Unit,
onOptionSelected: (ActiveEntry) -> Unit,
onDisabledProvidersSelected: () -> Unit,
@@ -369,9 +264,7 @@ fun MoreOptionsSelectionCard(
CredentialType.UNKNOWN -> stringResource(R.string.sign_in_info)
}
),
- onNavigationIconClicked =
- if (isFromProviderSelection) onBackProviderSelectionButtonSelected
- else onBackCreationSelectionButtonSelected,
+ onNavigationIconClicked = onBackCreationSelectionButtonSelected,
bottomPadding = 16.dp,
)
}) {
@@ -379,30 +272,26 @@ fun MoreOptionsSelectionCard(
item {
CredentialContainerCard {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
- // Only in the flows with default provider(not first time use) we can show the
- // createOptions here, or they will be shown on ProviderSelectionCard
- if (hasDefaultProvider) {
- sortedCreateOptionsPairs.forEach { entry ->
- MoreOptionsInfoRow(
- requestDisplayInfo = requestDisplayInfo,
- providerInfo = entry.second,
- createOptionInfo = entry.first,
- onOptionSelected = {
- onOptionSelected(
- ActiveEntry(
- entry.second,
- entry.first
- )
+ sortedCreateOptionsPairs.forEach { entry ->
+ MoreOptionsInfoRow(
+ requestDisplayInfo = requestDisplayInfo,
+ providerInfo = entry.second,
+ createOptionInfo = entry.first,
+ onOptionSelected = {
+ onOptionSelected(
+ ActiveEntry(
+ entry.second,
+ entry.first
)
- }
- )
- }
- MoreOptionsDisabledProvidersRow(
- disabledProviders = disabledProviderList,
- onDisabledProvidersSelected =
- onDisabledProvidersSelected,
+ )
+ }
)
}
+ MoreOptionsDisabledProvidersRow(
+ disabledProviders = disabledProviderList,
+ onDisabledProvidersSelected =
+ onDisabledProvidersSelected,
+ )
enabledProviderList.forEach {
if (it.remoteEntry != null) {
RemoteEntryRow(
@@ -420,10 +309,10 @@ fun MoreOptionsSelectionCard(
}
@Composable
-fun DefaultProviderConfirmationCard(
+fun NonDefaultUsageConfirmationCard(
selectedEntry: ActiveEntry,
onIllegalScreenState: (String) -> Unit,
- onChangeDefaultSelected: () -> Unit,
+ onLaunchSettings: () -> Unit,
onUseOnceSelected: () -> Unit,
onLog: @Composable (UiEventEnum) -> Unit,
) {
@@ -454,14 +343,14 @@ fun DefaultProviderConfirmationCard(
CtaButtonRow(
leftButton = {
ActionButton(
- stringResource(R.string.use_once),
- onClick = onUseOnceSelected
+ stringResource(R.string.settings),
+ onClick = onLaunchSettings,
)
},
rightButton = {
ConfirmButton(
- stringResource(R.string.set_as_default),
- onClick = onChangeDefaultSelected
+ stringResource(R.string.use_once),
+ onClick = onUseOnceSelected,
)
},
)
@@ -479,7 +368,6 @@ fun CreationSelectionCard(
onOptionSelected: (BaseEntry) -> Unit,
onConfirm: () -> Unit,
onMoreOptionsSelected: () -> Unit,
- hasDefaultProvider: Boolean,
onLog: @Composable (UiEventEnum) -> Unit,
) {
SheetContainerCard {
@@ -527,16 +415,9 @@ fun CreationSelectionCard(
if (enabledProvider.remoteEntry != null) {
remoteEntry = enabledProvider.remoteEntry
}
- createOptionsSize += enabledProvider.createOptions.size
- }
- val shouldShowMoreOptionsButton = if (!hasDefaultProvider) {
- // User has already been presented with all options on the default provider
- // selection screen. Don't show them again. Therefore, only show the more option
- // button if remote option is present.
- remoteEntry != null
- } else {
- createOptionsSize > 1 || remoteEntry != null
+ createOptionsSize += enabledProvider.sortedCreateOptions.size
}
+ val shouldShowMoreOptionsButton = createOptionsSize > 1 || remoteEntry != null
item {
CtaButtonRow(
leftButton = if (shouldShowMoreOptionsButton) {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 225dbf2b744f..fe1ce1b60413 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -29,12 +29,9 @@ data class CreateCredentialUiState(
val currentScreenState: CreateScreenState,
val requestDisplayInfo: RequestDisplayInfo,
val sortedCreateOptionsPairs: List<Pair<CreateOptionInfo, EnabledProviderInfo>>,
- // Should not change with the real time update of default provider, only determine whether
- // we're showing provider selection page at the beginning
- val hasDefaultProvider: Boolean,
val activeEntry: ActiveEntry? = null,
val remoteEntry: RemoteInfo? = null,
- val isFromProviderSelection: Boolean? = null,
+ val foundCandidateFromUserDefaultProvider: Boolean,
)
internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean {
@@ -50,11 +47,12 @@ open class ProviderInfo(
)
class EnabledProviderInfo(
- icon: Drawable,
- id: String,
- displayName: String,
- var createOptions: List<CreateOptionInfo>,
- var remoteEntry: RemoteInfo?,
+ icon: Drawable,
+ id: String,
+ displayName: String,
+ // Sorted by last used time
+ var sortedCreateOptions: List<CreateOptionInfo>,
+ var remoteEntry: RemoteInfo?,
) : ProviderInfo(icon, id, displayName)
class DisabledProviderInfo(
@@ -108,6 +106,7 @@ data class RequestDisplayInfo(
val typeIcon: Drawable,
val preferImmediatelyAvailableCredentials: Boolean,
val appPreferredDefaultProviderId: String?,
+ val userSetDefaultProviderIds: Set<String>,
)
/**
@@ -123,7 +122,6 @@ data class ActiveEntry (
enum class CreateScreenState {
PASSKEY_INTRO,
MORE_ABOUT_PASSKEYS_INTRO,
- PROVIDER_SELECTION,
CREATION_OPTION_SELECTION,
MORE_OPTIONS_SELECTION,
DEFAULT_PROVIDER_CONFIRMATION,