[CredManUI] Honor preferImmediatelyAvailableCred
Fail early when it's true and only remote entries are available, or otherwise show the remote only screen. Bug: 270616566 Test: manual Change-Id: Ibee0021472ceea84c26872eb13de0a39c560eaa0
This commit is contained in:
@@ -45,6 +45,8 @@ import com.android.credentialmanager.getflow.GetCredentialUiState
|
||||
import androidx.credentials.CreateCredentialRequest.DisplayInfo
|
||||
import androidx.credentials.CreatePublicKeyCredentialRequest
|
||||
import androidx.credentials.CreatePasswordRequest
|
||||
import androidx.credentials.GetPasswordOption
|
||||
import androidx.credentials.GetPublicKeyCredentialOption
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
@@ -71,7 +73,7 @@ class CredentialManagerRepo(
|
||||
requestInfo = intent.extras?.getParcelable(
|
||||
RequestInfo.EXTRA_REQUEST_INFO,
|
||||
RequestInfo::class.java
|
||||
) ?: testCreatePasswordRequestInfo()
|
||||
) ?: testCreatePasskeyRequestInfo()
|
||||
|
||||
val originName: String? = when (requestInfo.type) {
|
||||
RequestInfo.TYPE_CREATE -> requestInfo.createCredentialRequest?.origin
|
||||
@@ -120,8 +122,7 @@ class CredentialManagerRepo(
|
||||
providerDisableListUiState,
|
||||
defaultProviderId,
|
||||
requestDisplayInfoUiState,
|
||||
/** isOnPasskeyIntroStateAlready */
|
||||
false,
|
||||
isOnPasskeyIntroStateAlready = false,
|
||||
isPasskeyFirstUse
|
||||
)!!,
|
||||
getCredentialUiState = null,
|
||||
@@ -400,7 +401,8 @@ class CredentialManagerRepo(
|
||||
" \"authenticatorSelection\": {\n" +
|
||||
" \"residentKey\": \"required\",\n" +
|
||||
" \"requireResidentKey\": true\n" +
|
||||
" }}"
|
||||
" }}",
|
||||
preferImmediatelyAvailableCredentials = true,
|
||||
)
|
||||
val credentialData = request.credentialData
|
||||
return RequestInfo.newCreateRequestInfo(
|
||||
@@ -446,19 +448,28 @@ class CredentialManagerRepo(
|
||||
}
|
||||
|
||||
private fun testGetRequestInfo(): RequestInfo {
|
||||
val passwordOption = GetPasswordOption()
|
||||
val passkeyOption = GetPublicKeyCredentialOption(
|
||||
"json", preferImmediatelyAvailableCredentials = false)
|
||||
return RequestInfo.newGetRequestInfo(
|
||||
Binder(),
|
||||
GetCredentialRequest.Builder(
|
||||
Bundle()
|
||||
).addCredentialOption(
|
||||
CredentialOption(
|
||||
"androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL",
|
||||
Bundle(),
|
||||
Bundle(), /*isSystemProviderRequired=*/
|
||||
false
|
||||
passwordOption.type,
|
||||
passwordOption.requestData,
|
||||
passwordOption.candidateQueryData,
|
||||
passwordOption.isSystemProviderRequired
|
||||
)
|
||||
)
|
||||
.build(),
|
||||
).addCredentialOption(
|
||||
CredentialOption(
|
||||
passkeyOption.type,
|
||||
passkeyOption.requestData,
|
||||
passkeyOption.candidateQueryData,
|
||||
passkeyOption.isSystemProviderRequired
|
||||
)
|
||||
).build(),
|
||||
"com.google.android.youtube"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,11 @@ import com.android.credentialmanager.getflow.RemoteEntryInfo
|
||||
import androidx.credentials.CreateCredentialRequest
|
||||
import androidx.credentials.CreateCustomCredentialRequest
|
||||
import androidx.credentials.CreatePasswordRequest
|
||||
import androidx.credentials.CredentialOption
|
||||
import androidx.credentials.CreatePublicKeyCredentialRequest
|
||||
import androidx.credentials.CreatePublicKeyCredentialRequestPrivileged
|
||||
import androidx.credentials.GetPublicKeyCredentialOption
|
||||
import androidx.credentials.GetPublicKeyCredentialOptionPrivileged
|
||||
import androidx.credentials.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
|
||||
import androidx.credentials.provider.Action
|
||||
import androidx.credentials.provider.AuthenticationAction
|
||||
@@ -172,10 +176,27 @@ class GetFlowUtils {
|
||||
context: Context,
|
||||
originName: String?,
|
||||
): com.android.credentialmanager.getflow.RequestDisplayInfo? {
|
||||
val getCredentialRequest = requestInfo.getCredentialRequest ?: return null
|
||||
val preferImmediatelyAvailableCredentials = getCredentialRequest.credentialOptions.any {
|
||||
val credentialOptionJetpack = CredentialOption.createFrom(
|
||||
it.type,
|
||||
it.credentialRetrievalData,
|
||||
it.credentialRetrievalData,
|
||||
it.isSystemProviderRequired
|
||||
)
|
||||
if (credentialOptionJetpack is GetPublicKeyCredentialOption) {
|
||||
credentialOptionJetpack.preferImmediatelyAvailableCredentials
|
||||
} else if (credentialOptionJetpack is GetPublicKeyCredentialOptionPrivileged) {
|
||||
credentialOptionJetpack.preferImmediatelyAvailableCredentials
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
return com.android.credentialmanager.getflow.RequestDisplayInfo(
|
||||
appName = originName
|
||||
?: getAppLabel(context.packageManager, requestInfo.appPackageName)
|
||||
?: return null
|
||||
?: return null,
|
||||
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
|
||||
)
|
||||
}
|
||||
|
||||
@@ -415,24 +436,25 @@ class CreateFlowUtils {
|
||||
createCredentialRequestJetpack.password,
|
||||
CredentialType.PASSWORD,
|
||||
appLabel,
|
||||
context.getDrawable(R.drawable.ic_password)!!
|
||||
context.getDrawable(R.drawable.ic_password) ?: return null,
|
||||
preferImmediatelyAvailableCredentials = false,
|
||||
)
|
||||
is CreatePublicKeyCredentialRequest -> {
|
||||
val requestJson = createCredentialRequestJetpack.requestJson
|
||||
val json = JSONObject(requestJson)
|
||||
var name = ""
|
||||
var displayName = ""
|
||||
if (json.has("user")) {
|
||||
val user: JSONObject = json.getJSONObject("user")
|
||||
name = user.getString("name")
|
||||
displayName = user.getString("displayName")
|
||||
}
|
||||
RequestDisplayInfo(
|
||||
name,
|
||||
displayName,
|
||||
CredentialType.PASSKEY,
|
||||
appLabel,
|
||||
context.getDrawable(R.drawable.ic_passkey)!!
|
||||
newRequestDisplayInfoFromPasskeyJson(
|
||||
requestJson = createCredentialRequestJetpack.requestJson,
|
||||
appLabel = appLabel,
|
||||
context = context,
|
||||
preferImmediatelyAvailableCredentials =
|
||||
createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
|
||||
)
|
||||
}
|
||||
is CreatePublicKeyCredentialRequestPrivileged -> {
|
||||
newRequestDisplayInfoFromPasskeyJson(
|
||||
requestJson = createCredentialRequestJetpack.requestJson,
|
||||
appLabel = appLabel,
|
||||
context = context,
|
||||
preferImmediatelyAvailableCredentials =
|
||||
createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
|
||||
)
|
||||
}
|
||||
is CreateCustomCredentialRequest -> {
|
||||
@@ -446,7 +468,8 @@ class CreateFlowUtils {
|
||||
type = CredentialType.UNKNOWN,
|
||||
appName = appLabel,
|
||||
typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context)
|
||||
?: context.getDrawable(R.drawable.ic_other_sign_in)!!
|
||||
?: context.getDrawable(R.drawable.ic_other_sign_in) ?: return null,
|
||||
preferImmediatelyAvailableCredentials = false,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
@@ -613,5 +636,29 @@ class CreateFlowUtils {
|
||||
)
|
||||
} else null
|
||||
}
|
||||
|
||||
private fun newRequestDisplayInfoFromPasskeyJson(
|
||||
requestJson: String,
|
||||
appLabel: String,
|
||||
context: Context,
|
||||
preferImmediatelyAvailableCredentials: Boolean,
|
||||
): RequestDisplayInfo? {
|
||||
val json = JSONObject(requestJson)
|
||||
var name = ""
|
||||
var displayName = ""
|
||||
if (json.has("user")) {
|
||||
val user: JSONObject = json.getJSONObject("user")
|
||||
name = user.getString("name")
|
||||
displayName = user.getString("displayName")
|
||||
}
|
||||
return RequestDisplayInfo(
|
||||
name,
|
||||
displayName,
|
||||
CredentialType.PASSKEY,
|
||||
appLabel,
|
||||
context.getDrawable(R.drawable.ic_passkey) ?: return null,
|
||||
preferImmediatelyAvailableCredentials,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,9 @@ data class CreateCredentialUiState(
|
||||
)
|
||||
|
||||
internal fun hasContentToDisplay(state: CreateCredentialUiState): Boolean {
|
||||
return state.sortedCreateOptionsPairs.isNotEmpty()
|
||||
return state.sortedCreateOptionsPairs.isNotEmpty() ||
|
||||
(!state.requestDisplayInfo.preferImmediatelyAvailableCredentials &&
|
||||
state.remoteEntry != null)
|
||||
}
|
||||
|
||||
open class ProviderInfo(
|
||||
@@ -104,6 +106,7 @@ data class RequestDisplayInfo(
|
||||
val type: CredentialType,
|
||||
val appName: String,
|
||||
val typeIcon: Drawable,
|
||||
val preferImmediatelyAvailableCredentials: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,8 @@ data class GetCredentialUiState(
|
||||
internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean {
|
||||
return state.providerDisplayInfo.sortedUserNameToCredentialEntryList.isNotEmpty() ||
|
||||
state.providerDisplayInfo.authenticationEntryList.isNotEmpty() ||
|
||||
state.providerDisplayInfo.remoteEntry != null
|
||||
(state.providerDisplayInfo.remoteEntry != null &&
|
||||
!state.requestDisplayInfo.preferImmediatelyAvailableCredentials)
|
||||
}
|
||||
|
||||
data class ProviderInfo(
|
||||
@@ -146,6 +147,7 @@ class ActionEntryInfo(
|
||||
|
||||
data class RequestDisplayInfo(
|
||||
val appName: String,
|
||||
val preferImmediatelyAvailableCredentials: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -246,7 +248,6 @@ private fun toActiveEntry(
|
||||
private fun toGetScreenState(
|
||||
providerDisplayInfo: ProviderDisplayInfo
|
||||
): GetScreenState {
|
||||
|
||||
return if (providerDisplayInfo.sortedUserNameToCredentialEntryList.isEmpty() &&
|
||||
providerDisplayInfo.remoteEntry == null &&
|
||||
providerDisplayInfo.authenticationEntryList.all { it.isUnlockedAndEmpty })
|
||||
|
||||
Reference in New Issue
Block a user