Java tutorial
/* * **************************************************************************** * 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) { } }; }