fixed ecr connection issues

This commit is contained in:
kizzy 2026-08-19 14:49:21 +07:00
parent 60fbc471af
commit acea64c89b
5 changed files with 78 additions and 32 deletions

View File

@ -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();

View File

@ -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");
}

View File

@ -87,6 +87,8 @@ public class SharedViewModel extends ViewModel {
/*May 31 2022*/
public SingleLiveEvent<Boolean> isEcrFinished = new SingleLiveEvent<>();
public final SingleLiveEvent<byte[]> ecrSerialData = new SingleLiveEvent<>();
/*Jun 3 2022*/
public SingleLiveEvent<Boolean> isEmv = new SingleLiveEvent<>();

View File

@ -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;

View File

@ -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) {