Merge "[CredManUi] App can specify preferred top level branding for sign-in flow" into udc-dev

This commit is contained in:
Helen Qin
2023-04-13 20:55:26 +00:00
committed by Android (Google) Code Review
3 changed files with 60 additions and 19 deletions

View File

@@ -46,6 +46,7 @@ import com.android.credentialmanager.getflow.AuthenticationEntryInfo
import com.android.credentialmanager.getflow.CredentialEntryInfo import com.android.credentialmanager.getflow.CredentialEntryInfo
import com.android.credentialmanager.getflow.ProviderInfo import com.android.credentialmanager.getflow.ProviderInfo
import com.android.credentialmanager.getflow.RemoteEntryInfo import com.android.credentialmanager.getflow.RemoteEntryInfo
import com.android.credentialmanager.getflow.TopBrandingContent
import androidx.credentials.CreateCredentialRequest import androidx.credentials.CreateCredentialRequest
import androidx.credentials.CreateCustomCredentialRequest import androidx.credentials.CreateCustomCredentialRequest
import androidx.credentials.CreatePasswordRequest import androidx.credentials.CreatePasswordRequest
@@ -207,6 +208,23 @@ class GetFlowUtils {
false false
} }
} }
val preferUiBrandingComponentName =
getCredentialRequest.data.getParcelable(
"androidx.credentials.BUNDLE_KEY_PREFER_UI_BRANDING_COMPONENT_NAME",
ComponentName::class.java
)
val preferTopBrandingContent: TopBrandingContent? =
if (preferUiBrandingComponentName == null) null
else {
val (displayName, icon) = getServiceLabelAndIcon(
context.packageManager, preferUiBrandingComponentName.flattenToString())
?: Pair(null, null)
if (displayName != null && icon != null) {
TopBrandingContent(icon, displayName)
} else {
null
}
}
return com.android.credentialmanager.getflow.RequestDisplayInfo( return com.android.credentialmanager.getflow.RequestDisplayInfo(
appName = originName appName = originName
?: getAppLabel(context.packageManager, requestInfo.appPackageName) ?: getAppLabel(context.packageManager, requestInfo.appPackageName)
@@ -216,6 +234,7 @@ class GetFlowUtils {
// TODO(b/276777444): replace with direct library constant reference once // TODO(b/276777444): replace with direct library constant reference once
// exposed. // exposed.
"androidx.credentials.BUNDLE_KEY_PREFER_IDENTITY_DOC_UI"), "androidx.credentials.BUNDLE_KEY_PREFER_IDENTITY_DOC_UI"),
preferTopBrandingContent = preferTopBrandingContent,
) )
} }

View File

@@ -16,6 +16,7 @@
package com.android.credentialmanager.getflow package com.android.credentialmanager.getflow
import android.graphics.drawable.Drawable
import android.text.TextUtils import android.text.TextUtils
import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
@@ -34,7 +35,6 @@ import androidx.compose.material3.Divider
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -168,26 +168,30 @@ fun PrimarySelectionCard(
providerDisplayInfo.sortedUserNameToCredentialEntryList providerDisplayInfo.sortedUserNameToCredentialEntryList
val authenticationEntryList = providerDisplayInfo.authenticationEntryList val authenticationEntryList = providerDisplayInfo.authenticationEntryList
SheetContainerCard { SheetContainerCard {
// When only one provider (not counting the remote-only provider) exists, display that val preferTopBrandingContent = requestDisplayInfo.preferTopBrandingContent
// provider's icon + name up top. if (preferTopBrandingContent != null) {
if (providerInfoList.size <= 2) { // It's only possible to be the single provider case item {
// if we are started with no more than 2 providers. HeadlineProviderIconAndName(
val nonRemoteProviderList = providerInfoList.filter( preferTopBrandingContent.icon,
{ it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() } preferTopBrandingContent.displayName
) )
if (nonRemoteProviderList.size == 1) { }
val providerInfo = nonRemoteProviderList.firstOrNull() // First should always work } else {
// but just to be safe. // When only one provider (not counting the remote-only provider) exists, display that
// provider's icon + name up top.
val providersWithActualEntries = providerInfoList.filter {
it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty()
}
if (providersWithActualEntries.size == 1) {
// First should always work but just to be safe.
val providerInfo = providersWithActualEntries.firstOrNull()
if (providerInfo != null) { if (providerInfo != null) {
item { item {
HeadlineIcon( HeadlineProviderIconAndName(
bitmap = providerInfo.icon.toBitmap().asImageBitmap(), providerInfo.icon,
tint = Color.Unspecified, providerInfo.displayName
) )
} }
item { Divider(thickness = 4.dp, color = Color.Transparent) }
item { LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName) }
item { Divider(thickness = 16.dp, color = Color.Transparent) }
} }
} }
} }
@@ -369,8 +373,19 @@ fun AllSignInOptionCard(
onLog(GetCredentialEvent.CREDMAN_GET_CRED_ALL_SIGN_IN_OPTION_CARD) onLog(GetCredentialEvent.CREDMAN_GET_CRED_ALL_SIGN_IN_OPTION_CARD)
} }
// TODO: create separate rows for primary and secondary pages. @Composable
// TODO: reuse rows and columns across types. fun HeadlineProviderIconAndName(
icon: Drawable,
name: String,
) {
HeadlineIcon(
bitmap = icon.toBitmap().asImageBitmap(),
tint = Color.Unspecified,
)
Divider(thickness = 4.dp, color = Color.Transparent)
LargeLabelTextOnSurfaceVariant(text = name)
Divider(thickness = 16.dp, color = Color.Transparent)
}
@Composable @Composable
fun ActionChips( fun ActionChips(

View File

@@ -173,6 +173,13 @@ data class RequestDisplayInfo(
val appName: String, val appName: String,
val preferImmediatelyAvailableCredentials: Boolean, val preferImmediatelyAvailableCredentials: Boolean,
val preferIdentityDocUi: Boolean, val preferIdentityDocUi: Boolean,
// A top level branding icon + display name preferred by the app.
val preferTopBrandingContent: TopBrandingContent?,
)
data class TopBrandingContent(
val icon: Drawable,
val displayName: String,
) )
/** /**