From acea64c89b5eb8615e6e45bdd3465550314a4bd8 Mon Sep 17 00:00:00 2001 From: kizzy Date: Wed, 19 Aug 2026 14:49:21 +0700 Subject: [PATCH] fixed ecr connection issues --- .../main/java/com/utsmm/kbz/MainActivity.java | 24 ++++++++++ .../main/java/com/utsmm/kbz/MainFragment.java | 45 +++++++++---------- .../ui/core_viewmodel/SharedViewModel.java | 2 + .../com/utsmm/kbz/util/ecr/CoreUtils.java | 6 +-- .../main/java/com/utsmyanmar/ecr/ECRHelper.kt | 33 ++++++++++++-- 5 files changed, 78 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/utsmm/kbz/MainActivity.java b/app/src/main/java/com/utsmm/kbz/MainActivity.java index 55ba8df..8f5e390 100644 --- a/app/src/main/java/com/utsmm/kbz/MainActivity.java +++ b/app/src/main/java/com/utsmm/kbz/MainActivity.java @@ -156,6 +156,9 @@ public class MainActivity extends AppCompatActivity implements // Initialize special back handling fragments initSpecialBackHandlingFragments(); + // ECR serial receive must live on Activity — MainFragment destroy clears listeners. + registerEcrSerialBridge(); + final Handler handler = new Handler(Looper.getMainLooper()); handler.postDelayed(new Runnable() { @Override @@ -167,6 +170,23 @@ public class MainActivity extends AppCompatActivity implements } + private void registerEcrSerialBridge() { + boolean ecrOn = SystemParamsOperation.getInstance().getECRStatus(); + boolean cmhlOn = SystemParamsOperation.getInstance().isCMHLEnabled(); + LogUtil.d(TAG, "RegisterEcrSerialBridge ecr=" + ecrOn + " cmhl=" + cmhlOn); + + ECRHelper.INSTANCE.initSerialPort(getApplicationContext()); + ECRHelper.INSTANCE.setOnECRReceive(bytes -> { + if (bytes == null || bytes.length == 0) { + return null; + } + LogUtil.d(TAG, "ECR bridge forwarding len=" + bytes.length); + sharedViewModel.ecrSerialData.postValue(bytes); + return null; + }); + } + + private void initKey(){ // SystemParamsOperation.getInstance().setTmsAddress("https://api-tms-uat.kbzbank.com:8443/sirius"); @@ -443,6 +463,9 @@ public class MainActivity extends AppCompatActivity implements SystemParamsOperation.getInstance().setSetupEcr(false); SystemParamsOperation.getInstance().setDownloadedParams(false); + // Re-bind in case a fragment cleared the listener. + registerEcrSerialBridge(); + handleAutoSettlementIntent(getIntent()); BaseApplication.getInstance().deviceEngine.getPlatform().hideNavigationBar(); } @@ -557,6 +580,7 @@ public class MainActivity extends AppCompatActivity implements // Clean up RxJava disposables compositeDisposable.clear(); // Reset screen mode + ECRHelper.INSTANCE.setOnECRReceive(null); // Disconnect serial port ECRHelper.INSTANCE.releaseSerialPort(); BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar(); diff --git a/app/src/main/java/com/utsmm/kbz/MainFragment.java b/app/src/main/java/com/utsmm/kbz/MainFragment.java index cb6e22f..9cf24db 100644 --- a/app/src/main/java/com/utsmm/kbz/MainFragment.java +++ b/app/src/main/java/com/utsmm/kbz/MainFragment.java @@ -43,7 +43,6 @@ import com.utsmyanmar.baselib.util.DataBindingConfig; import com.utsmyanmar.baselib.util.DialogCallback; import com.utsmyanmar.baselib.util.TerminalUtil; import com.utsmyanmar.checkxread.sdk.NexGoSDK; -import com.utsmyanmar.ecr.ECRHelper; import com.utsmyanmar.ecr.ECRProcess; import com.utsmyanmar.ecr.data.ResultOf; import com.utsmyanmar.ecr.data.model.Transactions; @@ -139,24 +138,16 @@ public class MainFragment extends DataBindingFragment { @Override public void onStart() { super.onStart(); - - if (SystemParamsOperation.getInstance().getECRStatus()) { - ECRHelper.INSTANCE.setOnECRReceive(bytes -> { - if (getActivity() == null) { - return null; - } - requireActivity().runOnUiThread(() -> handleSerialData(bytes)); - return null; - }); - ECRHelper.INSTANCE.initSerialPort(requireContext().getApplicationContext()); - LogUtil.d(TAG, "ECR SerialPortDriver listening"); - } } @Override public void onStop() { super.onStop(); - ECRHelper.INSTANCE.setOnECRReceive(bytes -> null); + } + + @Override + public void onDestroy() { + super.onDestroy(); } private void handleSerialData(byte[] data) { @@ -167,8 +158,10 @@ public class MainFragment extends DataBindingFragment { if (SystemParamsOperation.getInstance().isCMHLEnabled()) { ECRActionCHML(data); - } else { + } else if (SystemParamsOperation.getInstance().getECRStatus()) { ECRAction(new String(data, StandardCharsets.UTF_8)); + } else { + LogUtil.e(TAG, "ECR/CMHL disabled — ignoring serial packet"); } } @@ -258,15 +251,6 @@ public class MainFragment extends DataBindingFragment { } } - @Override - public void onDestroy() { - super.onDestroy(); -// BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar(); -// enableTaskButton(); -// enableHomeButton(); - } - - @Override public void onPause() { super.onPause(); @@ -288,6 +272,14 @@ public class MainFragment extends DataBindingFragment { } sharedViewModel.setManualEntryStatus(SystemParamsOperation.getInstance().getManualEntryStatus()); + sharedViewModel.ecrSerialData.observe(getViewLifecycleOwner(), bytes -> { + if (bytes == null || bytes.length == 0) { + return; + } + LogUtil.d(TAG, "ECR LiveData received len=" + bytes.length); + handleSerialData(bytes); + }); + // queryAidCAPKList(); queryAidCAPKList(); // generateMockQR(); @@ -786,9 +778,10 @@ public class MainFragment extends DataBindingFragment { private void ECRActionCHML(byte[] data) { -// LogUtil.d(TAG, "ECR msg here : " + msg); + LogUtil.d(TAG, "ECR CMHL packet len=" + data.length); try { EcrPacket ecrPacket = EcrManager.parsePacket(data); + LogUtil.d(TAG, "ECR CMHL cmd=0x" + Integer.toHexString(ecrPacket.getCommandCode() & 0xFF)); EcrRequestDispatcher.dispatch(ecrPacket, new EcrRequestListener() { @Override @@ -809,6 +802,8 @@ public class MainFragment extends DataBindingFragment { if (CoreUtils.getInstance(sharedViewModel).setUpECRSale(request)) { LogUtil.d(TAG,"Starting to process sale transaction!"); delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment)); + } else { + LogUtil.e(TAG, "CMHL Sale setup failed"); } diff --git a/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java b/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java index 37de649..dcaf66e 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java +++ b/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java @@ -87,6 +87,8 @@ public class SharedViewModel extends ViewModel { /*May 31 2022*/ public SingleLiveEvent isEcrFinished = new SingleLiveEvent<>(); + public final SingleLiveEvent ecrSerialData = new SingleLiveEvent<>(); + /*Jun 3 2022*/ public SingleLiveEvent isEmv = new SingleLiveEvent<>(); diff --git a/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java b/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java index 17716f5..8b3856a 100644 --- a/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java +++ b/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java @@ -250,7 +250,7 @@ public class CoreUtils implements OldECRSetups,ECRSetups,ECRSetupsCMHL { try{ LogUtil.d(TAG, "amount is "+trans.getAmount()); - if (trans.getAmount() == null && Long.parseLong(trans.getAmount()) <= 0) { + if (trans.getAmount() == null || Long.parseLong(trans.getAmount()) <= 0) { LogUtil.d(TAG,"Amount field is invalid!"); return false; @@ -276,7 +276,7 @@ public class CoreUtils implements OldECRSetups,ECRSetups,ECRSetupsCMHL { try{ LogUtil.d(TAG, "amount is "+trans.getAmount()); - if (trans.getAmount() == null && Long.parseLong(trans.getAmount()) <= 0) { + if (trans.getAmount() == null || Long.parseLong(trans.getAmount()) <= 0) { LogUtil.d(TAG,"Amount field is invalid!"); return false; @@ -324,7 +324,7 @@ public class CoreUtils implements OldECRSetups,ECRSetups,ECRSetupsCMHL { try{ LogUtil.d(TAG, "amount is "+trans.getAmount()); - if (trans.getAmount() == null && Long.parseLong(trans.getAmount()) <= 0) { + if (trans.getAmount() == null || Long.parseLong(trans.getAmount()) <= 0) { LogUtil.d(TAG,"Amount field is invalid!"); return false; diff --git a/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt b/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt index 9dd3c20..7f2b507 100644 --- a/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt +++ b/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt @@ -1,6 +1,8 @@ package com.utsmyanmar.ecr import android.content.Context +import android.os.Handler +import android.os.Looper import com.nexgo.oaf.apiv3.APIProxy import com.nexgo.oaf.apiv3.SdkResult import com.nexgo.oaf.apiv3.device.serialport.SerialCfgEntity @@ -8,6 +10,7 @@ import com.nexgo.oaf.apiv3.device.serialport.SerialPortDriver import com.utsmyanmar.paylibs.utils.LogUtil import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicReference /** * NexGo SerialPortDriver wrapper (port 0 = physical USB serial). @@ -17,13 +20,15 @@ object ECRHelper { val TAG: String = ECRHelper::class.java.simpleName - private const val PORT_NO = 101 + private const val PORT_NO = 0 private const val RECV_BUFFER_SIZE = 2048 private const val RECV_TIMEOUT_MS = 3000L private var serialPort: SerialPortDriver? = null private var receiveThread: Thread? = null private val receiving = AtomicBoolean(false) + private val mainHandler = Handler(Looper.getMainLooper()) + private val receiveListener = AtomicReference<((ByteArray) -> Unit)?>(null) var onBindSuccess: () -> Unit = { } var onBindFailure: () -> Unit = { } @@ -34,7 +39,11 @@ object ECRHelper { var onSendSuccess: () -> Unit = { } var onSendFailure: (Int, String) -> Unit = { _, _ -> } - var onECRReceive: (bytes: ByteArray) -> Unit = { } + /** Thread-safe receive callback. Invoked on the main thread. */ + fun setOnECRReceive(listener: ((ByteArray) -> Unit)?) { + receiveListener.set(listener) + LogUtil.d(TAG, "onECRReceive listener ${if (listener != null) "registered" else "cleared"}") + } val isConnected: Boolean get() = serialPort != null @@ -139,6 +148,22 @@ object ECRHelper { } } + private fun dispatchReceive(data: ByteArray) { + val listener = receiveListener.get() + if (listener == null) { + LogUtil.e(TAG, "Serial data dropped: no onECRReceive listener") + return + } + mainHandler.post { + try { + listener.invoke(data) + } catch (ex: Throwable) { + LogUtil.e(TAG, "onECRReceive error: ${ex.message}") + ex.printStackTrace() + } + } + } + private fun startReceiveLoop() { if (receiving.getAndSet(true)) { return @@ -153,8 +178,8 @@ object ECRHelper { if (len > 0) { val data = buffer.copyOf(len) LogUtil.d(TAG, "Serial recv len=$len") - LogUtil.d(TAG," Receive packet : "+ ByteUtil.bytes2HexStr(data)); - onECRReceive(data) + LogUtil.d(TAG, " Receive packet : " + ByteUtil.bytes2HexStr(data)) + dispatchReceive(data) } // timeout / no data: keep listening } catch (ex: Throwable) {