Merge "[CredManUi] App can specify preferred top level branding for sign-in flow" into udc-dev
This commit is contained in:
@@ -46,6 +46,7 @@ import com.android.credentialmanager.getflow.AuthenticationEntryInfo
|
||||
import com.android.credentialmanager.getflow.CredentialEntryInfo
|
||||
import com.android.credentialmanager.getflow.ProviderInfo
|
||||
import com.android.credentialmanager.getflow.RemoteEntryInfo
|
||||
import com.android.credentialmanager.getflow.TopBrandingContent
|
||||
import androidx.credentials.CreateCredentialRequest
|
||||
import androidx.credentials.CreateCustomCredentialRequest
|
||||
import androidx.credentials.CreatePasswordRequest
|
||||
@@ -207,6 +208,23 @@ class GetFlowUtils {
|
||||
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(
|
||||
appName = originName
|
||||
?: getAppLabel(context.packageManager, requestInfo.appPackageName)
|
||||
@@ -216,6 +234,7 @@ class GetFlowUtils {
|
||||
// TODO(b/276777444): replace with direct library constant reference once
|
||||
// exposed.
|
||||
"androidx.credentials.BUNDLE_KEY_PREFER_IDENTITY_DOC_UI"),
|
||||
preferTopBrandingContent = preferTopBrandingContent,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.credentialmanager.getflow
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.TextUtils
|
||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
import androidx.activity.result.ActivityResult
|
||||
@@ -34,7 +35,6 @@ import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -168,26 +168,30 @@ fun PrimarySelectionCard(
|
||||
providerDisplayInfo.sortedUserNameToCredentialEntryList
|
||||
val authenticationEntryList = providerDisplayInfo.authenticationEntryList
|
||||
SheetContainerCard {
|
||||
// When only one provider (not counting the remote-only provider) exists, display that
|
||||
// provider's icon + name up top.
|
||||
if (providerInfoList.size <= 2) { // It's only possible to be the single provider case
|
||||
// if we are started with no more than 2 providers.
|
||||
val nonRemoteProviderList = providerInfoList.filter(
|
||||
{ it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() }
|
||||
)
|
||||
if (nonRemoteProviderList.size == 1) {
|
||||
val providerInfo = nonRemoteProviderList.firstOrNull() // First should always work
|
||||
// but just to be safe.
|
||||
val preferTopBrandingContent = requestDisplayInfo.preferTopBrandingContent
|
||||
if (preferTopBrandingContent != null) {
|
||||
item {
|
||||
HeadlineProviderIconAndName(
|
||||
preferTopBrandingContent.icon,
|
||||
preferTopBrandingContent.displayName
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// 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) {
|
||||
item {
|
||||
HeadlineIcon(
|
||||
bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
|
||||
tint = Color.Unspecified,
|
||||
HeadlineProviderIconAndName(
|
||||
providerInfo.icon,
|
||||
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)
|
||||
}
|
||||
|
||||
// TODO: create separate rows for primary and secondary pages.
|
||||
// TODO: reuse rows and columns across types.
|
||||
@Composable
|
||||
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
|
||||
fun ActionChips(
|
||||
|
||||
@@ -173,6 +173,13 @@ data class RequestDisplayInfo(
|
||||
val appName: String,
|
||||
val preferImmediatelyAvailableCredentials: 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,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user