diff --git a/crypto-onramp/src/main/java/com/stripe/android/crypto/onramp/OnrampInteractor.kt b/crypto-onramp/src/main/java/com/stripe/android/crypto/onramp/OnrampInteractor.kt index c04de7429a0..eff678830c5 100644 --- a/crypto-onramp/src/main/java/com/stripe/android/crypto/onramp/OnrampInteractor.kt +++ b/crypto-onramp/src/main/java/com/stripe/android/crypto/onramp/OnrampInteractor.kt @@ -1231,5 +1231,8 @@ internal fun LinkController.PaymentMethodType.toDisplayType(): PaymentMethodDisp LinkController.PaymentMethodType.BankAccount -> PaymentMethodDisplayData.Type.BankAccount + + LinkController.PaymentMethodType.Generic -> + PaymentMethodDisplayData.Type.Card } } diff --git a/payments-core/src/main/java/com/stripe/android/model/LinkPaymentDetails.kt b/payments-core/src/main/java/com/stripe/android/model/LinkPaymentDetails.kt index f988a7498d9..11230609b8f 100644 --- a/payments-core/src/main/java/com/stripe/android/model/LinkPaymentDetails.kt +++ b/payments-core/src/main/java/com/stripe/android/model/LinkPaymentDetails.kt @@ -26,4 +26,14 @@ sealed interface LinkPaymentDetails : Parcelable { val bankName: String?, override val last4: String, ) : LinkPaymentDetails + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + @Parcelize + data class Generic( + val nickname: String?, + val label: String, + val sublabel: String?, + val icon: ConsumerPaymentDetails.Display.Icon?, + override val last4: String + ) : LinkPaymentDetails } diff --git a/payments-core/src/test/java/com/stripe/android/model/ConsumerFixtures.kt b/payments-core/src/test/java/com/stripe/android/model/ConsumerFixtures.kt index 7c79474cd55..4d561881bf4 100644 --- a/payments-core/src/test/java/com/stripe/android/model/ConsumerFixtures.kt +++ b/payments-core/src/test/java/com/stripe/android/model/ConsumerFixtures.kt @@ -264,6 +264,63 @@ object ConsumerFixtures { """.trimIndent() ) + val CONSUMER_SINGLE_GENERIC_PAYMENT_DETAILS_JSON = JSONObject( + """ + { + "redacted_payment_details": [ + { + "id": "csmrpd_126", + "is_default": false, + "type": "CRYPTO", + "display": { + "type": "0x••••22Dd", + "label": "Crypto", + "sublabel": "0x••••22Dd", + "last4": "0x••••22Dd", + "icon": { + "default": "https://example.com/crypto-icon.png" + } + }, + "next_action_types": ["redirect_to_url"] + } + ] + } + """.trimIndent() + ) + + val CONSUMER_GENERIC_PAYMENT_DETAILS_NO_SUBLABEL_ICON_JSON = JSONObject( + """ + { + "redacted_payment_details": [ + { + "id": "csmrpd_126", + "is_default": false, + "type": "CRYPTO", + "display": { + "type": "0x••••22Dd", + "label": "Crypto" + }, + "next_action_types": [] + } + ] + } + """.trimIndent() + ) + + val CONSUMER_GENERIC_PAYMENT_DETAILS_NO_DISPLAY_JSON = JSONObject( + """ + { + "redacted_payment_details": [ + { + "id": "csmrpd_126", + "is_default": false, + "type": "CRYPTO" + } + ] + } + """.trimIndent() + ) + val PAYMENT_DETAILS_SHARE_JSON = JSONObject( """ { diff --git a/payments-core/src/test/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParserTest.kt b/payments-core/src/test/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParserTest.kt index 68b5a6ec13c..eaabb86b288 100644 --- a/payments-core/src/test/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParserTest.kt +++ b/payments-core/src/test/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParserTest.kt @@ -223,7 +223,72 @@ class ConsumerPaymentDetailsJsonParserTest { } @Test - fun `parse card with unrecognized funding defaults to Unknown`() { + fun `parse generic payment type`() { + assertEquals( + ConsumerPaymentDetails( + listOf( + ConsumerPaymentDetails.Generic( + id = "csmrpd_126", + last4 = "0x••••22Dd", + isDefault = false, + nickname = null, + billingAddress = null, + billingEmailAddress = null, + rawType = "CRYPTO", + display = ConsumerPaymentDetails.Display( + label = "Crypto", + sublabel = "0x••••22Dd", + icon = ConsumerPaymentDetails.Display.Icon( + defaultUrl = "https://example.com/crypto-icon.png" + ) + ), + nextActionTypes = listOf("redirect_to_url") + ) + ) + ), + ConsumerPaymentDetailsJsonParser + .parse(ConsumerFixtures.CONSUMER_SINGLE_GENERIC_PAYMENT_DETAILS_JSON), + ) + } + + @Test + fun `parse generic payment type without sublabel or icon`() { + assertEquals( + ConsumerPaymentDetails( + listOf( + ConsumerPaymentDetails.Generic( + id = "csmrpd_126", + last4 = "", + isDefault = false, + nickname = null, + billingAddress = null, + billingEmailAddress = null, + rawType = "CRYPTO", + display = ConsumerPaymentDetails.Display( + label = "Crypto", + sublabel = null, + icon = null + ), + nextActionTypes = emptyList() + ) + ) + ), + ConsumerPaymentDetailsJsonParser + .parse(ConsumerFixtures.CONSUMER_GENERIC_PAYMENT_DETAILS_NO_SUBLABEL_ICON_JSON), + ) + } + + @Test + fun `parse generic payment type without display is dropped`() { + assertEquals( + ConsumerPaymentDetails(emptyList()), + ConsumerPaymentDetailsJsonParser + .parse(ConsumerFixtures.CONSUMER_GENERIC_PAYMENT_DETAILS_NO_DISPLAY_JSON), + ) + } + + @Test + fun `parse card with unrecognized funding defaults to Generic`() { val json = createCardJsonWithFunding("INVALID") val expected = createExpectedCardWithFunding(ConsumerPaymentDetails.Card.Funding.Unknown) assertEquals(expected, ConsumerPaymentDetailsJsonParser.parse(json)) diff --git a/payments-model/src/main/java/com/stripe/android/model/ConsumerPaymentDetails.kt b/payments-model/src/main/java/com/stripe/android/model/ConsumerPaymentDetails.kt index 68160a7fac3..c03ea033bbb 100644 --- a/payments-model/src/main/java/com/stripe/android/model/ConsumerPaymentDetails.kt +++ b/payments-model/src/main/java/com/stripe/android/model/ConsumerPaymentDetails.kt @@ -21,6 +21,7 @@ data class ConsumerPaymentDetails( open val nickname: String?, open val billingAddress: BillingAddress?, open val billingEmailAddress: String?, + open val display: Display? = null ) : Parcelable { abstract val last4: String @@ -60,7 +61,7 @@ data class ConsumerPaymentDetails( @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) companion object { fun fromCode(code: String?): Funding { - return Funding.entries.firstOrNull { it.code == code } + return entries.firstOrNull { it.code == code } ?: Unknown } } @@ -132,6 +133,27 @@ data class ConsumerPaymentDetails( } } + @Parcelize + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + data class Generic( + override val id: String, + override val last4: String, + override val isDefault: Boolean, + override val nickname: String?, + override val billingAddress: BillingAddress?, + override val billingEmailAddress: String?, + val rawType: String, + override val display: Display, + val nextActionTypes: List, + ) : PaymentDetails( + id = id, + type = rawType, + isDefault = isDefault, + nickname = nickname, + billingAddress = billingAddress, + billingEmailAddress = billingEmailAddress + ) + @Parcelize @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class BillingAddress( @@ -143,4 +165,16 @@ data class ConsumerPaymentDetails( val postalCode: String?, val countryCode: CountryCode?, ) : Parcelable + + @Parcelize + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + data class Display( + val label: String, + val sublabel: String?, + val icon: Icon? + ) : Parcelable { + @Parcelize + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) + data class Icon(val defaultUrl: String) : Parcelable + } } diff --git a/payments-model/src/main/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParser.kt b/payments-model/src/main/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParser.kt index 2c47d78e431..2cf50e1e386 100644 --- a/payments-model/src/main/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParser.kt +++ b/payments-model/src/main/java/com/stripe/android/model/parsers/ConsumerPaymentDetailsJsonParser.kt @@ -17,6 +17,7 @@ private const val FIELD_CARD_DETAILS = "card_details" private const val FIELD_CARD_LAST_4 = "last4" private const val FIELD_BANK_ACCOUNT_DETAILS = "bank_account_details" private const val FIELD_BANK_ACCOUNT_LAST_4 = "last4" +private const val FIELD_UNKNOWN_LAST_4 = "last4" private const val FIELD_BANK_ACCOUNT_BANK_ACCOUNT_NAME = "bank_account_name" private const val FIELD_BILLING_ADDRESS = "billing_address" @@ -41,6 +42,12 @@ private const val FIELD_BANK_ACCOUNT_BANK_ICON_CODE = "bank_icon_code" private const val FIELD_IS_DEFAULT = "is_default" private const val FIELD_NICKNAME = "nickname" private const val FIELD_FUNDING = "funding" +private const val FIELD_DISPLAY = "display" +private const val FIELD_LABEL = "label" +private const val FIELD_SUBLABEL = "sublabel" +private const val FIELD_ICON = "icon" +private const val FIELD_DEFAULT_ICON = "default" +private const val FIELD_NEXT_ACTION_TYPES = "next_action_types" @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) object ConsumerPaymentDetailsJsonParser : ModelJsonParser { @@ -63,7 +70,6 @@ object ConsumerPaymentDetailsJsonParser : ModelJsonParser { val cardDetails = json.getJSONObject(FIELD_CARD_DETAILS) @@ -100,10 +106,32 @@ object ConsumerPaymentDetailsJsonParser : ModelJsonParser null + else -> { + val display = json.optJSONObject(FIELD_DISPLAY) + display?.let { + ConsumerPaymentDetails.Generic( + id = id, + last4 = display.optString(FIELD_UNKNOWN_LAST_4), + isDefault = isDefault, + nickname = nickname, + billingAddress = parseBillingAddress(json), + billingEmailAddress = optString(json, FIELD_BILLING_EMAIL_ADDRESS), + rawType = type, + display = parseDisplay(display), + nextActionTypes = jsonArrayToList(json.getJSONArray(FIELD_NEXT_ACTION_TYPES)) + ) + } + } } } + private fun parseDisplay(display: JSONObject) = ConsumerPaymentDetails.Display( + label = display.getString(FIELD_LABEL), + sublabel = display.optString(FIELD_SUBLABEL).takeIf { it.isNotBlank() }, + icon = display.optJSONObject(FIELD_ICON) + ?.let { ConsumerPaymentDetails.Display.Icon(defaultUrl = it.getString(FIELD_DEFAULT_ICON)) } + ) + private fun parseBillingAddress(json: JSONObject) = json.optJSONObject(FIELD_BILLING_ADDRESS)?.let { address -> ConsumerPaymentDetails.BillingAddress( diff --git a/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt b/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt index 75fc8951d2b..f2c42d01c43 100644 --- a/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt +++ b/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt @@ -133,7 +133,7 @@ interface ConsumersApiService { suspend fun sharePaymentDetails( consumerSessionClientSecret: String, paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, requestSurface: String, requestOptions: ApiRequest.Options, @@ -481,7 +481,7 @@ class ConsumersApiServiceImpl( override suspend fun sharePaymentDetails( consumerSessionClientSecret: String, paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, requestSurface: String, requestOptions: ApiRequest.Options, diff --git a/paymentsheet/api/paymentsheet.api b/paymentsheet/api/paymentsheet.api index 02b6d7d699d..94d893cc935 100644 --- a/paymentsheet/api/paymentsheet.api +++ b/paymentsheet/api/paymentsheet.api @@ -362,13 +362,24 @@ public final class com/stripe/android/link/ui/verification/VerificationScreenKt public static final fun VerificationPreview (Landroidx/compose/runtime/Composer;I)V } +public final class com/stripe/android/link/ui/wallet/ComposableSingletons$IconKt { + public static final field INSTANCE Lcom/stripe/android/link/ui/wallet/ComposableSingletons$IconKt; + public fun ()V + public final fun getLambda$-2139801056$paymentsheet_release ()Lkotlin/jvm/functions/Function3; +} + public final class com/stripe/android/link/ui/wallet/ComposableSingletons$PaymentDetailsKt { public static final field INSTANCE Lcom/stripe/android/link/ui/wallet/ComposableSingletons$PaymentDetailsKt; public fun ()V + public final fun getLambda$-1132714699$paymentsheet_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$1381508991$paymentsheet_release ()Lkotlin/jvm/functions/Function3; public final fun getLambda$629401301$paymentsheet_release ()Lkotlin/jvm/functions/Function2; } +public final class com/stripe/android/link/ui/wallet/IconKt { + public static final fun Icon (Ljava/lang/String;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V +} + public abstract interface annotation class com/stripe/android/paymentelement/AddressAutocompletePreview : java/lang/annotation/Annotation { } diff --git a/paymentsheet/res/values/strings.xml b/paymentsheet/res/values/strings.xml index 7cd7436fe2e..dc3d59a0335 100644 --- a/paymentsheet/res/values/strings.xml +++ b/paymentsheet/res/values/strings.xml @@ -177,6 +177,8 @@ to be saved and used in future checkout sessions. --> Manage cards Manage bank account + + Manage payment method Manage payment methods @@ -249,6 +251,8 @@ to be saved and used in future checkout sessions. --> Default payment method was not changed. Please try again. Total: %s + + Payment method details cannot be changed. Card brand was not updated. Please try again. diff --git a/paymentsheet/src/main/java/com/stripe/android/common/validation/PaymentMethodUtils.kt b/paymentsheet/src/main/java/com/stripe/android/common/validation/PaymentMethodUtils.kt index 3172425cedc..547c42b7cfe 100644 --- a/paymentsheet/src/main/java/com/stripe/android/common/validation/PaymentMethodUtils.kt +++ b/paymentsheet/src/main/java/com/stripe/android/common/validation/PaymentMethodUtils.kt @@ -35,6 +35,9 @@ internal fun ConsumerPaymentDetails.PaymentDetails.isSupportedWithBillingConfig( allowedCountries.contains(it.value.uppercase()) } ?: false is ConsumerPaymentDetails.BankAccount -> allowedCountries.contains(CountryCode.US.value) + is ConsumerPaymentDetails.Generic -> billingAddress?.countryCode?.let { + allowedCountries.contains(it.value.uppercase()) + } ?: false is ConsumerPaymentDetails.Passthrough -> false } } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/LinkController.kt b/paymentsheet/src/main/java/com/stripe/android/link/LinkController.kt index c4f07add3c8..c4d665dc63a 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/LinkController.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/LinkController.kt @@ -757,7 +757,8 @@ class LinkController @Inject internal constructor( @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) enum class PaymentMethodType { Card, - BankAccount + BankAccount, + Generic } /** diff --git a/paymentsheet/src/main/java/com/stripe/android/link/LinkControllerInteractor.kt b/paymentsheet/src/main/java/com/stripe/android/link/LinkControllerInteractor.kt index acc91ca8e9f..eb96e9bc37b 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/LinkControllerInteractor.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/LinkControllerInteractor.kt @@ -234,6 +234,9 @@ internal class LinkControllerInteractor @Inject constructor( LinkController.PaymentMethodType.Card -> { config.billingDetailsCollectionConfiguration.name } + LinkController.PaymentMethodType.Generic -> { + PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Automatic + } } val billingDetailsCollectionConfiguration = config.billingDetailsCollectionConfiguration @@ -734,6 +737,9 @@ internal fun ConsumerPaymentDetails.PaymentDetails.toPreview( is ConsumerPaymentDetails.BankAccount -> { LinkController.PaymentMethodType.BankAccount } + is ConsumerPaymentDetails.Generic -> { + LinkController.PaymentMethodType.Generic + } } return LinkController.PaymentMethodPreview( @@ -763,6 +769,8 @@ internal fun ConsumerPaymentDetails.PaymentDetails.getIconDrawableRes(isDarkThem getIconDrawableRes(PaymentMethodPreviewDetails.Card(brand, funding.code, last4), isDarkTheme) is ConsumerPaymentDetails.Passthrough -> getLinkIconArrow() + is ConsumerPaymentDetails.Generic -> + getLinkIconArrow() } } @@ -798,4 +806,5 @@ private fun LinkController.PaymentMethodType.toFilter(): LinkPaymentMethodFilter when (this) { LinkController.PaymentMethodType.Card -> LinkPaymentMethodFilter.Card LinkController.PaymentMethodType.BankAccount -> LinkPaymentMethodFilter.BankAccount + LinkController.PaymentMethodType.Generic -> LinkPaymentMethodFilter.Generic } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethod.kt b/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethod.kt index 9a003b1e377..cc2200790df 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethod.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethod.kt @@ -21,6 +21,7 @@ internal sealed class LinkPaymentMethod( !currentDetails.isExpired && cvcReady } is ConsumerPaymentDetailsModel.Passthrough -> true + is ConsumerPaymentDetailsModel.Generic -> true } /** diff --git a/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethodFilter.kt b/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethodFilter.kt index 27b0d162c3e..392c3a4e1e3 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethodFilter.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/LinkPaymentMethodFilter.kt @@ -4,12 +4,14 @@ import com.stripe.android.model.ConsumerPaymentDetails internal enum class LinkPaymentMethodFilter { Card, - BankAccount; + BankAccount, + Generic; operator fun invoke(details: ConsumerPaymentDetails.PaymentDetails): Boolean { return when (details) { is ConsumerPaymentDetails.BankAccount -> this == BankAccount is ConsumerPaymentDetails.Card -> this == Card + is ConsumerPaymentDetails.Generic -> this == Generic else -> false } } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/account/DefaultLinkAccountManager.kt b/paymentsheet/src/main/java/com/stripe/android/link/account/DefaultLinkAccountManager.kt index b1cad13fe35..d06105c838f 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/account/DefaultLinkAccountManager.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/account/DefaultLinkAccountManager.kt @@ -290,7 +290,7 @@ internal class DefaultLinkAccountManager @Inject constructor( override suspend fun sharePaymentDetails( paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, cvc: String?, allowRedisplay: String?, diff --git a/paymentsheet/src/main/java/com/stripe/android/link/account/LinkAccountManager.kt b/paymentsheet/src/main/java/com/stripe/android/link/account/LinkAccountManager.kt index 6b48165a7fe..10951999088 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/account/LinkAccountManager.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/account/LinkAccountManager.kt @@ -131,7 +131,7 @@ internal interface LinkAccountManager { suspend fun sharePaymentDetails( paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, cvc: String?, allowRedisplay: String? = null, diff --git a/paymentsheet/src/main/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandler.kt b/paymentsheet/src/main/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandler.kt index f6cb116c7d0..fad58af83e9 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandler.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandler.kt @@ -185,9 +185,9 @@ internal class DefaultLinkConfirmationHandler @Inject constructor( ) } - private fun allowRedisplay(paymentMethodType: String): PaymentMethod.AllowRedisplay? { + private fun allowRedisplay(paymentMethodType: String?): PaymentMethod.AllowRedisplay? { val isSettingUp = when (val intent = configuration.stripeIntent) { - is PaymentIntent -> intent.isSetupFutureUsageSet(paymentMethodType) + is PaymentIntent -> paymentMethodType != null && intent.isSetupFutureUsageSet(paymentMethodType) is SetupIntent -> true } @@ -273,11 +273,12 @@ internal fun createPaymentMethodCreateParams( internal fun computeExpectedPaymentMethodType( configuration: LinkConfiguration, paymentDetails: ConsumerPaymentDetails.PaymentDetails -): String { +): String? { return when (paymentDetails) { is ConsumerPaymentDetails.BankAccount -> computeBankAccountExpectedPaymentMethodType(configuration) - is ConsumerPaymentDetails.Card -> ConsumerPaymentDetails.Card.TYPE + is ConsumerPaymentDetails.Card, is ConsumerPaymentDetails.Passthrough -> ConsumerPaymentDetails.Card.TYPE + is ConsumerPaymentDetails.Generic -> null } } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkApiRepository.kt b/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkApiRepository.kt index 636e00e62e3..30ca1391d7f 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkApiRepository.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkApiRepository.kt @@ -346,7 +346,7 @@ internal class LinkApiRepository @Inject constructor( override suspend fun sharePaymentDetails( consumerSessionClientSecret: String, paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, cvc: String?, allowRedisplay: String?, diff --git a/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkRepository.kt b/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkRepository.kt index 418768b092e..b835b3dbd85 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkRepository.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/repositories/LinkRepository.kt @@ -140,7 +140,7 @@ internal interface LinkRepository { suspend fun sharePaymentDetails( consumerSessionClientSecret: String, paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, cvc: String?, allowRedisplay: String?, diff --git a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/Icon.kt b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/Icon.kt new file mode 100644 index 00000000000..72390c04f30 --- /dev/null +++ b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/Icon.kt @@ -0,0 +1,30 @@ +package com.stripe.android.link.ui.wallet + +import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.BoxWithConstraintsScope +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import com.stripe.android.uicore.image.LocalStripeImageLoader +import com.stripe.android.uicore.image.StripeImage + +@Composable +fun Icon( + iconUrl: String?, + modifier: Modifier = Modifier, + errorContent: @Composable BoxWithConstraintsScope.() -> Unit = {}, +) { + BoxWithConstraints(modifier = modifier) { + iconUrl?.let { + StripeImage( + url = iconUrl, + imageLoader = LocalStripeImageLoader.current, + contentDescription = null, + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Fit, + errorContent = errorContent + ) + } ?: errorContent() + } +} diff --git a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetails.kt b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetails.kt index 8a62792fce4..d126bf9de76 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetails.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetails.kt @@ -50,6 +50,8 @@ import com.stripe.android.model.CardBrand import com.stripe.android.model.ConsumerPaymentDetails import com.stripe.android.model.ConsumerPaymentDetails.BankAccount import com.stripe.android.model.ConsumerPaymentDetails.Card +import com.stripe.android.model.ConsumerPaymentDetails.Display +import com.stripe.android.model.ConsumerPaymentDetails.Generic import com.stripe.android.model.CvcCheck import com.stripe.android.paymentsheet.R import com.stripe.android.paymentsheet.ui.getCardBrandIconForVerticalMode @@ -204,6 +206,21 @@ private fun PaymentDetailsListItemPreview() { billingAddress = null, billingEmailAddress = null ) + val generic = Generic( + id = "unknown_id", + last4 = "4444", + isDefault = false, + nickname = null, + billingAddress = null, + billingEmailAddress = null, + rawType = "CRYPTO", + display = Display( + label = "Crypto", + sublabel = "0x••••22Dd", + icon = null + ), + nextActionTypes = emptyList() + ) DefaultLinkTheme { Column { PaymentDetailsListItem( @@ -246,6 +263,16 @@ private fun PaymentDetailsListItemPreview() { onClick = {}, onMenuButtonClick = {} ) + PaymentDetailsListItem( + paymentDetails = generic, + isClickable = true, + isMenuButtonClickable = true, + isSelected = true, + isAvailable = true, + isUpdating = false, + onClick = {}, + onMenuButtonClick = {} + ) } } } @@ -334,6 +361,14 @@ internal fun RowScope.PaymentDetails( icon = CardBrand.Unknown.getCardBrandIconForVerticalMode(), ) } + is Generic -> { + PaymentMethodInfo( + modifier = modifier, + title = paymentDetails.displayName.resolve(), + subtitle = paymentDetails.display.sublabel, + icon = { Icon(iconUrl = paymentDetails.display.icon?.defaultUrl, errorContent = { BankIcon(null) }) } + ) + } } } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetailsNickname.kt b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetailsNickname.kt index 5696df9e4cd..72d814a4f25 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetailsNickname.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/PaymentDetailsNickname.kt @@ -8,6 +8,7 @@ import com.stripe.android.model.ConsumerPaymentDetails import com.stripe.android.model.LinkPaymentDetails import com.stripe.android.model.LinkPaymentDetails.BankAccount import com.stripe.android.model.LinkPaymentDetails.Card +import com.stripe.android.model.LinkPaymentDetails.Generic import com.stripe.android.paymentsheet.R import com.stripe.android.ui.core.R as StripeUiCoreR @@ -21,12 +22,14 @@ internal val LinkPaymentDetails.label: ResolvableString get() = when (this) { is Card -> makeCardDisplayName(nickname, funding, brand) is BankAccount -> bankName?.resolvableString ?: "••••$last4".resolvableString + is Generic -> label.resolvableString } internal val LinkPaymentDetails.sublabel: ResolvableString? get() = when (this) { is Card -> "•••• $last4".resolvableString is BankAccount -> if (bankName != null) "••••$last4".resolvableString else null + is Generic -> sublabel?.resolvableString } internal val ConsumerPaymentDetails.PaymentDetails.displayName: ResolvableString @@ -36,6 +39,7 @@ internal val ConsumerPaymentDetails.PaymentDetails.displayName: ResolvableString is ConsumerPaymentDetails.Passthrough -> { "•••• $last4".resolvableString } + is ConsumerPaymentDetails.Generic -> display.label.resolvableString } internal val ConsumerPaymentDetails.PaymentDetails.paymentOptionLabel: ResolvableString @@ -50,6 +54,9 @@ internal val ConsumerPaymentDetails.PaymentDetails.paymentOptionLabel: Resolvabl is ConsumerPaymentDetails.Passthrough -> { listOf("•••• $last4".resolvableString) } + is ConsumerPaymentDetails.Generic -> { + listOfNotNull(display.label.resolvableString, display.sublabel?.resolvableString) + } } return components.joinToString(separator = " ") } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenu.kt b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenu.kt index 74d33900d67..425146b1ac9 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenu.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenu.kt @@ -18,7 +18,7 @@ internal fun WalletPaymentMethodMenu( ) { val items = remember(paymentDetails) { buildList { - if (!paymentDetails.isDefault) { + if (paymentDetails.canBeSetAsDefault) { add(WalletPaymentMethodMenuItem.SetAsDefault) } @@ -52,4 +52,13 @@ private val ConsumerPaymentDetails.PaymentDetails.removeLabel is ConsumerPaymentDetails.Card, is ConsumerPaymentDetails.Passthrough -> R.string.stripe_paymentsheet_remove_card is ConsumerPaymentDetails.BankAccount -> R.string.stripe_wallet_remove_linked_account + is ConsumerPaymentDetails.Generic -> R.string.stripe_paymentsheet_remove_pm_title + } + +private val ConsumerPaymentDetails.PaymentDetails.canBeSetAsDefault + get() = when (this) { + is ConsumerPaymentDetails.BankAccount, + is ConsumerPaymentDetails.Card, + is ConsumerPaymentDetails.Passthrough -> !isDefault + is ConsumerPaymentDetails.Generic -> false } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletUiState.kt b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletUiState.kt index e1bc6ac84e3..1f74a7db18c 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletUiState.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletUiState.kt @@ -117,11 +117,12 @@ internal data class WalletUiState( private fun cardFundingAccepted(item: ConsumerPaymentDetails.PaymentDetails): Boolean { return when (item) { - is ConsumerPaymentDetails.BankAccount -> true + is ConsumerPaymentDetails.BankAccount, + is ConsumerPaymentDetails.Passthrough, + is ConsumerPaymentDetails.Generic -> true is ConsumerPaymentDetails.Card -> { cardFundingFilter.isAccepted(item.funding.cardFunding) } - is ConsumerPaymentDetails.Passthrough -> true } } @@ -175,5 +176,6 @@ private fun ConsumerPaymentDetails.PaymentDetails.makeMandateText( ) else -> null } + is ConsumerPaymentDetails.Generic -> null } } diff --git a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletViewModel.kt index 7de345d09a9..3fb569e24e5 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/ui/wallet/WalletViewModel.kt @@ -52,7 +52,6 @@ import com.stripe.android.uicore.utils.mapAsStateFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.update @@ -435,6 +434,7 @@ internal class WalletViewModel( details.copy(isDefault = item.id == details.id) } is ConsumerPaymentDetails.Passthrough -> details + is ConsumerPaymentDetails.Generic -> details } }, cardBeingUpdated = null diff --git a/paymentsheet/src/main/java/com/stripe/android/link/utils/LinkBillingDetailsUtils.kt b/paymentsheet/src/main/java/com/stripe/android/link/utils/LinkBillingDetailsUtils.kt index 26393851624..f8311cf7df4 100644 --- a/paymentsheet/src/main/java/com/stripe/android/link/utils/LinkBillingDetailsUtils.kt +++ b/paymentsheet/src/main/java/com/stripe/android/link/utils/LinkBillingDetailsUtils.kt @@ -40,7 +40,8 @@ internal fun PaymentDetails.supports( linkAccount: LinkAccount ): Boolean = when (this) { is ConsumerPaymentDetails.BankAccount, - is ConsumerPaymentDetails.Card -> when { + is ConsumerPaymentDetails.Card, + is ConsumerPaymentDetails.Generic -> when { // Check if full address is required but missing or incomplete billingDetailsConfig.address == AddressCollectionMode.Full && billingAddress.isIncomplete() -> false // Check if phone is required but missing from Link account @@ -95,6 +96,10 @@ internal fun PaymentDetails.withEffectiveBillingDetails( billingEmailAddress = effectiveEmailAddress ) is ConsumerPaymentDetails.Passthrough -> this + is ConsumerPaymentDetails.Generic -> copy( + billingAddress = effectiveBillingAddress, + billingEmailAddress = effectiveEmailAddress + ) } } diff --git a/paymentsheet/src/main/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParser.kt b/paymentsheet/src/main/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParser.kt index 9f4ff8859c4..38f65a7e182 100644 --- a/paymentsheet/src/main/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParser.kt +++ b/paymentsheet/src/main/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParser.kt @@ -1,7 +1,6 @@ package com.stripe.android.model.parsers import com.stripe.android.core.model.StripeJsonUtils.optBoolean -import com.stripe.android.core.model.StripeJsonUtils.optString import com.stripe.android.core.model.parsers.ModelJsonParser import com.stripe.android.model.ConsumerPaymentDetails import com.stripe.android.model.LinkPaymentDetails @@ -10,16 +9,11 @@ import org.json.JSONObject internal object PaymentMethodWithLinkDetailsJsonParser : ModelJsonParser { - override fun parse(json: JSONObject): PaymentMethod? { + override fun parse(json: JSONObject): PaymentMethod { val paymentMethod = PaymentMethodJsonParser().parse(json.getJSONObject("payment_method")) val linkPaymentDetailsJson = json.optJSONObject("link_payment_details") val isLinkOrigin = optBoolean(json, "is_link_origin") - if (isUnsupportedLinkPaymentDetailsType(linkPaymentDetailsJson)) { - // This is a Link payment method, but we don't support the type yet. We can't render them, so hide them. - return null - } - val consumerPaymentDetails = linkPaymentDetailsJson?.let { ConsumerPaymentDetailsJsonParser.parsePaymentDetails(it) } @@ -41,6 +35,15 @@ internal object PaymentMethodWithLinkDetailsJsonParser : ModelJsonParser { + LinkPaymentDetails.Generic( + nickname = consumerPaymentDetails.nickname, + label = consumerPaymentDetails.display.label, + sublabel = consumerPaymentDetails.display.sublabel, + icon = consumerPaymentDetails.display.icon, + last4 = consumerPaymentDetails.last4 + ) + } is ConsumerPaymentDetails.Passthrough, null -> { null @@ -55,9 +58,4 @@ internal object PaymentMethodWithLinkDetailsJsonParser : ModelJsonParser displayName } } is SavedPaymentMethod.Unexpected -> resolvableString("") diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodsUiExtension.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodsUiExtension.kt index bbc6b3298b1..dd98db56335 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodsUiExtension.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/PaymentMethodsUiExtension.kt @@ -304,6 +304,7 @@ internal fun PaymentMethod.getLabelIcon(): Int? { when (linkPaymentDetails) { is LinkPaymentDetails.BankAccount -> bankIcon is LinkPaymentDetails.Card, null -> null + is LinkPaymentDetails.Generic -> bankIcon } } PaymentMethod.Type.USBankAccount -> bankIcon @@ -311,6 +312,7 @@ internal fun PaymentMethod.getLabelIcon(): Int? { when (linkPaymentDetails) { is LinkPaymentDetails.BankAccount -> bankIcon is LinkPaymentDetails.Card, null -> null + is LinkPaymentDetails.Generic -> bankIcon } } else -> null diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/RemovePaymentMethodDialogUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/RemovePaymentMethodDialogUI.kt index 2dd4d130347..d6a903512ea 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/RemovePaymentMethodDialogUI.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/RemovePaymentMethodDialogUI.kt @@ -49,6 +49,9 @@ private fun DisplayableSavedPaymentMethod.getRemoveDialogTitle() = when (payment is LinkPaymentDetails.Card -> { resolvableString(R.string.stripe_paymentsheet_remove_card_title) } + is LinkPaymentDetails.Generic -> { + resolvableString(R.string.stripe_paymentsheet_remove_pm, displayName) + } null -> resolvableString("") } } @@ -93,6 +96,9 @@ private fun DisplayableSavedPaymentMethod.getRemoveDialogDescription() = when (p this.brandDisplayName(), linkDetails.last4 ) + is LinkPaymentDetails.Generic -> { + displayName + } null -> resolvableString("") } } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodInteractor.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodInteractor.kt index da5a9e9e3ab..2bb51595086 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodInteractor.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodInteractor.kt @@ -82,6 +82,9 @@ internal interface UpdatePaymentMethodInteractor { is LinkPaymentDetails.Card -> { R.string.stripe_paymentsheet_manage_card } + is LinkPaymentDetails.Generic -> { + R.string.stripe_paymentsheet_manage_payment_method + } null -> null } } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodUI.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodUI.kt index b97167f270d..9e55b1147f3 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodUI.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/ui/UpdatePaymentMethodUI.kt @@ -76,6 +76,7 @@ internal fun UpdatePaymentMethodUI(interactor: UpdatePaymentMethodInteractor, mo editCardDetailsInteractor = interactor.editCardDetailsInteractor, ) } + is LinkPaymentDetails.Generic -> {} } } is SavedPaymentMethod.SepaDebit -> SepaDebitUI( @@ -377,6 +378,9 @@ private fun DisplayableSavedPaymentMethod.getDetailsCannotBeChangedText( is LinkPaymentDetails.Card -> { PaymentSheetR.string.stripe_paymentsheet_card_details_cannot_be_changed } + is LinkPaymentDetails.Generic -> { + PaymentSheetR.string.stripe_paymentsheet_unknown_details_cannot_be_changed + } } } is SavedPaymentMethod.USBankAccount -> diff --git a/paymentsheet/src/test/java/com/stripe/android/link/FakeConsumersApiService.kt b/paymentsheet/src/test/java/com/stripe/android/link/FakeConsumersApiService.kt index b8f43e10415..971eb478e37 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/FakeConsumersApiService.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/FakeConsumersApiService.kt @@ -191,7 +191,7 @@ internal open class FakeConsumersApiService : ConsumersApiService { override suspend fun sharePaymentDetails( consumerSessionClientSecret: String, paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, requestSurface: String, requestOptions: ApiRequest.Options, diff --git a/paymentsheet/src/test/java/com/stripe/android/link/LinkControllerInteractorTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/LinkControllerInteractorTest.kt index 797ebdc719a..6bf1a813342 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/LinkControllerInteractorTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/LinkControllerInteractorTest.kt @@ -537,6 +537,23 @@ class LinkControllerInteractorTest { .isEqualTo(PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always) } + @Test + fun `onPresentPaymentMethods() with Generic payment method uses automatic name collection`() = runTest { + val interactor = createInteractor() + configure(interactor) + + val launcher = FakeActivityResultLauncher() + interactor.presentPaymentMethods( + launcher = launcher, + email = null, + paymentMethodType = LinkController.PaymentMethodType.Generic + ) + + val collectionConfig = launcher.calls.awaitItem().input.configuration.billingDetailsCollectionConfiguration + assertThat(collectionConfig.name) + .isEqualTo(PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Automatic) + } + @Test fun `onLinkActivityResult() with PaymentMethodObtained result does nothing`() = runTest { val interactor = createInteractor() diff --git a/paymentsheet/src/test/java/com/stripe/android/link/TestFactory.kt b/paymentsheet/src/test/java/com/stripe/android/link/TestFactory.kt index 3a32eaf4ca3..eeedc5a855c 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/TestFactory.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/TestFactory.kt @@ -160,6 +160,22 @@ internal object TestFactory { paymentMethodId = "pm_123" ) + val CONSUMER_PAYMENT_DETAILS_GENERIC = ConsumerPaymentDetails.Generic( + id = "csmrpd_126", + last4 = "0x••••22Dd", + isDefault = false, + nickname = null, + billingAddress = null, + billingEmailAddress = null, + rawType = "CRYPTO", + display = ConsumerPaymentDetails.Display( + label = "Crypto", + sublabel = "0x••••22Dd", + icon = null + ), + nextActionTypes = emptyList() + ) + val LINK_ACCOUNT_SESSION = LinkAccountSession( id = "fcsess_123", clientSecret = CLIENT_SECRET, @@ -214,6 +230,7 @@ internal object TestFactory { CONSUMER_PAYMENT_DETAILS_CARD, CONSUMER_PAYMENT_DETAILS_BANK_ACCOUNT, CONSUMER_PAYMENT_DETAILS_PASSTHROUGH, + CONSUMER_PAYMENT_DETAILS_GENERIC ) ) diff --git a/paymentsheet/src/test/java/com/stripe/android/link/account/FakeLinkAccountManager.kt b/paymentsheet/src/test/java/com/stripe/android/link/account/FakeLinkAccountManager.kt index 7985dfe0976..dd6a5bb3080 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/account/FakeLinkAccountManager.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/account/FakeLinkAccountManager.kt @@ -244,7 +244,7 @@ internal open class FakeLinkAccountManager( override suspend fun sharePaymentDetails( paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, cvc: String?, allowRedisplay: String?, diff --git a/paymentsheet/src/test/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandlerTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandlerTest.kt index 7db704ab186..b1637c5b716 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandlerTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/confirmation/DefaultLinkConfirmationHandlerTest.kt @@ -35,6 +35,7 @@ import org.junit.After import org.junit.Before import org.junit.Test +@Suppress("LargeClass") internal class DefaultLinkConfirmationHandlerTest { private val dispatcher = UnconfinedTestDispatcher() @@ -365,6 +366,39 @@ internal class DefaultLinkConfirmationHandlerTest { assertThat(option.expectedPaymentMethodType).isEqualTo(ConsumerPaymentDetails.Card.TYPE) } + @Test + fun `confirm with unknown payment details in passthrough mode uses correct confirmation args`() = + runTest(dispatcher) { + val configuration = TestFactory.LINK_CONFIGURATION.copy(passthroughModeEnabled = true) + val confirmationHandler = FakeConfirmationHandler() + val handler = createHandler( + confirmationHandler = confirmationHandler, + configuration = configuration + ) + + confirmationHandler.awaitResultTurbine.add( + item = ConfirmationHandler.Result.Succeeded( + intent = configuration.stripeIntent, + ) + ) + + val result = handler.confirm( + paymentDetails = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC, + linkAccount = TestFactory.LINK_ACCOUNT, + cvc = CVC, + billingPhone = null + ) + + assertThat(result).isEqualTo(Result.Succeeded) + + val args = confirmationHandler.startTurbine.awaitItem() + assertThat(args.intent).isEqualTo(configuration.stripeIntent) + + val option = args.confirmationOption as LinkPassthroughConfirmationOption + assertThat(option.paymentDetailsId).isEqualTo(TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC.id) + assertThat(option.expectedPaymentMethodType).isNull() + } + @Test fun `confirm with bank account in passthrough mode uses correct confirmation args`() = runTest(dispatcher) { val configuration = TestFactory.LINK_CONFIGURATION.copy( diff --git a/paymentsheet/src/test/java/com/stripe/android/link/repositories/FakeLinkRepository.kt b/paymentsheet/src/test/java/com/stripe/android/link/repositories/FakeLinkRepository.kt index 5aa75d20f43..cef2d9013c8 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/repositories/FakeLinkRepository.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/repositories/FakeLinkRepository.kt @@ -194,7 +194,7 @@ internal open class FakeLinkRepository : LinkRepository { override suspend fun sharePaymentDetails( consumerSessionClientSecret: String, paymentDetailsId: String, - expectedPaymentMethodType: String, + expectedPaymentMethodType: String?, billingPhone: String?, cvc: String?, allowRedisplay: String?, diff --git a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/AddPaymentMethodOptionsTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/AddPaymentMethodOptionsTest.kt index 13f0d5ab09f..39e2cba9cd4 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/AddPaymentMethodOptionsTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/AddPaymentMethodOptionsTest.kt @@ -91,6 +91,13 @@ class AddPaymentMethodOptionsTest { ) } + @Test + fun `values returns empty when Generic filter applied`() { + val options = createOptions(paymentMethodFilter = LinkPaymentMethodFilter.Generic) + + assertThat(options.values).isEmpty() + } + @Test fun `values handles empty funding sources with card fallback`() { val options = createOptions(fundingSources = emptyList()) diff --git a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/PaymentDetailsListItemScreenShotTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/PaymentDetailsListItemScreenShotTest.kt index 2366eed6bae..28160ade3c4 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/PaymentDetailsListItemScreenShotTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/PaymentDetailsListItemScreenShotTest.kt @@ -251,6 +251,60 @@ internal class PaymentDetailsListItemScreenShotTest { ) } + @Test + fun testUnknownWithSublabelEnabled() { + snapshot( + state = State( + details = ConsumerPaymentDetails.Generic( + id = "csmrpd_126", + last4 = "0x••••22Dd", + isDefault = false, + nickname = null, + billingAddress = null, + billingEmailAddress = null, + rawType = "CRYPTO", + display = ConsumerPaymentDetails.Display( + label = "Crypto", + sublabel = "0x••••22Dd", + icon = null + ), + nextActionTypes = emptyList() + ), + enabled = true, + isSelected = false, + isAvailable = true, + isUpdating = false + ) + ) + } + + @Test + fun testUnknownWithoutSublabelEnabled() { + snapshot( + state = State( + details = ConsumerPaymentDetails.Generic( + id = "csmrpd_126", + last4 = "0x••••22Dd", + isDefault = false, + nickname = null, + billingAddress = null, + billingEmailAddress = null, + rawType = "CRYPTO", + display = ConsumerPaymentDetails.Display( + label = "Crypto", + sublabel = null, + icon = null + ), + nextActionTypes = emptyList() + ), + enabled = true, + isSelected = false, + isAvailable = true, + isUpdating = false + ) + ) + } + private fun snapshot(state: State) { paparazziRule.snapshot { DefaultLinkTheme { diff --git a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenuScreenshotTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenuScreenshotTest.kt index e075818b1ef..b381b64204b 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenuScreenshotTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletPaymentMethodMenuScreenshotTest.kt @@ -53,6 +53,16 @@ internal class WalletPaymentMethodMenuScreenshotTest { ) } + @Test + fun testUnknown() { + snapshot( + paymentDetails = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC + .copy( + isDefault = false + ) + ) + } + @Test fun testBankAccountAsDefault() { snapshot( diff --git a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletScreenScreenshotTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletScreenScreenshotTest.kt index 00c2c7cf8b9..65f1084c183 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletScreenScreenshotTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletScreenScreenshotTest.kt @@ -169,6 +169,30 @@ internal class WalletScreenScreenshotTest { ) } + @Test + fun testCollapsedStateWithUnknownSelected() { + snapshot( + state = walletUiState( + selectedItem = TestFactory.CONSUMER_PAYMENT_DETAILS.paymentDetails.firstOrNull { + it is ConsumerPaymentDetails.Generic + }, + userSetIsExpanded = false, + ) + ) + } + + @Test + fun testUnknownPaymentOption() { + snapshot( + state = walletUiState( + selectedItem = TestFactory.CONSUMER_PAYMENT_DETAILS.paymentDetails.firstOrNull { + it is ConsumerPaymentDetails.Generic + }, + userSetIsExpanded = true, + ) + ) + } + @Test fun testAlertMessage() { snapshot( diff --git a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletUiStateTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletUiStateTest.kt index 5ec807f1c73..0c6668d55e8 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletUiStateTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/ui/wallet/WalletUiStateTest.kt @@ -121,6 +121,34 @@ class WalletUiStateTest { ) } + @Test + fun testShowNoTermsForSelectedUnknownPaymentMethod() { + val state = walletUiState( + selectedItem = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC, + ) + + assertThat(state.mandate).isNull() + } + + @Test + fun testShowNoTermsForSelectedUnknownPaymentMethodWhenSettingUp() { + val state = walletUiState( + selectedItem = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC, + isSettingUp = true, + ) + + assertThat(state.mandate).isNull() + } + + @Test + fun testEnabledButtonStateForUnknown() { + val state = walletUiState( + selectedItem = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC, + ) + + assertThat(state.primaryButtonState).isEqualTo(PrimaryButtonState.Enabled) + } + @Test fun testDisabledButtonStateForExpiredCardWithIncompleteExpiryDate() { val selectedItem = TestFactory.CONSUMER_PAYMENT_DETAILS_CARD.copy(expiryYear = 1900) @@ -300,8 +328,17 @@ class WalletUiStateTest { ) val bankAccount = TestFactory.CONSUMER_PAYMENT_DETAILS_BANK_ACCOUNT val passthrough = TestFactory.CONSUMER_PAYMENT_DETAILS_PASSTHROUGH + val unknown = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC val state = walletUiState( - paymentDetailsList = listOf(creditCard, debitCard, prepaidCard, unknownCard, bankAccount, passthrough), + paymentDetailsList = listOf( + creditCard, + debitCard, + prepaidCard, + unknownCard, + bankAccount, + passthrough, + unknown + ), selectedItem = creditCard, cardFundingFilter = PaymentSheetCardFundingFilter(listOf(PaymentSheet.CardFundingType.Credit)) ) @@ -312,6 +349,7 @@ class WalletUiStateTest { assertThat(state.isItemAvailable(unknownCard)).isTrue() assertThat(state.isItemAvailable(bankAccount)).isTrue() assertThat(state.isItemAvailable(passthrough)).isTrue() + assertThat(state.isItemAvailable(unknown)).isTrue() } private fun walletUiState( diff --git a/paymentsheet/src/test/java/com/stripe/android/link/utils/LinkBillingDetailsUtilsTest.kt b/paymentsheet/src/test/java/com/stripe/android/link/utils/LinkBillingDetailsUtilsTest.kt index f0baeec8491..3dcf251ad6f 100644 --- a/paymentsheet/src/test/java/com/stripe/android/link/utils/LinkBillingDetailsUtilsTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/link/utils/LinkBillingDetailsUtilsTest.kt @@ -385,4 +385,80 @@ class LinkBillingDetailsUtilsTest { // Should still supplement email from effective billing details assertThat(result.billingEmailAddress).isEqualTo("default@example.com") } + + @Test + fun `ConsumerPaymentDetails Unknown supports when address is complete`() { + val unknown = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC.copy( + billingAddress = ConsumerPaymentDetails.BillingAddress( + name = "John Doe", + line1 = "123 Main St", + locality = "San Francisco", + postalCode = "94105", + countryCode = CountryCode.US, + line2 = null, + administrativeArea = "CA" + ) + ) + val configuration = PaymentSheet.BillingDetailsCollectionConfiguration( + address = AddressCollectionMode.Full + ) + + val result = unknown.supports(configuration, linkAccount) + + assertThat(result).isTrue() + } + + @Test + fun `ConsumerPaymentDetails Unknown does not support when address is incomplete`() { + val unknown = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC.copy( + billingAddress = ConsumerPaymentDetails.BillingAddress( + name = "John Doe", + line1 = null, + locality = "San Francisco", + postalCode = "94105", + countryCode = CountryCode.US, + line2 = null, + administrativeArea = "CA" + ) + ) + val configuration = PaymentSheet.BillingDetailsCollectionConfiguration( + address = AddressCollectionMode.Full + ) + + val result = unknown.supports(configuration, linkAccount) + + assertThat(result).isFalse() + } + + @Test + fun `ConsumerPaymentDetails Unknown does not support when phone required but missing from Link account`() { + val unknown = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC + val configuration = PaymentSheet.BillingDetailsCollectionConfiguration( + phone = CollectionMode.Always + ) + val linkAccountWithoutPhone = LinkAccount( + ConsumerSession( + emailAddress = testEmail, + clientSecret = "secret", + verificationSessions = emptyList(), + redactedPhoneNumber = "+1********00", + redactedFormattedPhoneNumber = "(***) *** **00", + unredactedPhoneNumber = null + ) + ) + + val result = unknown.supports(configuration, linkAccountWithoutPhone) + + assertThat(result).isFalse() + } + + @Test + fun `withEffectiveBillingDetails returns same Unknown when linkAccount is null`() { + val unknown = TestFactory.CONSUMER_PAYMENT_DETAILS_GENERIC + val configuration = TestFactory.LINK_CONFIGURATION + + val result = unknown.withEffectiveBillingDetails(configuration, null) + + assertThat(result).isEqualTo(unknown) + } } diff --git a/paymentsheet/src/test/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParserTest.kt b/paymentsheet/src/test/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParserTest.kt index 7420d8d41bc..0a9cf36a49d 100644 --- a/paymentsheet/src/test/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParserTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/model/parsers/PaymentMethodWithLinkDetailsJsonParserTest.kt @@ -1,6 +1,7 @@ package com.stripe.android.model.parsers import com.google.common.truth.Truth.assertThat +import com.stripe.android.model.LinkPaymentDetails import org.json.JSONObject import org.junit.Test @@ -14,7 +15,7 @@ class PaymentMethodWithLinkDetailsJsonParserTest { val paymentMethod = PaymentMethodWithLinkDetailsJsonParser.parse(json) assertThat(paymentMethod).isNotNull() - assertThat(paymentMethod?.linkPaymentDetails).isNull() + assertThat(paymentMethod.linkPaymentDetails).isNull() } @Test @@ -28,7 +29,7 @@ class PaymentMethodWithLinkDetailsJsonParserTest { val paymentMethod = PaymentMethodWithLinkDetailsJsonParser.parse(json) assertThat(paymentMethod).isNotNull() - assertThat(paymentMethod?.linkPaymentDetails).isNotNull() + assertThat(paymentMethod.linkPaymentDetails).isNotNull() } @Test @@ -42,13 +43,40 @@ class PaymentMethodWithLinkDetailsJsonParserTest { val paymentMethod = PaymentMethodWithLinkDetailsJsonParser.parse(json) assertThat(paymentMethod).isNotNull() - assertThat(paymentMethod?.linkPaymentDetails).isNotNull() + assertThat(paymentMethod.linkPaymentDetails).isNotNull() + } + + @Test + fun `Supports payment method that has Link payment details of unknown type`() { + val linkPaymentDetails = JSONObject().apply { + put("id", "UNKNOWN123") + put("type", "Crypto") + put("is_default", false) + put("next_action_types", org.json.JSONArray()) + put( + "display", + JSONObject().apply { + put("label", "Klarna") + put("last4", "1234") + } + ) + } + val json = JSONObject().apply { + put("payment_method", PAYMENT_METHOD_JSON) + put("link_payment_details", linkPaymentDetails) + } + val paymentMethod = PaymentMethodWithLinkDetailsJsonParser.parse(json) + + assertThat(paymentMethod).isNotNull() + assertThat(paymentMethod.linkPaymentDetails).isInstanceOf(LinkPaymentDetails.Generic::class.java as Class<*>) } @Test fun `Does not support method that has Link payment details of unsupported type`() { val linkPaymentDetails = JSONObject().apply { + put("id", "UNKNOWN123") put("type", "KLARNA") + put("is_default", false) } val json = JSONObject().apply { put("payment_method", PAYMENT_METHOD_JSON) @@ -56,7 +84,8 @@ class PaymentMethodWithLinkDetailsJsonParserTest { } val paymentMethod = PaymentMethodWithLinkDetailsJsonParser.parse(json) - assertThat(paymentMethod).isNull() + assertThat(paymentMethod).isNotNull() + assertThat(paymentMethod.linkPaymentDetails).isNull() } private companion object { diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[DarkTheme,DefaultFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[DarkTheme,DefaultFont].png new file mode 100644 index 00000000000..2ba4e2c6c2e Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[DarkTheme,DefaultFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[DarkTheme,LargeFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[DarkTheme,LargeFont].png new file mode 100644 index 00000000000..35e8f186f43 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[DarkTheme,LargeFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[LightTheme,DefaultFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[LightTheme,DefaultFont].png new file mode 100644 index 00000000000..56359a32119 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[LightTheme,DefaultFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[LightTheme,LargeFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[LightTheme,LargeFont].png new file mode 100644 index 00000000000..8381d865227 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithSublabelEnabled[LightTheme,LargeFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[DarkTheme,DefaultFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[DarkTheme,DefaultFont].png new file mode 100644 index 00000000000..e6991e6461f Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[DarkTheme,DefaultFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[DarkTheme,LargeFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[DarkTheme,LargeFont].png new file mode 100644 index 00000000000..622231d2f0b Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[DarkTheme,LargeFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[LightTheme,DefaultFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[LightTheme,DefaultFont].png new file mode 100644 index 00000000000..2a746bf1748 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[LightTheme,DefaultFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[LightTheme,LargeFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[LightTheme,LargeFont].png new file mode 100644 index 00000000000..c41ced1306d Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_PaymentDetailsListItemScreenShotTest_testUnknownWithoutSublabelEnabled[LightTheme,LargeFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[DarkTheme,DefaultFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[DarkTheme,DefaultFont].png new file mode 100644 index 00000000000..94f82ec1d74 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[DarkTheme,DefaultFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[DarkTheme,LargeFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[DarkTheme,LargeFont].png new file mode 100644 index 00000000000..b16dc0208aa Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[DarkTheme,LargeFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[LightTheme,DefaultFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[LightTheme,DefaultFont].png new file mode 100644 index 00000000000..06eb7d64e31 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[LightTheme,DefaultFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[LightTheme,LargeFont].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[LightTheme,LargeFont].png new file mode 100644 index 00000000000..00013588f00 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletPaymentMethodMenuScreenshotTest_testUnknown[LightTheme,LargeFont].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,DarkTheme].png index 524f431511e..3a5ff04ca79 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,LightTheme].png index e9f854505a6..e5be5598749 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,DarkTheme].png index 14ef93e7ff3..31570ad1e34 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,LightTheme].png index 5d31f5221e2..cc7c835fd47 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testAlertMessage[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,DarkTheme].png index e3392f35655..3a1aee01f5d 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,LightTheme].png index 35808dfde14..e9f7ef49254 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,DarkTheme].png index c933b918b42..2a4722ff198 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,LightTheme].png index f6ae0fad700..492b817797b 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testBankAccountSelectedState[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,DarkTheme].png index 89961ce90f9..1c89ca20aba 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,LightTheme].png index 44be30bed50..3aaef4214a4 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,DarkTheme].png index 141a89a2849..fa60ce5b602 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,LightTheme].png index 45b27bb7329..8103a4f739a 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCannotAddCreditCard[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Landscape,DarkTheme].png new file mode 100644 index 00000000000..315321ec09b Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Landscape,LightTheme].png new file mode 100644 index 00000000000..081007065c2 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Portrait,DarkTheme].png new file mode 100644 index 00000000000..456f7ddfce7 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Portrait,LightTheme].png new file mode 100644 index 00000000000..a3fbdf2d6ac Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testCollapsedStateWithUnknownSelected[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,DarkTheme].png index da760c0f823..2f8f53ce572 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,LightTheme].png index a88e7ef8394..8aa3f4ba0ad 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,DarkTheme].png index 06a4b49a300..bb3be70f7b2 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,LightTheme].png index ee453e1dcb6..a37dd180bab 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedStateWithUnavailable[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,DarkTheme].png index 97bb55f4794..a0dc8118d53 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,LightTheme].png index b1c3dca4afe..a39bee2244d 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,DarkTheme].png index 72be36ccbbf..35bac843cb4 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,LightTheme].png index 1330cc7e255..499aba9c4ad 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testExpandedState[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,DarkTheme].png index 97bb55f4794..a0dc8118d53 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,LightTheme].png index b1c3dca4afe..a39bee2244d 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,DarkTheme].png index 72be36ccbbf..35bac843cb4 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,LightTheme].png index 1330cc7e255..499aba9c4ad 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonCompletedState[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,DarkTheme].png index 97bb55f4794..a0dc8118d53 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,LightTheme].png index b1c3dca4afe..a39bee2244d 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,DarkTheme].png index 581a64a4507..64ce507f4ee 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,DarkTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,LightTheme].png index eb19af1fd41..f5fbc100ec6 100644 Binary files a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,LightTheme].png and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testPayButtonProcessingState[Portrait,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Landscape,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Landscape,DarkTheme].png new file mode 100644 index 00000000000..74ca6e8c5d3 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Landscape,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Landscape,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Landscape,LightTheme].png new file mode 100644 index 00000000000..378fd0fea6a Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Landscape,LightTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Portrait,DarkTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Portrait,DarkTheme].png new file mode 100644 index 00000000000..cde4407e042 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Portrait,DarkTheme].png differ diff --git a/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Portrait,LightTheme].png b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Portrait,LightTheme].png new file mode 100644 index 00000000000..6157a49bdb8 Binary files /dev/null and b/paymentsheet/src/test/snapshots/images/com.stripe.android.link.ui.wallet_WalletScreenScreenshotTest_testUnknownPaymentOption[Portrait,LightTheme].png differ