Skip to content

Commit

Permalink
PIMOB: Java sample app updated for CVV tokenization
Browse files Browse the repository at this point in the history
  • Loading branch information
chintan-soni-cko committed Oct 12, 2023
1 parent 1236bb1 commit 927cba9
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 54 deletions.
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);

// 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

0 comments on commit 927cba9

Please sign in to comment.