Safepoint Check EMV
This commit is contained in:
parent
2ea0792d28
commit
f48e3e64a4
@ -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");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user