Преглед изворни кода

refactor(蓝牙):
- `BleQueueDispatcher`: 调整`scheduleDisconnect`逻辑,确保即使设备未完全连接,也能清理其在队列中的任务,避免任务残留。
- `BleQueueDispatcher`: 在断开连接后增加1秒延迟再执行下一个队列任务,以提高稳定性。
- `BleConnectionManager`: 移除`getCurrentStatus`中的手动超时和重试逻辑,改为在`onWriteFailure`回调中实现,简化了状态获取流程。
- `BleConnectionManager`: 在蓝牙扫描到目标设备后立即停止扫描,优化连接效率和功耗。
- `BleBusinessManager`: 钥匙归还成功并切换到待机模式后,通过`BleReturnDispatcher`调度断开连接。
- `HardwareBusinessManager`: 钥匙取出时,统一调用`scheduleDisconnect`来处理蓝牙断连,以集中管理断连逻辑。
- `BleUtil`: 连接状态检查从`isConnecting`修正为`isConnected`,修复逻辑判断错误。

refactor(启动):
- `ISCSApplication`: 将人脸识别引擎(`ArcSoftUtil`)的初始化逻辑从`LoginActivity`提前至应用启动时,确保引擎尽早可用。

fix(UI):
- `MainViewModel`: 将“作业票获取失败”的提示方式由`showTip`改为`LoadingEvent`,改善用户体验。
- 更新中英文“作业票获取失败”的提示文案,增加了“请关闭钥匙电源并重新拿取并归还钥匙”的用户操作指引。

fix(登录):
- `LoginDialog`: 修复人脸识别验证失败后,UI检测状态(`inDetecting`, `inFaceChecking`)未被正确重置的问题。

周文健 пре 1 месец
родитељ
комит
a335c3a43e

+ 1 - 1
app/src/main/assets/i18n/en-US.json

@@ -2762,7 +2762,7 @@
   "ticket_get_failed": {
     "key": "ticket_get_failed",
     "type": "text",
-    "value": "Failed to obtain job ticket"
+    "value": "Failed to obtain job ticket, Please shutdown the key then take and return key again."
   },
   "ticket_lost": {
     "key": "ticket_lost",

+ 1 - 1
app/src/main/assets/i18n/zh-CN.json

@@ -2762,7 +2762,7 @@
   "ticket_get_failed": {
     "key": "ticket_get_failed",
     "type": "text",
-    "value": "作业票获取失败"
+    "value": "作业票获取失败,请关闭钥匙电源并重新拿取并归还钥匙"
   },
   "ticket_lost": {
     "key": "ticket_lost",

+ 3 - 0
app/src/main/java/com/grkj/iscs/ISCSApplication.kt

@@ -105,6 +105,9 @@ class ISCSApplication : Application() {
         if (ISCSConfig.isInit) {
             BleUtil.instance?.initBle(this)
         }
+        //todo 模拟器不支持 测试用,直接创建管理员账号
+        ArcSoftUtil.checkActiveStatus(SIKCore.getApplication())
+        ArcSoftUtil.initEngine(SIKCore.getApplication())
         AutoSizeConfig.getInstance().isCustomFragment = false
         StateConfig.emptyLayout = com.grkj.ui_base.R.layout.layout_empty
         ThreadUtils.runOnIO {

+ 0 - 3
app/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt

@@ -189,9 +189,6 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
         super.initData()
         viewModel.registerFaceFeature().observe(this) {}
         viewModel.checkPresetWorkflowStepIcon().observe(this) {}
-        //todo 模拟器不支持 测试用,直接创建管理员账号
-        ArcSoftUtil.checkActiveStatus(SIKCore.getApplication())
-        ArcSoftUtil.initEngine(SIKCore.getApplication())
 //        viewModel.insertAdminAccount().observe(this) {}
         requestPermissionsIfNeeded(*Constants.needPermission) {
             if (it) {

+ 6 - 5
app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt

@@ -22,6 +22,7 @@ import com.sik.sikcore.SIKCore
 import com.sik.sikcore.extension.setDebouncedClickListener
 import com.sik.sikcore.thread.ThreadUtils
 import com.sik.sikimage.ImageConvertUtils
+import kotlinx.coroutines.delay
 
 /**
  * 登录弹窗
@@ -181,15 +182,15 @@ class LoginDialog(
                     if (it == LoginResultEnum.FACE_VERIFY_FAILED) {
                         viewModel.loginWithFace(ImageConvertUtils.bitmapToBase64(bitmap).toString())
                             .observe(lifecycleOwner) {
-                                if (it == LoginResultEnum.FACE_VERIFY_FAILED) {
-                                    ThreadUtils.runOnMainDelayed(1000) {
+                                ThreadUtils.runOnMainDelayed(1000) {
+                                    if (it == LoginResultEnum.FACE_VERIFY_FAILED) {
                                         inDetecting = false
                                         inFaceChecking = false
+                                    } else {
+                                        ArcSoftUtil.stop()
                                     }
-                                } else {
-                                    ArcSoftUtil.stop()
+                                    callBack?.invoke(it)
                                 }
-                                callBack?.invoke(it)
                             }
                     } else {
                         ArcSoftUtil.stop()

+ 5 - 3
app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt

@@ -139,7 +139,9 @@ class MainViewModel @Inject constructor(
                                                         logger.info("钥匙连接失败")
                                                         HardwareMode.getCurrentHardwareMode()
                                                             .controlKeyBuckle(true, mac) {
-                                                                showTip(CommonUtils.getStr("ticket_get_failed"))
+                                                                LoadingEvent.sendLoadingEvent(
+                                                                    CommonUtils.getStr("ticket_get_failed")
+                                                                )
                                                             }
                                                     }
                                                 }
@@ -193,7 +195,7 @@ class MainViewModel @Inject constructor(
                                                             CanCommands.forDevice(deviceModel.nodeId)
                                                                 .controlLatch(deviceModel.id, 0)
                                                         CanHelper.writeTo(req) {
-                                                            showTip(
+                                                            LoadingEvent.sendLoadingEvent(
                                                                 CommonUtils.getStr("ticket_get_failed")
                                                             )
                                                         }
@@ -247,7 +249,7 @@ class MainViewModel @Inject constructor(
                             logger.info("钥匙连接失败")
                             HardwareMode.getCurrentHardwareMode()
                                 .controlKeyBuckle(true, mac) {
-                                    showTip(CommonUtils.getStr("ticket_get_failed"))
+                                    LoadingEvent.sendLoadingEvent(CommonUtils.getStr("ticket_get_failed"))
                                 }
                         }
                     }

+ 12 - 44
data/src/main/java/com/grkj/data/hardware/ble/BleConnectionManager.kt

@@ -323,6 +323,7 @@ object BleConnectionManager {
                 if (scanMac.equals(mac, ignoreCase = true)) {
                     // 找到目标设备,马上停止扫描
                     logger.info("找到目标设备 $mac,停止扫描并尝试连接")
+                    BleUtil.instance?.stopScan()
                     // 立刻调用 doConnect,下一步进入连接流程
                     doConnect(
                         newDevice,
@@ -449,6 +450,7 @@ object BleConnectionManager {
 
     /**
      * 获取当前钥匙的状态
+     * todo 取消获取状态发送的超时
      */
     @SuppressLint("MissingPermission")
     fun getCurrentStatus(
@@ -458,42 +460,6 @@ object BleConnectionManager {
         timeoutCallBack: ((Boolean) -> Unit)? = null
     ) {
         logger.info("getCurrentStatus - ${bleDevice.mac} - from : $from")
-        var isTimeout = true
-        // 加1秒防止早于onWriteFailure开始处理导致多次处理
-        ThreadUtils.runOnMainDelayed((BleUtil.OPERATE_TIMEOUT + 1).toLong()) {
-            if (isTimeout) {
-                logger.error("getCurrentStatus timeout : mac = ${bleDevice.mac}, retryCount = $retryCount")
-                if (retryCount > 0) {
-                    if (from != 4) {
-                        val canConnect = BleSendDispatcher.canConnect()
-                        logger.info("发送队列是否可以连接:${canConnect}")
-                        if (BleSendDispatcher.isConnected(bleDevice.mac)) {
-                            BleSendDispatcher.scheduleDisconnect(bleDevice.mac)
-                        }
-                        BleSendDispatcher.submit(bleDevice.mac) {
-                            getCurrentStatus(
-                                from, bleDevice, retryCount - 1, timeoutCallBack
-                            )
-                        }
-                    } else {
-                        BleReturnDispatcher.clearNotInBusyConnectedDevice()
-                        BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
-                        BleReturnDispatcher.submit(bleDevice.mac) {
-                            getCurrentStatus(
-                                from, bleDevice, retryCount - 1, timeoutCallBack
-                            )
-                        }
-                    }
-                } else {
-                    BleSendDispatcher.scheduleDisconnect(bleDevice.mac)
-                    BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
-                    HardwareMode.getCurrentHardwareMode().getRfidByKeyMac(bleDevice.mac)?.let {
-                        addExceptionKey(it)
-                        timeoutCallBack?.invoke(true)
-                    }
-                }
-            }
-        }
         BleCmdManager.getCurrentStatus(bleDevice, object : CustomBleWriteCallback() {
             override fun onWriteSuccess(
                 bleDevice: BleDevice,
@@ -504,7 +470,6 @@ object BleConnectionManager {
                 data: ByteArray
             ) {
                 logger.info("getCurrentStatus success : ${bleDevice.mac}")
-                isTimeout = false
                 timeoutCallBack?.invoke(false)
             }
 
@@ -519,14 +484,17 @@ object BleConnectionManager {
                 isTotalFail: Boolean
             ) {
                 logger.info("getCurrentStatus fail : ${bleDevice.mac}")
-                isTimeout = false
                 ThreadUtils.runOnMainDelayed(1000) {
-                    getCurrentStatus(
-                        from,
-                        bleDevice,
-                        retryCount - 1,
-                        timeoutCallBack = timeoutCallBack
-                    )
+                    if (retryCount > 0) {
+                        getCurrentStatus(
+                            from,
+                            bleDevice,
+                            retryCount - 1,
+                            timeoutCallBack = timeoutCallBack
+                        )
+                    }else{
+                        timeoutCallBack?.invoke(true)
+                    }
                 }
             }
         })

+ 9 - 1
data/src/main/java/com/grkj/data/hardware/ble/BleQueueDispatcher.kt

@@ -169,8 +169,14 @@ abstract class BleQueueDispatcher {
     @SuppressLint("MissingPermission")
     @Synchronized
     fun scheduleDisconnect(mac: String, delayMillis: Long = 0) {
-        if (!connectedMacs.contains(mac)) return
         pendingDisconnectJobs[mac]?.cancel()
+        // 【修复点1】未连接也要清:把队列/连接中的该 mac 直接清掉,避免后续再被调度
+        if (!connectedMacs.contains(mac)) {
+            logger.info("scheduleDisconnect: not connected → clear only | mac=$mac")
+            BleConnectionManager.unregisterConnectListener(mac)
+            clear(mac)  // 会清 taskQueue / activeMacs / connectedMacs / pendingDisconnectJobs
+            return
+        }
         val job = dispatcherScope.launch {
             logger.info("计划移除硬件:$mac")
             delay(delayMillis)
@@ -181,11 +187,13 @@ abstract class BleQueueDispatcher {
                             BleConnectionManager.deviceList.find { it.bleDevice.mac == mac }
                         deviceBean?.let {
                             disconnectDeviceByMac(mac)
+                            BleConnectionManager.unregisterConnectListener(mac)
                             BleConnectionManager.deviceList.removeIf { it.bleDevice.mac == deviceBean.bleDevice.mac }
                         }
                         logger.info("当前线程:${Thread.currentThread().name}")
                         clear(mac)
                         if ((activeMacs.size + connectedMacs.size) < maxConnections && taskQueue.isNotEmpty()) {
+                            delay(1000)
                             tryStartNext()
                         }
                     }

+ 1 - 1
data/src/main/java/com/grkj/data/hardware/ble/BleUtil.kt

@@ -242,7 +242,7 @@ class BleUtil private constructor() {
             fun connectAndWrite() {
                 ThreadUtils.runOnIO {
                     val isConnect =
-                        BleSendDispatcher.isConnecting(bleDevice.mac) || BleReturnDispatcher.isConnecting(
+                        BleSendDispatcher.isConnected(bleDevice.mac) || BleReturnDispatcher.isConnected(
                             bleDevice.mac
                         )
                     if (isConnect) {

+ 9 - 9
ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt

@@ -164,10 +164,12 @@ object BleBusinessManager {
                     HardwareMode.getCurrentHardwareMode().updateKeyReadyStatus(
                         bleBean.bleDevice.mac, true, 2
                     )
+                    BleReturnDispatcher.scheduleDisconnect(bleBean.bleDevice.mac)
                     // 延时再次获取当前状态,触发handleCurrentMode里工作票下发状态检查
-                    Executor.delayOnMain(500) {
-                        BleConnectionManager.getCurrentStatus(1, bleBean.bleDevice)
-                    }
+                    //切换回待机之后不再次查询状态,没有意义,单机操作没有并发需求
+//                    Executor.delayOnMain(500) {
+//                        BleConnectionManager.getCurrentStatus(1, bleBean.bleDevice)
+//                    }
                 } else {
                     logger.error("切换待机模式失败 : ${bleBean.bleDevice.mac}")
                     Executor.delayOnMain(500) {
@@ -924,8 +926,7 @@ object BleBusinessManager {
         mac?.let {
             BleSendDispatcher.submit(it) {
                 BleConnectionManager.getBleDeviceByMac(
-                    HardwareMode.getCurrentHardwareMode()
-                        .getKeyMacByRfid(deviceTakeUpdateBO.nfc)
+                    HardwareMode.getCurrentHardwareMode().getKeyMacByRfid(deviceTakeUpdateBO.nfc)
                 )?.let {
                     BleConnectionManager.getCurrentStatus(
                         2, BleConnectionManager.getBleDeviceByMac(
@@ -945,11 +946,10 @@ object BleBusinessManager {
                         ) { keyPair, lockMap ->
                             if (keyPair == null) {
                                 TipDialog.show(
-                                    msg = CommonUtils.getStr("key_take_error_tip")
-                                        .toString(), onConfirmClick = {
+                                    msg = CommonUtils.getStr("key_take_error_tip").toString(),
+                                    onConfirmClick = {
                                         DeviceExceptionEvent.sendDeviceExceptionEvent(
-                                            DeviceConst.DEVICE_TYPE_KEY,
-                                            deviceTakeUpdateBO.nfc
+                                            DeviceConst.DEVICE_TYPE_KEY, deviceTakeUpdateBO.nfc
                                         )
                                     })
                             } else {

+ 1 - 4
ui-base/src/main/java/com/grkj/ui_base/business/HardwareBusinessManager.kt

@@ -174,10 +174,7 @@ object HardwareBusinessManager {
                                 removeDeviceTake(DeviceConst.DEVICE_TYPE_KEY, info.nfc)
                                 logger.info("设备取出信息:${mDeviceTakeList}")
                                 HardwareMode.getCurrentHardwareMode().getKeyMacByRfid(info.nfc)
-                                    ?.let {
-                                        BleConnectionManager.unregisterConnectListener(it)
-                                    }
-
+                                    ?.let { BleSendDispatcher.scheduleDisconnect(it) }
                             } else {
                                 logger.info("更新钥匙取出异常")
                             }