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

Commit 636fea07 authored by Helen Qin's avatar Helen Qin
Browse files

[CredManUi] App can specify preferred top level branding for sign-in flow

Bug: 277129959
Test: manual (see bug for recording)
Change-Id: I95e6bb832d1e6b24addc660fb4a315515dabcfce
parent 7250ff26
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -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,
            )
        }

+34 −19
Original line number Diff line number Diff line
@@ -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 {
        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.
        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 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(
+7 −0
Original line number Diff line number Diff line
@@ -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,
)

/**