Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PIMOB: Java sample app updated for CVV tokenization #246

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
</activity>

<activity android:name=".DemoActivity" />
<activity
android:name=".CVVTokenizationActivity"
android:screenOrientation="portrait" />

</application>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package checkout.checkout_android;

import static checkout.checkout_android.Constants.PUBLIC_KEY_CVV_TOKENIZATION;

import android.app.AlertDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

import androidx.activity.ComponentActivity;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;

import com.checkout.base.model.CardScheme;
import com.checkout.base.model.Environment;
import com.checkout.frames.cvvinputfield.CVVComponentApiFactory;
import com.checkout.frames.cvvinputfield.api.CVVComponentApi;
import com.checkout.frames.cvvinputfield.api.CVVComponentMediator;
import com.checkout.frames.cvvinputfield.models.CVVComponentConfig;
import com.checkout.frames.cvvinputfield.style.DefaultCVVInputFieldStyle;
import com.checkout.frames.model.CornerRadius;
import com.checkout.frames.model.Shape;
import com.checkout.frames.style.component.base.ContainerStyle;
import com.checkout.frames.style.component.base.InputFieldIndicatorStyle;
import com.checkout.frames.style.component.base.InputFieldStyle;
import com.checkout.frames.style.component.base.TextStyle;
import com.checkout.tokenization.model.CVVTokenDetails;
import com.checkout.tokenization.model.CVVTokenizationResultHandler;

import checkout.checkout_android.viewmodels.CVVTokenizationViewModel;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;

public class CVVTokenizationActivity extends ComponentActivity {
private Button amexCVVTokenizationButton;
private Button cvvTokenizationButton;
private LinearLayout cvvComponentLinearLayout;
private LinearLayout amexCustomCVVComponentLinearLayout;
private Function1<CVVTokenizationResultHandler, Unit> resultHandler;
private CVVTokenizationViewModel cvvTokenizationViewModel;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cvv_tokenization);
initViews();

cvvTokenizationViewModel = new ViewModelProvider(this).get(CVVTokenizationViewModel.class);

setupObservers();

// Create cvvComponentApi
CVVComponentApi cvvComponentApi = CVVComponentApiFactory.create(PUBLIC_KEY_CVV_TOKENIZATION, Environment.SANDBOX, this);

// initialise CVVTokenizationResultHandler for tokenization
resultHandler = result -> {
if (result instanceof CVVTokenizationResultHandler.Success) {
CVVTokenDetails tokenDetails = ((CVVTokenizationResultHandler.Success) result).getTokenDetails();
displayTokenResultDialog(tokenDetails.getToken(), "Token Created Successfully");
} else if (result instanceof CVVTokenizationResultHandler.Failure) {
String errorMessage = ((CVVTokenizationResultHandler.Failure) result).getErrorMessage();
displayTokenResultDialog(errorMessage, "Token Failure");
}
return Unit.INSTANCE;
};

createCVVComponentMediator(cvvComponentApi);

createAMEXCVVComponentMediator(cvvComponentApi);
}

private void setupObservers() {
cvvTokenizationViewModel.getIsEnteredAMEXCVVValid().observe(this, isCVVValid -> {
if (isCVVValid)
amexCVVTokenizationButton.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark, this.getTheme()));
else {
amexCVVTokenizationButton.setBackgroundColor(getResources().getColor(R.color.colorGray, this.getTheme()));
}
amexCVVTokenizationButton.setEnabled(isCVVValid);
});
}

private void initViews() {
amexCVVTokenizationButton = findViewById(R.id.btnAmexCVVTokenization);
cvvTokenizationButton = findViewById(R.id.btnCVVTokenization);
cvvComponentLinearLayout = findViewById(R.id.linearCVVComponent);
amexCustomCVVComponentLinearLayout = findViewById(R.id.linearAMEXCustomCVVComponent);
cvvTokenizationButton.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark, this.getTheme()));
}

private void createCVVComponentMediator(CVVComponentApi cvvComponentApi) {
// Create config for CVV component
CVVComponentConfig visaCVVComponentConfig = new CVVComponentConfig(
CardScheme.Companion.fromString("unknown"),
isEnteredCVVValid -> Unit.INSTANCE,
DefaultCVVInputFieldStyle.INSTANCE.create()
);

// Create CVVComponentMediator for CVV component
CVVComponentMediator defaultCVVComponentMediator = cvvComponentApi.createComponentMediator(visaCVVComponentConfig);
View defaultCVVComponentView = defaultCVVComponentMediator.provideCvvComponentContent(cvvComponentLinearLayout);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add final for all the immutable variables, same for all the other code

Suggested change
private void createCVVComponentMediator(CVVComponentApi cvvComponentApi) {
// Create config for CVV component
CVVComponentConfig visaCVVComponentConfig = new CVVComponentConfig(
CardScheme.Companion.fromString("unknown"),
isEnteredCVVValid -> Unit.INSTANCE,
DefaultCVVInputFieldStyle.INSTANCE.create()
);
// Create CVVComponentMediator for CVV component
CVVComponentMediator defaultCVVComponentMediator = cvvComponentApi.createComponentMediator(visaCVVComponentConfig);
View defaultCVVComponentView = defaultCVVComponentMediator.provideCvvComponentContent(cvvComponentLinearLayout);
private void createCVVComponentMediator(CVVComponentApi cvvComponentApi) {
// Create config for CVV component
final CVVComponentConfig visaCVVComponentConfig = new CVVComponentConfig(
CardScheme.Companion.fromString("unknown"),
isEnteredCVVValid -> Unit.INSTANCE,
DefaultCVVInputFieldStyle.INSTANCE.create()
);
// Create CVVComponentMediator for CVV component
final CVVComponentMediator defaultCVVComponentMediator = cvvComponentApi.createComponentMediator(visaCVVComponentConfig);
final View defaultCVVComponentView = defaultCVVComponentMediator.provideCvvComponentContent(cvvComponentLinearLayout);

// Add defaultCVVComponent as view in parent layout
cvvComponentLinearLayout.addView(defaultCVVComponentView);

cvvTokenizationButton.setOnClickListener(v -> defaultCVVComponentMediator.createToken(resultHandler));
}


private void createAMEXCVVComponentMediator(CVVComponentApi cvvComponentApi) {
CVVComponentConfig visaCVVComponentConfig = new CVVComponentConfig(
CardScheme.Companion.fromString("American_express"),
isEnteredCVVValid -> {
cvvTokenizationViewModel.setIsAmexCVVValid(isEnteredCVVValid);
return Unit.INSTANCE;
},
new InputFieldStyle(new TextStyle(), "Enter cvv",
null, new TextStyle(),
new ContainerStyle(Constants.backgroundColor
, Shape.RoundCorner,
new CornerRadius(9)),
new InputFieldIndicatorStyle.Underline()
)
);

CVVComponentMediator amexCVVComponentMediator = cvvComponentApi.createComponentMediator(visaCVVComponentConfig);

View amexCVVComponentView = amexCVVComponentMediator.provideCvvComponentContent(amexCustomCVVComponentLinearLayout);
amexCustomCVVComponentLinearLayout.addView(amexCVVComponentView);

amexCVVTokenizationButton.setOnClickListener(v -> amexCVVComponentMediator.createToken(resultHandler));
}


private void displayTokenResultDialog(String message, String title) {
new AlertDialog.Builder(this).setTitle(title)
.setMessage(message)
.setCancelable(false)
.setNeutralButton("Ok", (dialog, id) -> dialog.dismiss())
.show();
}

}
60 changes: 35 additions & 25 deletions app/src/main/java/checkout/checkout_android/CheckoutActivity.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package checkout.checkout_android;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

Expand All @@ -14,29 +16,37 @@
import java.util.Locale;

public class CheckoutActivity extends Activity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);

initItemUI("Simple Bike", Constants.PAYMENT_AMOUNT, R.drawable.bike);

findViewById(R.id.button_buy).setOnClickListener(this::onBuyButtonClicked);
}

private void initItemUI(String name, long price, @DrawableRes int imageResource) {
TextView itemName = findViewById(R.id.text_item_name);
ImageView itemImage = findViewById(R.id.image_item_image);
TextView itemPrice = findViewById(R.id.text_item_price);

itemName.setText(name);
itemImage.setImageResource(imageResource);
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.getDefault());
itemPrice.setText(numberFormat.format((double) price / 100));
}

private void onBuyButtonClicked(View view) {
startActivity(new Intent(this, DemoActivity.class));
}
private Button cvvToknizationButton;
private Button cardTokenizationButton;

@SuppressLint("CutPasteId")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);

cvvToknizationButton = findViewById(R.id.button_cvv_tokenization);
cardTokenizationButton = findViewById(R.id.button_buy);

initItemUI("Simple Bike", Constants.PAYMENT_AMOUNT, R.drawable.bike, cardTokenizationButton);

findViewById(R.id.button_buy).setOnClickListener(this::onBuyButtonClicked);

cvvToknizationButton.setOnClickListener(v -> {
startActivity(new Intent(this, CVVTokenizationActivity.class));
});
}

private void initItemUI(String name, long price, @DrawableRes int imageResource, Button cvvToknizationButton) {
TextView itemName = findViewById(R.id.text_item_name);
ImageView itemImage = findViewById(R.id.image_item_image);
itemName.setText(name);
itemImage.setImageResource(imageResource);
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.getDefault());
cvvToknizationButton.setText(getText(R.string.button_buy) + numberFormat.format((double) price / 100));
}

private void onBuyButtonClicked(View view) {
startActivity(new Intent(this, DemoActivity.class));
}
}
56 changes: 31 additions & 25 deletions app/src/main/java/checkout/checkout_android/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,36 @@
import com.checkout.base.model.Environment;

public class Constants {
private Constants() { }
/**
* Target platform environment
*/
public static final Environment ENVIRONMENT = Environment.SANDBOX;
/**
* Replace with public key from Hub in Sandbox Environment
*/
public static final String PUBLIC_KEY = "pk_test_b37b8b6b-fc9a-483f-a77e-3386b606f90e";

/**
* Target platform environment
*/
public static final Environment ENVIRONMENT = Environment.SANDBOX;
/**
* Replace with public key from Hub in Sandbox Environment
*/
public static final String PUBLIC_KEY = "pk_test_b37b8b6b-fc9a-483f-a77e-3386b606f90e";
/**
* Replace with Secret key from Hub in Sandbox Environment
*/
public static final String SECRET_KEY = "sk_test_568e6077-a08f-4692-9237-cc6c48dcf6aa";
/**
* Replace with Success/Failure Urls from Hub in Sandbox Environment
*/
public static final String SUCCESS_URL = "https://httpstat.us/200?q=Success";
public static final String FAILURE_URL = "https://httpstat.us/200?q=Failure";
/**
* The payment amount to used when creating a payment for 3DS authentication.
* <p>
* Using specific amount values will trigger certain failure modes.
* </p>
*/
public static final Long PAYMENT_AMOUNT = 10000L;
/**
* Replace with public key from Hub in Sandbox Environment, testing key for CVV Tokenization
*/
public static final String PUBLIC_KEY_CVV_TOKENIZATION = "pk_6b30805a-1f3b-4c63-8b75-eb3030109173";
/**
* Replace with Secret key from Hub in Sandbox Environment
*/
public static final String SECRET_KEY = "sk_test_568e6077-a08f-4692-9237-cc6c48dcf6aa";
/**
* Replace with Success/Failure Urls from Hub in Sandbox Environment
*/
public static final String SUCCESS_URL = "https://httpstat.us/200?q=Success";
public static final String FAILURE_URL = "https://httpstat.us/200?q=Failure";
/**
* The payment amount to used when creating a payment for 3DS authentication.
* <p>
* Using specific amount values will trigger certain failure modes.
* </p>
*/
public static final Long PAYMENT_AMOUNT = 10000L;


public static Long backgroundColor = 0XFFFFCDC2L;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package checkout.checkout_android.viewmodels;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class CVVTokenizationViewModel extends ViewModel {

private final MutableLiveData<Boolean> isEnteredAMEXCVVValid = new MutableLiveData<>();

public MutableLiveData<Boolean> getIsEnteredAMEXCVVValid() {
return isEnteredAMEXCVVValid;
}

public void setIsAmexCVVValid(Boolean isCVVValid) {
isEnteredAMEXCVVValid.setValue(isCVVValid);
}
}
14 changes: 12 additions & 2 deletions app/src/main/res/layout/activity_checkout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,29 @@

</LinearLayout>

<FrameLayout
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/margin_xlarge">

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/button_cvv_tokenization"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cvv_tokenization_label"
android:minWidth="@dimen/buy_button_min_width"/>


<androidx.appcompat.widget.AppCompatButton
android:layout_marginTop="@dimen/margin_xlarge"
android:id="@+id/button_buy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_buy"
android:minWidth="@dimen/buy_button_min_width"/>
</FrameLayout>
</LinearLayout>

</LinearLayout>

Expand Down
Loading