diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9027cba..2e7dcfd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -71,9 +71,17 @@
+
+
+
+
+
diff --git a/app/src/main/java/com/example/bdkipoc/MainActivity.java b/app/src/main/java/com/example/bdkipoc/MainActivity.java
index b5f704e..4c04cae 100644
--- a/app/src/main/java/com/example/bdkipoc/MainActivity.java
+++ b/app/src/main/java/com/example/bdkipoc/MainActivity.java
@@ -19,6 +19,8 @@ import androidx.core.view.WindowInsetsCompat;
import com.google.android.material.button.MaterialButton;
+import com.example.bdkipoc.kredit.CreateTransactionActivity;
+import com.example.bdkipoc.kredit.EmvTransactionActivity;
import com.example.bdkipoc.kredit.CreditCardActivity;
public class MainActivity extends AppCompatActivity {
@@ -160,7 +162,7 @@ public class MainActivity extends AppCompatActivity {
if (cardView != null) {
cardView.setOnClickListener(v -> {
if (cardId == R.id.card_kartu_kredit) {
- startActivity(new Intent(MainActivity.this, CreditCardActivity.class));
+ startActivity(new Intent(MainActivity.this, CreateTransactionActivity.class));
} else if (cardId == R.id.card_kartu_debit) {
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
} else if (cardId == R.id.card_qris) {
diff --git a/app/src/main/java/com/example/bdkipoc/kredit/CreateTransactionActivity.java b/app/src/main/java/com/example/bdkipoc/kredit/CreateTransactionActivity.java
new file mode 100644
index 0000000..cc8f56b
--- /dev/null
+++ b/app/src/main/java/com/example/bdkipoc/kredit/CreateTransactionActivity.java
@@ -0,0 +1,179 @@
+package com.example.bdkipoc.kredit;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import com.example.bdkipoc.R;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * CreateTransactionActivity - Handle amount input and transaction creation
+ */
+public class CreateTransactionActivity extends AppCompatActivity {
+ private static final String TAG = "CreateTransaction";
+
+ // UI Components
+ private TextView tvAmountDisplay;
+ private TextView tvModeIndicator;
+ private Button btnConfirm;
+ private Button btnToggleMode;
+
+ // Amount Input Keypad
+ private Button btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0, btn00, btnClear;
+
+ // State Management
+ private String transactionAmount = "0";
+ private boolean isEMVMode = true; // Default to EMV mode
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_create_transaction);
+
+ initViews();
+ setupListeners();
+ updateAmountDisplay();
+ updateModeDisplay();
+ }
+
+ private void initViews() {
+ // Setup Toolbar
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle("Input Nominal Transaksi");
+ }
+
+ // Initialize UI components
+ tvAmountDisplay = findViewById(R.id.tv_amount_display);
+ tvModeIndicator = findViewById(R.id.tv_mode_indicator);
+ btnConfirm = findViewById(R.id.btn_confirm);
+ btnToggleMode = findViewById(R.id.btn_toggle_mode);
+
+ // Initialize keypad buttons
+ btn1 = findViewById(R.id.btn_1);
+ btn2 = findViewById(R.id.btn_2);
+ btn3 = findViewById(R.id.btn_3);
+ btn4 = findViewById(R.id.btn_4);
+ btn5 = findViewById(R.id.btn_5);
+ btn6 = findViewById(R.id.btn_6);
+ btn7 = findViewById(R.id.btn_7);
+ btn8 = findViewById(R.id.btn_8);
+ btn9 = findViewById(R.id.btn_9);
+ btn0 = findViewById(R.id.btn_0);
+ btn00 = findViewById(R.id.btn_00);
+ btnClear = findViewById(R.id.btn_clear);
+ }
+
+ private void setupListeners() {
+ // Keypad number listeners
+ View.OnClickListener numberClickListener = v -> {
+ Button btn = (Button) v;
+ String number = btn.getText().toString();
+ appendToAmount(number);
+ };
+
+ btn1.setOnClickListener(numberClickListener);
+ btn2.setOnClickListener(numberClickListener);
+ btn3.setOnClickListener(numberClickListener);
+ btn4.setOnClickListener(numberClickListener);
+ btn5.setOnClickListener(numberClickListener);
+ btn6.setOnClickListener(numberClickListener);
+ btn7.setOnClickListener(numberClickListener);
+ btn8.setOnClickListener(numberClickListener);
+ btn9.setOnClickListener(numberClickListener);
+ btn0.setOnClickListener(numberClickListener);
+ btn00.setOnClickListener(numberClickListener);
+
+ // Clear button
+ btnClear.setOnClickListener(v -> clearAmount());
+
+ // Confirm button
+ btnConfirm.setOnClickListener(v -> handleConfirmAmount());
+
+ // Toggle mode button
+ btnToggleMode.setOnClickListener(v -> toggleEMVMode());
+ }
+
+ private void appendToAmount(String number) {
+ // Remove leading zeros and handle maximum amount
+ String currentAmount = transactionAmount.equals("0") ? "" : transactionAmount;
+ String newAmount = currentAmount + number;
+
+ // Limit to reasonable amount (max 999999999 = 9,999,999.99)
+ if (newAmount.length() <= 9) {
+ transactionAmount = newAmount;
+ updateAmountDisplay();
+ }
+ }
+
+ private void clearAmount() {
+ if (transactionAmount.length() > 1) {
+ transactionAmount = transactionAmount.substring(0, transactionAmount.length() - 1);
+ } else {
+ transactionAmount = "0";
+ }
+ updateAmountDisplay();
+ }
+
+ private void updateAmountDisplay() {
+ if (tvAmountDisplay != null) {
+ long amountCents = Long.parseLong(transactionAmount);
+ double amountRupiah = amountCents / 100.0;
+ NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
+ String formattedAmount = formatter.format(amountRupiah);
+ tvAmountDisplay.setText(formattedAmount);
+ }
+ }
+
+ private void handleConfirmAmount() {
+ long amountCents = Long.parseLong(transactionAmount);
+ if (amountCents < 100) { // Minimum Rp 1.00
+ showToast("Minimum amount is Rp 1.00");
+ return;
+ }
+
+ // Start EMV Transaction Activity
+ Intent intent = new Intent(this, EmvTransactionActivity.class);
+ intent.putExtra("TRANSACTION_AMOUNT", transactionAmount);
+ intent.putExtra("EMV_MODE", isEMVMode);
+ startActivity(intent);
+ finish(); // Remove this activity from stack
+ }
+
+ private void toggleEMVMode() {
+ isEMVMode = !isEMVMode;
+ updateModeDisplay();
+ showToast("Mode switched to: " + (isEMVMode ? "EMV Mode" : "Simple Mode"));
+ }
+
+ private void updateModeDisplay() {
+ String mode = isEMVMode ? "EMV Mode (Full Card Data)" : "Simple Mode (Basic Detection)";
+ if (tvModeIndicator != null) {
+ tvModeIndicator.setText("Current Mode: " + mode);
+ }
+ if (btnToggleMode != null) {
+ btnToggleMode.setText(isEMVMode ? "Switch to Simple" : "Switch to EMV");
+ }
+ }
+
+ private void showToast(String message) {
+ Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ onBackPressed();
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bdkipoc/kredit/CreditCardActivity.java b/app/src/main/java/com/example/bdkipoc/kredit/CreditCardActivity.java
index ba3c26c..2318b79 100644
--- a/app/src/main/java/com/example/bdkipoc/kredit/CreditCardActivity.java
+++ b/app/src/main/java/com/example/bdkipoc/kredit/CreditCardActivity.java
@@ -3,20 +3,16 @@ package com.example.bdkipoc.kredit;
import android.content.ClipboardManager;
import android.content.ClipData;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
import android.os.RemoteException;
import android.text.TextUtils;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
-import android.widget.EditText;
-import android.view.View;
-import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
import com.example.bdkipoc.MyApplication;
import com.example.bdkipoc.R;
@@ -24,1010 +20,102 @@ import com.example.bdkipoc.utils.ByteUtil;
import com.example.bdkipoc.utils.Utility;
import com.sunmi.emv.l2.utils.iso8583.TLV;
import com.sunmi.emv.l2.utils.iso8583.TLVUtils;
-import com.sunmi.pay.hardware.aidl.AidlConstants.CardType;
-import com.sunmi.pay.hardware.aidl.bean.CardInfo;
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
-import com.sunmi.pay.hardware.aidlv2.AidlErrorCodeV2;
-import com.sunmi.pay.hardware.aidlv2.bean.EMVCandidateV2;
-import com.sunmi.pay.hardware.aidlv2.bean.PinPadConfigV2;
-import com.sunmi.pay.hardware.aidlv2.emv.EMVListenerV2;
import com.sunmi.pay.hardware.aidlv2.emv.EMVOptV2;
-import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadListenerV2;
-import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadOptV2;
-import com.sunmi.pay.hardware.aidlv2.readcard.CheckCardCallbackV2;
+import java.text.NumberFormat;
import java.util.Arrays;
-import java.util.List;
+import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.text.NumberFormat;
-import java.util.Locale;
/**
- * Enhanced CreditCardActivity with EMV capabilities and Amount Input
+ * CreditCardActivity - Display detailed transaction results and TLV data
*/
public class CreditCardActivity extends AppCompatActivity {
private static final String TAG = "CreditCard";
- // UI State Constants
- private static final int STATE_INPUT_AMOUNT = 0;
- private static final int STATE_SCANNING = 1;
- private static final int STATE_EMV_PROCESS = 2;
-
// UI Components
- private TextView tvResult;
- private TextView tvModeIndicator;
- private TextView tvAmountDisplay;
- private EditText etAmountInput;
- private Button btnCheckCard;
- private Button btnToggleMode;
+ private TextView tvTransactionSummary;
+ private TextView tvCardData;
private Button btnCopyData;
- private Button btnClearData;
+ private Button btnNewTransaction;
+ private Button btnPrintReceipt;
- // Amount Input Keypad
- private Button btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0, btn00, btnClear;
- private View layoutAmountInput;
- private View layoutCardResult;
-
- // State Management
- private int currentState = STATE_INPUT_AMOUNT;
- private boolean checkingCard = false;
- private String transactionAmount = "0";
+ // Transaction Data
+ private String transactionAmount;
+ private String cardType;
+ private boolean isEMVMode;
+ private String cardNo;
+ private Bundle cardData;
// EMV Components
private EMVOptV2 mEMVOptV2;
- private PinPadOptV2 mPinPadOptV2;
-
- // EMV Process Variables
- private int mCardType;
- private String mCardNo;
- private int mPinType;
- private String mCertInfo;
- private int mSelectIndex;
- private int mProcessStep;
- private AlertDialog mAppSelectDialog;
- private boolean isEMVMode = false;
-
- // EMV Process Constants
- private static final int EMV_APP_SELECT = 1;
- private static final int EMV_FINAL_APP_SELECT = 2;
- private static final int EMV_CONFIRM_CARD_NO = 3;
- private static final int EMV_CERT_VERIFY = 4;
- private static final int EMV_SHOW_PIN_PAD = 5;
- private static final int EMV_ONLINE_PROCESS = 6;
- private static final int EMV_SIGNATURE = 7;
- private static final int EMV_TRANS_SUCCESS = 888;
- private static final int EMV_TRANS_FAIL = 999;
-
- private static final int PIN_CLICK_NUMBER = 50;
- private static final int PIN_CLICK_PIN = 51;
- private static final int PIN_CLICK_CONFIRM = 52;
- private static final int PIN_CLICK_CANCEL = 53;
- private static final int PIN_ERROR = 54;
-
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case EMV_FINAL_APP_SELECT:
- importFinalAppSelectStatus(0);
- break;
-
- case EMV_APP_SELECT:
- String[] candiNames = (String[]) msg.obj;
- showAppSelectDialog(candiNames);
- break;
-
- case EMV_CONFIRM_CARD_NO:
- showCardNumberConfirmation();
- break;
-
- case EMV_CERT_VERIFY:
- showCertificateVerification();
- break;
-
- case EMV_SHOW_PIN_PAD:
- dismissLoadingDialog();
- android.util.Log.d(TAG, "Initializing PIN pad...");
- initPinPad();
- break;
-
- case EMV_ONLINE_PROCESS:
- mockOnlineProcess();
- break;
-
- case EMV_SIGNATURE:
- importSignatureStatus(0);
- break;
-
- case PIN_CLICK_PIN:
- android.util.Log.d(TAG, "PIN input confirmed");
- importPinInputStatus(0);
- break;
-
- case PIN_CLICK_CONFIRM:
- android.util.Log.d(TAG, "PIN confirm without input (bypass)");
- importPinInputStatus(2);
- break;
-
- case PIN_CLICK_CANCEL:
- showToast("PIN input cancelled by user");
- importPinInputStatus(1);
- break;
-
- case PIN_ERROR:
- android.util.Log.e(TAG, "PIN Error: " + msg.obj + " -- " + msg.arg1);
- showToast("PIN Error: " + msg.obj);
- importPinInputStatus(3);
- break;
-
- case EMV_TRANS_FAIL:
- resetToAmountInput();
- showToast("Transaction failed: " + msg.obj + " -- " + msg.arg1);
- break;
-
- case EMV_TRANS_SUCCESS:
- getTlvData(); // Get complete card data with amount
- showToast("Transaction successful!");
- break;
- }
- }
- };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- android.util.Log.d(TAG, "onCreate called");
setContentView(R.layout.activity_credit_card);
+ getIntentData();
+ initViews();
initEMVComponents();
- initView();
- initEMVData();
- checkPaySDKStatus();
- updateUIForCurrentState();
+ loadCardData();
+ }
+
+ private void getIntentData() {
+ Intent intent = getIntent();
+ transactionAmount = intent.getStringExtra("TRANSACTION_AMOUNT");
+ cardType = intent.getStringExtra("CARD_TYPE");
+ isEMVMode = intent.getBooleanExtra("EMV_MODE", true);
+ cardNo = intent.getStringExtra("CARD_NO");
+ cardData = intent.getBundleExtra("CARD_DATA");
+
+ if (transactionAmount == null) {
+ transactionAmount = "0";
+ }
+ }
+
+ private void initViews() {
+ // Setup Toolbar
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle("Detail Transaksi");
+ }
+
+ tvTransactionSummary = findViewById(R.id.tv_transaction_summary);
+ tvCardData = findViewById(R.id.tv_card_data);
+ btnCopyData = findViewById(R.id.btn_copy_data);
+ btnNewTransaction = findViewById(R.id.btn_new_transaction);
+ btnPrintReceipt = findViewById(R.id.btn_print_receipt);
+
+ btnCopyData.setOnClickListener(v -> copyCardDataToClipboard());
+ btnNewTransaction.setOnClickListener(v -> startNewTransaction());
+ btnPrintReceipt.setOnClickListener(v -> printReceipt());
}
private void initEMVComponents() {
if (MyApplication.app != null) {
mEMVOptV2 = MyApplication.app.emvOptV2;
- mPinPadOptV2 = MyApplication.app.pinPadOptV2;
- android.util.Log.d(TAG, "EMV components initialized");
+ android.util.Log.d(TAG, "EMV components initialized for TLV data retrieval");
+ }
+ }
+
+ private void loadCardData() {
+ if (isEMVMode && mEMVOptV2 != null) {
+ loadEMVTlvData();
} else {
- android.util.Log.e(TAG, "MyApplication.app is null");
+ loadSimpleCardData();
}
}
- private void initEMVData() {
- try {
- if (mEMVOptV2 != null) {
- mEMVOptV2.initEmvProcess();
- initEmvTlvData();
- android.util.Log.d(TAG, "EMV data initialized successfully");
- }
- } catch (Exception e) {
- android.util.Log.e(TAG, "Error initializing EMV data: " + e.getMessage());
- e.printStackTrace();
- }
- }
-
- private void initEmvTlvData() {
- try {
- // Set PayPass (MasterCard) TLV data
- String[] tagsPayPass = {"DF8117", "DF8118", "DF8119", "DF811F", "DF811E", "DF812C",
- "DF8123", "DF8124", "DF8125", "DF8126", "DF811B", "DF811D", "DF8122", "DF8120", "DF8121"};
- String[] valuesPayPass = {"E0", "F8", "F8", "E8", "00", "00",
- "000000000000", "000000100000", "999999999999", "000000100000",
- "30", "02", "0000000000", "000000000000", "000000000000"};
- mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, tagsPayPass, valuesPayPass);
-
- // Set AMEX (American Express) TLV data
- String[] tagsAE = {"9F6D", "9F6E", "9F33", "9F35", "DF8168", "DF8167", "DF8169", "DF8170"};
- String[] valuesAE = {"C0", "D8E00000", "E0E888", "22", "00", "00", "00", "60"};
- mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_AE, tagsAE, valuesAE);
-
- // Set JCB TLV data
- String[] tagsJCB = {"9F53", "DF8161"};
- String[] valuesJCB = {"708000", "7F00"};
- mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_JCB, tagsJCB, valuesJCB);
-
- // Set DPAS TLV data
- String[] tagsDPAS = {"9F66"};
- String[] valuesDPAS = {"B600C000"};
- mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_DPAS, tagsDPAS, valuesDPAS);
-
- // Set Flash TLV data
- String[] tagsFLASH = {"9F58", "9F59", "9F5A", "9F5D", "9F5E"};
- String[] valuesFLASH = {"03", "D88700", "00", "000000000000", "E000"};
- mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_FLASH, tagsFLASH, valuesFLASH);
-
- // Set Pure TLV data
- String[] tagsPURE = {"DF7F", "DF8134", "DF8133"};
- String[] valuesPURE = {"A0000007271010", "DF", "36006043F9"};
- mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PURE, tagsPURE, valuesPURE);
-
- Bundle bundle = new Bundle();
- bundle.putBoolean("optOnlineRes", true);
- mEMVOptV2.setTermParamEx(bundle);
-
- } catch (RemoteException e) {
- android.util.Log.e(TAG, "Error setting EMV TLV data: " + e.getMessage());
- e.printStackTrace();
- }
- }
-
- private void checkPaySDKStatus() {
- if (MyApplication.app != null) {
- android.util.Log.d(TAG, "MyApplication.app exists");
- android.util.Log.d(TAG, "PaySDK connected: " + MyApplication.app.isConnectPaySDK());
- android.util.Log.d(TAG, "readCardOptV2 null: " + (MyApplication.app.readCardOptV2 == null));
- android.util.Log.d(TAG, "emvOptV2 null: " + (MyApplication.app.emvOptV2 == null));
- } else {
- android.util.Log.e(TAG, "MyApplication.app is null");
- }
- }
-
- private void initView() {
- android.util.Log.d(TAG, "initView called");
-
- // Setup Toolbar as ActionBar
- androidx.appcompat.widget.Toolbar toolbar = findViewById(R.id.toolbar);
- if (toolbar != null) {
- setSupportActionBar(toolbar);
- if (getSupportActionBar() != null) {
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setTitle("Enhanced Card Reader with EMV");
- }
- }
-
- // Initialize UI components
- tvResult = findViewById(R.id.tv_result);
- tvModeIndicator = findViewById(R.id.tv_mode_indicator);
- tvAmountDisplay = findViewById(R.id.tv_amount_display);
- etAmountInput = findViewById(R.id.et_amount_input);
- btnCheckCard = findViewById(R.id.btn_check_card);
- btnToggleMode = findViewById(R.id.btn_toggle_mode);
- btnCopyData = findViewById(R.id.btn_copy_data);
- btnClearData = findViewById(R.id.btn_clear_data);
-
- // Initialize layouts
- layoutAmountInput = findViewById(R.id.layout_amount_input);
- layoutCardResult = findViewById(R.id.layout_card_result);
-
- // Initialize keypad buttons
- btn1 = findViewById(R.id.btn_1);
- btn2 = findViewById(R.id.btn_2);
- btn3 = findViewById(R.id.btn_3);
- btn4 = findViewById(R.id.btn_4);
- btn5 = findViewById(R.id.btn_5);
- btn6 = findViewById(R.id.btn_6);
- btn7 = findViewById(R.id.btn_7);
- btn8 = findViewById(R.id.btn_8);
- btn9 = findViewById(R.id.btn_9);
- btn0 = findViewById(R.id.btn_0);
- btn00 = findViewById(R.id.btn_00);
- btnClear = findViewById(R.id.btn_clear);
-
- setupKeypadListeners();
- setupButtonListeners();
-
- // Initialize amount display
- updateAmountDisplay();
- }
-
- private void setupKeypadListeners() {
- View.OnClickListener numberClickListener = v -> {
- Button btn = (Button) v;
- String number = btn.getText().toString();
- appendToAmount(number);
- };
-
- btn1.setOnClickListener(numberClickListener);
- btn2.setOnClickListener(numberClickListener);
- btn3.setOnClickListener(numberClickListener);
- btn4.setOnClickListener(numberClickListener);
- btn5.setOnClickListener(numberClickListener);
- btn6.setOnClickListener(numberClickListener);
- btn7.setOnClickListener(numberClickListener);
- btn8.setOnClickListener(numberClickListener);
- btn9.setOnClickListener(numberClickListener);
- btn0.setOnClickListener(numberClickListener);
- btn00.setOnClickListener(numberClickListener);
-
- btnClear.setOnClickListener(v -> clearAmount());
- }
-
- private void setupButtonListeners() {
- if (btnToggleMode != null) {
- btnToggleMode.setOnClickListener(v -> toggleEMVMode());
- }
-
- if (btnCheckCard != null) {
- btnCheckCard.setOnClickListener(v -> handleMainButtonClick());
- }
-
- if (btnCopyData != null) {
- btnCopyData.setOnClickListener(v -> copyCardDataToClipboard());
- }
-
- if (btnClearData != null) {
- btnClearData.setOnClickListener(v -> clearCardData());
- }
- }
-
- private void appendToAmount(String number) {
- if (currentState != STATE_INPUT_AMOUNT) return;
-
- // Remove leading zeros and handle maximum amount
- String currentAmount = transactionAmount.equals("0") ? "" : transactionAmount;
- String newAmount = currentAmount + number;
-
- // Limit to reasonable amount (max 999999999 = 9,999,999.99)
- if (newAmount.length() <= 9) {
- transactionAmount = newAmount;
- updateAmountDisplay();
- }
- }
-
- private void clearAmount() {
- if (currentState != STATE_INPUT_AMOUNT) return;
-
- if (transactionAmount.length() > 1) {
- transactionAmount = transactionAmount.substring(0, transactionAmount.length() - 1);
- } else {
- transactionAmount = "0";
- }
- updateAmountDisplay();
- }
-
- private void updateAmountDisplay() {
- if (tvAmountDisplay != null) {
- long amountCents = Long.parseLong(transactionAmount);
- double amountRupiah = amountCents / 100.0;
- NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
- String formattedAmount = formatter.format(amountRupiah);
- tvAmountDisplay.setText(formattedAmount);
- }
-
- if (etAmountInput != null) {
- etAmountInput.setText(transactionAmount);
- }
- }
-
- private void handleMainButtonClick() {
- switch (currentState) {
- case STATE_INPUT_AMOUNT:
- handleConfirmAmount();
- break;
- case STATE_SCANNING:
- handleScanAction();
- break;
- case STATE_EMV_PROCESS:
- handleEMVAction();
- break;
- }
- }
-
- private void handleConfirmAmount() {
- long amountCents = Long.parseLong(transactionAmount);
- if (amountCents < 100) { // Minimum Rp 1.00
- showToast("Minimum amount is Rp 1.00");
- return;
- }
-
- // Transition to scanning state
- currentState = STATE_SCANNING;
- updateUIForCurrentState();
-
- android.util.Log.d(TAG, "Amount confirmed: " + transactionAmount + " cents");
- showToast("Amount confirmed: " + formatAmount(amountCents));
- }
-
- private void handleScanAction() {
- if (mProcessStep == 0) {
- if (checkingCard) {
- stopCardCheck();
- } else {
- startCardCheck();
- }
- } else if (mProcessStep == EMV_CONFIRM_CARD_NO) {
- android.util.Log.d(TAG, "User confirmed card number");
- showLoadingDialog("Processing card confirmation...");
- btnCheckCard.setText("Processing...");
- importCardNoStatus(0);
- } else if (mProcessStep == EMV_CERT_VERIFY) {
- android.util.Log.d(TAG, "User confirmed certificate");
- showLoadingDialog("Processing certificate...");
- btnCheckCard.setText("Processing...");
- importCertStatus(0);
- }
- }
-
- private void handleEMVAction() {
- // Handle EMV process actions (same as before)
- android.util.Log.d(TAG, "EMV action in process step: " + mProcessStep);
- }
-
- private void updateUIForCurrentState() {
- runOnUiThread(() -> {
- switch (currentState) {
- case STATE_INPUT_AMOUNT:
- showAmountInput();
- break;
- case STATE_SCANNING:
- showScanningUI();
- break;
- case STATE_EMV_PROCESS:
- // UI handled by EMV process
- break;
- }
- });
- }
-
- private void showAmountInput() {
- layoutAmountInput.setVisibility(View.VISIBLE);
- layoutCardResult.setVisibility(View.GONE);
-
- btnCheckCard.setText("Konfirmasi");
- btnCheckCard.setEnabled(true);
-
- if (tvResult != null) {
- tvResult.setText("Masukkan nominal pembayaran\nGunakan keypad di bawah untuk memasukkan nominal");
- }
-
- updateModeDisplay();
- updateAmountDisplay();
- }
-
- private void showScanningUI() {
- layoutAmountInput.setVisibility(View.GONE);
- layoutCardResult.setVisibility(View.VISIBLE);
-
- btnCheckCard.setText("Start Scanning");
- btnCheckCard.setEnabled(true);
-
- if (tvResult != null) {
- String mode = isEMVMode ? "EMV Mode (Full Card Data)" : "Simple Mode (Basic Detection)";
- tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nReady to scan card...\nCurrent Mode: " + mode +
- "\nPlace your card on the reader");
- }
-
- updateModeDisplay();
- }
-
- private void toggleEMVMode() {
- isEMVMode = !isEMVMode;
- updateModeDisplay();
- android.util.Log.d(TAG, "EMV Mode toggled to: " + isEMVMode);
-
- if (btnToggleMode == null) {
- showToast("Mode switched to: " + (isEMVMode ? "EMV Mode" : "Simple Mode"));
- }
- }
-
- private void updateModeDisplay() {
- String mode = isEMVMode ? "EMV Mode (Full Card Data)" : "Simple Mode (Basic Detection)";
-
- if (tvModeIndicator != null) {
- tvModeIndicator.setText("Current Mode: " + mode);
- }
- }
-
- private String formatAmount(long amountCents) {
- double amountRupiah = amountCents / 100.0;
- NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
- return formatter.format(amountRupiah);
- }
-
- // ====== CARD SCANNING METHODS (Same as before) ======
- private void startCardCheck() {
- try {
- if (isEMVMode) {
- startEMVCardCheck();
- } else {
- startSimpleCardCheck();
- }
- checkingCard = true;
- btnCheckCard.setText("Stop Scanning");
- currentState = STATE_EMV_PROCESS;
- } catch (Exception e) {
- android.util.Log.e(TAG, "Error starting card check: " + e.getMessage());
- updateUI("Error starting card check: " + e.getMessage(), false);
- }
- }
-
- private void startSimpleCardCheck() {
- try {
- if (!validateApplicationState()) {
- return;
- }
-
- if (!MyApplication.app.isConnectPaySDK()) {
- tvResult.setText("Connecting to PaySDK...");
- android.util.Log.d(TAG, "PaySDK not connected, binding service...");
- MyApplication.app.bindPaySDKService();
-
- btnCheckCard.postDelayed(() -> {
- if (MyApplication.app.isConnectPaySDK() && MyApplication.app.readCardOptV2 != null) {
- startSimpleCardScan();
- } else {
- updateUI("Error: Failed to connect to PaySDK", false);
- }
- }, 2000);
- return;
- }
-
- if (MyApplication.app.readCardOptV2 == null) {
- updateUI("Error: Card reader not initialized", false);
- android.util.Log.e(TAG, "readCardOptV2 is null");
- return;
- }
-
- startSimpleCardScan();
-
- } catch (Exception e) {
- e.printStackTrace();
- android.util.Log.e(TAG, "Error in startSimpleCardCheck: " + e.getMessage());
- updateUI("Error starting card scan: " + e.getMessage(), false);
- }
- }
-
- private void startEMVCardCheck() {
- try {
- if (!validateApplicationState()) {
- return;
- }
-
- if (mEMVOptV2 == null) {
- updateUI("Error: EMV not initialized", false);
- android.util.Log.e(TAG, "EMV not initialized");
- return;
- }
-
- mEMVOptV2.initEmvProcess();
- initEmvTlvData();
-
- tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nEMV Mode: Starting card scan...\nPlease insert, swipe, or tap your card");
-
- int cardType = AidlConstantsV2.CardType.NFC.getValue() | AidlConstantsV2.CardType.IC.getValue();
- android.util.Log.d(TAG, "Starting EMV checkCard with cardType: " + cardType);
-
- MyApplication.app.readCardOptV2.checkCard(cardType, mEMVCheckCardCallback, 60);
-
- } catch (Exception e) {
- e.printStackTrace();
- android.util.Log.e(TAG, "Error in startEMVCardCheck: " + e.getMessage());
- updateUI("Error starting EMV card scan: " + e.getMessage(), false);
- }
- }
-
- private void startSimpleCardScan() {
- try {
- int cardType = CardType.MAGNETIC.getValue() | CardType.IC.getValue() | CardType.NFC.getValue();
- tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nSimple Mode: Starting card scan...\nPlease insert, swipe, or tap your card");
-
- android.util.Log.d(TAG, "Starting simple checkCard with cardType: " + cardType);
-
- MyApplication.app.readCardOptV2.checkCard(cardType, mSimpleCheckCardCallback, 60);
-
- } catch (Exception e) {
- e.printStackTrace();
- android.util.Log.e(TAG, "Error in startSimpleCardScan: " + e.getMessage());
- updateUI("Error starting card scan: " + e.getMessage(), false);
- }
- }
-
- private void stopCardCheck() {
- try {
- if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) {
- MyApplication.app.readCardOptV2.cancelCheckCard();
- }
- checkingCard = false;
- btnCheckCard.setText("Start Scanning");
- currentState = STATE_SCANNING;
- updateUIForCurrentState();
- } catch (Exception e) {
- android.util.Log.e(TAG, "Error stopping card check: " + e.getMessage());
- checkingCard = false;
- btnCheckCard.setText("Start Scanning");
- }
- }
-
- private boolean validateApplicationState() {
- if (MyApplication.app == null) {
- updateUI("Error: Application not initialized", false);
- android.util.Log.e(TAG, "MyApplication.app is null");
- return false;
- }
- return true;
- }
-
- // ====== SIMPLE CARD DETECTION CALLBACK (Same as before) ======
- private final CheckCardCallbackV2 mSimpleCheckCardCallback = new CheckCardCallbackV2.Stub() {
- @Override
- public void findMagCard(Bundle info) throws RemoteException {
- android.util.Log.d(TAG, "Simple Mode: findMagCard callback triggered");
- runOnUiThread(() -> handleSimpleMagCardResult(info));
- }
-
- @Override
- public void findICCard(String atr) throws RemoteException {
- android.util.Log.d(TAG, "Simple Mode: findICCard callback triggered with ATR: " + atr);
- Bundle info = new Bundle();
- info.putString("atr", atr);
- runOnUiThread(() -> handleSimpleICCardResult(info));
- }
-
- @Override
- public void findRFCard(String uuid) throws RemoteException {
- android.util.Log.d(TAG, "Simple Mode: findRFCard callback triggered with UUID: " + uuid);
- Bundle info = new Bundle();
- info.putString("uuid", uuid);
- runOnUiThread(() -> handleSimpleRFCardResult(info));
- }
-
- @Override
- public void onError(int code, String message) throws RemoteException {
- android.util.Log.e(TAG, "Simple Mode: onError callback triggered - Code: " + code + ", Message: " + message);
- Bundle info = new Bundle();
- info.putInt("code", code);
- info.putString("message", message);
- runOnUiThread(() -> handleSimpleErrorResult(info));
- }
-
- @Override
- public void findICCardEx(Bundle info) throws RemoteException {
- android.util.Log.d(TAG, "Simple Mode: findICCardEx callback triggered");
- runOnUiThread(() -> handleSimpleICCardResult(info));
- }
-
- @Override
- public void findRFCardEx(Bundle info) throws RemoteException {
- android.util.Log.d(TAG, "Simple Mode: findRFCardEx callback triggered");
- runOnUiThread(() -> handleSimpleRFCardResult(info));
- }
-
- @Override
- public void onErrorEx(Bundle info) throws RemoteException {
- android.util.Log.e(TAG, "Simple Mode: onErrorEx callback triggered");
- runOnUiThread(() -> handleSimpleErrorResult(info));
- }
- };
-
- // ====== EMV CARD DETECTION CALLBACK (Same as before) ======
- private final CheckCardCallbackV2 mEMVCheckCardCallback = new CheckCardCallbackV2.Stub() {
- @Override
- public void findMagCard(Bundle info) throws RemoteException {
- android.util.Log.d(TAG, "EMV Mode: findMagCard callback triggered");
- runOnUiThread(() -> handleEMVMagCardResult(info));
- }
-
- @Override
- public void findICCard(String atr) throws RemoteException {
- android.util.Log.d(TAG, "EMV Mode: findICCard callback triggered with ATR: " + atr);
- MyApplication.app.basicOptV2.buzzerOnDevice(1, 2750, 200, 0);
- mCardType = AidlConstantsV2.CardType.IC.getValue();
- runOnUiThread(() -> startEMVTransactionProcess());
- }
-
- @Override
- public void findRFCard(String uuid) throws RemoteException {
- android.util.Log.d(TAG, "EMV Mode: findRFCard callback triggered with UUID: " + uuid);
- mCardType = AidlConstantsV2.CardType.NFC.getValue();
- runOnUiThread(() -> startEMVTransactionProcess());
- }
-
- @Override
- public void onError(int code, String message) throws RemoteException {
- android.util.Log.e(TAG, "EMV Mode: onError callback triggered - Code: " + code + ", Message: " + message);
- Bundle info = new Bundle();
- info.putInt("code", code);
- info.putString("message", message);
- runOnUiThread(() -> handleEMVErrorResult(info));
- }
-
- @Override
- public void findICCardEx(Bundle info) throws RemoteException {
- android.util.Log.d(TAG, "EMV Mode: findICCardEx callback triggered");
- mCardType = AidlConstantsV2.CardType.IC.getValue();
- runOnUiThread(() -> startEMVTransactionProcess());
- }
-
- @Override
- public void findRFCardEx(Bundle info) throws RemoteException {
- android.util.Log.d(TAG, "EMV Mode: findRFCardEx callback triggered");
- mCardType = AidlConstantsV2.CardType.NFC.getValue();
- runOnUiThread(() -> startEMVTransactionProcess());
- }
-
- @Override
- public void onErrorEx(Bundle info) throws RemoteException {
- android.util.Log.e(TAG, "EMV Mode: onErrorEx callback triggered");
- runOnUiThread(() -> handleEMVErrorResult(info));
- }
- };
-
- // ====== SIMPLE CARD RESULT HANDLERS (Updated with amount) ======
- private void handleSimpleMagCardResult(Bundle info) {
- logMagneticCardData(info);
-
- String track1 = Utility.null2String(info.getString("TRACK1"));
- String track2 = Utility.null2String(info.getString("TRACK2"));
- String track3 = Utility.null2String(info.getString("TRACK3"));
-
- StringBuilder sb = new StringBuilder();
- sb.append("==== TRANSACTION SUMMARY ====\n");
- sb.append("Amount: ").append(formatAmount(Long.parseLong(transactionAmount))).append("\n");
- sb.append("Payment Method: Magnetic Card\n\n");
- sb.append("MAGNETIC CARD DETECTED (Simple Mode)\n");
- sb.append("Track1: ").append(track1.isEmpty() ? "N/A" : track1).append("\n");
- sb.append("Track2: ").append(track2.isEmpty() ? "N/A" : track2).append("\n");
- sb.append("Track3: ").append(track3.isEmpty() ? "N/A" : track3);
-
- updateUI(sb.toString(), true);
- }
-
- private void handleSimpleICCardResult(Bundle info) {
- logICCardData(info);
-
- String atr = info.getString("atr", "");
- int cardType = info.getInt("cardType", -1);
-
- StringBuilder sb = new StringBuilder();
- sb.append("==== TRANSACTION SUMMARY ====\n");
- sb.append("Amount: ").append(formatAmount(Long.parseLong(transactionAmount))).append("\n");
- sb.append("Payment Method: IC Card\n\n");
- sb.append("IC CARD DETECTED (Simple Mode)\n");
- sb.append("ATR: ").append(atr.isEmpty() ? "N/A" : atr).append("\n");
- if (cardType != -1) {
- sb.append("Card Type: ").append(cardType).append("\n");
- }
-
- updateUI(sb.toString(), true);
- }
-
- private void handleSimpleRFCardResult(Bundle info) {
- logRFCardData(info);
-
- String uuid = info.getString("uuid", "");
- String ats = info.getString("ats", "");
- int sak = info.getInt("sak", -1);
-
- StringBuilder sb = new StringBuilder();
- sb.append("==== TRANSACTION SUMMARY ====\n");
- sb.append("Amount: ").append(formatAmount(Long.parseLong(transactionAmount))).append("\n");
- sb.append("Payment Method: NFC/RF Card\n\n");
- sb.append("RF/NFC CARD DETECTED (Simple Mode)\n");
- sb.append("UUID: ").append(uuid.isEmpty() ? "N/A" : uuid).append("\n");
- if (!ats.isEmpty()) {
- sb.append("ATS: ").append(ats).append("\n");
- }
- if (sak != -1) {
- sb.append("SAK: ").append(String.format("0x%02X", sak)).append("\n");
- sb.append("Type: ").append(analyzeCardTypeBySAK(sak)).append("\n");
- }
-
- updateUI(sb.toString(), true);
- }
-
- private void handleSimpleErrorResult(Bundle info) {
- logCardError(info);
-
- int code = info.getInt("code", -1);
- String msg = info.getString("message", "Unknown error");
- String error = "Error: " + msg + " (Code: " + code + ")";
- updateUI(error, true);
- }
-
- // ====== EMV CARD RESULT HANDLERS (Same as before) ======
- private void handleEMVMagCardResult(Bundle info) {
- handleSimpleMagCardResult(info);
- String currentText = tvResult.getText().toString();
- tvResult.setText(currentText.replace("(Simple Mode)", "(EMV Mode - Magnetic)"));
- }
-
- private void handleEMVErrorResult(Bundle info) {
- logCardError(info);
-
- int code = info.getInt("code", -1);
- String msg = info.getString("message", "Unknown error");
- String error = "EMV Error: " + msg + " (Code: " + code + ")";
- updateUI(error, true);
- }
-
- // ====== EMV TRANSACTION PROCESS (Updated with amount) ======
- private void startEMVTransactionProcess() {
- android.util.Log.d(TAG, "Starting EMV transaction process");
- try {
- Bundle bundle = new Bundle();
- bundle.putString("amount", transactionAmount); // Use actual transaction amount
- bundle.putString("transType", "00");
-
- if (mCardType == AidlConstantsV2.CardType.NFC.getValue()) {
- bundle.putInt("flowType", AidlConstantsV2.EMV.FlowType.TYPE_EMV_STANDARD);
- } else {
- bundle.putInt("flowType", AidlConstantsV2.EMV.FlowType.TYPE_EMV_STANDARD);
- }
- bundle.putInt("cardType", mCardType);
-
- tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nEMV processing started...\nReading card data...");
-
- mEMVOptV2.transactProcessEx(bundle, mEMVListener);
- } catch (Exception e) {
- android.util.Log.e(TAG, "Error starting EMV transaction: " + e.getMessage());
- e.printStackTrace();
- updateUI("Error starting EMV transaction: " + e.getMessage(), true);
- }
- }
-
- // ====== EMV LISTENER (Same as before) ======
- private final EMVListenerV2 mEMVListener = new EMVListenerV2.Stub() {
-
- @Override
- public void onWaitAppSelect(List appNameList, boolean isFirstSelect) throws RemoteException {
- android.util.Log.d(TAG, "onWaitAppSelect isFirstSelect:" + isFirstSelect);
- mProcessStep = EMV_APP_SELECT;
- String[] candidateNames = getCandidateNames(appNameList);
- mHandler.obtainMessage(EMV_APP_SELECT, candidateNames).sendToTarget();
- }
-
- @Override
- public void onAppFinalSelect(String tag9F06Value) throws RemoteException {
- android.util.Log.d(TAG, "onAppFinalSelect tag9F06Value:" + tag9F06Value);
- mProcessStep = EMV_FINAL_APP_SELECT;
- mHandler.obtainMessage(EMV_FINAL_APP_SELECT, tag9F06Value).sendToTarget();
- }
-
- @Override
- public void onConfirmCardNo(String cardNo) throws RemoteException {
- android.util.Log.d(TAG, "onConfirmCardNo cardNo:" + maskCardNumber(cardNo));
- mCardNo = cardNo;
- mProcessStep = EMV_CONFIRM_CARD_NO;
- mHandler.obtainMessage(EMV_CONFIRM_CARD_NO).sendToTarget();
- }
-
- @Override
- public void onRequestShowPinPad(int pinType, int remainTime) throws RemoteException {
- android.util.Log.d(TAG, "onRequestShowPinPad pinType:" + pinType + " remainTime:" + remainTime);
- mPinType = pinType;
- if (mCardNo == null) {
- mCardNo = getCardNo();
- }
- mProcessStep = EMV_SHOW_PIN_PAD;
- mHandler.obtainMessage(EMV_SHOW_PIN_PAD).sendToTarget();
- }
-
- @Override
- public void onRequestSignature() throws RemoteException {
- android.util.Log.d(TAG, "onRequestSignature");
- mProcessStep = EMV_SIGNATURE;
- mHandler.obtainMessage(EMV_SIGNATURE).sendToTarget();
- }
-
- @Override
- public void onCertVerify(int certType, String certInfo) throws RemoteException {
- android.util.Log.d(TAG, "onCertVerify certType:" + certType + " certInfo:" + certInfo);
- mCertInfo = certInfo;
- mProcessStep = EMV_CERT_VERIFY;
- mHandler.obtainMessage(EMV_CERT_VERIFY).sendToTarget();
- }
-
- @Override
- public void onOnlineProc() throws RemoteException {
- android.util.Log.d(TAG, "onOnlineProcess");
- mProcessStep = EMV_ONLINE_PROCESS;
- mHandler.obtainMessage(EMV_ONLINE_PROCESS).sendToTarget();
- }
-
- @Override
- public void onCardDataExchangeComplete() throws RemoteException {
- android.util.Log.d(TAG, "onCardDataExchangeComplete");
- if (mCardType == AidlConstantsV2.CardType.NFC.getValue()) {
- MyApplication.app.basicOptV2.buzzerOnDevice(1, 2750, 200, 0);
- }
- }
-
- @Override
- public void onTransResult(int code, String desc) throws RemoteException {
- if (mCardNo == null) {
- mCardNo = getCardNo();
- }
- android.util.Log.d(TAG, "onTransResult code:" + code + " desc:" + desc);
-
- if (code == 1 || code == 2 || code == 5 || code == 6) {
- mHandler.obtainMessage(EMV_TRANS_SUCCESS, code, code, desc).sendToTarget();
- } else {
- mHandler.obtainMessage(EMV_TRANS_FAIL, code, code, desc).sendToTarget();
- }
- }
-
- @Override
- public void onConfirmationCodeVerified() throws RemoteException {
- android.util.Log.d(TAG, "onConfirmationCodeVerified");
- }
-
- @Override
- public void onRequestDataExchange(String cardNo) throws RemoteException {
- android.util.Log.d(TAG, "onRequestDataExchange,cardNo:" + cardNo);
- mEMVOptV2.importDataExchangeStatus(0);
- }
-
- @Override
- public void onTermRiskManagement() throws RemoteException {
- android.util.Log.d(TAG, "onTermRiskManagement");
- mEMVOptV2.importTermRiskManagementStatus(0);
- }
-
- @Override
- public void onPreFirstGenAC() throws RemoteException {
- android.util.Log.d(TAG, "onPreFirstGenAC");
- mEMVOptV2.importPreFirstGenACStatus(0);
- }
-
- @Override
- public void onDataStorageProc(String[] containerID, String[] containerContent) throws RemoteException {
- android.util.Log.d(TAG, "onDataStorageProc");
- String[] tags = new String[0];
- String[] values = new String[0];
- mEMVOptV2.importDataStorage(tags, values);
- }
- };
-
- // ====== EMV DIALOG HANDLERS (Same as before) ======
- private void showAppSelectDialog(String[] candidateNames) {
- mAppSelectDialog = new AlertDialog.Builder(this)
- .setTitle("Please select application")
- .setNegativeButton("Cancel", (dialog, which) -> importAppSelect(-1))
- .setPositiveButton("OK", (dialog, which) -> importAppSelect(mSelectIndex))
- .setSingleChoiceItems(candidateNames, 0, (dialog, which) -> mSelectIndex = which)
- .create();
- mSelectIndex = 0;
- mAppSelectDialog.show();
- }
-
- private void showCardNumberConfirmation() {
- runOnUiThread(() -> {
- dismissLoadingDialog();
-
- String displayText = "Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nCard Number: " + maskCardNumber(mCardNo) +
- "\n\nPlease confirm this card number to continue";
- tvResult.setText(displayText);
-
- btnCheckCard.setText("Confirm Card Number");
- mProcessStep = EMV_CONFIRM_CARD_NO;
-
- android.util.Log.d(TAG, "Card number confirmation UI updated, waiting for user input");
- });
- }
-
- private void showCertificateVerification() {
- runOnUiThread(() -> {
- dismissLoadingDialog();
-
- String displayText = "Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nCertificate Information:\n" + mCertInfo +
- "\n\nPlease confirm certificate to continue";
- tvResult.setText(displayText);
-
- btnCheckCard.setText("Confirm Certificate");
- mProcessStep = EMV_CERT_VERIFY;
-
- android.util.Log.d(TAG, "Certificate verification UI updated, waiting for user input");
- });
- }
-
- // ====== TLV DATA RETRIEVAL (Updated with transaction summary) ======
- private void getTlvData() {
- android.util.Log.d(TAG, "======== RETRIEVING COMPLETE CARD DATA ========");
+ private void loadEMVTlvData() {
+ android.util.Log.d(TAG, "======== RETRIEVING COMPLETE EMV CARD DATA ========");
try {
String[] standardTagList = {
@@ -1056,7 +144,7 @@ public class CreditCardActivity extends AppCompatActivity {
Map allTlvMap = new TreeMap<>();
int tlvOpCode = AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL;
- if (mCardType == AidlConstantsV2.CardType.NFC.getValue()) {
+ if ("NFC".equals(cardType)) {
tlvOpCode = AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS;
}
@@ -1074,7 +162,7 @@ public class CreditCardActivity extends AppCompatActivity {
android.util.Log.d(TAG, "Parsed " + tlvMap.size() + " standard TLV tags");
}
- if (mCardType == AidlConstantsV2.CardType.NFC.getValue()) {
+ if ("NFC".equals(cardType)) {
android.util.Log.d(TAG, "Requesting " + payPassTagList.length + " PayPass specific tags");
len = mEMVOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, payPassTagList, outData);
@@ -1089,149 +177,207 @@ public class CreditCardActivity extends AppCompatActivity {
}
}
- StringBuilder sb = new StringBuilder();
+ displayEMVData(allTlvMap);
- // Transaction Summary
- sb.append("==== TRANSACTION COMPLETED ====\n");
- sb.append("Amount: ").append(formatAmount(Long.parseLong(transactionAmount))).append("\n");
- sb.append("Payment Method: EMV ").append(mCardType == AidlConstantsV2.CardType.NFC.getValue() ? "NFC" : "IC").append("\n");
- sb.append("Status: SUCCESS\n\n");
-
- // Card Summary
- sb.append("==== CARD SUMMARY ====\n");
-
- TLV panTlv = allTlvMap.get("5A");
- if (panTlv != null && !TextUtils.isEmpty(panTlv.getValue())) {
- sb.append("Card Number: ").append(panTlv.getValue()).append("\n");
- }
-
- TLV labelTlv = allTlvMap.get("50");
- if (labelTlv != null && !TextUtils.isEmpty(labelTlv.getValue())) {
- sb.append("App Label: ").append(hexToString(labelTlv.getValue())).append("\n");
- }
-
- TLV nameTlv = allTlvMap.get("5F20");
- if (nameTlv != null && !TextUtils.isEmpty(nameTlv.getValue())) {
- sb.append("Cardholder: ").append(hexToString(nameTlv.getValue()).trim()).append("\n");
- }
-
- TLV expiryTlv = allTlvMap.get("5F24");
- if (expiryTlv != null && !TextUtils.isEmpty(expiryTlv.getValue())) {
- String expiry = expiryTlv.getValue();
- if (expiry.length() == 6) {
- sb.append("Expiry: ").append(expiry.substring(2, 4)).append("/").append(expiry.substring(0, 2)).append("\n");
- }
- }
-
- TLV aidTlv = allTlvMap.get("9F06");
- if (aidTlv != null && !TextUtils.isEmpty(aidTlv.getValue())) {
- sb.append("Scheme: ").append(identifyPaymentScheme(aidTlv.getValue())).append("\n");
- }
-
- sb.append("\n==== ALL TLV DATA ====\n");
-
- // All TLV Data
- Set keySet = allTlvMap.keySet();
- for (String key : keySet) {
- TLV tlv = allTlvMap.get(key);
- String value = tlv != null ? tlv.getValue() : "";
- String description = getTlvDescription(key);
-
- sb.append(key);
- if (!description.equals("Unknown")) {
- sb.append(" (").append(description).append(")");
- }
- sb.append(": ");
-
- if (key.equals("5A") && !value.isEmpty()) {
- sb.append(value);
- } else if (key.equals("50") && !value.isEmpty()) {
- String decodedLabel = hexToString(value);
- sb.append(value).append(" (").append(decodedLabel).append(")");
- } else if (key.equals("5F20") && !value.isEmpty()) {
- String decodedName = hexToString(value);
- sb.append(value).append(" (").append(decodedName.trim()).append(")");
- } else if (key.equals("9F06") && !value.isEmpty()) {
- String scheme = identifyPaymentScheme(value);
- sb.append(value).append(" (").append(scheme).append(")");
- } else if (key.equals("5F24") && !value.isEmpty()) {
- sb.append(value);
- if (value.length() == 6) {
- sb.append(" (").append(value.substring(2, 4)).append("/").append(value.substring(0, 2)).append(")");
- }
- } else if (key.equals("9F02") && !value.isEmpty()) {
- sb.append(value);
- try {
- long amount = Long.parseLong(value, 16);
- sb.append(" (").append(String.format("%.2f", amount / 100.0)).append(")");
- } catch (Exception e) {
- // Keep original value
- }
- } else {
- sb.append(value);
- }
-
- sb.append("\n");
-
- android.util.Log.d(TAG, "Tag " + key + " (" + description + "): " + value);
- }
-
- sb.append("\nTotal TLV tags retrieved: ").append(keySet.size());
-
- android.util.Log.d(TAG, "Total TLV tags retrieved: " + keySet.size());
+ android.util.Log.d(TAG, "Total TLV tags retrieved: " + allTlvMap.size());
android.util.Log.d(TAG, "==================================");
- android.util.Log.d(TAG, "Complete card data retrieved successfully");
- updateUI(sb.toString(), true);
-
} catch (Exception e) {
android.util.Log.e(TAG, "Error retrieving TLV data: " + e.getMessage());
e.printStackTrace();
- updateUI("Error retrieving card data: " + e.getMessage(), true);
+ showSimpleError("Error retrieving EMV data: " + e.getMessage());
}
}
- // ====== RESET AND CLEANUP METHODS ======
- private void resetToAmountInput() {
- runOnUiThread(() -> {
- currentState = STATE_INPUT_AMOUNT;
- mProcessStep = 0;
- checkingCard = false;
+ private void loadSimpleCardData() {
+ StringBuilder summary = new StringBuilder();
+ StringBuilder cardInfo = new StringBuilder();
+
+ // Transaction Summary
+ summary.append("==== TRANSACTION COMPLETED ====\n");
+ summary.append("Amount: ").append(formatAmount(Long.parseLong(transactionAmount))).append("\n");
+ summary.append("Payment Method: ").append(getCardTypeDisplay()).append("\n");
+ summary.append("Status: SUCCESS\n");
+
+ // Card Information
+ if (cardData != null) {
+ cardInfo.append("==== CARD INFORMATION ====\n");
- dismissAppSelectDialog();
- updateUIForCurrentState();
-
- if (btnCopyData != null) {
- btnCopyData.setVisibility(View.GONE);
+ if ("MAGNETIC".equals(cardType)) {
+ String track1 = Utility.null2String(cardData.getString("TRACK1"));
+ String track2 = Utility.null2String(cardData.getString("TRACK2"));
+ String track3 = Utility.null2String(cardData.getString("TRACK3"));
+
+ cardInfo.append("Track1: ").append(track1.isEmpty() ? "N/A" : track1).append("\n");
+ cardInfo.append("Track2: ").append(track2.isEmpty() ? "N/A" : track2).append("\n");
+ cardInfo.append("Track3: ").append(track3.isEmpty() ? "N/A" : track3).append("\n");
+
+ } else if ("IC".equals(cardType)) {
+ String atr = cardData.getString("atr", "");
+ cardInfo.append("ATR: ").append(atr.isEmpty() ? "N/A" : atr).append("\n");
+
+ } else if ("NFC".equals(cardType)) {
+ String uuid = cardData.getString("uuid", "");
+ String ats = cardData.getString("ats", "");
+ int sak = cardData.getInt("sak", -1);
+
+ cardInfo.append("UUID: ").append(uuid.isEmpty() ? "N/A" : uuid).append("\n");
+ if (!ats.isEmpty()) {
+ cardInfo.append("ATS: ").append(ats).append("\n");
+ }
+ if (sak != -1) {
+ cardInfo.append("SAK: ").append(String.format("0x%02X", sak)).append("\n");
+ cardInfo.append("Type: ").append(analyzeCardTypeBySAK(sak)).append("\n");
+ }
}
- if (btnClearData != null) {
- btnClearData.setVisibility(View.GONE);
+ }
+
+ tvTransactionSummary.setText(summary.toString());
+ tvCardData.setText(cardInfo.toString());
+ }
+
+ private void displayEMVData(Map allTlvMap) {
+ StringBuilder summary = new StringBuilder();
+ StringBuilder cardInfo = new StringBuilder();
+
+ // Transaction Summary
+ summary.append("==== TRANSACTION COMPLETED ====\n");
+ summary.append("Amount: ").append(formatAmount(Long.parseLong(transactionAmount))).append("\n");
+ summary.append("Payment Method: EMV ").append(cardType).append("\n");
+ summary.append("Status: SUCCESS\n");
+
+ // Card Summary
+ summary.append("\n==== CARD SUMMARY ====\n");
+
+ TLV panTlv = allTlvMap.get("5A");
+ if (panTlv != null && !TextUtils.isEmpty(panTlv.getValue())) {
+ summary.append("Card Number: ").append(panTlv.getValue()).append("\n");
+ }
+
+ TLV labelTlv = allTlvMap.get("50");
+ if (labelTlv != null && !TextUtils.isEmpty(labelTlv.getValue())) {
+ summary.append("App Label: ").append(hexToString(labelTlv.getValue())).append("\n");
+ }
+
+ TLV nameTlv = allTlvMap.get("5F20");
+ if (nameTlv != null && !TextUtils.isEmpty(nameTlv.getValue())) {
+ summary.append("Cardholder: ").append(hexToString(nameTlv.getValue()).trim()).append("\n");
+ }
+
+ TLV expiryTlv = allTlvMap.get("5F24");
+ if (expiryTlv != null && !TextUtils.isEmpty(expiryTlv.getValue())) {
+ String expiry = expiryTlv.getValue();
+ if (expiry.length() == 6) {
+ summary.append("Expiry: ").append(expiry.substring(2, 4)).append("/").append(expiry.substring(0, 2)).append("\n");
+ }
+ }
+
+ TLV aidTlv = allTlvMap.get("9F06");
+ if (aidTlv != null && !TextUtils.isEmpty(aidTlv.getValue())) {
+ summary.append("Scheme: ").append(identifyPaymentScheme(aidTlv.getValue())).append("\n");
+ }
+
+ // Detailed TLV Data
+ cardInfo.append("==== DETAILED TLV DATA ====\n");
+
+ Set keySet = allTlvMap.keySet();
+ for (String key : keySet) {
+ TLV tlv = allTlvMap.get(key);
+ String value = tlv != null ? tlv.getValue() : "";
+ String description = getTlvDescription(key);
+
+ cardInfo.append(key);
+ if (!description.equals("Unknown")) {
+ cardInfo.append(" (").append(description).append(")");
+ }
+ cardInfo.append(": ");
+
+ if (key.equals("5A") && !value.isEmpty()) {
+ cardInfo.append(value);
+ } else if (key.equals("50") && !value.isEmpty()) {
+ String decodedLabel = hexToString(value);
+ cardInfo.append(value).append(" (").append(decodedLabel).append(")");
+ } else if (key.equals("5F20") && !value.isEmpty()) {
+ String decodedName = hexToString(value);
+ cardInfo.append(value).append(" (").append(decodedName.trim()).append(")");
+ } else if (key.equals("9F06") && !value.isEmpty()) {
+ String scheme = identifyPaymentScheme(value);
+ cardInfo.append(value).append(" (").append(scheme).append(")");
+ } else if (key.equals("5F24") && !value.isEmpty()) {
+ cardInfo.append(value);
+ if (value.length() == 6) {
+ cardInfo.append(" (").append(value.substring(2, 4)).append("/").append(value.substring(0, 2)).append(")");
+ }
+ } else if (key.equals("9F02") && !value.isEmpty()) {
+ cardInfo.append(value);
+ try {
+ long amount = Long.parseLong(value, 16);
+ cardInfo.append(" (").append(String.format("%.2f", amount / 100.0)).append(")");
+ } catch (Exception e) {
+ // Keep original value
+ }
+ } else {
+ cardInfo.append(value);
}
- android.util.Log.d(TAG, "UI reset to amount input state");
- });
+ cardInfo.append("\n");
+ }
+
+ cardInfo.append("\nTotal TLV tags retrieved: ").append(keySet.size());
+
+ tvTransactionSummary.setText(summary.toString());
+ tvCardData.setText(cardInfo.toString());
+ }
+
+ private void showSimpleError(String error) {
+ StringBuilder summary = new StringBuilder();
+ summary.append("==== TRANSACTION ERROR ====\n");
+ summary.append("Amount: ").append(formatAmount(Long.parseLong(transactionAmount))).append("\n");
+ summary.append("Status: FAILED\n");
+
+ tvTransactionSummary.setText(summary.toString());
+ tvCardData.setText(error);
+ }
+
+ private String getCardTypeDisplay() {
+ switch (cardType) {
+ case "MAGNETIC": return "Magnetic Card";
+ case "IC": return "IC Card";
+ case "NFC": return "NFC/RF Card";
+ default: return cardType;
+ }
+ }
+
+ private String formatAmount(long amountCents) {
+ double amountRupiah = amountCents / 100.0;
+ NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
+ return formatter.format(amountRupiah);
}
private void copyCardDataToClipboard() {
- if (tvResult != null) {
- String cardData = tvResult.getText().toString();
- if (!cardData.isEmpty() && !cardData.contains("Ready to scan")) {
- ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText("Card Data", cardData);
- clipboard.setPrimaryClip(clip);
- showToast("Card data copied to clipboard");
- } else {
- showToast("No card data to copy");
- }
- }
+ String summary = tvTransactionSummary.getText().toString();
+ String cardData = tvCardData.getText().toString();
+ String fullData = summary + "\n\n" + cardData;
+
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText("Transaction Data", fullData);
+ clipboard.setPrimaryClip(clip);
+ showToast("Transaction data copied to clipboard");
}
- private void clearCardData() {
- resetToAmountInput();
- showToast("Transaction cleared");
+ private void startNewTransaction() {
+ Intent intent = new Intent(this, CreateTransactionActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(intent);
+ finish();
}
- // ====== HELPER METHODS (All the same as before) ======
+ private void printReceipt() {
+ // TODO: Implement print functionality
+ showToast("Print functionality to be implemented");
+ }
+
+ // ====== HELPER METHODS ======
private String getTlvDescription(String tag) {
switch (tag.toUpperCase()) {
case "4F": return "Application Identifier";
@@ -1422,79 +568,6 @@ public class CreditCardActivity extends AppCompatActivity {
}
}
- private String getCardNo() {
- try {
- String[] tagList = {"57", "5A"};
- byte[] outData = new byte[256];
- int len = mEMVOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagList, outData);
- if (len <= 0) {
- return "";
- }
- byte[] bytes = Arrays.copyOf(outData, len);
- Map tlvMap = TLVUtils.buildTLVMap(bytes);
-
- if (tlvMap.get("57") != null && !TextUtils.isEmpty(Objects.requireNonNull(tlvMap.get("57")).getValue())) {
- TLV tlv57 = tlvMap.get("57");
- CardInfo cardInfo = parseTrack2(tlv57.getValue());
- return cardInfo.cardNo;
- }
- if (tlvMap.get("5A") != null && !TextUtils.isEmpty(Objects.requireNonNull(tlvMap.get("5A")).getValue())) {
- return Objects.requireNonNull(tlvMap.get("5A")).getValue();
- }
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- return "";
- }
-
- public static CardInfo parseTrack2(String track2) {
- String track_2 = stringFilter(track2);
- int index = track_2.indexOf("=");
- if (index == -1) {
- index = track_2.indexOf("D");
- }
- CardInfo cardInfo = new CardInfo();
- if (index == -1) {
- return cardInfo;
- }
- String cardNumber = "";
- if (track_2.length() > index) {
- cardNumber = track_2.substring(0, index);
- }
- String expiryDate = "";
- if (track_2.length() > index + 5) {
- expiryDate = track_2.substring(index + 1, index + 5);
- }
- String serviceCode = "";
- if (track_2.length() > index + 8) {
- serviceCode = track_2.substring(index + 5, index + 8);
- }
- cardInfo.cardNo = cardNumber;
- cardInfo.expireDate = expiryDate;
- cardInfo.serviceCode = serviceCode;
- return cardInfo;
- }
-
- static String stringFilter(String str) {
- String regEx = "[^0-9=D]";
- Pattern p = Pattern.compile(regEx);
- Matcher matcher = p.matcher(str);
- return matcher.replaceAll("").trim();
- }
-
- private String maskCardNumber(String cardNo) {
- if (cardNo == null || cardNo.length() < 8) {
- return cardNo;
- }
- String first4 = cardNo.substring(0, 4);
- String last4 = cardNo.substring(cardNo.length() - 4);
- StringBuilder middle = new StringBuilder();
- for (int i = 0; i < cardNo.length() - 8; i++) {
- middle.append("*");
- }
- return first4 + middle.toString() + last4;
- }
-
private String identifyPaymentScheme(String aid) {
if (aid == null) return "Unknown";
@@ -1536,362 +609,13 @@ public class CreditCardActivity extends AppCompatActivity {
}
}
- private String[] getCandidateNames(List candiList) {
- if (candiList == null || candiList.size() == 0) return new String[0];
- String[] result = new String[candiList.size()];
- for (int i = 0; i < candiList.size(); i++) {
- EMVCandidateV2 candi = candiList.get(i);
- String name = candi.appPreName;
- name = TextUtils.isEmpty(name) ? candi.appLabel : name;
- name = TextUtils.isEmpty(name) ? candi.appName : name;
- name = TextUtils.isEmpty(name) ? "" : name;
- result[i] = name;
- }
- return result;
- }
-
- // ====== EMV IMPORT METHODS (Same as before) ======
- private void importAppSelect(int selectIndex) {
- try {
- mEMVOptV2.importAppSelect(selectIndex);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private void importFinalAppSelectStatus(int status) {
- try {
- mEMVOptV2.importAppFinalSelectStatus(status);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- private void importCardNoStatus(int status) {
- try {
- mEMVOptV2.importCardNoStatus(status);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private void importCertStatus(int status) {
- try {
- mEMVOptV2.importCertStatus(status);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private void importPinInputStatus(int inputResult) {
- try {
- mEMVOptV2.importPinInputStatus(mPinType, inputResult);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- private void importSignatureStatus(int status) {
- try {
- mEMVOptV2.importSignatureStatus(status);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- // ====== PIN PAD METHODS (Same as before) ======
- private void initPinPad() {
- android.util.Log.e(TAG, "========== PIN PAD INITIALIZATION ==========");
- try {
- if (mPinPadOptV2 == null) {
- throw new IllegalStateException("PIN Pad service not available");
- }
-
- if (mCardNo == null || mCardNo.length() < 13) {
- throw new IllegalArgumentException("Invalid card number for PIN");
- }
-
- PinPadConfigV2 pinPadConfig = new PinPadConfigV2();
- pinPadConfig.setPinPadType(0);
- pinPadConfig.setPinType(mPinType);
- pinPadConfig.setOrderNumKey(false);
-
- String panForPin = mCardNo.substring(mCardNo.length() - 13, mCardNo.length() - 1);
- byte[] panBytes = panForPin.getBytes("US-ASCII");
- pinPadConfig.setPan(panBytes);
-
- pinPadConfig.setTimeout(60 * 1000);
- pinPadConfig.setPinKeyIndex(12);
- pinPadConfig.setMaxInput(12);
- pinPadConfig.setMinInput(0);
- pinPadConfig.setKeySystem(0);
- pinPadConfig.setAlgorithmType(0);
-
- runOnUiThread(() -> {
- updateUI("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nPIN Input Required\n\nPIN pad is ready\nPlease enter your PIN on the device", false);
- btnCheckCard.setText("PIN Pad Active");
- btnCheckCard.setEnabled(false);
- });
-
- mPinPadOptV2.initPinPad(pinPadConfig, mPinPadListener);
-
- } catch (Exception e) {
- android.util.Log.e(TAG, "PIN pad initialization failed: " + e.getMessage());
- mHandler.obtainMessage(PIN_ERROR, -1, -1,
- "PIN Error: " + e.getMessage()).sendToTarget();
- }
- }
-
- private final PinPadListenerV2 mPinPadListener = new PinPadListenerV2.Stub() {
- @Override
- public void onPinLength(int len) throws RemoteException {
- android.util.Log.d(TAG, "PIN input length: " + len);
- runOnUiThread(() -> {
- String dots = "";
- for (int i = 0; i < len; i++) {
- dots += "• ";
- }
- tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nPIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)");
- });
- }
-
- @Override
- public void onConfirm(int i, byte[] pinBlock) throws RemoteException {
- android.util.Log.d(TAG, "PIN input confirmed");
-
- runOnUiThread(() -> {
- btnCheckCard.setEnabled(true);
- btnCheckCard.setText("Processing...");
- tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nPIN confirmed, processing...");
- });
-
- if (pinBlock != null) {
- String hexStr = ByteUtil.bytes2HexStr(pinBlock);
- android.util.Log.d(TAG, "PIN block received: " + hexStr);
- mHandler.obtainMessage(PIN_CLICK_PIN, pinBlock).sendToTarget();
- } else {
- android.util.Log.d(TAG, "PIN bypass confirmed");
- mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
- }
- }
-
- @Override
- public void onCancel() throws RemoteException {
- android.util.Log.d(TAG, "PIN input cancelled by user");
-
- runOnUiThread(() -> {
- btnCheckCard.setEnabled(true);
- btnCheckCard.setText("Start Scanning");
- tvResult.setText("PIN input cancelled");
- });
-
- mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
- }
-
- @Override
- public void onError(int code) throws RemoteException {
- android.util.Log.e(TAG, "PIN pad error: " + code);
- String msg = AidlErrorCodeV2.valueOf(code).getMsg();
-
- runOnUiThread(() -> {
- btnCheckCard.setEnabled(true);
- btnCheckCard.setText("Start Scanning");
- tvResult.setText("PIN error: " + msg);
- });
-
- mHandler.obtainMessage(PIN_ERROR, code, code, msg).sendToTarget();
- }
-
- @Override
- public void onHover(int event, byte[] data) throws RemoteException {
- android.util.Log.d(TAG, "PIN pad hover event: " + event);
- }
- };
-
- // ====== MOCK ONLINE PROCESS (Same as before) ======
- private void mockOnlineProcess() {
- new Thread(() -> {
- try {
- runOnUiThread(() -> tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\nProcessing online authorization..."));
- Thread.sleep(2000);
-
- try {
- String[] tags = {"71", "72", "91", "8A", "89"};
- String[] values = {"", "", "", "", ""};
- byte[] out = new byte[1024];
- int len = mEMVOptV2.importOnlineProcStatus(0, tags, values, out);
- if (len < 0) {
- android.util.Log.e(TAG, "importOnlineProcessStatus error,code:" + len);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }).start();
- }
-
- // ====== UI UPDATE METHODS ======
- private void updateUI(String message, boolean isTransactionComplete) {
- runOnUiThread(() -> {
- if (tvResult != null) {
- tvResult.setText(message);
- }
- if (isTransactionComplete) {
- checkingCard = false;
- btnCheckCard.setText("New Transaction");
- btnCheckCard.setOnClickListener(v -> resetToAmountInput());
- currentState = STATE_INPUT_AMOUNT; // Will be updated when button clicked
-
- if (btnCopyData != null && message.contains("====")) {
- btnCopyData.setVisibility(View.VISIBLE);
- }
- if (btnClearData != null && message.contains("====")) {
- btnClearData.setVisibility(View.VISIBLE);
- }
- }
- });
- }
-
- private void showLoadingDialog(String message) {
- runOnUiThread(() -> {
- if (tvResult != null) {
- tvResult.setText("Amount: " + formatAmount(Long.parseLong(transactionAmount)) +
- "\n\n" + message + "...");
- }
- android.util.Log.d(TAG, "Loading: " + message);
- });
- }
-
- private void dismissLoadingDialog() {
- android.util.Log.d(TAG, "Loading dismissed");
- }
-
- private void dismissAppSelectDialog() {
- if (mAppSelectDialog != null) {
- try {
- mAppSelectDialog.dismiss();
- } catch (Exception e) {
- e.printStackTrace();
- }
- mAppSelectDialog = null;
- }
- }
-
private void showToast(String message) {
- runOnUiThread(() -> Toast.makeText(this, message, Toast.LENGTH_SHORT).show());
+ Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
- // ====== LOGGING METHODS (Same as before) ======
- private void logMagneticCardData(Bundle info) {
- android.util.Log.d(TAG, "=======================================");
- android.util.Log.d(TAG, " MAGNETIC CARD DETECTED ");
- android.util.Log.d(TAG, "=======================================");
-
- String track1 = Utility.null2String(info.getString("TRACK1"));
- String track2 = Utility.null2String(info.getString("TRACK2"));
- String track3 = Utility.null2String(info.getString("TRACK3"));
-
- android.util.Log.d(TAG, "TRACK DATA:");
- android.util.Log.d(TAG, " Track1: " + (track1.isEmpty() ? "N/A" : track1));
- android.util.Log.d(TAG, " Track2: " + (track2.isEmpty() ? "N/A" : track2));
- android.util.Log.d(TAG, " Track3: " + (track3.isEmpty() ? "N/A" : track3));
- android.util.Log.d(TAG, "=======================================");
- }
-
- private void logICCardData(Bundle info) {
- android.util.Log.d(TAG, "=======================================");
- android.util.Log.d(TAG, " IC CARD DETECTED ");
- android.util.Log.d(TAG, "=======================================");
-
- String atr = info.getString("atr", "");
- int cardType = info.getInt("cardType", -1);
-
- android.util.Log.d(TAG, "BASIC INFO:");
- android.util.Log.d(TAG, " ATR: " + (atr.isEmpty() ? "N/A" : atr));
- android.util.Log.d(TAG, " Card Type: " + cardType);
- android.util.Log.d(TAG, "=======================================");
- }
-
- private void logRFCardData(Bundle info) {
- android.util.Log.d(TAG, "=======================================");
- android.util.Log.d(TAG, " RF/NFC CARD DETECTED ");
- android.util.Log.d(TAG, "=======================================");
-
- String uuid = info.getString("uuid", "");
- String ats = info.getString("ats", "");
- int sak = info.getInt("sak", -1);
-
- android.util.Log.d(TAG, "BASIC INFO:");
- android.util.Log.d(TAG, " UUID: " + (uuid.isEmpty() ? "N/A" : uuid));
- android.util.Log.d(TAG, " ATS: " + (ats.isEmpty() ? "N/A" : ats));
- android.util.Log.d(TAG, " SAK: " + (sak == -1 ? "N/A" : String.format("0x%02X (%d)", sak, sak)));
- android.util.Log.d(TAG, "=======================================");
- }
-
- private void logCardError(Bundle info) {
- android.util.Log.e(TAG, "=======================================");
- android.util.Log.e(TAG, " CARD READ ERROR ");
- android.util.Log.e(TAG, "=======================================");
-
- int code = info.getInt("code", -1);
- String message = info.getString("message", "");
-
- android.util.Log.e(TAG, "ERROR INFO:");
- android.util.Log.e(TAG, " Error Code: " + code);
- android.util.Log.e(TAG, " Error Message: " + (message.isEmpty() ? "N/A" : message));
- android.util.Log.e(TAG, "=======================================");
- }
-
- // ====== LIFECYCLE METHODS (Same as before) ======
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
-
- // ====== LIFECYCLE METHODS ======
- @Override
- protected void onDestroy() {
- android.util.Log.d(TAG, "onDestroy called");
- cancelCheckCard();
- super.onDestroy();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- android.util.Log.d(TAG, "onPause called");
- if (checkingCard) {
- android.util.Log.d(TAG, "App paused, stopping card check");
- stopCardCheck();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- android.util.Log.d(TAG, "onResume called");
- checkPaySDKStatus();
- }
-
- private void cancelCheckCard() {
- try {
- if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) {
- android.util.Log.d(TAG, "Cancelling card operations...");
- MyApplication.app.readCardOptV2.cardOff(CardType.NFC.getValue());
- MyApplication.app.readCardOptV2.cardOff(CardType.IC.getValue());
- MyApplication.app.readCardOptV2.cancelCheckCard();
- android.util.Log.d(TAG, "Card operations cancelled successfully");
- }
- } catch (Exception e) {
- android.util.Log.e(TAG, "Error cancelling card operations: " + e.getMessage());
- e.printStackTrace();
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bdkipoc/kredit/EmvTransactionActivity.java b/app/src/main/java/com/example/bdkipoc/kredit/EmvTransactionActivity.java
new file mode 100644
index 0000000..bfd86f0
--- /dev/null
+++ b/app/src/main/java/com/example/bdkipoc/kredit/EmvTransactionActivity.java
@@ -0,0 +1,1082 @@
+package com.example.bdkipoc.kredit;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import com.example.bdkipoc.MyApplication;
+import com.example.bdkipoc.R;
+import com.example.bdkipoc.utils.ByteUtil;
+import com.example.bdkipoc.utils.Utility;
+import com.sunmi.pay.hardware.aidl.AidlConstants.CardType;
+import com.sunmi.pay.hardware.aidl.bean.CardInfo;
+import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
+import com.sunmi.pay.hardware.aidlv2.AidlErrorCodeV2;
+import com.sunmi.pay.hardware.aidlv2.bean.EMVCandidateV2;
+import com.sunmi.pay.hardware.aidlv2.bean.PinPadConfigV2;
+import com.sunmi.pay.hardware.aidlv2.emv.EMVListenerV2;
+import com.sunmi.pay.hardware.aidlv2.emv.EMVOptV2;
+import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadListenerV2;
+import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadOptV2;
+import com.sunmi.pay.hardware.aidlv2.readcard.CheckCardCallbackV2;
+
+import java.text.NumberFormat;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * EmvTransactionActivity - Handle card reading and EMV processing
+ */
+public class EmvTransactionActivity extends AppCompatActivity {
+ private static final String TAG = "EmvTransaction";
+
+ // UI Components
+ private TextView tvStatus;
+ private TextView tvAmountDisplay;
+ private Button btnAction;
+ private Button btnCancel;
+
+ // Transaction Data
+ private String transactionAmount;
+ private boolean isEMVMode;
+ private boolean isProcessing = false;
+ private boolean isButtonProcessing = false;
+
+ // EMV Components
+ private EMVOptV2 mEMVOptV2;
+ private PinPadOptV2 mPinPadOptV2;
+
+ // EMV Process Variables
+ private int mCardType;
+ private String mCardNo;
+ private int mPinType;
+ private String mCertInfo;
+ private int mSelectIndex;
+ private int mProcessStep;
+ private AlertDialog mAppSelectDialog;
+
+ // EMV Process Constants
+ private static final int EMV_APP_SELECT = 1;
+ private static final int EMV_FINAL_APP_SELECT = 2;
+ private static final int EMV_CONFIRM_CARD_NO = 3;
+ private static final int EMV_CERT_VERIFY = 4;
+ private static final int EMV_SHOW_PIN_PAD = 5;
+ private static final int EMV_ONLINE_PROCESS = 6;
+ private static final int EMV_SIGNATURE = 7;
+ private static final int EMV_TRANS_SUCCESS = 888;
+ private static final int EMV_TRANS_FAIL = 999;
+
+ private static final int PIN_CLICK_PIN = 51;
+ private static final int PIN_CLICK_CONFIRM = 52;
+ private static final int PIN_CLICK_CANCEL = 53;
+ private static final int PIN_ERROR = 54;
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what) {
+ case EMV_FINAL_APP_SELECT:
+ importFinalAppSelectStatus(0);
+ break;
+
+ case EMV_APP_SELECT:
+ String[] candiNames = (String[]) msg.obj;
+ showAppSelectDialog(candiNames);
+ break;
+
+ case EMV_CONFIRM_CARD_NO:
+ showCardNumberConfirmation();
+ break;
+
+ case EMV_CERT_VERIFY:
+ showCertificateVerification();
+ break;
+
+ case EMV_SHOW_PIN_PAD:
+ android.util.Log.d(TAG, "Initializing PIN pad...");
+ initPinPad();
+ break;
+
+ case EMV_ONLINE_PROCESS:
+ mockOnlineProcess();
+ break;
+
+ case EMV_SIGNATURE:
+ importSignatureStatus(0);
+ break;
+
+ case PIN_CLICK_PIN:
+ android.util.Log.d(TAG, "PIN input confirmed");
+ importPinInputStatus(0);
+ break;
+
+ case PIN_CLICK_CONFIRM:
+ android.util.Log.d(TAG, "PIN confirm without input (bypass)");
+ importPinInputStatus(2);
+ break;
+
+ case PIN_CLICK_CANCEL:
+ showToast("PIN input cancelled by user");
+ importPinInputStatus(1);
+ break;
+
+ case PIN_ERROR:
+ android.util.Log.e(TAG, "PIN Error: " + msg.obj + " -- " + msg.arg1);
+ showToast("PIN Error: " + msg.obj);
+ importPinInputStatus(3);
+ break;
+
+ case EMV_TRANS_FAIL:
+ // Handle EMV transaction failure with error code check
+ int errorCode = msg.arg1;
+ String errorDesc = (String) msg.obj;
+
+ Log.e(TAG, "EMV Transaction failed: " + errorDesc + " (Code: " + errorCode + ")");
+
+ if (errorCode == -50009) {
+ // EMV process conflict - reset and retry
+ Log.d(TAG, "EMV process conflict detected - resetting...");
+ showToast("EMV busy, resetting...");
+ resetEMVAndRetry();
+ } else {
+ // Other errors - show message but don't finish
+ showToast("Transaction failed: " + errorDesc);
+ resetScanningState();
+ }
+ break;
+
+ case EMV_TRANS_SUCCESS:
+ // Navigate to results screen
+ navigateToResults();
+ break;
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_emv_transaction);
+
+ getIntentData();
+ initViews();
+ initEMVComponents();
+ initEMVData();
+ updateUI();
+ }
+
+ private void getIntentData() {
+ Intent intent = getIntent();
+ transactionAmount = intent.getStringExtra("TRANSACTION_AMOUNT");
+ isEMVMode = intent.getBooleanExtra("EMV_MODE", true);
+
+ if (transactionAmount == null) {
+ transactionAmount = "0";
+ finish();
+ return;
+ }
+ }
+
+ private void initViews() {
+ // Setup Toolbar
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle("Scan Kartu");
+ }
+
+ tvStatus = findViewById(R.id.tv_status);
+ tvAmountDisplay = findViewById(R.id.tv_amount_display);
+ btnAction = findViewById(R.id.btn_action);
+ btnCancel = findViewById(R.id.btn_cancel);
+
+ btnAction.setOnClickListener(v -> handleActionClick());
+ btnCancel.setOnClickListener(v -> finish());
+ }
+
+ private void initEMVComponents() {
+ if (MyApplication.app != null) {
+ mEMVOptV2 = MyApplication.app.emvOptV2;
+ mPinPadOptV2 = MyApplication.app.pinPadOptV2;
+ android.util.Log.d(TAG, "EMV components initialized");
+ } else {
+ android.util.Log.e(TAG, "MyApplication.app is null");
+ showToast("Application error");
+ finish();
+ }
+ }
+
+ private void initEMVData() {
+ try {
+ if (mEMVOptV2 != null) {
+ // Reset any existing EMV process first
+ mEMVOptV2.initEmvProcess();
+
+ // Small delay to ensure reset is complete
+ new Handler(Looper.getMainLooper()).postDelayed(() -> {
+ try {
+ initEmvTlvData();
+ android.util.Log.d(TAG, "EMV data initialized successfully");
+ } catch (Exception e) {
+ android.util.Log.e(TAG, "Error in delayed EMV init: " + e.getMessage());
+ }
+ }, 500);
+ }
+ } catch (Exception e) {
+ android.util.Log.e(TAG, "Error initializing EMV data: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ private void initEmvTlvData() {
+ try {
+ // Set PayPass (MasterCard) TLV data
+ String[] tagsPayPass = {"DF8117", "DF8118", "DF8119", "DF811F", "DF811E", "DF812C",
+ "DF8123", "DF8124", "DF8125", "DF8126", "DF811B", "DF811D", "DF8122", "DF8120", "DF8121"};
+ String[] valuesPayPass = {"E0", "F8", "F8", "E8", "00", "00",
+ "000000000000", "000000100000", "999999999999", "000000100000",
+ "30", "02", "0000000000", "000000000000", "000000000000"};
+ mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, tagsPayPass, valuesPayPass);
+
+ // Set AMEX TLV data
+ String[] tagsAE = {"9F6D", "9F6E", "9F33", "9F35", "DF8168", "DF8167", "DF8169", "DF8170"};
+ String[] valuesAE = {"C0", "D8E00000", "E0E888", "22", "00", "00", "00", "60"};
+ mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_AE, tagsAE, valuesAE);
+
+ // Set JCB TLV data
+ String[] tagsJCB = {"9F53", "DF8161"};
+ String[] valuesJCB = {"708000", "7F00"};
+ mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_JCB, tagsJCB, valuesJCB);
+
+ // Set DPAS TLV data
+ String[] tagsDPAS = {"9F66"};
+ String[] valuesDPAS = {"B600C000"};
+ mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_DPAS, tagsDPAS, valuesDPAS);
+
+ // Set Flash TLV data
+ String[] tagsFLASH = {"9F58", "9F59", "9F5A", "9F5D", "9F5E"};
+ String[] valuesFLASH = {"03", "D88700", "00", "000000000000", "E000"};
+ mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_FLASH, tagsFLASH, valuesFLASH);
+
+ // Set Pure TLV data
+ String[] tagsPURE = {"DF7F", "DF8134", "DF8133"};
+ String[] valuesPURE = {"A0000007271010", "DF", "36006043F9"};
+ mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PURE, tagsPURE, valuesPURE);
+
+ Bundle bundle = new Bundle();
+ bundle.putBoolean("optOnlineRes", true);
+ mEMVOptV2.setTermParamEx(bundle);
+
+ } catch (RemoteException e) {
+ android.util.Log.e(TAG, "Error setting EMV TLV data: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ private void updateUI() {
+ long amountCents = Long.parseLong(transactionAmount);
+ double amountRupiah = amountCents / 100.0;
+ NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
+ String formattedAmount = formatter.format(amountRupiah);
+
+ tvAmountDisplay.setText("Nominal: " + formattedAmount);
+
+ String mode = isEMVMode ? "EMV Mode (Full Card Data)" : "Simple Mode (Basic Detection)";
+ String status = "Ready to scan card...\n" +
+ "Current Mode: " + mode + "\n\n" +
+ "Please insert, swipe, or tap your card";
+
+ tvStatus.setText(status);
+ btnAction.setText("Start Scanning");
+ }
+
+ private void handleActionClick() {
+ // Prevent multiple rapid clicks
+ if (isButtonProcessing) {
+ Log.d(TAG, "Button click ignored - already processing");
+ return;
+ }
+
+ isButtonProcessing = true;
+ Log.d(TAG, "handleActionClick - mProcessStep: " + mProcessStep + ", isProcessing: " + isProcessing);
+
+ // Reset button processing flag after delay
+ btnAction.postDelayed(() -> isButtonProcessing = false, 1000);
+
+ if (mProcessStep == 0) {
+ if (isProcessing) {
+ stopCardCheck();
+ } else {
+ startCardCheck();
+ }
+ } else if (mProcessStep == EMV_CONFIRM_CARD_NO) {
+ android.util.Log.d(TAG, "User confirmed card number");
+ btnAction.setText("Processing...");
+ importCardNoStatus(0);
+ } else if (mProcessStep == EMV_CERT_VERIFY) {
+ android.util.Log.d(TAG, "User confirmed certificate");
+ btnAction.setText("Processing...");
+ importCertStatus(0);
+ }
+ }
+
+ private void startCardCheck() {
+ // Prevent multiple calls
+ if (isProcessing) {
+ Log.d(TAG, "Card check already in progress - ignoring call");
+ return;
+ }
+
+ Log.d(TAG, "Starting card check - setting isProcessing = true");
+ isProcessing = true;
+ btnAction.setText("Initializing...");
+ btnAction.setEnabled(false);
+
+ try {
+ // Force EMV reset before any operation
+ if (mEMVOptV2 != null) {
+ Log.d(TAG, "Forcing EMV reset before card check");
+ mEMVOptV2.initEmvProcess();
+
+ // Wait a bit before continuing
+ btnAction.postDelayed(() -> {
+ if (isProcessing) { // Double check we're still processing
+ continueCardCheck();
+ }
+ }, 500);
+
+ } else {
+ continueCardCheck();
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "Error in startCardCheck: " + e.getMessage(), e);
+ resetScanningState();
+ showToast("Error: " + e.getMessage());
+ }
+ }
+
+ private void continueCardCheck() {
+ try {
+ Log.d(TAG, "continueCardCheck - isProcessing: " + isProcessing);
+
+ if (!isProcessing) {
+ Log.d(TAG, "continueCardCheck called but not processing - returning");
+ return;
+ }
+
+ btnAction.setText("Stop Scanning");
+ btnAction.setEnabled(true);
+
+ if (isEMVMode) {
+ startEMVCardCheck();
+ } else {
+ startSimpleCardCheck();
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "Error in continueCardCheck: " + e.getMessage(), e);
+ resetScanningState();
+ showToast("Error: " + e.getMessage());
+ }
+ }
+
+ private void startEMVCardCheck() {
+ try {
+ if (mEMVOptV2 == null) {
+ showToast("EMV not initialized");
+ return;
+ }
+
+ mEMVOptV2.initEmvProcess();
+ initEmvTlvData();
+
+ tvStatus.setText("EMV Mode: Starting card scan...\nPlease insert, swipe, or tap your card");
+
+ int cardType = AidlConstantsV2.CardType.NFC.getValue() | AidlConstantsV2.CardType.IC.getValue();
+ android.util.Log.d(TAG, "Starting EMV checkCard with cardType: " + cardType);
+
+ MyApplication.app.readCardOptV2.checkCard(cardType, mEMVCheckCardCallback, 60);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ android.util.Log.e(TAG, "Error in startEMVCardCheck: " + e.getMessage());
+ showToast("Error starting EMV card scan: " + e.getMessage());
+ }
+ }
+
+ private void startSimpleCardCheck() {
+ try {
+ if (!MyApplication.app.isConnectPaySDK()) {
+ tvStatus.setText("Connecting to PaySDK...");
+ MyApplication.app.bindPaySDKService();
+ return;
+ }
+
+ int cardType = CardType.MAGNETIC.getValue() | CardType.IC.getValue() | CardType.NFC.getValue();
+ tvStatus.setText("Simple Mode: Starting card scan...\nPlease insert, swipe, or tap your card");
+
+ MyApplication.app.readCardOptV2.checkCard(cardType, mSimpleCheckCardCallback, 60);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ showToast("Error starting card scan: " + e.getMessage());
+ }
+ }
+
+ private void stopCardCheck() {
+ try {
+ if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) {
+ MyApplication.app.readCardOptV2.cancelCheckCard();
+ }
+ isProcessing = false;
+ btnAction.setText("Start Scanning");
+ updateUI();
+ } catch (Exception e) {
+ android.util.Log.e(TAG, "Error stopping card check: " + e.getMessage());
+ }
+ }
+
+ // ====== SIMPLE CARD DETECTION CALLBACK ======
+ private final CheckCardCallbackV2 mSimpleCheckCardCallback = new CheckCardCallbackV2.Stub() {
+ @Override
+ public void findMagCard(Bundle info) throws RemoteException {
+ android.util.Log.d(TAG, "Simple Mode: findMagCard callback triggered");
+ runOnUiThread(() -> handleSimpleCardResult(info, "MAGNETIC"));
+ }
+
+ @Override
+ public void findICCard(String atr) throws RemoteException {
+ Bundle info = new Bundle();
+ info.putString("atr", atr);
+ runOnUiThread(() -> handleSimpleCardResult(info, "IC"));
+ }
+
+ @Override
+ public void findRFCard(String uuid) throws RemoteException {
+ Bundle info = new Bundle();
+ info.putString("uuid", uuid);
+ runOnUiThread(() -> handleSimpleCardResult(info, "NFC"));
+ }
+
+ @Override
+ public void onError(int code, String message) throws RemoteException {
+ runOnUiThread(() -> {
+ showToast("Card error: " + message);
+ stopCardCheck();
+ });
+ }
+
+ @Override
+ public void findICCardEx(Bundle info) throws RemoteException {
+ runOnUiThread(() -> handleSimpleCardResult(info, "IC"));
+ }
+
+ @Override
+ public void findRFCardEx(Bundle info) throws RemoteException {
+ runOnUiThread(() -> handleSimpleCardResult(info, "NFC"));
+ }
+
+ @Override
+ public void onErrorEx(Bundle info) throws RemoteException {
+ runOnUiThread(() -> {
+ String msg = info.getString("message", "Unknown error");
+ showToast("Card error: " + msg);
+ stopCardCheck();
+ });
+ }
+ };
+
+ // ====== EMV CARD DETECTION CALLBACK ======
+ private final CheckCardCallbackV2 mEMVCheckCardCallback = new CheckCardCallbackV2.Stub() {
+ @Override
+ public void findMagCard(Bundle info) throws RemoteException {
+ runOnUiThread(() -> handleSimpleCardResult(info, "MAGNETIC"));
+ }
+
+ @Override
+ public void findICCard(String atr) throws RemoteException {
+ MyApplication.app.basicOptV2.buzzerOnDevice(1, 2750, 200, 0);
+ mCardType = AidlConstantsV2.CardType.IC.getValue();
+ runOnUiThread(() -> startEMVTransactionProcess());
+ }
+
+ @Override
+ public void findRFCard(String uuid) throws RemoteException {
+ mCardType = AidlConstantsV2.CardType.NFC.getValue();
+ runOnUiThread(() -> startEMVTransactionProcess());
+ }
+
+ @Override
+ public void onError(int code, String message) throws RemoteException {
+ runOnUiThread(() -> {
+ showToast("EMV Error: " + message);
+ stopCardCheck();
+ });
+ }
+
+ @Override
+ public void findICCardEx(Bundle info) throws RemoteException {
+ mCardType = AidlConstantsV2.CardType.IC.getValue();
+ runOnUiThread(() -> startEMVTransactionProcess());
+ }
+
+ @Override
+ public void findRFCardEx(Bundle info) throws RemoteException {
+ mCardType = AidlConstantsV2.CardType.NFC.getValue();
+ runOnUiThread(() -> startEMVTransactionProcess());
+ }
+
+ @Override
+ public void onErrorEx(Bundle info) throws RemoteException {
+ runOnUiThread(() -> {
+ String msg = info.getString("message", "Unknown error");
+ showToast("EMV Error: " + msg);
+ stopCardCheck();
+ });
+ }
+ };
+
+ private void handleSimpleCardResult(Bundle info, String cardType) {
+ // For simple mode, navigate directly to results
+ Intent intent = new Intent(this, CreditCardActivity.class);
+ intent.putExtra("TRANSACTION_AMOUNT", transactionAmount);
+ intent.putExtra("CARD_TYPE", cardType);
+ intent.putExtra("CARD_DATA", info);
+ intent.putExtra("EMV_MODE", isEMVMode);
+ startActivity(intent);
+ finish();
+ }
+
+ private void startEMVTransactionProcess() {
+ // Prevent multiple calls
+ if (mProcessStep != 0) {
+ Log.d(TAG, "EMV transaction already in progress (step: " + mProcessStep + ") - ignoring call");
+ return;
+ }
+
+ android.util.Log.d(TAG, "Starting EMV transaction process");
+ mProcessStep = 1; // Set step to prevent multiple calls
+
+ try {
+ // Ensure EMV is properly reset before starting
+ mEMVOptV2.initEmvProcess();
+
+ // Small delay to ensure reset is complete
+ new Handler(Looper.getMainLooper()).postDelayed(() -> {
+ try {
+ // Double check we're still in the right state
+ if (mProcessStep <= 0) {
+ Log.d(TAG, "EMV process was cancelled - not starting");
+ return;
+ }
+
+ Bundle bundle = new Bundle();
+ bundle.putString("amount", transactionAmount);
+ bundle.putString("transType", "00");
+
+ if (mCardType == AidlConstantsV2.CardType.NFC.getValue()) {
+ bundle.putInt("flowType", AidlConstantsV2.EMV.FlowType.TYPE_EMV_STANDARD);
+ } else {
+ bundle.putInt("flowType", AidlConstantsV2.EMV.FlowType.TYPE_EMV_STANDARD);
+ }
+ bundle.putInt("cardType", mCardType);
+
+ tvStatus.setText("EMV processing started...\nReading card data...");
+
+ Log.d(TAG, "Starting transactProcessEx with reset EMV");
+ mEMVOptV2.transactProcessEx(bundle, mEMVListener);
+
+ } catch (Exception e) {
+ Log.e(TAG, "Error in delayed EMV start: " + e.getMessage(), e);
+ resetScanningState();
+ showToast("Error starting EMV: " + e.getMessage());
+ }
+ }, 300); // 300ms delay
+
+ } catch (Exception e) {
+ android.util.Log.e(TAG, "Error starting EMV transaction: " + e.getMessage());
+ e.printStackTrace();
+ resetScanningState();
+ showToast("Error starting EMV transaction: " + e.getMessage());
+ }
+ }
+
+ // ====== EMV LISTENER ======
+ private final EMVListenerV2 mEMVListener = new EMVListenerV2.Stub() {
+
+ @Override
+ public void onWaitAppSelect(List appNameList, boolean isFirstSelect) throws RemoteException {
+ android.util.Log.d(TAG, "onWaitAppSelect isFirstSelect:" + isFirstSelect);
+ mProcessStep = EMV_APP_SELECT;
+ String[] candidateNames = getCandidateNames(appNameList);
+ mHandler.obtainMessage(EMV_APP_SELECT, candidateNames).sendToTarget();
+ }
+
+ @Override
+ public void onAppFinalSelect(String tag9F06Value) throws RemoteException {
+ android.util.Log.d(TAG, "onAppFinalSelect tag9F06Value:" + tag9F06Value);
+ mProcessStep = EMV_FINAL_APP_SELECT;
+ mHandler.obtainMessage(EMV_FINAL_APP_SELECT, tag9F06Value).sendToTarget();
+ }
+
+ @Override
+ public void onConfirmCardNo(String cardNo) throws RemoteException {
+ android.util.Log.d(TAG, "onConfirmCardNo cardNo:" + maskCardNumber(cardNo));
+ mCardNo = cardNo;
+ mProcessStep = EMV_CONFIRM_CARD_NO;
+ mHandler.obtainMessage(EMV_CONFIRM_CARD_NO).sendToTarget();
+ }
+
+ @Override
+ public void onRequestShowPinPad(int pinType, int remainTime) throws RemoteException {
+ android.util.Log.d(TAG, "onRequestShowPinPad pinType:" + pinType + " remainTime:" + remainTime);
+ mPinType = pinType;
+ if (mCardNo == null) {
+ mCardNo = getCardNo();
+ }
+ mProcessStep = EMV_SHOW_PIN_PAD;
+ mHandler.obtainMessage(EMV_SHOW_PIN_PAD).sendToTarget();
+ }
+
+ @Override
+ public void onRequestSignature() throws RemoteException {
+ android.util.Log.d(TAG, "onRequestSignature");
+ mProcessStep = EMV_SIGNATURE;
+ mHandler.obtainMessage(EMV_SIGNATURE).sendToTarget();
+ }
+
+ @Override
+ public void onCertVerify(int certType, String certInfo) throws RemoteException {
+ android.util.Log.d(TAG, "onCertVerify certType:" + certType + " certInfo:" + certInfo);
+ mCertInfo = certInfo;
+ mProcessStep = EMV_CERT_VERIFY;
+ mHandler.obtainMessage(EMV_CERT_VERIFY).sendToTarget();
+ }
+
+ @Override
+ public void onOnlineProc() throws RemoteException {
+ android.util.Log.d(TAG, "onOnlineProcess");
+ mProcessStep = EMV_ONLINE_PROCESS;
+ mHandler.obtainMessage(EMV_ONLINE_PROCESS).sendToTarget();
+ }
+
+ @Override
+ public void onCardDataExchangeComplete() throws RemoteException {
+ android.util.Log.d(TAG, "onCardDataExchangeComplete");
+ if (mCardType == AidlConstantsV2.CardType.NFC.getValue()) {
+ MyApplication.app.basicOptV2.buzzerOnDevice(1, 2750, 200, 0);
+ }
+ }
+
+ @Override
+ public void onTransResult(int code, String desc) throws RemoteException {
+ if (mCardNo == null) {
+ mCardNo = getCardNo();
+ }
+ android.util.Log.d(TAG, "onTransResult code:" + code + " desc:" + desc);
+
+ if (code == 1 || code == 2 || code == 5 || code == 6) {
+ mHandler.obtainMessage(EMV_TRANS_SUCCESS, code, code, desc).sendToTarget();
+ } else {
+ mHandler.obtainMessage(EMV_TRANS_FAIL, code, code, desc).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onConfirmationCodeVerified() throws RemoteException {
+ android.util.Log.d(TAG, "onConfirmationCodeVerified");
+ }
+
+ @Override
+ public void onRequestDataExchange(String cardNo) throws RemoteException {
+ android.util.Log.d(TAG, "onRequestDataExchange,cardNo:" + cardNo);
+ mEMVOptV2.importDataExchangeStatus(0);
+ }
+
+ @Override
+ public void onTermRiskManagement() throws RemoteException {
+ android.util.Log.d(TAG, "onTermRiskManagement");
+ mEMVOptV2.importTermRiskManagementStatus(0);
+ }
+
+ @Override
+ public void onPreFirstGenAC() throws RemoteException {
+ android.util.Log.d(TAG, "onPreFirstGenAC");
+ mEMVOptV2.importPreFirstGenACStatus(0);
+ }
+
+ @Override
+ public void onDataStorageProc(String[] containerID, String[] containerContent) throws RemoteException {
+ android.util.Log.d(TAG, "onDataStorageProc");
+ String[] tags = new String[0];
+ String[] values = new String[0];
+ mEMVOptV2.importDataStorage(tags, values);
+ }
+ };
+
+ // ====== EMV DIALOG HANDLERS ======
+ private void showAppSelectDialog(String[] candidateNames) {
+ mAppSelectDialog = new AlertDialog.Builder(this)
+ .setTitle("Please select application")
+ .setNegativeButton("Cancel", (dialog, which) -> importAppSelect(-1))
+ .setPositiveButton("OK", (dialog, which) -> importAppSelect(mSelectIndex))
+ .setSingleChoiceItems(candidateNames, 0, (dialog, which) -> mSelectIndex = which)
+ .create();
+ mSelectIndex = 0;
+ mAppSelectDialog.show();
+ }
+
+ private void showCardNumberConfirmation() {
+ runOnUiThread(() -> {
+ String displayText = "Card Number: " + maskCardNumber(mCardNo) +
+ "\n\nConfirming card number automatically...";
+ tvStatus.setText(displayText);
+
+ // Auto-confirm after short delay to avoid manual interaction
+ btnAction.postDelayed(() -> {
+ Log.d(TAG, "Auto-confirming card number");
+ btnAction.setText("Processing...");
+ importCardNoStatus(0);
+ }, 1500);
+
+ mProcessStep = EMV_CONFIRM_CARD_NO;
+ });
+ }
+
+ private void showCertificateVerification() {
+ runOnUiThread(() -> {
+ String displayText = "Certificate Information:\n" + mCertInfo +
+ "\n\nConfirming certificate automatically...";
+ tvStatus.setText(displayText);
+
+ // Auto-confirm after short delay
+ btnAction.postDelayed(() -> {
+ Log.d(TAG, "Auto-confirming certificate");
+ btnAction.setText("Processing...");
+ importCertStatus(0);
+ }, 1500);
+
+ mProcessStep = EMV_CERT_VERIFY;
+ });
+ }
+
+ // ====== PIN PAD METHODS ======
+ private void initPinPad() {
+ android.util.Log.e(TAG, "========== PIN PAD INITIALIZATION ==========");
+ try {
+ if (mPinPadOptV2 == null) {
+ throw new IllegalStateException("PIN Pad service not available");
+ }
+
+ if (mCardNo == null || mCardNo.length() < 13) {
+ throw new IllegalArgumentException("Invalid card number for PIN");
+ }
+
+ PinPadConfigV2 pinPadConfig = new PinPadConfigV2();
+ pinPadConfig.setPinPadType(0);
+ pinPadConfig.setPinType(mPinType);
+ pinPadConfig.setOrderNumKey(false);
+
+ String panForPin = mCardNo.substring(mCardNo.length() - 13, mCardNo.length() - 1);
+ byte[] panBytes = panForPin.getBytes("US-ASCII");
+ pinPadConfig.setPan(panBytes);
+
+ pinPadConfig.setTimeout(60 * 1000);
+ pinPadConfig.setPinKeyIndex(12);
+ pinPadConfig.setMaxInput(12);
+ pinPadConfig.setMinInput(0);
+ pinPadConfig.setKeySystem(0);
+ pinPadConfig.setAlgorithmType(0);
+
+ runOnUiThread(() -> {
+ tvStatus.setText("PIN Input Required\n\nPIN pad is ready\nPlease enter your PIN on the device");
+ btnAction.setText("PIN Pad Active");
+ btnAction.setEnabled(false);
+ });
+
+ mPinPadOptV2.initPinPad(pinPadConfig, mPinPadListener);
+
+ } catch (Exception e) {
+ android.util.Log.e(TAG, "PIN pad initialization failed: " + e.getMessage());
+ mHandler.obtainMessage(PIN_ERROR, -1, -1,
+ "PIN Error: " + e.getMessage()).sendToTarget();
+ }
+ }
+
+ private final PinPadListenerV2 mPinPadListener = new PinPadListenerV2.Stub() {
+ @Override
+ public void onPinLength(int len) throws RemoteException {
+ android.util.Log.d(TAG, "PIN input length: " + len);
+ runOnUiThread(() -> {
+ String dots = "";
+ for (int i = 0; i < len; i++) {
+ dots += "• ";
+ }
+ tvStatus.setText("PIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)");
+ });
+ }
+
+ @Override
+ public void onConfirm(int i, byte[] pinBlock) throws RemoteException {
+ android.util.Log.d(TAG, "PIN input confirmed");
+
+ runOnUiThread(() -> {
+ btnAction.setEnabled(true);
+ btnAction.setText("Processing...");
+ tvStatus.setText("PIN confirmed, processing...");
+ });
+
+ if (pinBlock != null) {
+ String hexStr = ByteUtil.bytes2HexStr(pinBlock);
+ android.util.Log.d(TAG, "PIN block received: " + hexStr);
+ mHandler.obtainMessage(PIN_CLICK_PIN, pinBlock).sendToTarget();
+ } else {
+ android.util.Log.d(TAG, "PIN bypass confirmed");
+ mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onCancel() throws RemoteException {
+ android.util.Log.d(TAG, "PIN input cancelled by user");
+
+ runOnUiThread(() -> {
+ btnAction.setEnabled(true);
+ btnAction.setText("Start Scanning");
+ tvStatus.setText("PIN input cancelled");
+ });
+
+ mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
+ }
+
+ @Override
+ public void onError(int code) throws RemoteException {
+ android.util.Log.e(TAG, "PIN pad error: " + code);
+ String msg = AidlErrorCodeV2.valueOf(code).getMsg();
+
+ runOnUiThread(() -> {
+ btnAction.setEnabled(true);
+ btnAction.setText("Start Scanning");
+ tvStatus.setText("PIN error: " + msg);
+ });
+
+ mHandler.obtainMessage(PIN_ERROR, code, code, msg).sendToTarget();
+ }
+
+ @Override
+ public void onHover(int event, byte[] data) throws RemoteException {
+ android.util.Log.d(TAG, "PIN pad hover event: " + event);
+ }
+ };
+
+ // ====== EMV RESET METHODS ======
+ private void resetEMVAndRetry() {
+ new Thread(() -> {
+ try {
+ Log.d(TAG, "Resetting EMV process...");
+
+ // Cancel any existing card operations first
+ if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) {
+ MyApplication.app.readCardOptV2.cancelCheckCard();
+ }
+
+ Thread.sleep(500); // Wait for cancel to complete
+
+ // Reset EMV process
+ if (mEMVOptV2 != null) {
+ mEMVOptV2.initEmvProcess(); // Reset EMV state
+ }
+
+ Thread.sleep(1500); // Wait longer for complete reset
+
+ runOnUiThread(() -> {
+ Log.d(TAG, "EMV reset complete - ready for retry");
+ resetScanningState();
+ showToast("Ready to scan - please try again");
+ });
+
+ } catch (Exception e) {
+ Log.e(TAG, "Error resetting EMV: " + e.getMessage(), e);
+ runOnUiThread(() -> {
+ resetScanningState();
+ showToast("Reset failed - please try again");
+ });
+ }
+ }).start();
+ }
+
+ private void resetScanningState() {
+ Log.d(TAG, "Resetting scanning state");
+ isProcessing = false;
+ isButtonProcessing = false;
+ mProcessStep = 0;
+ btnAction.setText("Start Scanning");
+ btnAction.setEnabled(true);
+ updateUI(); // Reset UI to initial state
+ }
+
+ // ====== HELPER METHODS ======
+ private void navigateToResults() {
+ Intent intent = new Intent(this, CreditCardActivity.class);
+ intent.putExtra("TRANSACTION_AMOUNT", transactionAmount);
+ intent.putExtra("CARD_TYPE", mCardType == AidlConstantsV2.CardType.NFC.getValue() ? "NFC" : "IC");
+ intent.putExtra("EMV_MODE", isEMVMode);
+ intent.putExtra("CARD_NO", mCardNo);
+ startActivity(intent);
+ finish();
+ }
+
+ private void mockOnlineProcess() {
+ new Thread(() -> {
+ try {
+ runOnUiThread(() -> tvStatus.setText("Processing online authorization..."));
+ Thread.sleep(2000);
+
+ try {
+ String[] tags = {"71", "72", "91", "8A", "89"};
+ String[] values = {"", "", "", "", ""};
+ byte[] out = new byte[1024];
+ int len = mEMVOptV2.importOnlineProcStatus(0, tags, values, out);
+ if (len < 0) {
+ android.util.Log.e(TAG, "importOnlineProcessStatus error,code:" + len);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+
+ private String getCardNo() {
+ // Implementation from original code
+ return "";
+ }
+
+ private String maskCardNumber(String cardNo) {
+ if (cardNo == null || cardNo.length() < 8) {
+ return cardNo;
+ }
+ String first4 = cardNo.substring(0, 4);
+ String last4 = cardNo.substring(cardNo.length() - 4);
+ StringBuilder middle = new StringBuilder();
+ for (int i = 0; i < cardNo.length() - 8; i++) {
+ middle.append("*");
+ }
+ return first4 + middle.toString() + last4;
+ }
+
+ private String[] getCandidateNames(List candiList) {
+ if (candiList == null || candiList.size() == 0) return new String[0];
+ String[] result = new String[candiList.size()];
+ for (int i = 0; i < candiList.size(); i++) {
+ EMVCandidateV2 candi = candiList.get(i);
+ String name = candi.appPreName;
+ name = TextUtils.isEmpty(name) ? candi.appLabel : name;
+ name = TextUtils.isEmpty(name) ? candi.appName : name;
+ name = TextUtils.isEmpty(name) ? "" : name;
+ result[i] = name;
+ }
+ return result;
+ }
+
+ // ====== EMV IMPORT METHODS ======
+ private void importAppSelect(int selectIndex) {
+ try {
+ mEMVOptV2.importAppSelect(selectIndex);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void importFinalAppSelectStatus(int status) {
+ try {
+ mEMVOptV2.importAppFinalSelectStatus(status);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void importCardNoStatus(int status) {
+ try {
+ mEMVOptV2.importCardNoStatus(status);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void importCertStatus(int status) {
+ try {
+ mEMVOptV2.importCertStatus(status);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void importPinInputStatus(int inputResult) {
+ try {
+ mEMVOptV2.importPinInputStatus(mPinType, inputResult);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void importSignatureStatus(int status) {
+ try {
+ mEMVOptV2.importSignatureStatus(status);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void showToast(String message) {
+ Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public boolean onSupportNavigateUp() {
+ onBackPressed();
+ return true;
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.d(TAG, "onDestroy - cleaning up EMV resources");
+
+ try {
+ // Cancel card operations
+ if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) {
+ MyApplication.app.readCardOptV2.cancelCheckCard();
+ }
+
+ // Reset EMV process
+ if (mEMVOptV2 != null) {
+ mEMVOptV2.initEmvProcess();
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, "Error cleaning up EMV: " + e.getMessage());
+ }
+
+ super.onDestroy();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_create_transaction.xml b/app/src/main/res/layout/activity_create_transaction.xml
new file mode 100644
index 0000000..ec0b3b2
--- /dev/null
+++ b/app/src/main/res/layout/activity_create_transaction.xml
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_credit_card.xml b/app/src/main/res/layout/activity_credit_card.xml
index 35e202c..140434e 100644
--- a/app/src/main/res/layout/activity_credit_card.xml
+++ b/app/src/main/res/layout/activity_credit_card.xml
@@ -1,367 +1,222 @@
-
-
+ android:background="@color/colorBackground"
+ tools:context=".kredit.CreditCardActivity">
+ android:background="@color/primary_blue"
+ android:theme="@style/CustomToolbarTheme"
+ app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
-
-
-
-
-
-
-
-
+ android:fillViewport="true">
-
-
-
-
+ android:padding="16dp">
-
+
+ android:layout_marginBottom="16dp"
+ app:cardCornerRadius="12dp"
+ app:cardElevation="4dp"
+ app:cardBackgroundColor="@color/accent_green">
-
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_marginBottom="16dp"
+ app:cardCornerRadius="12dp"
+ app:cardElevation="4dp">
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_marginBottom="16dp"
+ app:cardCornerRadius="12dp"
+ app:cardElevation="4dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:background="@android:color/white"
+ android:elevation="8dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_emv_transaction.xml b/app/src/main/res/layout/activity_emv_transaction.xml
new file mode 100644
index 0000000..fb47bc8
--- /dev/null
+++ b/app/src/main/res/layout/activity_emv_transaction.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 1bd9eab..827fd47 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -31,4 +31,88 @@
#F5F5F5
#E0E0E0
#757575
+
+
+
+
+
+ @color/primary_blue
+ @color/colorPrimaryDark
+ @color/white
+ @color/primary_blue
+ @color/medium_gray
+
+
+ @color/colorBackground
+ @color/white
+ @color/white
+
+
+ @color/colorTextTitle
+ @color/colorTextContent
+ @color/colorTextHelp
+ @color/C999999
+ @color/white
+
+
+ @color/accent_green
+ @color/FD5A52
+ @color/colorOrange
+ @color/light_blue
+
+
+ @color/colorOrange
+ @color/accent_green
+ @color/FD5A52
+ @color/dark_gray
+
+
+ @color/white
+ @color/medium_gray
+ @color/colorLineColor
+
+
+ @color/primary_blue
+ @color/light_blue
+ @color/accent_green
+
+
+ @color/colorLineColor
+ @color/medium_gray
+ @color/dark_gray
+
+
+ @color/transparent
+ @color/transparent
+ @color/medium_gray
+
+
+ @color/primary_blue
+ @color/accent_green
+ @color/colorOrange
+ @color/FD5A52
+
+
+ @color/colorTextTitle
+ @color/white
+ @color/light_gray
+
+
+ @color/primary_blue
+ @color/white
+ @color/white
+ @color/light_gray
+
+
+ @color/primary_blue
+ @color/white
+ @color/white
+
+
+ @color/primary_blue
+ @color/dark_gray
+ @color/accent_green
+ @color/FD5A52
+ @color/white
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 90af3f0..f82c7d5 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -50,4 +50,172 @@
- true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file