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:
importFinalAppSelectStatus(0);
break;
case EMV_APP_SELECT:
String[] candiNames = (String[]) msg.obj;
showAppSelectDialog(candiNames);
break;
case EMV_CONFIRM_CARD_NO:
// Tampilkan UI konfirmasi, JANGAN langsung import
showCardNumberConfirmation();
break;
case EMV_CERT_VERIFY:
// Tampilkan UI sertifikat, JANGAN langsung import
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("User cancelled PIN input");
showToast("PIN input cancelled by user");
importPinInputStatus(1);
break;
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);
break;
case EMV_TRANS_FAIL:
resetUI();
showToast("Transaction failed: " + msg.obj + " -- " + msg.arg1);
break;
case EMV_TRANS_SUCCESS:
resetUI();
getTlvData(); // Get complete card data
showToast("Transaction successful: " + msg.obj + " -- " + msg.arg1);
showToast("Transaction successful!");
break;
}
}
@ -382,22 +401,63 @@ public class CreditCardActivity extends AppCompatActivity {
}
private void switchCheckCard() {
android.util.Log.d(TAG, "switchCheckCard called, checkingCard: " + checkingCard);
android.util.Log.d(TAG, "switchCheckCard called, mProcessStep: " + mProcessStep);
try {
if (checkingCard) {
android.util.Log.d(TAG, "Stopping card check");
stopCardCheck();
// Handle berbagai process steps
if (mProcessStep == 0) {
// 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 {
android.util.Log.d(TAG, "Starting card check");
startCardCheck();
android.util.Log.w(TAG, "Unknown process step: " + mProcessStep);
}
} catch (Exception e) {
android.util.Log.e(TAG, "Error in switchCheckCard: " + e.getMessage());
e.printStackTrace();
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() {
try {
if (isEMVMode) {
@ -860,22 +920,38 @@ public class CreditCardActivity extends AppCompatActivity {
}
private void showCardNumberConfirmation() {
tvResult.setText("Card Number: " + maskCardNumber(mCardNo) + "\n\nPlease confirm card number");
btnCheckCard.setText("Confirm");
btnCheckCard.setOnClickListener(v -> {
importCardNoStatus(0);
btnCheckCard.setText("Processing...");
btnCheckCard.setOnClickListener(null);
runOnUiThread(() -> {
dismissLoadingDialog(); // Pastikan loading dialog ditutup
String displayText = "Card Number: " + maskCardNumber(mCardNo) +
"\n\nPlease confirm this card number to continue";
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() {
tvResult.setText("Certificate Info: " + mCertInfo + "\n\nPlease confirm certificate");
btnCheckCard.setText("Confirm");
btnCheckCard.setOnClickListener(v -> {
importCertStatus(0);
btnCheckCard.setText("Processing...");
btnCheckCard.setOnClickListener(null);
runOnUiThread(() -> {
dismissLoadingDialog();
String displayText = "Certificate Information:\n" + mCertInfo +
"\n\nPlease confirm certificate to continue";
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 ======
private void initPinPad() {
android.util.Log.e(TAG, "========== PIN PAD INITIALIZATION ==========");
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();
pinPadConfig.setPinPadType(0);
pinPadConfig.setPinType(mPinType);
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);
} catch (Exception e) {
e.printStackTrace();
mHandler.obtainMessage(PIN_ERROR, Integer.MIN_VALUE, Integer.MIN_VALUE, "initPinPad() failure").sendToTarget();
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) {
android.util.Log.d(TAG, "onPinLength:" + len);
mHandler.obtainMessage(PIN_CLICK_NUMBER, len).sendToTarget();
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("PIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)");
});
}
@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) {
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();
} else {
android.util.Log.d(TAG, "PIN bypass confirmed");
mHandler.obtainMessage(PIN_CLICK_CONFIRM).sendToTarget();
}
}
@Override
public void onCancel() {
android.util.Log.d(TAG, "onCancel");
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) {
android.util.Log.e(TAG, "onError:" + code);
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, "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() {
runOnUiThread(() -> {
mProcessStep = 0;
mProcessStep = 0; // Reset process step ke initial state
btnCheckCard.setText("Start Scanning");
// Reset click listener ke original method
btnCheckCard.setOnClickListener(v -> switchCheckCard());
dismissAppSelectDialog();
updateModeDisplay();
@ -1556,6 +1689,8 @@ public class CreditCardActivity extends AppCompatActivity {
if (btnClearData != null) {
btnClearData.setVisibility(android.view.View.GONE);
}
android.util.Log.d(TAG, "UI reset to initial state");
});
}