From f40335855453e5b6e25bae2517d32917ba91569a Mon Sep 17 00:00:00 2001 From: riz081 Date: Mon, 23 Jun 2025 09:20:26 +0700 Subject: [PATCH] Safepoint Modal Scan Card --- .../kredit/EmvTransactionActivity.java | 253 ++++++------------ app/src/main/res/anim/fade_in.xml | 8 +- .../res/layout/activity_emv_transaction.xml | 174 ++++-------- 3 files changed, 149 insertions(+), 286 deletions(-) diff --git a/app/src/main/java/com/example/bdkipoc/kredit/EmvTransactionActivity.java b/app/src/main/java/com/example/bdkipoc/kredit/EmvTransactionActivity.java index 2551ebe..f9b74d6 100644 --- a/app/src/main/java/com/example/bdkipoc/kredit/EmvTransactionActivity.java +++ b/app/src/main/java/com/example/bdkipoc/kredit/EmvTransactionActivity.java @@ -8,7 +8,9 @@ import android.os.Message; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; -import android.widget.Button; +import android.view.View; +import android.widget.ImageView; +import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; @@ -45,17 +47,15 @@ import java.util.regex.Pattern; public class EmvTransactionActivity extends AppCompatActivity { private static final String TAG = "EmvTransaction"; - // UI Components + // UI Components - SIMPLIFIED private TextView tvStatus; - private TextView tvAmountDisplay; - private Button btnAction; - private Button btnCancel; + private ProgressBar progressBar; + private ImageView ivCardReader; // Transaction Data private String transactionAmount; private boolean isEMVMode; private boolean isProcessing = false; - private boolean isButtonProcessing = false; // ADD THIS MISSING FIELD // EMV Components private EMVOptV2 mEMVOptV2; @@ -197,8 +197,9 @@ public class EmvTransactionActivity extends AppCompatActivity { } } + // ====== UPDATED INIT VIEWS METHOD ====== private void initViews() { - // Setup Toolbar + // Setup Toolbar with back navigation Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); if (getSupportActionBar() != null) { @@ -206,13 +207,21 @@ public class EmvTransactionActivity extends AppCompatActivity { getSupportActionBar().setTitle("Scan Kartu"); } + // Initialize UI components 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); + progressBar = findViewById(R.id.progress_bar); + ivCardReader = findViewById(R.id.iv_card_reader); - btnAction.setOnClickListener(v -> handleActionClick()); - btnCancel.setOnClickListener(v -> finish()); + // Set initial state + updateStatusUI("Initializing scanner...", true); + } + + // ====== NEW METHOD TO UPDATE STATUS UI ====== + private void updateStatusUI(String statusText, boolean showProgress) { + runOnUiThread(() -> { + tvStatus.setText(statusText); + progressBar.setVisibility(showProgress ? View.VISIBLE : View.GONE); + }); } private void initEMVComponents() { @@ -294,7 +303,7 @@ public class EmvTransactionActivity extends AppCompatActivity { } } - // ====== AUTO-SCAN METHODS ====== + // ====== UPDATED AUTO-START SCANNING METHOD ====== private void autoStartScanning() { Log.d(TAG, "Auto-starting card scanning..."); @@ -303,11 +312,7 @@ public class EmvTransactionActivity extends AppCompatActivity { return; } - runOnUiThread(() -> { - tvStatus.setText("Ready for card...\n\nPlease insert, swipe, or tap your card\n\nScanning will start automatically"); - btnAction.setText("CANCEL"); - btnAction.setEnabled(true); - }); + updateStatusUI("Ready for card...\n\nPlease insert, swipe, or tap your card\n\nScanning will start automatically", true); // Start scanning automatically startCardCheck(); @@ -324,87 +329,8 @@ public class EmvTransactionActivity extends AppCompatActivity { }, 2000); // 2 second delay before restart } - // ====== CARD SCANNING METHODS ====== - - 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 = "Auto-scanning active...\n" + - "Mode: " + mode + "\n\n" + - "Please insert, swipe, or tap your card\n" + - "Processing will start automatically"; - - tvStatus.setText(status); - btnAction.setText("CANCEL"); - } - - 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) { - // Only handle cancel in auto-scan mode - if (isProcessing) { - cancelScanning(); - } else { - // If not processing, this becomes cancel to go back - finish(); - } - } 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 cancelScanning() { - Log.d(TAG, "User cancelled scanning"); - - try { - // Cancel current operations - if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) { - MyApplication.app.readCardOptV2.cancelCheckCard(); - } - - // Reset EMV process - if (mEMVOptV2 != null) { - mEMVOptV2.initEmvProcess(); - } - - // Reset state - isProcessing = false; - mProcessStep = 0; - - // Go back to previous activity - finish(); - - } catch (Exception e) { - Log.e(TAG, "Error cancelling scan: " + e.getMessage(), e); - finish(); - } - } - + // ====== UPDATED CARD CHECK METHODS ====== private void startCardCheck() { - // Prevent multiple calls if (isProcessing) { Log.d(TAG, "Card check already in progress - ignoring call"); return; @@ -413,21 +339,15 @@ public class EmvTransactionActivity extends AppCompatActivity { Log.d(TAG, "Starting auto card check - setting isProcessing = true"); isProcessing = true; - runOnUiThread(() -> { - tvStatus.setText("Initializing scanner...\n\nPlease wait..."); - btnAction.setText("CANCEL"); - btnAction.setEnabled(true); - }); + updateStatusUI("Initializing scanner...\n\nPlease wait...", true); 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 new Handler(Looper.getMainLooper()).postDelayed(() -> { - if (isProcessing && !isFinishing()) { // Double check we're still processing + if (isProcessing && !isFinishing()) { continueCardCheck(); } }, 500); @@ -451,12 +371,8 @@ public class EmvTransactionActivity extends AppCompatActivity { return; } - runOnUiThread(() -> { - String mode = isEMVMode ? "EMV Mode" : "Simple Mode"; - tvStatus.setText("Scanning for card...\n\nMode: " + mode + "\n\nPlease insert, swipe, or tap your card"); - btnAction.setText("CANCEL"); - btnAction.setEnabled(true); - }); + String mode = isEMVMode ? "EMV Mode" : "Simple Mode"; + updateStatusUI("Scanning for card...\n\nMode: " + mode + "\n\nPlease insert, swipe, or tap your card", true); if (isEMVMode) { startEMVCardCheck(); @@ -470,21 +386,18 @@ public class EmvTransactionActivity extends AppCompatActivity { } } + // ====== UPDATED HANDLE SCAN ERROR ====== private void handleScanError(String errorMessage) { Log.e(TAG, "Scan error: " + errorMessage); - runOnUiThread(() -> { - isProcessing = false; - mProcessStep = 0; - - tvStatus.setText("Scan error: " + errorMessage + "\n\nRetrying in 2 seconds..."); - btnAction.setText("CANCEL"); - - showToast(errorMessage); - - // Auto-restart scanning after error - restartAutoScanning(); - }); + isProcessing = false; + mProcessStep = 0; + + updateStatusUI("Scan error: " + errorMessage + "\n\nRetrying in 2 seconds...", false); + showToast(errorMessage); + + // Auto-restart scanning after error + restartAutoScanning(); } private void startEMVCardCheck() { @@ -497,7 +410,7 @@ public class EmvTransactionActivity extends AppCompatActivity { mEMVOptV2.initEmvProcess(); initEmvTlvData(); - tvStatus.setText("EMV Mode: Starting card scan...\nPlease insert, swipe, or tap your card"); + updateStatusUI("EMV Mode: Starting card scan...\nPlease insert, swipe, or tap your card", true); int cardType = AidlConstantsV2.CardType.NFC.getValue() | AidlConstantsV2.CardType.IC.getValue(); android.util.Log.d(TAG, "Starting EMV checkCard with cardType: " + cardType); @@ -514,13 +427,13 @@ public class EmvTransactionActivity extends AppCompatActivity { private void startSimpleCardCheck() { try { if (!MyApplication.app.isConnectPaySDK()) { - tvStatus.setText("Connecting to PaySDK..."); + updateStatusUI("Connecting to PaySDK...", true); 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"); + updateStatusUI("Simple Mode: Starting card scan...\nPlease insert, swipe, or tap your card", true); MyApplication.app.readCardOptV2.checkCard(cardType, mSimpleCheckCardCallback, 60); @@ -536,8 +449,7 @@ public class EmvTransactionActivity extends AppCompatActivity { MyApplication.app.readCardOptV2.cancelCheckCard(); } isProcessing = false; - btnAction.setText("Start Scanning"); - updateUI(); + updateStatusUI("Ready for card...\n\nPlease insert, swipe, or tap your card", true); } catch (Exception e) { android.util.Log.e(TAG, "Error stopping card check: " + e.getMessage()); } @@ -688,7 +600,7 @@ public class EmvTransactionActivity extends AppCompatActivity { } bundle.putInt("cardType", mCardType); - tvStatus.setText("EMV processing started...\nReading card data..."); + updateStatusUI("EMV processing started...\nReading card data...", true); Log.d(TAG, "Starting transactProcessEx with reset EMV"); mEMVOptV2.transactProcessEx(bundle, mEMVListener); @@ -833,16 +745,16 @@ public class EmvTransactionActivity extends AppCompatActivity { mAppSelectDialog.show(); } + // ====== UPDATED EMV DIALOG HANDLERS ====== private void showCardNumberConfirmation() { runOnUiThread(() -> { - String displayText = "Card Number: " + maskCardNumber(mCardNo) + - "\n\nConfirming card number automatically..."; - tvStatus.setText(displayText); + String displayText = "Card Number Detected:\n" + maskCardNumber(mCardNo) + + "\n\nConfirming automatically..."; + updateStatusUI(displayText, true); - // Auto-confirm after short delay to avoid manual interaction - btnAction.postDelayed(() -> { + // Auto-confirm after short delay + new Handler(Looper.getMainLooper()).postDelayed(() -> { Log.d(TAG, "Auto-confirming card number"); - btnAction.setText("Processing..."); importCardNoStatus(0); }, 1500); @@ -852,14 +764,13 @@ public class EmvTransactionActivity extends AppCompatActivity { private void showCertificateVerification() { runOnUiThread(() -> { - String displayText = "Certificate Information:\n" + mCertInfo + - "\n\nConfirming certificate automatically..."; - tvStatus.setText(displayText); + String displayText = "Certificate Verification:\n" + mCertInfo + + "\n\nProcessing automatically..."; + updateStatusUI(displayText, true); // Auto-confirm after short delay - btnAction.postDelayed(() -> { + new Handler(Looper.getMainLooper()).postDelayed(() -> { Log.d(TAG, "Auto-confirming certificate"); - btnAction.setText("Processing..."); importCertStatus(0); }, 1500); @@ -867,7 +778,7 @@ public class EmvTransactionActivity extends AppCompatActivity { }); } - // ====== PIN PAD METHODS ====== + // ====== UPDATED PIN PAD METHODS ====== private void initPinPad() { android.util.Log.e(TAG, "========== PIN PAD INITIALIZATION =========="); try { @@ -882,7 +793,7 @@ public class EmvTransactionActivity extends AppCompatActivity { PinPadConfigV2 pinPadConfig = new PinPadConfigV2(); pinPadConfig.setPinPadType(0); pinPadConfig.setPinType(mPinType); - pinPadConfig.setOrderNumKey(false); + pinPadConfig.setOrderNumKey(true); String panForPin = mCardNo.substring(mCardNo.length() - 13, mCardNo.length() - 1); byte[] panBytes = panForPin.getBytes("US-ASCII"); @@ -895,11 +806,7 @@ public class EmvTransactionActivity extends AppCompatActivity { 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); - }); + updateStatusUI("PIN Input Required\n\nPIN pad is ready\nPlease enter your PIN on the device", true); mPinPadOptV2.initPinPad(pinPadConfig, mPinPadListener); @@ -910,6 +817,7 @@ public class EmvTransactionActivity extends AppCompatActivity { } } + // ====== UPDATED PIN PAD LISTENER ====== private final PinPadListenerV2 mPinPadListener = new PinPadListenerV2.Stub() { @Override public void onPinLength(int len) throws RemoteException { @@ -919,7 +827,7 @@ public class EmvTransactionActivity extends AppCompatActivity { for (int i = 0; i < len; i++) { dots += "• "; } - tvStatus.setText("PIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)"); + updateStatusUI("PIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)", true); }); } @@ -928,9 +836,7 @@ public class EmvTransactionActivity extends AppCompatActivity { android.util.Log.d(TAG, "PIN input confirmed"); runOnUiThread(() -> { - btnAction.setEnabled(true); - btnAction.setText("Processing..."); - tvStatus.setText("PIN confirmed, processing..."); + updateStatusUI("PIN confirmed, processing...", true); }); if (pinBlock != null) { @@ -948,9 +854,7 @@ public class EmvTransactionActivity extends AppCompatActivity { android.util.Log.d(TAG, "PIN input cancelled by user"); runOnUiThread(() -> { - btnAction.setEnabled(true); - btnAction.setText("Start Scanning"); - tvStatus.setText("PIN input cancelled"); + updateStatusUI("PIN input cancelled", false); }); mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget(); @@ -962,9 +866,7 @@ public class EmvTransactionActivity extends AppCompatActivity { String msg = AidlErrorCodeV2.valueOf(code).getMsg(); runOnUiThread(() -> { - btnAction.setEnabled(true); - btnAction.setText("Start Scanning"); - tvStatus.setText("PIN error: " + msg); + updateStatusUI("PIN error: " + msg, false); }); mHandler.obtainMessage(PIN_ERROR, code, code, msg).sendToTarget(); @@ -1001,7 +903,7 @@ public class EmvTransactionActivity extends AppCompatActivity { isProcessing = false; mProcessStep = 0; - tvStatus.setText("EMV reset complete\n\nRestarting auto-scan..."); + updateStatusUI("EMV reset complete\n\nRestarting auto-scan...", true); showToast("EMV reset - restarting scan"); // Auto-restart scanning @@ -1017,17 +919,13 @@ public class EmvTransactionActivity extends AppCompatActivity { }).start(); } + // ====== UPDATED RESET SCANNING STATE ====== private void resetScanningState() { Log.d(TAG, "Resetting scanning state for auto-scan mode"); isProcessing = false; - isButtonProcessing = false; mProcessStep = 0; - runOnUiThread(() -> { - btnAction.setText("CANCEL"); - btnAction.setEnabled(true); - updateUI(); - }); + updateStatusUI("Ready for card...\n\nPlease insert, swipe, or tap your card", true); } // ====== HELPER METHODS ====== @@ -1041,10 +939,11 @@ public class EmvTransactionActivity extends AppCompatActivity { finish(); } + // ====== UPDATED MOCK ONLINE PROCESS ====== private void mockOnlineProcess() { new Thread(() -> { try { - runOnUiThread(() -> tvStatus.setText("Processing online authorization...")); + runOnUiThread(() -> updateStatusUI("Processing online authorization...", true)); Thread.sleep(2000); try { @@ -1149,9 +1048,29 @@ public class EmvTransactionActivity extends AppCompatActivity { Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); } + // ====== UPDATED ON SUPPORT NAVIGATE UP ====== @Override public boolean onSupportNavigateUp() { - onBackPressed(); + // Handle back button press - clean up and go back + try { + // Cancel any ongoing operations + if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) { + MyApplication.app.readCardOptV2.cancelCheckCard(); + } + + // Reset EMV process + if (mEMVOptV2 != null) { + mEMVOptV2.initEmvProcess(); + } + + isProcessing = false; + mProcessStep = 0; + + } catch (Exception e) { + Log.e(TAG, "Error cleaning up on back press: " + e.getMessage()); + } + + finish(); return true; } diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml index b553a7a..a448dbe 100644 --- a/app/src/main/res/anim/fade_in.xml +++ b/app/src/main/res/anim/fade_in.xml @@ -1,4 +1,4 @@ - \ No newline at end of file + \ 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 index 5c62fc7..bd4f73b 100644 --- a/app/src/main/res/layout/activity_emv_transaction.xml +++ b/app/src/main/res/layout/activity_emv_transaction.xml @@ -17,147 +17,91 @@ android:theme="@style/CustomToolbarTheme" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> - + + android:gravity="center" + android:padding="24dp"> - + + android:layout_gravity="center" + app:cardCornerRadius="16dp" + app:cardElevation="8dp" + app:cardBackgroundColor="@android:color/white"> + android:padding="32dp" + android:gravity="center"> + + + + + + + + + + + android:visibility="visible" + android:indeterminateTint="@color/primary_blue" + android:layout_marginBottom="16dp" /> + + android:text="Please insert, tap, or swipe your card\nScanning will start automatically" + android:textSize="14sp" + android:textColor="#8A9BAE" + android:gravity="center" + android:lineSpacingExtra="2dp" + android:fontFamily="@font/inter" /> - - - - - - - - - - - - - - - - - - - - - - - - - - -