| Index: chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7b881eb50eb681eadadcdd377ab4664916e70c17
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/CardEditor.java
|
| @@ -0,0 +1,555 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.chrome.browser.payments;
|
| +
|
| +import android.os.AsyncTask;
|
| +import android.os.Handler;
|
| +import android.text.TextUtils;
|
| +import android.util.Pair;
|
| +
|
| +import org.chromium.base.Callback;
|
| +import org.chromium.chrome.R;
|
| +import org.chromium.chrome.browser.autofill.PersonalDataManager;
|
| +import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
|
| +import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
|
| +import org.chromium.chrome.browser.payments.PaymentRequestImpl.PaymentRequestServiceObserverForTest;
|
| +import org.chromium.chrome.browser.payments.ui.EditorFieldModel;
|
| +import org.chromium.chrome.browser.payments.ui.EditorFieldModel.EditorFieldValidator;
|
| +import org.chromium.chrome.browser.payments.ui.EditorModel;
|
| +import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.DropdownKeyValue;
|
| +import org.chromium.content_public.browser.WebContents;
|
| +
|
| +import java.text.SimpleDateFormat;
|
| +import java.util.ArrayList;
|
| +import java.util.Calendar;
|
| +import java.util.Date;
|
| +import java.util.HashMap;
|
| +import java.util.HashSet;
|
| +import java.util.List;
|
| +import java.util.Locale;
|
| +import java.util.Map;
|
| +import java.util.Set;
|
| +
|
| +import javax.annotation.Nullable;
|
| +
|
| +/**
|
| + * A credit card editor. Can be used for editing both local and server credit cards. Everything in
|
| + * local cards can be edited. For server cards, only the billing address is editable.
|
| + */
|
| +public class CardEditor extends EditorBase<AutofillPaymentInstrument> {
|
| + /** The web contents where the web payments API is invoked. */
|
| + private final WebContents mWebContents;
|
| +
|
| + /** Used for verifying billing address completeness and also editing billing addresses. */
|
| + private final AddressEditor mAddressEditor;
|
| +
|
| + private final PaymentRequestServiceObserverForTest mObserverForTest;
|
| +
|
| + /** All card types recognized by this editor. This is a subset of card types in
|
| + * https://w3c.github.io/webpayments-methods-card/#method-id */
|
| + private final Set<String> mCardTypes;
|
| +
|
| + /** A mapping from the recognized card types to their icons. */
|
| + private final Map<String, Integer> mCardTypeIcons;
|
| +
|
| + /** A mapping from the recognized card types to the string resource identifiers of their
|
| + * human-readable descriptions. This is for the screen reader. */
|
| + private final Map<String, Integer> mCardTypeDescriptions;
|
| +
|
| + /** The card types accepted by the merchant website. This is a subset of recognized cards. Used
|
| + * in the validator. */
|
| + private final Set<String> mAcceptedCardTypes;
|
| +
|
| + /** The resource identifiers for the icons of the accepted card types. Used in the editor as a
|
| + * hint to the user about the valid card types. This is important to keep in a list, because the
|
| + * display order matters to the merchants. */
|
| + private final List<Integer> mAcceptedCardTypeResourceIds;
|
| +
|
| + /** The string resource identifiers for the human-readable descriptions of the accepted card
|
| + * types. Used for the screen reader on the card type icons. Should match the icons in
|
| + * mAcceptedCardTypeResourceIds. */
|
| + private final List<Integer> mAcceptedCardTypeDescriptions;
|
| +
|
| + private final Handler mHandler;
|
| +
|
| + @Nullable private Calendar mCalendar;
|
| +
|
| + @Nullable private EditorFieldValidator mCardNumberValidator;
|
| + @Nullable private EditorFieldModel mIconHint;
|
| + @Nullable private EditorFieldModel mNumberField;
|
| + @Nullable private EditorFieldModel mNameField;
|
| + @Nullable private EditorFieldModel mMonthField;
|
| + @Nullable private EditorFieldModel mYearField;
|
| + @Nullable private EditorFieldModel mBillingAddressField;
|
| + @Nullable private EditorFieldModel mSaveCardCheckbox;
|
| +
|
| + /**
|
| + * Builds a credit card editor.
|
| + *
|
| + * @param webContents The web contents where the web payments API is invoked. Should not be
|
| + * null.
|
| + * @param addressEditor Used for verifying billing address completeness and also editing
|
| + * billing addresses. Should not be null.
|
| + * @param observerForTest Optional observer for test.
|
| + */
|
| + public CardEditor(WebContents webContents, AddressEditor addressEditor,
|
| + @Nullable PaymentRequestServiceObserverForTest observerForTest) {
|
| + assert webContents != null;
|
| + assert addressEditor != null;
|
| +
|
| + mWebContents = webContents;
|
| + mAddressEditor = addressEditor;
|
| + mObserverForTest = observerForTest;
|
| +
|
| + mCardTypes = new HashSet<>();
|
| + mCardTypes.add("amex");
|
| + mCardTypes.add("diners");
|
| + mCardTypes.add("discover");
|
| + mCardTypes.add("jcb");
|
| + mCardTypes.add("mastercard");
|
| + mCardTypes.add("unionpay");
|
| + mCardTypes.add("visa");
|
| +
|
| + mCardTypeIcons = new HashMap<>();
|
| + mCardTypeIcons.put("amex", R.drawable.pr_amex);
|
| + mCardTypeIcons.put("diners", R.drawable.pr_dinersclub);
|
| + mCardTypeIcons.put("discover", R.drawable.pr_discover);
|
| + mCardTypeIcons.put("jcb", R.drawable.pr_jcb);
|
| + mCardTypeIcons.put("mastercard", R.drawable.pr_mc);
|
| + mCardTypeIcons.put("unionpay", R.drawable.pr_unionpay);
|
| + mCardTypeIcons.put("visa", R.drawable.pr_visa);
|
| + assert mCardTypes.size() == mCardTypeIcons.size();
|
| +
|
| + mCardTypeDescriptions = new HashMap<>();
|
| + mCardTypeDescriptions.put("amex", R.string.autofill_cc_amex);
|
| + mCardTypeDescriptions.put("diners", R.string.autofill_cc_diners);
|
| + mCardTypeDescriptions.put("discover", R.string.autofill_cc_discover);
|
| + mCardTypeDescriptions.put("jcb", R.string.autofill_cc_jcb);
|
| + mCardTypeDescriptions.put("mastercard", R.string.autofill_cc_mastercard);
|
| + mCardTypeDescriptions.put("unionpay", R.string.autofill_cc_union_pay);
|
| + mCardTypeDescriptions.put("visa", R.string.autofill_cc_visa);
|
| + assert mCardTypes.size() == mCardTypeDescriptions.size();
|
| +
|
| + mAcceptedCardTypes = new HashSet<>();
|
| + mAcceptedCardTypeResourceIds = new ArrayList<>();
|
| + mAcceptedCardTypeDescriptions = new ArrayList<>();
|
| + mHandler = new Handler();
|
| +
|
| + // Avoid strict mode violation when reading timezone information from disk.
|
| + new AsyncTask<Void, Void, Calendar>() {
|
| + @Override
|
| + protected Calendar doInBackground(Void... unused) {
|
| + return Calendar.getInstance();
|
| + }
|
| +
|
| + @Override
|
| + protected void onPostExecute(Calendar result) {
|
| + mCalendar = result;
|
| + }
|
| + }.execute();
|
| + }
|
| +
|
| + /**
|
| + * Returns whether the given credit card is complete, i.e., can be sent to the merchant as-is
|
| + * without editing first.
|
| + *
|
| + * For both local and server cards, verifies that the billing address is complete. For local
|
| + * cards also verifies that the card number is valid and the name on card is not empty.
|
| + *
|
| + * Does not check the expiration date. If the card is expired, the user has the opportunity
|
| + * update the expiration date when providing their CVC in the card unmask dialog.
|
| + *
|
| + * Does not check that the card type is accepted by the merchant. This is done elsewhere to
|
| + * filter out such cards from view entirely. Cards that are not accepted by the merchant should
|
| + * not be edited.
|
| + *
|
| + * @param card The card to check.
|
| + * @return Whether the card is complete.
|
| + */
|
| + public boolean isCardComplete(CreditCard card) {
|
| + if (card == null || TextUtils.isEmpty(card.getBillingAddressId())
|
| + || !mAddressEditor.isProfileComplete(PersonalDataManager.getInstance().getProfile(
|
| + card.getBillingAddressId()))) {
|
| + return false;
|
| + }
|
| +
|
| + if (!card.getIsLocal()) return true;
|
| +
|
| + return !TextUtils.isEmpty(card.getName())
|
| + || getCardNumberValidator().isValid(card.getNumber());
|
| + }
|
| +
|
| + private EditorFieldValidator getCardNumberValidator() {
|
| + if (mCardNumberValidator == null) {
|
| + mCardNumberValidator = new EditorFieldValidator() {
|
| + @Override
|
| + public boolean isValid(@Nullable CharSequence value) {
|
| + return value != null && mAcceptedCardTypes.contains(
|
| + PersonalDataManager.getInstance().getBasicCardPaymentTypeIfValid(
|
| + value.toString()));
|
| + }
|
| + };
|
| + }
|
| +
|
| + return mCardNumberValidator;
|
| + }
|
| +
|
| + /**
|
| + * Adds accepted payment methods to the editor, if they are recognized credit card types.
|
| + *
|
| + * @param acceptedMethods The accepted method payments.
|
| + */
|
| + public void addAcceptedPaymentMethodsIfRecognized(String[] acceptedMethods) {
|
| + assert acceptedMethods != null;
|
| + for (int i = 0; i < acceptedMethods.length; i++) {
|
| + String method = acceptedMethods[i];
|
| + if (mCardTypes.contains(method) && !mAcceptedCardTypes.contains(method)) {
|
| + mAcceptedCardTypes.add(method);
|
| + if (mCardTypeIcons.containsKey(method)) {
|
| + mAcceptedCardTypeResourceIds.add(mCardTypeIcons.get(method));
|
| + mAcceptedCardTypeDescriptions.add(mCardTypeDescriptions.get(method));
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Builds and shows an editor model with the following fields for local cards.
|
| + *
|
| + * [ accepted card types hint images ]
|
| + * [ card number ]
|
| + * [ name on card ]
|
| + * [ expiration month ][ expiration year ]
|
| + * [ billing address dropdown ]
|
| + * [ save this card checkbox ] <-- Shown only for new cards.
|
| + *
|
| + * Server cards have the following fields instead.
|
| + *
|
| + * [ card's obfuscated number ]
|
| + * [ billing address dropdown ]
|
| + */
|
| + @Override
|
| + public void edit(@Nullable final AutofillPaymentInstrument toEdit,
|
| + final Callback<AutofillPaymentInstrument> callback) {
|
| + super.edit(toEdit, callback);
|
| +
|
| + // Ensure that |instrument| and |card| are always not null. If |toEdit| is null, we're
|
| + // creating a new credit card.
|
| + final AutofillPaymentInstrument instrument = toEdit == null
|
| + ? new AutofillPaymentInstrument(mWebContents, new CreditCard(), null) : toEdit;
|
| + final CreditCard card = instrument.getCard();
|
| +
|
| + // The title of the editor depends on whether we're adding a new card (toEdit is null) or
|
| + // editing an existing card (toEdit is not null).
|
| + final EditorModel editor = new EditorModel(mContext.getString(toEdit == null
|
| + ? R.string.autofill_create_credit_card : R.string.autofill_edit_credit_card));
|
| +
|
| + if (card.getIsLocal()) {
|
| + // It's unlikely, but possible that the calendar retrieval task has not completed yet.
|
| + // The calendar is required only for local cards. Error out if it's not ready.
|
| + if (mCalendar == null) {
|
| + mHandler.post(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + callback.onResult(null);
|
| + }
|
| + });
|
| + return;
|
| + }
|
| +
|
| + // Let user edit any part of the local card.
|
| + addLocalCardInputs(editor, card);
|
| + } else {
|
| + // Display some information about the server card.
|
| + editor.addField(EditorFieldModel.createLabel(card.getObfuscatedNumber(), card.getName(),
|
| + card.getFormattedExpirationDate(mContext), card.getIssuerIconDrawableId()));
|
| + }
|
| +
|
| + // Always show the billing address dropdown.
|
| + addBillingAddressDropdown(editor, card);
|
| +
|
| + // Allow saving new cards on disk.
|
| + if (toEdit == null) {
|
| + addSaveCardCheckbox(editor);
|
| + }
|
| +
|
| + // If the user clicks [Cancel], send a null card back to the caller.
|
| + editor.setCancelCallback(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + callback.onResult(null);
|
| + }
|
| + });
|
| +
|
| + // If the user clicks [Done], save changes on disk, mark the card "complete," and send it
|
| + // back to the caller.
|
| + editor.setDoneCallback(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + commitChanges(card, toEdit == null);
|
| + instrument.completeInstrument(card,
|
| + PersonalDataManager.getInstance().getProfile(card.getBillingAddressId()));
|
| + callback.onResult(instrument);
|
| + }
|
| + });
|
| +
|
| + mEditorView.show(editor);
|
| + }
|
| +
|
| + /**
|
| + * Adds the following fields to the editor.
|
| + *
|
| + * [ accepted card types hint images ]
|
| + * [ card number ]
|
| + * [ name on card ]
|
| + * [ expiration month ][ expiration year ]
|
| + */
|
| + private void addLocalCardInputs(EditorModel editor, CreditCard card) {
|
| + assert mCalendar != null;
|
| +
|
| + // Local card editor shows a card icon hint.
|
| + if (mIconHint == null) {
|
| + mIconHint = EditorFieldModel.createIconList(
|
| + mContext.getString(R.string.payments_accepted_cards_label),
|
| + mAcceptedCardTypeResourceIds, mAcceptedCardTypeDescriptions);
|
| + }
|
| + editor.addField(mIconHint);
|
| +
|
| + // Card number is validated.
|
| + if (mNumberField == null) {
|
| + mNumberField = EditorFieldModel.createTextInput(
|
| + EditorFieldModel.INPUT_TYPE_HINT_CREDIT_CARD,
|
| + mContext.getString(R.string.autofill_credit_card_editor_number),
|
| + null, getCardNumberValidator(),
|
| + mContext.getString(R.string.payments_card_number_required_validation_message),
|
| + mContext.getString(R.string.payments_card_number_invalid_validation_message),
|
| + null);
|
| + }
|
| + mNumberField.setValue(card.getNumber());
|
| + editor.addField(mNumberField);
|
| +
|
| + // Name on card is required.
|
| + if (mNameField == null) {
|
| + mNameField = EditorFieldModel.createTextInput(
|
| + EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME,
|
| + mContext.getString(R.string.autofill_credit_card_editor_name), null, null,
|
| + mContext.getString(R.string.payments_name_on_card_required_validation_message),
|
| + null, null);
|
| + }
|
| + mNameField.setValue(card.getName());
|
| + editor.addField(mNameField);
|
| +
|
| + // Expiration month dropdown.
|
| + if (mMonthField == null) {
|
| + mMonthField = EditorFieldModel.createDropdown(
|
| + mContext.getString(R.string.autofill_credit_card_editor_expiration_date),
|
| + buildMonthDropdownKeyValues(mCalendar));
|
| + mMonthField.setIsFullLine(false);
|
| + }
|
| + mMonthField.setDropdownCallback(new Callback<Pair<String, Runnable>>() {
|
| + @Override
|
| + public void onResult(final Pair<String, Runnable> eventData) {
|
| + mMonthField.setValue(eventData.first);
|
| + }
|
| + });
|
| + mMonthField.setValue(card.getMonth());
|
| + editor.addField(mMonthField);
|
| +
|
| + // Expiration year dropdown is side-by-side with the expiration year dropdown. The dropdown
|
| + // should include the card's expiration year, so it's not cached.
|
| + mYearField = EditorFieldModel.createDropdown(
|
| + null, buildYearDropdownKeyValues(mCalendar, card.getYear()));
|
| + mYearField.setIsFullLine(false);
|
| + mYearField.setDropdownCallback(new Callback<Pair<String, Runnable>>() {
|
| + @Override
|
| + public void onResult(final Pair<String, Runnable> eventData) {
|
| + mYearField.setValue(eventData.first);
|
| + }
|
| + });
|
| + mYearField.setValue(card.getYear());
|
| + editor.addField(mYearField);
|
| + }
|
| +
|
| + /** Builds the key-value pairs for the month dropdown. */
|
| + private static List<DropdownKeyValue> buildMonthDropdownKeyValues(Calendar calendar) {
|
| + assert calendar != null;
|
| +
|
| + List<DropdownKeyValue> result = new ArrayList<>();
|
| +
|
| + Locale locale = Locale.getDefault();
|
| + SimpleDateFormat keyFormatter = new SimpleDateFormat("MM", locale);
|
| + SimpleDateFormat valueFormatter = new SimpleDateFormat("MMMM (MM)", locale);
|
| +
|
| + calendar.set(Calendar.DAY_OF_MONTH, 1);
|
| + for (int month = 0; month < 12; month++) {
|
| + calendar.set(Calendar.MONTH, month);
|
| + Date date = calendar.getTime();
|
| + result.add(
|
| + new DropdownKeyValue(keyFormatter.format(date), valueFormatter.format(date)));
|
| + }
|
| +
|
| + return result;
|
| + }
|
| +
|
| + /** Builds the key-value pairs for the year dropdown. */
|
| + private static List<DropdownKeyValue> buildYearDropdownKeyValues(
|
| + Calendar calendar, String alwaysIncludeYear) {
|
| + assert calendar != null;
|
| +
|
| + List<DropdownKeyValue> result = new ArrayList<>();
|
| +
|
| + int initialYear = calendar.get(Calendar.YEAR);
|
| + boolean foundAlwaysIncludeYear = false;
|
| + for (int year = initialYear; year < initialYear + 10; year++) {
|
| + String yearString = Integer.toString(year);
|
| + if (yearString.equals(alwaysIncludeYear)) foundAlwaysIncludeYear = true;
|
| + result.add(new DropdownKeyValue(yearString, yearString));
|
| + }
|
| +
|
| + if (!foundAlwaysIncludeYear && !TextUtils.isEmpty(alwaysIncludeYear)) {
|
| + result.add(0, new DropdownKeyValue(alwaysIncludeYear, alwaysIncludeYear));
|
| + }
|
| +
|
| + return result;
|
| + }
|
| +
|
| + /**
|
| + * Adds the billing address dropdown to the editor with the following items.
|
| + *
|
| + * | "select" |
|
| + * | complete address 1 |
|
| + * | complete address 2 |
|
| + * ...
|
| + * | complete address n |
|
| + * | "add address" |
|
| + */
|
| + private void addBillingAddressDropdown(EditorModel editor, final CreditCard card) {
|
| + final List<DropdownKeyValue> billingAddresses = new ArrayList<>();
|
| +
|
| + // The empty key indicates no selection has been made.
|
| + billingAddresses.add(new DropdownKeyValue("",
|
| + mContext.getString(R.string.autofill_billing_address_select_prompt)));
|
| +
|
| + // Re-read profiles every time, in case any of them have changed. This does not cause a disk
|
| + // read, because personal_data_manager.h holds a cache.
|
| + final PersonalDataManager pdm = PersonalDataManager.getInstance();
|
| + List<AutofillProfile> profiles = pdm.getProfilesForSettings();
|
| +
|
| + // 1) Include only local profiles, because GUIDs of server profiles change on every browser
|
| + // restart. Server profiles are not supported as billing addresses.
|
| + // 2) Include only complete profiles, so that user launches the editor only when explicitly
|
| + // selecting [+ ADD ADDRESS] in the dropdown.
|
| + for (int i = 0; i < profiles.size(); i++) {
|
| + AutofillProfile profile = profiles.get(i);
|
| + if (profile.getIsLocal() && mAddressEditor.isProfileComplete(profile)) {
|
| + // Key is profile GUID. Value is profile label.
|
| + billingAddresses.add(new DropdownKeyValue(profile.getGUID(), profile.getLabel()));
|
| + }
|
| + }
|
| +
|
| + // The "add" key indicates the user wishes to add a new profile.
|
| + billingAddresses.add(new DropdownKeyValue("add",
|
| + mContext.getString(R.string.autofill_create_profile)));
|
| +
|
| + // Don't cache the billing address dropdown, because the user may have added or removed
|
| + // profiles.
|
| + mBillingAddressField = EditorFieldModel.createDropdown(
|
| + mContext.getString(R.string.autofill_credit_card_editor_billing_address),
|
| + billingAddresses);
|
| +
|
| + // The billing address is required.
|
| + mBillingAddressField.setRequiredErrorMessage(
|
| + mContext.getString(R.string.payments_billing_address_required_validation_message));
|
| +
|
| + mBillingAddressField.setDropdownCallback(new Callback<Pair<String, Runnable>>() {
|
| + @Override
|
| + public void onResult(final Pair<String, Runnable> eventData) {
|
| + // Ignore all billing address dropdown selection except [+ ADD ADDRESS].
|
| + if (!"add".equals(eventData.first)) {
|
| + if (mObserverForTest != null) {
|
| + mObserverForTest.onPaymentRequestServiceProcessBillingAddressChange();
|
| + }
|
| + return;
|
| + }
|
| +
|
| + mAddressEditor.edit(null, new Callback<AutofillAddress>() {
|
| + @Override
|
| + public void onResult(AutofillAddress billingAddress) {
|
| + if (billingAddress == null) {
|
| + // User has cancelled the address editor.
|
| + mBillingAddressField.setValue(null);
|
| + } else {
|
| + // User has added a new complete address. Add it to the top of the
|
| + // dropdown, under the "Select" prompt.
|
| + billingAddresses.add(1, new DropdownKeyValue(
|
| + billingAddress.getIdentifier(), billingAddress.getSublabel()));
|
| + mBillingAddressField.setDropdownKeyValues(billingAddresses);
|
| + mBillingAddressField.setValue(billingAddress.getIdentifier());
|
| + }
|
| +
|
| + // Let the card editor UI re-read the model and re-create UI elements.
|
| + mHandler.post(eventData.second);
|
| + }
|
| + });
|
| + }
|
| + });
|
| +
|
| + mBillingAddressField.setValue(card.getBillingAddressId());
|
| + editor.addField(mBillingAddressField);
|
| + }
|
| +
|
| + /** Adds the "save this card" checkbox to the editor. */
|
| + private void addSaveCardCheckbox(EditorModel editor) {
|
| + if (mSaveCardCheckbox == null) {
|
| + mSaveCardCheckbox = EditorFieldModel.createCheckbox(
|
| + mContext.getString(R.string.payments_save_card_to_device_checkbox));
|
| + }
|
| +
|
| + // Saving locally is disabled by default, similar to autofill always prompting the user to
|
| + // save card on device, instead of silently saving it.
|
| + mSaveCardCheckbox.setIsChecked(false);
|
| +
|
| + editor.addField(mSaveCardCheckbox);
|
| + }
|
| +
|
| + /**
|
| + * Saves the edited credit card.
|
| + *
|
| + * If this is a server card, then only its billing address identifier is updated.
|
| + *
|
| + * If this is a new local card, then it's saved on this device only if the user has checked the
|
| + * "save this card" checkbox.
|
| + */
|
| + private void commitChanges(CreditCard card, boolean isNewCard) {
|
| + card.setBillingAddressId(mBillingAddressField.getValue().toString());
|
| + PersonalDataManager pdm = PersonalDataManager.getInstance();
|
| + if (!card.getIsLocal()) {
|
| + pdm.updateServerCardBillingAddress(card.getGUID(), card.getBillingAddressId());
|
| + return;
|
| + }
|
| +
|
| + card.setNumber(mNumberField.getValue().toString().replace(" ", "").replace("-", ""));
|
| + card.setName(mNameField.getValue().toString());
|
| + card.setMonth(mMonthField.getValue().toString());
|
| + card.setYear(mYearField.getValue().toString());
|
| +
|
| + // Calculate the basic card payment type, obfuscated number, and the icon for this card.
|
| + // All of these depend on the card number. The type is sent to the merchant website. The
|
| + // obfuscated number and the icon are displayed in the user interface.
|
| + CreditCard displayableCard = pdm.getCreditCardForNumber(card.getNumber());
|
| + card.setBasicCardPaymentType(displayableCard.getBasicCardPaymentType());
|
| + card.setObfuscatedNumber(displayableCard.getObfuscatedNumber());
|
| + card.setIssuerIconDrawableId(displayableCard.getIssuerIconDrawableId());
|
| +
|
| + if (!isNewCard) {
|
| + pdm.setCreditCard(card);
|
| + return;
|
| + }
|
| +
|
| + if (mSaveCardCheckbox != null && mSaveCardCheckbox.isChecked()) {
|
| + card.setGUID(pdm.setCreditCard(card));
|
| + }
|
| + }
|
| +}
|
|
|