Safepoint Check EMV

This commit is contained in:
riz081 2025-06-18 23:42:48 +07:00
parent 2ea0792d28
commit f48e3e64a4

View File

@ -98,47 +98,66 @@ public class CreditCardActivity extends AppCompatActivity {
case EMV_FINAL_APP_SELECT: case EMV_FINAL_APP_SELECT:
importFinalAppSelectStatus(0); importFinalAppSelectStatus(0);
break; break;
case EMV_APP_SELECT: case EMV_APP_SELECT:
String[] candiNames = (String[]) msg.obj; String[] candiNames = (String[]) msg.obj;
showAppSelectDialog(candiNames); showAppSelectDialog(candiNames);
break; break;
case EMV_CONFIRM_CARD_NO: case EMV_CONFIRM_CARD_NO:
// Tampilkan UI konfirmasi, JANGAN langsung import
showCardNumberConfirmation(); showCardNumberConfirmation();
break; break;
case EMV_CERT_VERIFY: case EMV_CERT_VERIFY:
// Tampilkan UI sertifikat, JANGAN langsung import
showCertificateVerification(); showCertificateVerification();
break; break;
case EMV_SHOW_PIN_PAD: case EMV_SHOW_PIN_PAD:
dismissLoadingDialog();
android.util.Log.d(TAG, "Initializing PIN pad...");
initPinPad(); initPinPad();
break; break;
case EMV_ONLINE_PROCESS: case EMV_ONLINE_PROCESS:
mockOnlineProcess(); mockOnlineProcess();
break; break;
case EMV_SIGNATURE: case EMV_SIGNATURE:
importSignatureStatus(0); importSignatureStatus(0);
break; break;
case PIN_CLICK_PIN: case PIN_CLICK_PIN:
android.util.Log.d(TAG, "PIN input confirmed");
importPinInputStatus(0); importPinInputStatus(0);
break; break;
case PIN_CLICK_CONFIRM: case PIN_CLICK_CONFIRM:
android.util.Log.d(TAG, "PIN confirm without input (bypass)");
importPinInputStatus(2); importPinInputStatus(2);
break; break;
case PIN_CLICK_CANCEL: case PIN_CLICK_CANCEL:
showToast("User cancelled PIN input"); showToast("PIN input cancelled by user");
importPinInputStatus(1); importPinInputStatus(1);
break; break;
case PIN_ERROR: case PIN_ERROR:
showToast("PIN Error: " + msg.obj + " -- " + msg.arg1); android.util.Log.e(TAG, "PIN Error: " + msg.obj + " -- " + msg.arg1);
showToast("PIN Error: " + msg.obj);
importPinInputStatus(3); importPinInputStatus(3);
break; break;
case EMV_TRANS_FAIL: case EMV_TRANS_FAIL:
resetUI(); resetUI();
showToast("Transaction failed: " + msg.obj + " -- " + msg.arg1); showToast("Transaction failed: " + msg.obj + " -- " + msg.arg1);
break; break;
case EMV_TRANS_SUCCESS: case EMV_TRANS_SUCCESS:
resetUI(); resetUI();
getTlvData(); // Get complete card data getTlvData(); // Get complete card data
showToast("Transaction successful: " + msg.obj + " -- " + msg.arg1); showToast("Transaction successful!");
break; break;
} }
} }
@ -382,22 +401,63 @@ public class CreditCardActivity extends AppCompatActivity {
} }
private void switchCheckCard() { private void switchCheckCard() {
android.util.Log.d(TAG, "switchCheckCard called, checkingCard: " + checkingCard); android.util.Log.d(TAG, "switchCheckCard called, mProcessStep: " + mProcessStep);
try { try {
if (checkingCard) { // Handle berbagai process steps
android.util.Log.d(TAG, "Stopping card check"); if (mProcessStep == 0) {
stopCardCheck(); // Initial state - start/stop card scanning
if (checkingCard) {
android.util.Log.d(TAG, "Stopping card check");
stopCardCheck();
} else {
android.util.Log.d(TAG, "Starting card check");
startCardCheck();
}
} else if (mProcessStep == EMV_CONFIRM_CARD_NO) {
// Handle card number confirmation
android.util.Log.d(TAG, "User confirmed card number");
showLoadingDialog("Processing card confirmation...");
btnCheckCard.setText("Processing...");
// Import card number status dan reset process step
importCardNoStatus(0);
} else if (mProcessStep == EMV_CERT_VERIFY) {
// Handle certificate verification
android.util.Log.d(TAG, "User confirmed certificate");
showLoadingDialog("Processing certificate...");
btnCheckCard.setText("Processing...");
// Import certificate status
importCertStatus(0);
} else { } else {
android.util.Log.d(TAG, "Starting card check"); android.util.Log.w(TAG, "Unknown process step: " + mProcessStep);
startCardCheck();
} }
} catch (Exception e) { } catch (Exception e) {
android.util.Log.e(TAG, "Error in switchCheckCard: " + e.getMessage()); android.util.Log.e(TAG, "Error in switchCheckCard: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
updateUI("Error: " + e.getMessage(), false); updateUI("Error: " + e.getMessage(), false);
resetUI();
} }
} }
private void showLoadingDialog(String message) {
runOnUiThread(() -> {
if (tvResult != null) {
tvResult.setText(message + "...");
}
android.util.Log.d(TAG, "Loading: " + message);
});
}
private void dismissLoadingDialog() {
// Method ini bisa kosong atau implement actual dialog dismissal
android.util.Log.d(TAG, "Loading dismissed");
}
private void startCardCheck() { private void startCardCheck() {
try { try {
if (isEMVMode) { if (isEMVMode) {
@ -860,22 +920,38 @@ public class CreditCardActivity extends AppCompatActivity {
} }
private void showCardNumberConfirmation() { private void showCardNumberConfirmation() {
tvResult.setText("Card Number: " + maskCardNumber(mCardNo) + "\n\nPlease confirm card number"); runOnUiThread(() -> {
btnCheckCard.setText("Confirm"); dismissLoadingDialog(); // Pastikan loading dialog ditutup
btnCheckCard.setOnClickListener(v -> {
importCardNoStatus(0); String displayText = "Card Number: " + maskCardNumber(mCardNo) +
btnCheckCard.setText("Processing..."); "\n\nPlease confirm this card number to continue";
btnCheckCard.setOnClickListener(null); tvResult.setText(displayText);
// HANYA ubah text button, JANGAN ubah listener
btnCheckCard.setText("Confirm Card Number");
// Set process step untuk onClick handler
mProcessStep = EMV_CONFIRM_CARD_NO;
android.util.Log.d(TAG, "Card number confirmation UI updated, waiting for user input");
}); });
} }
private void showCertificateVerification() { private void showCertificateVerification() {
tvResult.setText("Certificate Info: " + mCertInfo + "\n\nPlease confirm certificate"); runOnUiThread(() -> {
btnCheckCard.setText("Confirm"); dismissLoadingDialog();
btnCheckCard.setOnClickListener(v -> {
importCertStatus(0); String displayText = "Certificate Information:\n" + mCertInfo +
btnCheckCard.setText("Processing..."); "\n\nPlease confirm certificate to continue";
btnCheckCard.setOnClickListener(null); tvResult.setText(displayText);
// HANYA ubah text button
btnCheckCard.setText("Confirm Certificate");
// Set process step
mProcessStep = EMV_CERT_VERIFY;
android.util.Log.d(TAG, "Certificate verification UI updated, waiting for user input");
}); });
} }
@ -1437,61 +1513,115 @@ public class CreditCardActivity extends AppCompatActivity {
// ====== PIN PAD METHODS ====== // ====== PIN PAD METHODS ======
private void initPinPad() { private void initPinPad() {
android.util.Log.e(TAG, "========== PIN PAD INITIALIZATION ==========");
try { try {
// Validate components
if (mPinPadOptV2 == null) {
throw new IllegalStateException("PIN Pad service not available");
}
// Validate card number
if (mCardNo == null || mCardNo.length() < 13) {
throw new IllegalArgumentException("Invalid card number for PIN");
}
PinPadConfigV2 pinPadConfig = new PinPadConfigV2(); PinPadConfigV2 pinPadConfig = new PinPadConfigV2();
pinPadConfig.setPinPadType(0); pinPadConfig.setPinPadType(0);
pinPadConfig.setPinType(mPinType); pinPadConfig.setPinType(mPinType);
pinPadConfig.setOrderNumKey(false); pinPadConfig.setOrderNumKey(false);
byte[] panBytes = mCardNo.substring(mCardNo.length() - 13, mCardNo.length() - 1).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);
// Use the correct PAN format (last 12 digits excluding check digit)
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); // Make sure this matches your key index
pinPadConfig.setMaxInput(12);
pinPadConfig.setMinInput(0); // Allow bypass
pinPadConfig.setKeySystem(0); // 0 = international, 1 = domestic
pinPadConfig.setAlgorithmType(0); // 0 = 3DES, 1 = SM4
// Update UI
runOnUiThread(() -> {
updateUI("PIN Input Required\n\nPIN pad is ready\nPlease enter your PIN on the device", false);
btnCheckCard.setText("PIN Pad Active");
btnCheckCard.setEnabled(false);
});
// Initialize PIN pad
mPinPadOptV2.initPinPad(pinPadConfig, mPinPadListener); mPinPadOptV2.initPinPad(pinPadConfig, mPinPadListener);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); android.util.Log.e(TAG, "PIN pad initialization failed: " + e.getMessage());
mHandler.obtainMessage(PIN_ERROR, Integer.MIN_VALUE, Integer.MIN_VALUE, "initPinPad() failure").sendToTarget(); mHandler.obtainMessage(PIN_ERROR, -1, -1,
"PIN Error: " + e.getMessage()).sendToTarget();
} }
} }
private final PinPadListenerV2 mPinPadListener = new PinPadListenerV2.Stub() { private final PinPadListenerV2 mPinPadListener = new PinPadListenerV2.Stub() {
@Override @Override
public void onPinLength(int len) { public void onPinLength(int len) throws RemoteException {
android.util.Log.d(TAG, "onPinLength:" + len); android.util.Log.d(TAG, "PIN input length: " + len);
mHandler.obtainMessage(PIN_CLICK_NUMBER, len).sendToTarget(); runOnUiThread(() -> {
String dots = "";
for (int i = 0; i < len; i++) {
dots += "";
}
tvResult.setText("PIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)");
});
} }
@Override @Override
public void onConfirm(int i, byte[] pinBlock) { 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("PIN confirmed, processing...");
});
if (pinBlock != null) { if (pinBlock != null) {
String hexStr = ByteUtil.bytes2HexStr(pinBlock); String hexStr = ByteUtil.bytes2HexStr(pinBlock);
android.util.Log.d(TAG, "onConfirm pin block:" + hexStr); android.util.Log.d(TAG, "PIN block received: " + hexStr);
mHandler.obtainMessage(PIN_CLICK_PIN, pinBlock).sendToTarget(); mHandler.obtainMessage(PIN_CLICK_PIN, pinBlock).sendToTarget();
} else { } else {
android.util.Log.d(TAG, "PIN bypass confirmed");
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget(); mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
} }
} }
@Override @Override
public void onCancel() { public void onCancel() throws RemoteException {
android.util.Log.d(TAG, "onCancel"); 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(); mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
} }
@Override @Override
public void onError(int code) { public void onError(int code) throws RemoteException {
android.util.Log.e(TAG, "onError:" + code); android.util.Log.e(TAG, "PIN pad error: " + code);
String msg = AidlErrorCodeV2.valueOf(code).getMsg(); 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(); mHandler.obtainMessage(PIN_ERROR, code, code, msg).sendToTarget();
} }
@Override @Override
public void onHover(int event, byte[] data) throws RemoteException { public void onHover(int event, byte[] data) throws RemoteException {
android.util.Log.d(TAG, "onHover(), event:" + event + ", data:" + ByteUtil.bytes2HexStr(data)); android.util.Log.d(TAG, "PIN pad hover event: " + event);
} }
}; };
@ -1543,9 +1673,12 @@ public class CreditCardActivity extends AppCompatActivity {
private void resetUI() { private void resetUI() {
runOnUiThread(() -> { runOnUiThread(() -> {
mProcessStep = 0; mProcessStep = 0; // Reset process step ke initial state
btnCheckCard.setText("Start Scanning"); btnCheckCard.setText("Start Scanning");
// Reset click listener ke original method
btnCheckCard.setOnClickListener(v -> switchCheckCard()); btnCheckCard.setOnClickListener(v -> switchCheckCard());
dismissAppSelectDialog(); dismissAppSelectDialog();
updateModeDisplay(); updateModeDisplay();
@ -1556,6 +1689,8 @@ public class CreditCardActivity extends AppCompatActivity {
if (btnClearData != null) { if (btnClearData != null) {
btnClearData.setVisibility(android.view.View.GONE); btnClearData.setVisibility(android.view.View.GONE);
} }
android.util.Log.d(TAG, "UI reset to initial state");
}); });
} }