com.mastercard.masterpasswallet.fragments.addcard.VerifyCardFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.mastercard.masterpasswallet.fragments.addcard.VerifyCardFragment.java

Source

/*
 *  ****************************************************************************
 *  Copyright (c) 2015, MasterCard International Incorporated and/or its
 *  affiliates. All rights reserved.
 *  <p/>
 *  The contents of this file may only be used subject to the MasterCard
 *  Mobile Payment SDK for MCBP and/or MasterCard Mobile MPP UI SDK
 *  Materials License.
 *  <p/>
 *  Please refer to the file LICENSE.TXT for full details.
 *  <p/>
 *  TO THE EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT
 *  WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 *  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NON INFRINGEMENT. TO THE EXTENT PERMITTED BY LAW, IN NO EVENT SHALL
 *  MASTERCARD OR ITS AFFILIATES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 *  IN THE SOFTWARE.
 *  *****************************************************************************
 */

package com.mastercard.masterpasswallet.fragments.addcard;

import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import com.mastercard.masterpasswallet.DataManager;
import com.mastercard.masterpasswallet.R;
import com.mastercard.masterpasswallet.fragments.BaseFragment;
import com.mastercard.masterpasswallet.models.Card;
import com.mastercard.masterpasswallet.models.ShippingAddress;
import com.mastercard.masterpasswallet.utils.DateUtils;

import org.apache.commons.validator.routines.CreditCardValidator;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Add card flow: Step 1
 */
public class VerifyCardFragment extends BaseFragment<VerifyCardFragment.VerifyCardFragmentListener> {
    /**
     * Logging tag.
     */
    private static final String TAG = VerifyCardFragment.class.getName();

    /**
     * Interface exposed by this fragment
     */
    public interface VerifyCardFragmentListener {
        boolean hasCardNumber();

        String getCardNumber();

        boolean hasCardExpiry();

        String getCardExpiryMonth();

        String getCardExpiryYear();

        boolean hasCardCvc();

        String getCardCvc();

        String getCardholderName();

        /**
         * Event raised when the first card is added
         *
         * @param cardNumber  The card number
         * @param cvc         The cards CVC
         * @param expiryMonth The cards expiry month
         * @param expiryYear  The cards expiry year
         */
        void addFirstCard(String cardholderName, String cardNumber, String cvc, String expiryMonth,
                String expiryYear, ShippingAddress shippingAddress);

        /**
         * Event raised when a card is added
         *
         * @param cardNumber  The card number
         * @param cvc         The cards CVC
         * @param expiryMonth The cards expiry month
         * @param expiryYear  The cards expiry year
         */
        void addCard(String cardholderName, String cardNumber, String cvc, String expiryMonth, String expiryYear);
    }

    private boolean mIsFirstCard;

    private View mLayScannedCard;
    private ImageView mImgScannedCard;
    private TextView mTxtScannedCardPan;
    private EditText mEdtCardholderName;
    private EditText mEdtCardNumber;
    private EditText mEdtCvc;
    private EditText mEdtExpiry;

    @Override
    protected int getLayoutResourceId() {
        return R.layout.fragment_verify_card;
    }

    @Override
    protected void initWidgets(View fragmentView) {
        setActionBarTitle(getActivity().getActionBar(), getString(R.string.title_verify_card), false);
        findWidgets(fragmentView);
        prePopulateWidgets();
        setupWidgetFormats();
        setupAddCardButton(fragmentView);

        mEdtCardNumber.addTextChangedListener(panTextWatcher);
    }

    private void findWidgets(View fragmentView) {
        mImgScannedCard = (ImageView) fragmentView.findViewById(R.id.img_card);
        mLayScannedCard = fragmentView.findViewById(R.id.lay_scanned_card);
        mTxtScannedCardPan = (TextView) fragmentView.findViewById(R.id.txt_card_pan);
        mEdtCardholderName = (EditText) fragmentView.findViewById(R.id.edt_cardholder_name);
        mEdtCardNumber = (EditText) fragmentView.findViewById(R.id.edt_card_number);
        mEdtCvc = (EditText) fragmentView.findViewById(R.id.edt_cvc);
        mEdtExpiry = (EditText) fragmentView.findViewById(R.id.edt_expiry);
    }

    private void prePopulateWidgets() {
        if (mListener.hasCardNumber()) {
            mEdtCardNumber.setText(mListener.getCardNumber());

            mTxtScannedCardPan.setText(getString(R.string.masked_pan,
                    mListener.getCardNumber().substring(mListener.getCardNumber().length() - 4)));

            // set the focus to the next field
            if (mListener.hasCardExpiry()) {
                mEdtCvc.requestFocus();
            } else {
                mEdtExpiry.requestFocus();
            }

            // show the keyboard
            InputMethodManager imm = (InputMethodManager) getActivity()
                    .getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.showSoftInput(mEdtCvc, InputMethodManager.SHOW_IMPLICIT);

            if (mListener.hasCardExpiry()) {
                // Otherwise attempt to use the expiry date
                String cardExpiryMonth = String.format("%02d", Integer.parseInt(mListener.getCardExpiryMonth()));
                String cardExpiryYear = mListener.getCardExpiryYear().substring(2);
                mEdtExpiry.setText(String.format("%s/%s", cardExpiryMonth, cardExpiryYear));
            }

            // Use the image we've decided upon, this will either be the correct one for the card
            // or default to the green one
            mImgScannedCard.setImageResource(Card.getDefaultCardImageFull());

            // Set the cardholder name
            mEdtCardholderName.setText(mListener.getCardholderName());
        } else {
            // If no card was scanned then we don't show any image
            mLayScannedCard.setVisibility(View.GONE);
        }
    }

    private void setupWidgetFormats() {

        // format the expiry date to mm/yy
        mEdtExpiry.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                String text = s.toString();

                int selection = mEdtExpiry.getSelectionStart();

                String pattern = "[0-9][0-9]\\/[0-9][0-9]";
                Pattern p = Pattern.compile(pattern);
                Matcher m = p.matcher(text);
                if (!m.find()) {
                    // if they have typed the second character
                    if (text.length() == 2 && before == 0) {
                        mEdtExpiry.setText(text + "/");
                        selection++;
                    } else {
                        // remove anything that isn't a number
                        String cleanText = text.replaceAll("[^0-9.]", "");

                        // if the / will be added we need to increase the cursor position by 1
                        if (!text.contains("/")) {
                            selection++;
                        }

                        if (text.length() > 2) {
                            // format the starting numbers
                            text = cleanText.substring(0, 2) + "/" + cleanText.substring(2);

                        }

                        // make sure we only set the text if there are changes (otherwise we infinite loop)
                        if (!text.equals(s.toString())) {
                            // set the text
                            mEdtExpiry.setText(text);
                        }
                    }
                }

                // don't allow the date to be greater than 5 characters (including the /)
                if (text.length() > 5) {
                    mEdtExpiry.setText(text.substring(0, 5));
                }

                // make sure the cursor isn't moved out of bounds
                if (selection > mEdtExpiry.getText().length()) {
                    selection = mEdtExpiry.getText().length();
                }

                // move the cursor back to where it was
                mEdtExpiry.setSelection(selection);
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
    }

    private void setupAddCardButton(View fragmentView) {
        Button btnAddCard = (Button) fragmentView.findViewById(R.id.btn_add_card);
        btnAddCard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d(TAG, "Card added button pressed");
                String cardholderName = mEdtCardholderName.getText().toString();
                String cardNumber = mEdtCardNumber.getText().toString();
                String cvc = mEdtCvc.getText().toString();
                String expiry = mEdtExpiry.getText().toString();
                String expiryMonth = "";
                String expiryYear = "";

                // Focus the field with the first error
                EditText focusField = null;

                // Expiry
                if (TextUtils.isEmpty(expiry)) {
                    mEdtExpiry.setError(getString(R.string.error_expiry_date_is_required));
                    focusField = mEdtExpiry;
                } else {
                    String[] expiryParts = expiry.split("/");
                    if (expiryParts.length != 2) {
                        mEdtExpiry.setError(getString(R.string.error_expiry_date_is_not_valid));
                        focusField = mEdtExpiry;
                    } else {
                        expiryMonth = expiryParts[0];
                        expiryYear = expiryParts[1];

                        // parse to an int for further validation
                        int month = Integer.parseInt(expiryMonth);
                        int year = Integer.parseInt(expiryYear);

                        // make sure the month is a valid number
                        if (month > 12 || month < 1) {
                            mEdtExpiry.setError(getString(R.string.error_expiry_date_is_not_valid));
                            focusField = mEdtExpiry;
                        } else {
                            if (!DateUtils.isInFuture(1, month, year + 2000)) {
                                mEdtExpiry.setError(getString(R.string.error_expiry_date_is_not_future));
                                focusField = mEdtExpiry;
                            }
                        }
                    }
                }

                // CVC
                if (TextUtils.isEmpty(cvc)) {
                    mEdtCvc.setError(getString(R.string.error_cvc_is_required));
                    focusField = mEdtCvc;
                } else if (!TextUtils.isDigitsOnly(cvc) || (cvc.length() != 3 && cvc.length() != 4)) {
                    mEdtCvc.setError(getString(R.string.error_cvc_is_not_valid));
                    focusField = mEdtCvc;
                }

                // Card Number
                if (TextUtils.isEmpty(cardNumber)) {
                    mEdtCardNumber.setError(getString(R.string.error_card_number_is_required));
                    focusField = mEdtCardNumber;
                } else {
                    // Check we don't already have this card in the list
                    ArrayList<Card> cards = DataManager.INSTANCE.getFreshCards();
                    for (Card card : cards) {
                        if (card.getPAN().replace(" ", "").equals(cardNumber.replace(" ", ""))) {
                            mEdtCardNumber.setError(getString(R.string.error_card_number_already_in_use));
                            focusField = mEdtCardNumber;
                            break;
                        }
                    }
                }

                // Card holder name
                if (TextUtils.isEmpty(cardholderName)) {
                    mEdtCardholderName.setError(getString(R.string.error_cardholder_name_is_required));
                    focusField = mEdtCardholderName;
                }

                // apache credit card validator
                CreditCardValidator ccv = new CreditCardValidator();

                if (!ccv.isValid(cardNumber.replace("-", "").replace(" ", ""))) {
                    mEdtCardNumber.setError(getString(R.string.error_card_number_not_valid));
                    focusField = mEdtCardNumber;
                }

                // If there is no focusField set then the form is valid
                if (focusField != null) {
                    focusField.requestFocus();
                } else {
                    hideKeyboard();

                    if (mIsFirstCard) {
                        // When adding first card we have to set shipping address
                        ShippingAddress shippingAddress = new ShippingAddress();
                        shippingAddress.mName = cardholderName;
                        shippingAddress.mNickname = getString(R.string.verifycard_prefill_nickname);
                        shippingAddress.mLine1 = getString(R.string.verifycard_prefill_billing_address);
                        shippingAddress.mCity = getString(R.string.verifycard_prefill_billing_city);
                        shippingAddress.mZipCode = getString(R.string.verifycard_prefill_billing_zipcode);
                        shippingAddress.mState = getString(R.string.verifycard_prefill_billing_state);
                        // only set as default if it's the first card
                        shippingAddress.bIsDefault = true;
                        mListener.addFirstCard(cardholderName, cardNumber, cvc, expiryMonth, expiryYear,
                                shippingAddress);
                    } else {
                        mListener.addCard(cardholderName, cardNumber, cvc, expiryMonth, expiryYear);
                    }
                }
            }
        });
    }

    private void hideKeyboard() {
        // Check if no view has focus:
        View view = getActivity().getCurrentFocus();
        if (view != null) {
            InputMethodManager inputManager = (InputMethodManager) getActivity()
                    .getSystemService(Context.INPUT_METHOD_SERVICE);
            inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    public void setFirstCard(boolean isFirstCard) {
        mIsFirstCard = isFirstCard;
    }

    private final TextWatcher panTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

            // Show last 4 digits if we've enetered at least 16, otherwise hide
            String newPan = s.toString();
            newPan = newPan.replace(" ", "");
            if (newPan.length() >= 16) {
                mTxtScannedCardPan.setText(getString(R.string.masked_pan, newPan.substring(newPan.length() - 4)));
                mTxtScannedCardPan.setVisibility(View.VISIBLE);
            } else {
                mTxtScannedCardPan.setVisibility(View.INVISIBLE);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    };
}