For #18271 - [Saved cards] Display the credit card provider icon and report the correct card type (#19652)

upstream-sync
Gabriel Luong 3 years ago committed by GitHub
parent bd8facb025
commit c11335fafc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -85,9 +85,5 @@ class CreditCardEditorFragment : SecureFragment(R.layout.fragment_credit_card_ed
companion object {
// Number of years to show in the expiry year dropdown.
const val NUMBER_OF_YEARS_TO_SHOW = 10
// Placeholder for the card type. This will be replaced when we can identify the card type.
// This is dependent on https://github.com/mozilla-mobile/android-components/issues/9813.
const val CARD_TYPE_PLACEHOLDER = ""
}
}

@ -5,9 +5,8 @@
package org.mozilla.fenix.settings.creditcards
import androidx.annotation.VisibleForTesting
import mozilla.components.support.utils.creditCardIIN
private const val MAX_CREDIT_CARD_NUMBER_LENGTH = 19
private const val MIN_CREDIT_CARD_NUMBER_LENGTH = 12
// Number of last digits to be shown when credit card number is obfuscated.
private const val LAST_VISIBLE_DIGITS_COUNT = 4
@ -27,17 +26,15 @@ fun String.last4Digits(): String {
}
/**
* Uses string size and Luhn Algorithm validation to validate a credit card number.
* Returns true if the provided string is a valid credit card by checking if it has a matching
* credit card issuer network passes the Luhn Algorithm, and false otherwise.
*/
fun String.validateCreditCardNumber(): Boolean {
val creditCardNumber = this.toCreditCardNumber()
if (creditCardNumber != this) return false
// credit card numbers have at least 12 digits and at most 19 digits
if (creditCardNumber.length < MIN_CREDIT_CARD_NUMBER_LENGTH ||
creditCardNumber.length > MAX_CREDIT_CARD_NUMBER_LENGTH
) return false
if (creditCardNumber != this || creditCardNumber.creditCardIIN() == null) {
return false
}
return luhnAlgorithmValidation(creditCardNumber)
}

@ -14,9 +14,9 @@ import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.view.hideKeyboard
import mozilla.components.support.utils.creditCardIIN
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.toEditable
import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment.Companion.CARD_TYPE_PLACEHOLDER
import org.mozilla.fenix.settings.creditcards.CreditCardEditorState
import org.mozilla.fenix.settings.creditcards.interactor.CreditCardEditorInteractor
import org.mozilla.fenix.settings.creditcards.last4Digits
@ -80,7 +80,7 @@ class CreditCardEditorView(
cardNumberLast4 = cardNumber.last4Digits(),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
cardType = cardNumber.creditCardIIN()?.creditCardIssuerNetwork?.name ?: ""
)
interactor.onUpdateCreditCard(state.guid, fields)
} else {
@ -90,7 +90,7 @@ class CreditCardEditorView(
cardNumberLast4 = cardNumber.last4Digits(),
expiryMonth = (expiry_month_drop_down.selectedItemPosition + 1).toLong(),
expiryYear = expiry_year_drop_down.selectedItem.toString().toLong(),
cardType = CARD_TYPE_PLACEHOLDER
cardType = cardNumber.creditCardIIN()?.creditCardIssuerNetwork?.name ?: ""
)
interactor.onSaveCreditCard(fields)
}

@ -7,6 +7,7 @@ package org.mozilla.fenix.settings.creditcards.view
import android.view.View
import kotlinx.android.synthetic.main.credit_card_list_item.*
import mozilla.components.concept.storage.CreditCard
import mozilla.components.support.utils.creditCardIssuerNetwork
import org.mozilla.fenix.R
import org.mozilla.fenix.settings.creditcards.interactor.CreditCardsManagementInteractor
import org.mozilla.fenix.utils.view.ViewHolder
@ -23,6 +24,8 @@ class CreditCardItemViewHolder(
) : ViewHolder(view) {
fun bind(creditCard: CreditCard) {
credit_card_logo.setImageResource(creditCard.cardType.creditCardIssuerNetwork().icon)
credit_card_number.text = creditCard.obfuscatedCardNumber
bindCreditCardExpiryDate(creditCard)

@ -10,19 +10,30 @@
android:background="?android:attr/selectableItemBackground"
android:minHeight="?android:attr/listPreferredItemHeight">
<ImageView
android:id="@+id/credit_card_logo"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="16dp"
android:scaleType="fitCenter"
android:importantForAccessibility="no"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<TextView
android:id="@+id/credit_card_number"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/saved_logins_item_margin_start"
android:layout_marginEnd="@dimen/saved_logins_item_margin_end"
android:layout_marginStart="@dimen/credit_cards_saved_cards_item_margin_start"
android:layout_marginEnd="@dimen/credit_cards_saved_cards_item_margin_end"
android:ellipsize="middle"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?primaryText"
app:layout_constraintBottom_toTopOf="@id/expiry_date"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toEndOf="@+id/credit_card_logo"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="mozilla.org" />
@ -38,7 +49,7 @@
android:textColor="?secondaryText"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toEndOf="@+id/credit_card_logo"
app:layout_constraintTop_toBottomOf="@id/credit_card_number"
app:layout_constraintVertical_chainStyle="packed"
tools:text="02/2022" />

@ -6,6 +6,7 @@ package org.mozilla.fenix.settings.creditcards
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.support.utils.CreditCardNetworkType
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@ -22,7 +23,7 @@ class CreditCardEditorStateTest {
cardNumberLast4 = "1110",
expiryMonth = 5,
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.AMEX.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,

@ -15,6 +15,7 @@ import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.utils.CreditCardNetworkType
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@ -24,7 +25,6 @@ import org.junit.runner.RunWith
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.toEditable
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment.Companion.CARD_TYPE_PLACEHOLDER
import org.mozilla.fenix.settings.creditcards.CreditCardEditorFragment.Companion.NUMBER_OF_YEARS_TO_SHOW
import org.mozilla.fenix.settings.creditcards.interactor.CreditCardEditorInteractor
import org.mozilla.fenix.settings.creditcards.view.CreditCardEditorView
@ -40,11 +40,11 @@ class CreditCardEditorViewTest {
private val creditCard = CreditCard(
guid = "id",
billingName = "Banana Apple",
encryptedCardNumber = CreditCardNumber.Encrypted("371449635398431"),
cardNumberLast4 = "8431",
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111111"),
cardNumberLast4 = "1111",
expiryMonth = 5,
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.VISA.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,
@ -133,7 +133,7 @@ class CreditCardEditorViewTest {
val calendar = Calendar.getInstance()
val billingName = "Banana Apple"
val cardNumber = "4111111111111110"
val cardNumber = "2221000000000000"
val expiryMonth = 5
val expiryYear = calendar.get(Calendar.YEAR)
@ -154,10 +154,10 @@ class CreditCardEditorViewTest {
NewCreditCardFields(
billingName = billingName,
plaintextCardNumber = CreditCardNumber.Plaintext(cardNumber),
cardNumberLast4 = "1110",
cardNumberLast4 = "0000",
expiryMonth = expiryMonth.toLong(),
expiryYear = expiryYear.toLong(),
cardType = CARD_TYPE_PLACEHOLDER
cardType = CreditCardNetworkType.MASTERCARD.cardName
)
)
}
@ -170,7 +170,7 @@ class CreditCardEditorViewTest {
val calendar = Calendar.getInstance()
val billingName = "Banana Apple"
val cardNumber = "371449635398431"
val cardNumber = "2720994326581252"
val expiryMonth = 5
val expiryYear = calendar.get(Calendar.YEAR)
@ -191,10 +191,10 @@ class CreditCardEditorViewTest {
NewCreditCardFields(
billingName = billingName,
plaintextCardNumber = CreditCardNumber.Plaintext(cardNumber),
cardNumberLast4 = "8431",
cardNumberLast4 = "1252",
expiryMonth = expiryMonth.toLong(),
expiryYear = expiryYear.toLong(),
cardType = CARD_TYPE_PLACEHOLDER
cardType = CreditCardNetworkType.MASTERCARD.cardName
)
)
}
@ -215,7 +215,7 @@ class CreditCardEditorViewTest {
cardNumberLast4 = creditCard.cardNumberLast4,
expiryMonth = creditCard.expiryMonth,
expiryYear = creditCard.expiryYear,
cardType = CARD_TYPE_PLACEHOLDER
cardType = creditCard.cardType
)
)
}

@ -12,6 +12,7 @@ import kotlinx.android.synthetic.main.credit_card_list_item.view.*
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.utils.CreditCardNetworkType
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@ -33,7 +34,7 @@ class CreditCardItemViewHolderTest {
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.AMEX.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,

@ -6,6 +6,7 @@ package org.mozilla.fenix.settings.creditcards
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.support.utils.CreditCardNetworkType
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
@ -22,7 +23,7 @@ class CreditCardsAdapterTest {
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.AMEX.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,
@ -35,7 +36,7 @@ class CreditCardsAdapterTest {
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.AMEX.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,
@ -56,7 +57,7 @@ class CreditCardsAdapterTest {
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.AMEX.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,

@ -18,6 +18,7 @@ import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.service.sync.autofill.AutofillCreditCardsAddressesStorage
import mozilla.components.support.test.rule.MainCoroutineRule
import mozilla.components.support.utils.CreditCardNetworkType
import org.junit.After
import org.junit.Before
import org.junit.Rule
@ -85,7 +86,7 @@ class DefaultCreditCardEditorControllerTest {
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2030,
cardType = "discover"
cardType = CreditCardNetworkType.DISCOVER.cardName
)
controller.handleSaveCreditCard(creditCardFields)
@ -105,7 +106,7 @@ class DefaultCreditCardEditorControllerTest {
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2034,
cardType = "discover"
cardType = CreditCardNetworkType.DISCOVER.cardName
)
controller.handleUpdateCreditCard(creditCardId, creditCardFields)

@ -10,6 +10,7 @@ import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.concept.storage.NewCreditCardFields
import mozilla.components.concept.storage.UpdatableCreditCardFields
import mozilla.components.support.utils.CreditCardNetworkType
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.settings.creditcards.controller.CreditCardEditorController
@ -41,7 +42,7 @@ class DefaultCreditCardEditorInteractorTest {
cardNumberLast4 = "1110",
expiryMonth = 1,
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.AMEX.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,
@ -59,7 +60,7 @@ class DefaultCreditCardEditorInteractorTest {
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2030,
cardType = "discover"
cardType = CreditCardNetworkType.DISCOVER.cardName
)
interactor.onSaveCreditCard(creditCardFields)
verify { controller.handleSaveCreditCard(creditCardFields) }
@ -74,7 +75,7 @@ class DefaultCreditCardEditorInteractorTest {
cardNumberLast4 = "1112",
expiryMonth = 1,
expiryYear = 2034,
cardType = "discover"
cardType = CreditCardNetworkType.DISCOVER.cardName
)
interactor.onUpdateCreditCard(guid, creditCardFields)
verify { controller.handleUpdateCreditCard(guid, creditCardFields) }

@ -10,6 +10,7 @@ import io.mockk.spyk
import io.mockk.verify
import mozilla.components.concept.storage.CreditCard
import mozilla.components.concept.storage.CreditCardNumber
import mozilla.components.support.utils.CreditCardNetworkType
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -43,7 +44,7 @@ class DefaultCreditCardsManagementControllerTest {
encryptedCardNumber = CreditCardNumber.Encrypted("4111111111111110"),
cardNumberLast4 = "1110",
expiryYear = 2030,
cardType = "amex",
cardType = CreditCardNetworkType.AMEX.cardName,
timeCreated = 1L,
timeLastUsed = 1L,
timeLastModified = 1L,

@ -42,7 +42,6 @@ class StringTest {
val jcbCard = "3530111333300000"
val masterCardCard = "5555555555554444"
val visaCard = "4111111111111111"
val voyagerCard = "869941728035895"
assertTrue(americanExpressCard.validateCreditCardNumber())
assertTrue(dinnersClubCard.validateCreditCardNumber())
@ -50,7 +49,6 @@ class StringTest {
assertTrue(jcbCard.validateCreditCardNumber())
assertTrue(masterCardCard.validateCreditCardNumber())
assertTrue(visaCard.validateCreditCardNumber())
assertTrue(voyagerCard.validateCreditCardNumber())
}
@Test

Loading…
Cancel
Save