diff --git a/stripe/src/main/java/com/stripe/android/model/Card.java b/stripe/src/main/java/com/stripe/android/model/Card.java index 0c70391607b..3e13b7a72ba 100644 --- a/stripe/src/main/java/com/stripe/android/model/Card.java +++ b/stripe/src/main/java/com/stripe/android/model/Card.java @@ -420,18 +420,6 @@ public List getLoggingTokens() { return loggingTokens; } - /** - * Add a logging token to this {@link Card} object. - * - * @param loggingToken a token to be logged with this card - * @return {@code this}, for chaining purposes - */ - @NonNull - public Card addLoggingToken(@NonNull String loggingToken) { - loggingTokens.add(loggingToken); - return this; - } - /** * @return the {@link #cvc} for this card */ @@ -947,7 +935,7 @@ public Builder metadata(@Nullable Map metadata) { } @NonNull - private Builder loggingTokens(@NonNull List loggingTokens) { + public Builder loggingTokens(@NonNull List loggingTokens) { this.loggingTokens = loggingTokens; return this; } diff --git a/stripe/src/main/java/com/stripe/android/view/CardInputWidget.java b/stripe/src/main/java/com/stripe/android/view/CardInputWidget.java index df8ba87de16..00624d61bbe 100644 --- a/stripe/src/main/java/com/stripe/android/view/CardInputWidget.java +++ b/stripe/src/main/java/com/stripe/android/view/CardInputWidget.java @@ -34,6 +34,8 @@ import com.stripe.android.model.Card; import com.stripe.android.model.PaymentMethodCreateParams; +import java.util.ArrayList; +import java.util.Collections; import java.util.Locale; import static com.stripe.android.model.Card.CardBrand; @@ -44,7 +46,7 @@ /** * A card input widget that handles all animation on its own. */ -public class CardInputWidget extends LinearLayout { +public class CardInputWidget extends LinearLayout implements CardWidget { static final String LOGGING_TOKEN = "CardInputView"; @@ -121,7 +123,8 @@ public PaymentMethodCreateParams.Card getPaymentMethodCard() { final String cvcValue = mCvcNumberEditText.getText().toString().trim(); // CVC/CVV is the only field not validated by the entry control itself, so we check here. - if (cardNumber == null || cardDate == null || cardDate.length != 2 || !isCvcLengthValid()) { + if (cardNumber == null || cardDate == null || cardDate.length != 2 || + !isCvcLengthValid(cvcValue)) { return null; } @@ -139,22 +142,30 @@ public PaymentMethodCreateParams.Card getPaymentMethodCard() { * @return a valid {@link Card} object based on user input, or {@code null} if any field is * invalid */ + @Override @Nullable public Card getCard() { - String cardNumber = mCardNumberEditText.getCardNumber(); - int[] cardDate = mExpiryDateEditText.getValidDateFields(); + final Card.Builder builder = getCardBuilder(); + return builder != null ? builder.build() : null; + } + + @Override + @Nullable + public Card.Builder getCardBuilder() { + final String cardNumber = mCardNumberEditText.getCardNumber(); + final int[] cardDate = mExpiryDateEditText.getValidDateFields(); if (cardNumber == null || cardDate == null || cardDate.length != 2) { return null; } // CVC/CVV is the only field not validated by the entry control itself, so we check here. - String cvcValue = mCvcNumberEditText.getText().toString().trim(); - if (!isCvcLengthValid()) { + final String cvcValue = mCvcNumberEditText.getText().toString().trim(); + if (!isCvcLengthValid(cvcValue)) { return null; } - return Card.create(cardNumber, cardDate[0], cardDate[1], cvcValue) - .addLoggingToken(LOGGING_TOKEN); + return new Card.Builder(cardNumber, cardDate[0], cardDate[1], cvcValue) + .loggingTokens(new ArrayList<>(Collections.singletonList(LOGGING_TOKEN))); } /** @@ -456,16 +467,13 @@ void updateSpaceSizes(boolean isCardViewed) { } } - private boolean isCvcLengthValid() { - String cvcValue = mCvcNumberEditText.getText().toString().trim(); - int cvcLength = cvcValue.length(); + private boolean isCvcLengthValid(@NonNull String cvcValue) { + final int cvcLength = cvcValue.length(); if (mIsAmEx && cvcLength == Card.CVC_LENGTH_AMERICAN_EXPRESS) { return true; } - if (cvcLength == Card.CVC_LENGTH_COMMON) { - return true; - } - return false; + + return cvcLength == Card.CVC_LENGTH_COMMON; } private void setLayoutValues(int width, int margin, @NonNull StripeEditText editText) { diff --git a/stripe/src/main/java/com/stripe/android/view/CardMultilineWidget.java b/stripe/src/main/java/com/stripe/android/view/CardMultilineWidget.java index 17f359c6d91..bf213b8965b 100644 --- a/stripe/src/main/java/com/stripe/android/view/CardMultilineWidget.java +++ b/stripe/src/main/java/com/stripe/android/view/CardMultilineWidget.java @@ -32,6 +32,8 @@ import java.math.BigDecimal; import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Collections; import java.util.Objects; import static com.stripe.android.view.CardInputListener.FocusField.FOCUS_CARD; @@ -43,7 +45,7 @@ * A multiline card input widget using the support design library's {@link TextInputLayout} * to match Material Design. */ -public class CardMultilineWidget extends LinearLayout { +public class CardMultilineWidget extends LinearLayout implements CardWidget { static final String CARD_MULTILINE_TOKEN = "CardMultilineView"; static final long CARD_NUMBER_HINT_DELAY = 120L; @@ -162,21 +164,28 @@ public PaymentMethod.BillingDetails getPaymentMethodBillingDetails() { * @return a valid {@link Card} object based on user input, or {@code null} if any field is * invalid */ + @Override @Nullable public Card getCard() { - if (validateAllFields()) { - final String cardNumber = mCardNumberEditText.getCardNumber(); - final int[] cardDate = Objects.requireNonNull(mExpiryDateEditText.getValidDateFields()); - final String cvcValue = mCvcEditText.getText().toString(); - - final Card card = new Card.Builder(cardNumber, cardDate[0], cardDate[1], cvcValue) - .addressZip(mShouldShowPostalCode ? - mPostalCodeEditText.getText().toString() : null) - .build(); - return card.addLoggingToken(CARD_MULTILINE_TOKEN); + final Card.Builder cardBuilder = getCardBuilder(); + return cardBuilder != null ? cardBuilder.build() : null; + } + + @Override + @Nullable + public Card.Builder getCardBuilder() { + if (!validateAllFields()) { + return null; } - return null; + final String cardNumber = mCardNumberEditText.getCardNumber(); + final int[] cardDate = Objects.requireNonNull(mExpiryDateEditText.getValidDateFields()); + final String cvcValue = mCvcEditText.getText().toString(); + + return new Card.Builder(cardNumber, cardDate[0], cardDate[1], cvcValue) + .addressZip(mShouldShowPostalCode ? + mPostalCodeEditText.getText().toString() : null) + .loggingTokens(new ArrayList<>(Collections.singletonList(CARD_MULTILINE_TOKEN))); } /** diff --git a/stripe/src/main/java/com/stripe/android/view/CardWidget.java b/stripe/src/main/java/com/stripe/android/view/CardWidget.java new file mode 100644 index 00000000000..237e6895323 --- /dev/null +++ b/stripe/src/main/java/com/stripe/android/view/CardWidget.java @@ -0,0 +1,11 @@ +package com.stripe.android.view; + +import android.support.annotation.Nullable; + +import com.stripe.android.model.Card; + +interface CardWidget { + @Nullable Card getCard(); + + @Nullable Card.Builder getCardBuilder(); +} diff --git a/stripe/src/test/java/com/stripe/android/model/CardTest.java b/stripe/src/test/java/com/stripe/android/model/CardTest.java index c8f85fa0be0..2b99ea3aa23 100644 --- a/stripe/src/test/java/com/stripe/android/model/CardTest.java +++ b/stripe/src/test/java/com/stripe/android/model/CardTest.java @@ -10,6 +10,7 @@ import org.junit.Test; import java.util.Calendar; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -693,7 +694,8 @@ public void toBuilder_whenUnchanged_isEquals() { @Test public void toBuilder_withLoggingToken_whenUnchanged_isEquals() { final Card card = Objects.requireNonNull(Card.fromString(JSON_CARD_USD)); - card.addLoggingToken("hello"); + card.toBuilder() + .loggingTokens(Collections.singletonList("hello")); assertEquals(card, card.toBuilder().build()); }