Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62fe64e4 authored by Helen Qin's avatar Helen Qin Committed by Android (Google) Code Review
Browse files

Merge "Prioritize Credential Types based on priority set by jetpack library" into main

parents c78e27ac ba3f8edd
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.util.Log
import androidx.activity.result.IntentSenderRequest
import androidx.credentials.PasswordCredential
import androidx.credentials.PublicKeyCredential
import androidx.credentials.provider.Action
import androidx.credentials.provider.AuthenticationAction
@@ -125,6 +126,7 @@ private fun getCredentialOptionInfoList(
                    pendingIntent = credentialEntry.pendingIntent,
                    fillInIntent = it.frameworkExtrasIntent,
                    credentialType = CredentialType.PASSWORD,
                    rawCredentialType = PasswordCredential.TYPE_PASSWORD_CREDENTIAL,
                    credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
                    userName = credentialEntry.username.toString(),
                    displayName = credentialEntry.displayName?.toString(),
@@ -149,6 +151,7 @@ private fun getCredentialOptionInfoList(
                    pendingIntent = credentialEntry.pendingIntent,
                    fillInIntent = it.frameworkExtrasIntent,
                    credentialType = CredentialType.PASSKEY,
                    rawCredentialType = PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
                    credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(),
                    userName = credentialEntry.username.toString(),
                    displayName = credentialEntry.displayName?.toString(),
@@ -175,6 +178,7 @@ private fun getCredentialOptionInfoList(
                    pendingIntent = credentialEntry.pendingIntent,
                    fillInIntent = it.frameworkExtrasIntent,
                    credentialType = CredentialType.UNKNOWN,
                    rawCredentialType = credentialEntry.type,
                    credentialTypeDisplayName =
                    credentialEntry.typeDisplayName?.toString().orEmpty(),
                    userName = credentialEntry.title.toString(),
+5 −0
Original line number Diff line number Diff line
@@ -31,6 +31,11 @@ class CredentialEntryInfo(
    fillInIntent: Intent?,
    /** Type of this credential used for sorting. Not localized so must not be directly displayed. */
    val credentialType: CredentialType,
    /**
     * String type value of this credential used for sorting. Not localized so must not be directly
     * displayed.
     */
    val rawCredentialType: String,
    /** Localized type value of this credential used for display purpose. */
    val credentialTypeDisplayName: String,
    val providerDisplayName: String,
+27 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.credentials.GetCredentialRequest
import android.credentials.selection.CreateCredentialProviderData
import android.credentials.selection.DisabledProviderData
import android.credentials.selection.Entry
@@ -44,6 +45,9 @@ import androidx.credentials.CreateCredentialRequest
import androidx.credentials.CreateCustomCredentialRequest
import androidx.credentials.CreatePasswordRequest
import androidx.credentials.CreatePublicKeyCredentialRequest
import androidx.credentials.PasswordCredential
import androidx.credentials.PriorityHints
import androidx.credentials.PublicKeyCredential
import androidx.credentials.provider.CreateEntry
import androidx.credentials.provider.RemoteEntry
import org.json.JSONObject
@@ -162,6 +166,25 @@ private fun getPackageInfo(
/** Utility functions for converting CredentialManager data structures to or from UI formats. */
class GetFlowUtils {
    companion object {
        fun extractTypePriorityMap(request: GetCredentialRequest): Map<String, Int> {
            val typePriorityMap = mutableMapOf<String, Int>()
            request.credentialOptions.forEach {option ->
                // TODO(b/280085288) - use jetpack conversion method when exposed, rather than
                // parsing from the raw Bundle
                val priority = option.candidateQueryData.getInt(
                        "androidx.credentials.BUNDLE_KEY_TYPE_PRIORITY_VALUE",
                        when (option.type) {
                            PasswordCredential.TYPE_PASSWORD_CREDENTIAL ->
                                PriorityHints.PRIORITY_PASSWORD_OR_SIMILAR
                            PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL -> 100
                            else -> PriorityHints.PRIORITY_DEFAULT
                        }
                )
                typePriorityMap[option.type] = priority
            }
            return typePriorityMap
        }

        // Returns the list (potentially empty) of enabled provider.
        fun toProviderList(
            providerDataList: List<GetCredentialProviderData>,
@@ -193,6 +216,9 @@ class GetFlowUtils {
                        null
                    }
                }

            val typePriorityMap = extractTypePriorityMap(getCredentialRequest)

            return com.android.credentialmanager.getflow.RequestDisplayInfo(
                appName = originName?.ifEmpty { null }
                    ?: getAppLabel(context.packageManager, requestInfo.packageName)
@@ -203,6 +229,7 @@ class GetFlowUtils {
                    // exposed.
                    "androidx.credentials.BUNDLE_KEY_PREFER_IDENTITY_DOC_UI"),
                preferTopBrandingContent = preferTopBrandingContent,
                typePriorityMap = typePriorityMap,
            )
        }
    }
+8 −6
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@ import android.graphics.drawable.Icon
import android.os.Bundle
import android.os.CancellationSignal
import android.os.OutcomeReceiver
import android.provider.Settings
import android.service.autofill.AutofillService
import android.service.autofill.Dataset
import android.service.autofill.Field
@@ -140,7 +139,7 @@ class CredentialAutofillService : AutofillService() {
            override fun onResult(result: GetCandidateCredentialsResponse) {
                Log.i(TAG, "getCandidateCredentials onResult")
                val fillResponse = convertToFillResponse(result, request,
                    responseClientState)
                    responseClientState, GetFlowUtils.extractTypePriorityMap(getCredRequest))
                if (fillResponse != null) {
                    callback.onSuccess(fillResponse)
                } else {
@@ -197,7 +196,8 @@ class CredentialAutofillService : AutofillService() {
    private fun convertToFillResponse(
            getCredResponse: GetCandidateCredentialsResponse,
            filLRequest: FillRequest,
            responseClientState: Bundle
            responseClientState: Bundle,
            typePriorityMap: Map<String, Int>,
    ): FillResponse? {
        val candidateProviders = getCredResponse.candidateProviderDataList
        if (candidateProviders.isEmpty()) {
@@ -213,7 +213,7 @@ class CredentialAutofillService : AutofillService() {
        autofillIdToProvidersMap.forEach { (autofillId, providers) ->
            validFillResponse = processProvidersForAutofillId(
                    filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder,
                    getCredResponse.intent)
                    getCredResponse.intent, typePriorityMap)
                    .or(validFillResponse)
        }
        if (!validFillResponse) {
@@ -229,7 +229,8 @@ class CredentialAutofillService : AutofillService() {
            providerDataList: ArrayList<GetCredentialProviderData>,
            entryIconMap: Map<String, Icon>,
            fillResponseBuilder: FillResponse.Builder,
            bottomSheetIntent: Intent
            bottomSheetIntent: Intent,
            typePriorityMap: Map<String, Int>,
    ): Boolean {
        val providerList = GetFlowUtils.toProviderList(
            providerDataList,
@@ -237,7 +238,8 @@ class CredentialAutofillService : AutofillService() {
        if (providerList.isEmpty()) {
            return false
        }
        val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerList)
        val providerDisplayInfo: ProviderDisplayInfo =
                toProviderDisplayInfo(providerList, typePriorityMap)
        var totalEntryCount = providerDisplayInfo.sortedUserNameToCredentialEntryList.size
        val inlineSuggestionsRequest = filLRequest.inlineSuggestionsRequest
        val inlinePresentationSpecs = inlineSuggestionsRequest?.inlinePresentationSpecs
+20 −8
Original line number Diff line number Diff line
@@ -18,9 +18,9 @@ package com.android.credentialmanager.getflow

import android.credentials.flags.Flags.selectorUiImprovementsEnabled
import android.graphics.drawable.Drawable
import androidx.credentials.PriorityHints
import com.android.credentialmanager.model.get.ProviderInfo
import com.android.credentialmanager.model.EntryInfo
import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.model.get.AuthenticationEntryInfo
import com.android.credentialmanager.model.get.CredentialEntryInfo
import com.android.credentialmanager.model.get.RemoteEntryInfo
@@ -30,7 +30,8 @@ data class GetCredentialUiState(
    val isRequestForAllOptions: Boolean,
    val providerInfoList: List<ProviderInfo>,
    val requestDisplayInfo: RequestDisplayInfo,
    val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
    val providerDisplayInfo: ProviderDisplayInfo =
            toProviderDisplayInfo(providerInfoList, requestDisplayInfo.typePriorityMap),
    val currentScreenState: GetScreenState = toGetScreenState(
            providerDisplayInfo, isRequestForAllOptions),
    val activeEntry: EntryInfo? = toActiveEntry(providerDisplayInfo),
@@ -79,6 +80,8 @@ data class RequestDisplayInfo(
    val preferIdentityDocUi: Boolean,
    // A top level branding icon + display name preferred by the app.
    val preferTopBrandingContent: TopBrandingContent?,
    // Map of credential type -> priority.
    val typePriorityMap: Map<String, Int>,
)

data class TopBrandingContent(
@@ -119,7 +122,8 @@ enum class GetScreenState {
 * @hide
 */
fun toProviderDisplayInfo(
    providerInfoList: List<ProviderInfo>
    providerInfoList: List<ProviderInfo>,
    typePriorityMap: Map<String, Int>,
): ProviderDisplayInfo {
    val userNameToCredentialEntryMap = mutableMapOf<String, MutableList<CredentialEntryInfo>>()
    val authenticationEntryList = mutableListOf<AuthenticationEntryInfo>()
@@ -147,7 +151,7 @@ fun toProviderDisplayInfo(
    }

    // Compose sortedUserNameToCredentialEntryList
    val comparator = CredentialEntryInfoComparatorByTypeThenTimestamp()
    val comparator = CredentialEntryInfoComparatorByTypeThenTimestamp(typePriorityMap)
    // Sort per username
    userNameToCredentialEntryMap.values.forEach {
        it.sortWith(comparator)
@@ -203,13 +207,21 @@ private fun toGetScreenState(
    else GetScreenState.PRIMARY_SELECTION
}

internal class CredentialEntryInfoComparatorByTypeThenTimestamp : Comparator<CredentialEntryInfo> {
internal class CredentialEntryInfoComparatorByTypeThenTimestamp(
        val typePriorityMap: Map<String, Int>,
) : Comparator<CredentialEntryInfo> {
    override fun compare(p0: CredentialEntryInfo, p1: CredentialEntryInfo): Int {
        // First prefer passkey type for its security benefits
        if (p0.credentialType != p1.credentialType) {
            if (CredentialType.PASSKEY == p0.credentialType) {
        if (p0.rawCredentialType != p1.rawCredentialType) {
            val p0Priority = typePriorityMap.getOrDefault(
                    p0.rawCredentialType, PriorityHints.PRIORITY_DEFAULT
            )
            val p1Priority = typePriorityMap.getOrDefault(
                    p1.rawCredentialType, PriorityHints.PRIORITY_DEFAULT
            )
            if (p0Priority < p1Priority) {
                return -1
            } else if (CredentialType.PASSKEY == p1.credentialType) {
            } else if (p1Priority < p0Priority) {
                return 1
            }
        }
Loading