Merge "Support autoselect for create flows." into udc-dev am: fcdac40e64
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23089737 Change-Id: Ic5d6b155a2888ff3ab93920c3a763fc1d0da5beb Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -38,6 +38,7 @@ import com.android.credentialmanager.createflow.RequestDisplayInfo
|
||||
import com.android.credentialmanager.getflow.GetCredentialUiState
|
||||
import com.android.credentialmanager.getflow.findAutoSelectEntry
|
||||
import com.android.credentialmanager.common.ProviderActivityState
|
||||
import com.android.credentialmanager.createflow.isFlowAutoSelectable
|
||||
|
||||
/**
|
||||
* Client for interacting with Credential Manager. Also holds data inputs from it.
|
||||
@@ -113,21 +114,30 @@ class CredentialManagerRepo(
|
||||
val providerDisableListUiState = getCreateProviderDisableListInitialUiState()
|
||||
val requestDisplayInfoUiState =
|
||||
getCreateRequestDisplayInfoInitialUiState(originName)!!
|
||||
val createCredentialUiState = CreateFlowUtils.toCreateCredentialUiState(
|
||||
enabledProviders = providerEnableListUiState,
|
||||
disabledProviders = providerDisableListUiState,
|
||||
defaultProviderIdPreferredByApp =
|
||||
requestDisplayInfoUiState.appPreferredDefaultProviderId,
|
||||
defaultProviderIdsSetByUser =
|
||||
requestDisplayInfoUiState.userSetDefaultProviderIds,
|
||||
requestDisplayInfo = requestDisplayInfoUiState,
|
||||
isOnPasskeyIntroStateAlready = false,
|
||||
isPasskeyFirstUse = isPasskeyFirstUse,
|
||||
)!!
|
||||
val isFlowAutoSelectable = isFlowAutoSelectable(createCredentialUiState)
|
||||
UiState(
|
||||
createCredentialUiState = CreateFlowUtils.toCreateCredentialUiState(
|
||||
enabledProviders = providerEnableListUiState,
|
||||
disabledProviders = providerDisableListUiState,
|
||||
defaultProviderIdPreferredByApp =
|
||||
requestDisplayInfoUiState.appPreferredDefaultProviderId,
|
||||
defaultProviderIdsSetByUser =
|
||||
requestDisplayInfoUiState.userSetDefaultProviderIds,
|
||||
requestDisplayInfo = requestDisplayInfoUiState,
|
||||
isOnPasskeyIntroStateAlready = false,
|
||||
isPasskeyFirstUse = isPasskeyFirstUse,
|
||||
)!!,
|
||||
createCredentialUiState = createCredentialUiState,
|
||||
getCredentialUiState = null,
|
||||
cancelRequestState = cancelUiRequestState,
|
||||
isInitialRender = isNewActivity,
|
||||
isAutoSelectFlow = isFlowAutoSelectable,
|
||||
providerActivityState =
|
||||
if (isFlowAutoSelectable) ProviderActivityState.READY_TO_LAUNCH
|
||||
else ProviderActivityState.NOT_APPLICABLE,
|
||||
selectedEntry =
|
||||
if (isFlowAutoSelectable) createCredentialUiState.activeEntry?.activeEntryInfo
|
||||
else null,
|
||||
)
|
||||
}
|
||||
RequestInfo.TYPE_GET -> {
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.android.credentialmanager.common.DialogState
|
||||
import com.android.credentialmanager.common.ProviderActivityResult
|
||||
import com.android.credentialmanager.common.ProviderActivityState
|
||||
import com.android.credentialmanager.createflow.ActiveEntry
|
||||
import com.android.credentialmanager.createflow.isFlowAutoSelectable
|
||||
import com.android.credentialmanager.createflow.CreateCredentialUiState
|
||||
import com.android.credentialmanager.createflow.CreateScreenState
|
||||
import com.android.credentialmanager.getflow.GetCredentialUiState
|
||||
@@ -262,30 +263,39 @@ class CredentialSelectorViewModel(
|
||||
/***** Create Flow Callbacks *****/
|
||||
/**************************************************************************/
|
||||
fun createFlowOnConfirmIntro() {
|
||||
userConfigRepo.setIsPasskeyFirstUse(false)
|
||||
val prevUiState = uiState.createCredentialUiState
|
||||
if (prevUiState == null) {
|
||||
Log.d(Constants.LOG_TAG, "Encountered unexpected null create ui state")
|
||||
onInternalError()
|
||||
return
|
||||
}
|
||||
val newUiState = CreateFlowUtils.toCreateCredentialUiState(
|
||||
enabledProviders = prevUiState.enabledProviders,
|
||||
disabledProviders = prevUiState.disabledProviders,
|
||||
defaultProviderIdPreferredByApp =
|
||||
prevUiState.requestDisplayInfo.appPreferredDefaultProviderId,
|
||||
defaultProviderIdsSetByUser =
|
||||
prevUiState.requestDisplayInfo.userSetDefaultProviderIds,
|
||||
requestDisplayInfo = prevUiState.requestDisplayInfo,
|
||||
val newScreenState = CreateFlowUtils.toCreateScreenState(
|
||||
createOptionSize = prevUiState.sortedCreateOptionsPairs.size,
|
||||
isOnPasskeyIntroStateAlready = true,
|
||||
isPasskeyFirstUse = userConfigRepo.getIsPasskeyFirstUse()
|
||||
requestDisplayInfo = prevUiState.requestDisplayInfo,
|
||||
remoteEntry = prevUiState.remoteEntry,
|
||||
isPasskeyFirstUse = true,
|
||||
)
|
||||
if (newUiState == null) {
|
||||
Log.d(Constants.LOG_TAG, "Unable to update create ui state")
|
||||
if (newScreenState == null) {
|
||||
Log.d(Constants.LOG_TAG, "Unexpected: couldn't resolve new screen state")
|
||||
onInternalError()
|
||||
return
|
||||
}
|
||||
uiState = uiState.copy(createCredentialUiState = newUiState)
|
||||
userConfigRepo.setIsPasskeyFirstUse(false)
|
||||
val newCreateCredentialUiState = prevUiState.copy(
|
||||
currentScreenState = newScreenState,
|
||||
)
|
||||
val isFlowAutoSelectable = isFlowAutoSelectable(newCreateCredentialUiState)
|
||||
uiState = uiState.copy(
|
||||
createCredentialUiState = newCreateCredentialUiState,
|
||||
isAutoSelectFlow = isFlowAutoSelectable,
|
||||
providerActivityState =
|
||||
if (isFlowAutoSelectable) ProviderActivityState.READY_TO_LAUNCH
|
||||
else ProviderActivityState.NOT_APPLICABLE,
|
||||
selectedEntry =
|
||||
if (isFlowAutoSelectable) newCreateCredentialUiState.activeEntry?.activeEntryInfo
|
||||
else null,
|
||||
)
|
||||
}
|
||||
|
||||
fun createFlowOnMoreOptionsSelectedOnCreationSelection() {
|
||||
|
||||
@@ -487,6 +487,7 @@ class CreateFlowUtils {
|
||||
createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
|
||||
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
|
||||
userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
|
||||
isAutoSelectRequest = createCredentialRequestJetpack.isAutoSelectAllowed,
|
||||
)
|
||||
is CreatePublicKeyCredentialRequest -> {
|
||||
newRequestDisplayInfoFromPasskeyJson(
|
||||
@@ -497,6 +498,7 @@ class CreateFlowUtils {
|
||||
createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
|
||||
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
|
||||
userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
|
||||
isAutoSelectRequest = createCredentialRequestJetpack.isAutoSelectAllowed,
|
||||
)
|
||||
}
|
||||
is CreateCustomCredentialRequest -> {
|
||||
@@ -515,6 +517,7 @@ class CreateFlowUtils {
|
||||
createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
|
||||
appPreferredDefaultProviderId = appPreferredDefaultProviderId,
|
||||
userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
|
||||
isAutoSelectRequest = createCredentialRequestJetpack.isAutoSelectAllowed,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
@@ -602,7 +605,7 @@ class CreateFlowUtils {
|
||||
)
|
||||
}
|
||||
|
||||
private fun toCreateScreenState(
|
||||
fun toCreateScreenState(
|
||||
createOptionSize: Int,
|
||||
isOnPasskeyIntroStateAlready: Boolean,
|
||||
requestDisplayInfo: RequestDisplayInfo,
|
||||
@@ -662,7 +665,13 @@ class CreateFlowUtils {
|
||||
passkeyCount = createEntry.getPublicKeyCredentialCount(),
|
||||
totalCredentialCount = createEntry.getTotalCredentialCount(),
|
||||
lastUsedTime = createEntry.lastUsedTime ?: Instant.MIN,
|
||||
footerDescription = createEntry.description?.toString()
|
||||
footerDescription = createEntry.description?.toString(),
|
||||
// TODO(b/281065680): replace with official library constant once available
|
||||
allowAutoSelect =
|
||||
it.slice.items.firstOrNull {
|
||||
it.hasHint("androidx.credentials.provider.createEntry.SLICE_HINT_AUTO_" +
|
||||
"SELECT_ALLOWED")
|
||||
}?.text == "true",
|
||||
))
|
||||
}
|
||||
return result.sortedWith(
|
||||
@@ -694,6 +703,7 @@ class CreateFlowUtils {
|
||||
preferImmediatelyAvailableCredentials: Boolean,
|
||||
appPreferredDefaultProviderId: String?,
|
||||
userSetDefaultProviderIds: Set<String>,
|
||||
isAutoSelectRequest: Boolean
|
||||
): RequestDisplayInfo? {
|
||||
val json = JSONObject(requestJson)
|
||||
var passkeyUsername = ""
|
||||
@@ -716,6 +726,7 @@ class CreateFlowUtils {
|
||||
preferImmediatelyAvailableCredentials,
|
||||
appPreferredDefaultProviderId,
|
||||
userSetDefaultProviderIds,
|
||||
isAutoSelectRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,14 +39,16 @@ fun ModalBottomSheet(
|
||||
onDismiss: () -> Unit,
|
||||
isInitialRender: Boolean,
|
||||
onInitialRenderComplete: () -> Unit,
|
||||
isAutoSelectFlow: Boolean,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val state = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Hidden,
|
||||
initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded
|
||||
else ModalBottomSheetValue.Hidden,
|
||||
skipHalfExpanded = true
|
||||
)
|
||||
val sysUiController = rememberSystemUiController()
|
||||
if (state.targetValue == ModalBottomSheetValue.Hidden) {
|
||||
if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) {
|
||||
setTransparentSystemBarsColor(sysUiController)
|
||||
} else {
|
||||
setBottomSheetSystemBarsColor(sysUiController)
|
||||
|
||||
@@ -166,6 +166,7 @@ fun CreateCredentialScreen(
|
||||
},
|
||||
onDismiss = viewModel::onUserCancel,
|
||||
isInitialRender = viewModel.uiState.isInitialRender,
|
||||
isAutoSelectFlow = viewModel.uiState.isAutoSelectFlow,
|
||||
onInitialRenderComplete = viewModel::onInitialRenderComplete,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,21 @@ data class CreateCredentialUiState(
|
||||
val foundCandidateFromUserDefaultProvider: Boolean,
|
||||
)
|
||||
|
||||
internal fun isFlowAutoSelectable(
|
||||
uiState: CreateCredentialUiState
|
||||
): Boolean {
|
||||
return uiState.requestDisplayInfo.isAutoSelectRequest &&
|
||||
// Even if the flow is auto selectable, still allow passkey intro screen to show once if
|
||||
// applicable.
|
||||
uiState.currentScreenState != CreateScreenState.PASSKEY_INTRO &&
|
||||
uiState.currentScreenState != CreateScreenState.MORE_ABOUT_PASSKEYS_INTRO &&
|
||||
uiState.remoteEntry == null &&
|
||||
uiState.sortedCreateOptionsPairs.size == 1 &&
|
||||
uiState.activeEntry?.activeEntryInfo?.let {
|
||||
it is CreateOptionInfo && it.allowAutoSelect
|
||||
} ?: false
|
||||
}
|
||||
|
||||
internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean {
|
||||
return state.sortedCreateOptionsPairs.isNotEmpty() ||
|
||||
(!state.requestDisplayInfo.preferImmediatelyAvailableCredentials &&
|
||||
@@ -74,6 +89,7 @@ class CreateOptionInfo(
|
||||
val totalCredentialCount: Int?,
|
||||
val lastUsedTime: Instant,
|
||||
val footerDescription: String?,
|
||||
val allowAutoSelect: Boolean,
|
||||
) : BaseEntry(
|
||||
providerId,
|
||||
entryKey,
|
||||
@@ -107,6 +123,8 @@ data class RequestDisplayInfo(
|
||||
val preferImmediatelyAvailableCredentials: Boolean,
|
||||
val appPreferredDefaultProviderId: String?,
|
||||
val userSetDefaultProviderIds: Set<String>,
|
||||
// Whether the given CreateCredentialRequest allows auto select.
|
||||
val isAutoSelectRequest: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -149,6 +149,7 @@ fun GetCredentialScreen(
|
||||
},
|
||||
onDismiss = viewModel::onUserCancel,
|
||||
isInitialRender = viewModel.uiState.isInitialRender,
|
||||
isAutoSelectFlow = viewModel.uiState.isAutoSelectFlow,
|
||||
onInitialRenderComplete = viewModel::onInitialRenderComplete,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user