diff options
| author | 2023-03-06 05:02:01 +0000 | |
|---|---|---|
| committer | 2023-03-06 05:03:45 +0000 | |
| commit | 79886a8928a755c64db45707097861cdcae54c25 (patch) | |
| tree | 29e15ab64189374d3335dbfa5af6120c22c95b36 | |
| parent | 1ee1185baa60d0303085a55c8f522a5437248ae4 (diff) | |
[CredManUi] Support auto select.
Bug: 265209303
Test: manual
Change-Id: Ie1b46eccec4116be1c0833f9399d19f23876defe
6 files changed, 83 insertions, 22 deletions
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index a2d1e4de8e35..b32fe3fef00d 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -42,11 +42,13 @@ import com.android.credentialmanager.createflow.DisabledProviderInfo import com.android.credentialmanager.createflow.EnabledProviderInfo import com.android.credentialmanager.createflow.RequestDisplayInfo import com.android.credentialmanager.getflow.GetCredentialUiState +import com.android.credentialmanager.getflow.findAutoSelectEntry import androidx.credentials.CreateCredentialRequest.DisplayInfo import androidx.credentials.CreatePublicKeyCredentialRequest import androidx.credentials.CreatePasswordRequest import androidx.credentials.GetPasswordOption import androidx.credentials.GetPublicKeyCredentialOption +import com.android.credentialmanager.common.ProviderActivityState import java.time.Instant @@ -128,10 +130,20 @@ class CredentialManagerRepo( getCredentialUiState = null, ) } - RequestInfo.TYPE_GET -> UiState( - createCredentialUiState = null, - getCredentialUiState = getCredentialInitialUiState(originName)!!, - ) + RequestInfo.TYPE_GET -> { + val getCredentialInitialUiState = getCredentialInitialUiState(originName)!! + val autoSelectEntry = + findAutoSelectEntry(getCredentialInitialUiState.providerDisplayInfo) + UiState( + createCredentialUiState = null, + getCredentialUiState = getCredentialInitialUiState, + selectedEntry = autoSelectEntry, + providerActivityState = + if (autoSelectEntry == null) ProviderActivityState.NOT_APPLICABLE + else ProviderActivityState.READY_TO_LAUNCH, + isAutoSelectFlow = autoSelectEntry != null, + ) + } else -> throw IllegalStateException("Unrecognized request type: ${requestInfo.type}") } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index a5c749432753..ca30c53a6d83 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -44,6 +44,9 @@ data class UiState( val selectedEntry: BaseEntry? = null, val providerActivityState: ProviderActivityState = ProviderActivityState.NOT_APPLICABLE, val dialogState: DialogState = DialogState.ACTIVE, + // True if the UI has one and onely one auto selectable entry. Its provider activiey will be + // launched immediately, and canceling it will cancel the whole UI flow. + val isAutoSelectFlow: Boolean = false, ) class CredentialSelectorViewModel( @@ -96,13 +99,20 @@ class CredentialSelectorViewModel( val resultCode = providerActivityResult.resultCode val resultData = providerActivityResult.data if (resultCode == Activity.RESULT_CANCELED) { - // Re-display the CredMan UI if the user canceled from the provider UI. - Log.d(Constants.LOG_TAG, "The provider activity was cancelled," + - " re-displaying our UI.") - uiState = uiState.copy( - selectedEntry = null, - providerActivityState = ProviderActivityState.NOT_APPLICABLE, - ) + // Re-display the CredMan UI if the user canceled from the provider UI, or cancel + // the UI if this is the auto select flow. + if (uiState.isAutoSelectFlow) { + Log.d(Constants.LOG_TAG, "The auto selected provider activity was cancelled," + + " ending the credential manager activity.") + onUserCancel() + } else { + Log.d(Constants.LOG_TAG, "The provider activity was cancelled," + + " re-displaying our UI.") + uiState = uiState.copy( + selectedEntry = null, + providerActivityState = ProviderActivityState.NOT_APPLICABLE, + ) + } } else { if (entry != null) { Log.d( diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index 43912c26f3c8..223806cdba3a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -222,6 +222,8 @@ class GetFlowUtils { displayName = credentialEntry.displayName?.toString(), icon = credentialEntry.icon.loadDrawable(context), lastUsedTimeMillis = credentialEntry.lastUsedTime, + isAutoSelectable = credentialEntry.isAutoSelectAllowed && + credentialEntry.autoSelectAllowedFromOption, )) } is PublicKeyCredentialEntry -> { @@ -237,6 +239,8 @@ class GetFlowUtils { displayName = credentialEntry.displayName?.toString(), icon = credentialEntry.icon.loadDrawable(context), lastUsedTimeMillis = credentialEntry.lastUsedTime, + isAutoSelectable = credentialEntry.isAutoSelectAllowed && + credentialEntry.autoSelectAllowedFromOption, )) } is CustomCredentialEntry -> { @@ -252,6 +256,8 @@ class GetFlowUtils { displayName = credentialEntry.subtitle?.toString(), icon = credentialEntry.icon.loadDrawable(context), lastUsedTimeMillis = credentialEntry.lastUsedTime, + isAutoSelectable = credentialEntry.isAutoSelectAllowed && + credentialEntry.autoSelectAllowedFromOption, )) } else -> Log.d( diff --git a/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt b/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt index 75b12ff756ad..82d6952bf826 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/TestUtils.kt @@ -155,21 +155,23 @@ class GetTestUtils { userName: String, userDisplayName: String?, lastUsedTime: Instant?, + isAutoSelectAllowed: Boolean = false, ): Entry { - val intent = Intent("com.androidauth.androidvault.CONFIRM_PASSWORD") - .setPackage("com.androidauth.androidvault") - intent.putExtra("provider_extra_sample", "testprovider") - val pendingIntent = PendingIntent.getActivity( - context, 1, - intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT - or PendingIntent.FLAG_ONE_SHOT) + val intent = Intent(Settings.ACTION_SYNC_SETTINGS) + val pendingIntent = + PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) + val candidateQueryData = Bundle() + candidateQueryData.putBoolean( + "androidx.credentials.BUNDLE_KEY_IS_AUTO_SELECT_ALLOWED", + isAutoSelectAllowed ) val passkeyEntry = PublicKeyCredentialEntry.Builder( context, userName, pendingIntent, - BeginGetPublicKeyCredentialOption(Bundle(), "id", "requestjson") - ).setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime).build() + BeginGetPublicKeyCredentialOption(candidateQueryData, "id", "requestjson") + ).setDisplayName(userDisplayName).setLastUsedTime(lastUsedTime) + .setAutoSelectAllowed(isAutoSelectAllowed).build() return Entry(key, subkey, passkeyEntry.slice, Intent()) } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt index b83c593fdffc..652cf0180b53 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt @@ -1,4 +1,18 @@ -@file:OptIn(ExperimentalMaterial3Api::class) +/* + * Copyright (C) 2022 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.createflow @@ -15,7 +29,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.Divider -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.NewReleases diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index 9727d3f39c4a..dbf199768bbf 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -41,6 +41,23 @@ internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean { !state.requestDisplayInfo.preferImmediatelyAvailableCredentials) } +internal fun findAutoSelectEntry(providerDisplayInfo: ProviderDisplayInfo): CredentialEntryInfo? { + if (providerDisplayInfo.authenticationEntryList.isNotEmpty()) { + return null + } + if (providerDisplayInfo.sortedUserNameToCredentialEntryList.size == 1) { + val entryList = providerDisplayInfo.sortedUserNameToCredentialEntryList.firstOrNull() + ?: return null + if (entryList.sortedCredentialEntryList.size == 1) { + val entry = entryList.sortedCredentialEntryList.firstOrNull() ?: return null + if (entry.isAutoSelectable) { + return entry + } + } + } + return null +} + data class ProviderInfo( /** * Unique id (component name) of this provider. @@ -81,6 +98,7 @@ class CredentialEntryInfo( val displayName: String?, val icon: Drawable?, val lastUsedTimeMillis: Instant?, + val isAutoSelectable: Boolean, ) : BaseEntry( providerId, entryKey, |