BleConnectionManager.kt 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. package com.grkj.iscs.ble
  2. import android.bluetooth.BluetoothGatt
  3. import androidx.appcompat.app.AppCompatActivity
  4. import com.clj.fastble.BleManager
  5. import com.clj.fastble.data.BleDevice
  6. import com.clj.fastble.exception.BleException
  7. import com.grkj.iscs.BusinessManager
  8. import com.grkj.iscs.BusinessManager.deviceList
  9. import com.grkj.iscs.BusinessManager.getBleDeviceByMac
  10. import com.grkj.iscs.BusinessManager.getCurrentStatus
  11. import com.grkj.iscs.BusinessManager.isTestMode
  12. import com.grkj.iscs.BusinessManager.removeExceptionKey
  13. import com.grkj.iscs.BusinessManager.sendEventMsg
  14. import com.grkj.iscs.BusinessManager.sendLoadingEventMsg
  15. import com.grkj.iscs.R
  16. import com.grkj.iscs.extentions.toHexStrings
  17. import com.grkj.iscs.modbus.ModBusController
  18. import com.grkj.iscs.modbus.ModBusController.controlKeyCharge
  19. import com.grkj.iscs.model.Constants.PERMISSION_REQUEST_CODE
  20. import com.grkj.iscs.model.eventmsg.LoadingMsg
  21. import com.grkj.iscs.model.eventmsg.MsgEvent
  22. import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_LOADING
  23. import com.grkj.iscs.util.ActivityUtils
  24. import com.grkj.iscs.util.CommonUtils
  25. import com.grkj.iscs.util.Executor
  26. import com.grkj.iscs.util.log.LogUtil
  27. import com.grkj.iscs.view.base.BaseActivity
  28. import com.sik.sikcore.activity.ActivityTracker
  29. import com.sik.sikcore.thread.ThreadUtils
  30. import kotlinx.coroutines.Dispatchers
  31. import kotlinx.coroutines.delay
  32. import kotlinx.coroutines.suspendCancellableCoroutine
  33. import kotlinx.coroutines.withContext
  34. import pub.devrel.easypermissions.AfterPermissionGranted
  35. import java.util.LinkedList
  36. import kotlin.coroutines.resume
  37. import kotlin.coroutines.suspendCoroutine
  38. /**
  39. * BLE 连接管理工具:保持原有扫描、连接、监听、取 Token 流程,
  40. * 并增加“最大待机数”功能,超出后断开最旧连接,保证同时在线设备数不超过阈值。
  41. */
  42. object BleConnectionManager {
  43. /**
  44. * 最大待机连接数,超过则断开最旧设备。
  45. * 默认为业务常量 MAX_KEY_STAND_BY,可根据需求调整。
  46. */
  47. @Volatile
  48. var maxStandbyCount: Int = BleConst.MAX_KEY_STAND_BY
  49. @Volatile
  50. var maxConnectCount: Int = BleConst.MAX_KEY_CONNECT_COUNT
  51. // 按连接完成顺序维护待机队列
  52. private val standbyQueue = LinkedList<String>()
  53. // 原有回调管理
  54. private val connectListeners = mutableListOf<ConnectListener>()
  55. private var isPreparing: Boolean = false
  56. @Volatile
  57. private var currentConnectingMac: String? = null
  58. /**
  59. * 注册连接监听:
  60. * - 如果设备已在 deviceList 且拥有 token,立即回调并返回
  61. * - 如果 mac 已在待连接队列或正在连接,忽略重复请求
  62. * - 否则将 mac 添加到队列并触发连接流程
  63. */
  64. fun registerConnectListener(
  65. mac: String,
  66. connectNow: Boolean = false,
  67. callBack: ((Boolean, BleBean?) -> Unit)? = null
  68. ) {
  69. LogUtil.i("蓝牙连接-开始连接 : $mac")
  70. // 已连接且已获取 token
  71. deviceList.find {
  72. it.bleDevice.mac == mac && BleManager.getInstance().isConnected(mac) && it.token != null
  73. }?.let { bean ->
  74. LogUtil.i("蓝牙连接-设备已连接")
  75. callBack?.invoke(true, bean)
  76. return
  77. }
  78. if (connectNow) {
  79. LogUtil.w("蓝牙连接-立即连接 mac: $mac")
  80. unregisterConnectListener(mac)
  81. }
  82. // 重复注册检查
  83. if (connectListeners.any { it.mac == mac } || currentConnectingMac == mac) {
  84. LogUtil.w("蓝牙连接-忽略重复注册 mac: $mac")
  85. callBack?.invoke(false, null)
  86. return
  87. }
  88. // 加入队列并启动连接
  89. fun checkAndConnect(isDisconnectAll: Boolean = false) {
  90. LogUtil.w("蓝牙连接-开始检查连接 mac: $mac")
  91. if (BleManager.getInstance().allConnectedDevice.size < maxConnectCount) {
  92. connectListeners.add(ConnectListener(mac, callBack))
  93. connectKey()
  94. } else {
  95. if (connectNow && !isDisconnectAll) {
  96. LogUtil.i("蓝牙连接-超过最大连接数,但是需要立即连接,断开所有连接进行连接")
  97. BleManager.getInstance().disconnectAllDevice()
  98. checkAndConnect(true)
  99. } else {
  100. ThreadUtils.runOnIODelayed(500) {
  101. checkAndConnect()
  102. }
  103. }
  104. }
  105. }
  106. checkAndConnect()
  107. }
  108. /**
  109. * 连接监听反注册
  110. */
  111. fun unregisterConnectListener(mac: String, bleBean: BleBean? = null) {
  112. LogUtil.i("蓝牙连接-unregisterConnectListener : $mac")
  113. connectListeners.removeAll { it.mac == mac }
  114. }
  115. /**
  116. * 检查是否能进行蓝牙连接准备的下一步,防止未准备完但是已经取消订阅
  117. */
  118. private fun checkProcess(mac: String?, hideLoading: Boolean = true): Boolean {
  119. val canProcess = connectListeners.any { it.mac == mac }
  120. if (!canProcess && hideLoading) sendLoadingEventMsg(null, false)
  121. return canProcess
  122. }
  123. /**
  124. * 连接钥匙,单个mac走完prepare再进行下一个
  125. */
  126. private fun connectKey() {
  127. if (connectListeners.isEmpty()) return
  128. if (isPreparing || BleManager.getInstance().allConnectedDevice.size > maxStandbyCount) {
  129. LogUtil.i("暂时不能连接:${isPreparing},${BleManager.getInstance().allConnectedDevice.size > maxStandbyCount}")
  130. Executor.delayOnMain(1000) { connectKey() }
  131. return
  132. }
  133. val listener = connectListeners.first()
  134. currentConnectingMac = listener.mac
  135. ThreadUtils.runOnIODelayed(10 * 1000) {
  136. isPreparing = false
  137. }
  138. isPreparing = true
  139. if (ActivityTracker.getCurrentActivity() == null) {
  140. LogUtil.w("蓝牙连接-Ignore connectKey : ${listener.mac} no current activity")
  141. isPreparing = false
  142. currentConnectingMac = null
  143. return
  144. }
  145. prepareBle(
  146. listener.mac, ActivityUtils.currentActivity() as BaseActivity<*>, false
  147. ) { isDone, bleBean ->
  148. Executor.runOnMain {
  149. isPreparing = false
  150. currentConnectingMac = null
  151. if (!isDone) {
  152. // 判断是否仍然待连,防止拿走;移到末尾,防止循环影响
  153. if (checkProcess(listener.mac)) {
  154. listener.callBack?.invoke(false, null)
  155. unregisterConnectListener(listener.mac)
  156. }
  157. return@runOnMain
  158. }
  159. // 判断是否仍然待连,防止拿走
  160. // TODO 暂时只处理准备成功
  161. if (connectListeners.contains(listener)) {
  162. listener.callBack?.invoke(true, bleBean)
  163. unregisterConnectListener(listener.mac)
  164. }
  165. if (connectListeners.isNotEmpty()) connectKey()
  166. }
  167. }
  168. }
  169. /**
  170. * @param loadingCallBack 是否显示loading、loading文字、流程是否结束
  171. * @param prepareDoneCallBack 蓝牙连接是否成功、蓝牙连接对象
  172. */
  173. private fun prepareBle(
  174. mac: String,
  175. activity: AppCompatActivity,
  176. isNeedLoading: Boolean = false,
  177. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  178. ) {
  179. if (!checkProcess(mac)) {
  180. LogUtil.e("蓝牙连接-Prepare is canceled : $mac")
  181. return
  182. }
  183. Executor.runOnMain {
  184. CommonUtils.checkBlePermission(activity) {
  185. doScanBle(mac, isNeedLoading, prepareDoneCallBack)
  186. }
  187. }
  188. }
  189. @AfterPermissionGranted(PERMISSION_REQUEST_CODE)
  190. private fun doScanBle(
  191. mac: String,
  192. isNeedLoading: Boolean = false,
  193. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  194. ) {
  195. LogUtil.i("蓝牙连接-doScanBle:$mac")
  196. if (!checkProcess(mac)) {
  197. LogUtil.e("蓝牙连接-Prepare is canceled : $mac")
  198. return
  199. }
  200. if (isNeedLoading) sendEventMsg(
  201. MsgEvent(
  202. MSG_EVENT_LOADING, LoadingMsg(true, "正在扫描设备...", null)
  203. )
  204. )
  205. BleUtil.instance?.scan(object : CustomBleScanCallback() {
  206. override fun onPrompt(promptStr: String?) {
  207. // 蓝牙未启动重试
  208. LogUtil.i("蓝牙连接-参数:${promptStr}")
  209. BleManager.getInstance().enableBluetooth()
  210. doScanBle(mac, isNeedLoading, prepareDoneCallBack)
  211. }
  212. override fun onScanStarted(success: Boolean) {
  213. LogUtil.i("蓝牙连接-onScanStarted:${success}")
  214. if (!success) {
  215. if (isNeedLoading) sendEventMsg(
  216. MsgEvent(
  217. MSG_EVENT_LOADING, LoadingMsg(false, null, null)
  218. )
  219. )
  220. prepareDoneCallBack?.invoke(false, null)
  221. }
  222. }
  223. override fun onScanning(bleDevice: BleDevice?) {
  224. val mac = bleDevice?.mac ?: return
  225. LogUtil.i("蓝牙连接-onScanning:$mac")
  226. if (mac.equals(mac, ignoreCase = true)) {
  227. // 找到目标设备,马上停止扫描
  228. LogUtil.i("找到目标设备 $mac,停止扫描并尝试连接")
  229. BleManager.getInstance().cancelScan()
  230. // 立刻调用 doConnect,下一步进入连接流程
  231. doConnect(bleDevice, isNeedLoading, prepareDoneCallBack)
  232. }
  233. }
  234. override fun onScanFinished(scanResultList: MutableList<BleDevice>?) {
  235. LogUtil.i("蓝牙连接-onScanFinished: $mac - ${scanResultList?.none { it.mac == mac }}")
  236. if (isNeedLoading) sendEventMsg(
  237. MsgEvent(
  238. MSG_EVENT_LOADING, LoadingMsg(false, null, null)
  239. )
  240. )
  241. // 没有扫描到
  242. if (scanResultList?.none { it.mac == mac } == true) {
  243. LogUtil.w("$mac is not scanned")
  244. prepareDoneCallBack?.invoke(false, null)
  245. }
  246. }
  247. })
  248. }
  249. /**
  250. * 连接蓝牙设备
  251. */
  252. private fun doConnect(
  253. bleDevice: BleDevice,
  254. isNeedLoading: Boolean = false,
  255. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  256. ) {
  257. LogUtil.i("蓝牙连接-doConnect : ${bleDevice.mac}")
  258. if (!checkProcess(bleDevice.mac)) {
  259. LogUtil.e("蓝牙连接-Prepare is canceled : ${bleDevice.mac}")
  260. return
  261. }
  262. if (isNeedLoading) sendEventMsg(
  263. MsgEvent(
  264. MSG_EVENT_LOADING,
  265. LoadingMsg(true, CommonUtils.getStr(R.string.ble_connecting), null)
  266. )
  267. )
  268. ThreadUtils.runOnIO {
  269. BleManager.getInstance().disconnect(bleDevice)
  270. delay(300)
  271. BleUtil.instance?.connectBySelect(
  272. bleDevice, object : CustomBleGattCallback() {
  273. override fun onPrompt(promptStr: String?) {
  274. if (isNeedLoading) sendEventMsg(
  275. MsgEvent(
  276. MSG_EVENT_LOADING, LoadingMsg(false, promptStr, null)
  277. )
  278. )
  279. }
  280. override fun onStartConnect() {}
  281. override fun onConnectFail(bleDevice: BleDevice?, exception: BleException?) {
  282. if (isNeedLoading) sendEventMsg(
  283. MsgEvent(
  284. MSG_EVENT_LOADING,
  285. LoadingMsg(
  286. false,
  287. CommonUtils.getStr(R.string.ble_connect_fail),
  288. false
  289. )
  290. )
  291. )
  292. LogUtil.e("蓝牙连接-onConnectFail : ${bleDevice?.mac} - ${exception?.description}")
  293. prepareDoneCallBack?.invoke(false, null)
  294. }
  295. override fun onConnectSuccess(
  296. bleDevice: BleDevice?, gatt: BluetoothGatt?, status: Int
  297. ) {
  298. if (isNeedLoading) sendEventMsg(
  299. MsgEvent(
  300. MSG_EVENT_LOADING, LoadingMsg(false, null, null)
  301. )
  302. )
  303. LogUtil.i("蓝牙连接-onConnectSuccess : ${bleDevice?.mac}")
  304. bleDevice?.let {
  305. deviceList.removeIf { it.bleDevice.mac == bleDevice.mac }
  306. val bleBean = BleBean(it)
  307. deviceList.add(bleBean)
  308. removeExceptionKey(it.mac)
  309. // 设置MTU
  310. Executor.delayOnMain(200) {
  311. if (!checkProcess(bleDevice.mac)) {
  312. LogUtil.e("Prepare is canceled : ${bleDevice.mac}")
  313. return@delayOnMain
  314. }
  315. BleUtil.instance?.setMtu(it)
  316. }
  317. // 监听
  318. Executor.delayOnMain(500) {
  319. indicate(bleBean, isNeedLoading, prepareDoneCallBack)
  320. }
  321. }
  322. }
  323. override fun onDisConnected(
  324. isActiveDisConnected: Boolean,
  325. device: BleDevice?,
  326. gatt: BluetoothGatt?,
  327. status: Int
  328. ) {
  329. if (isNeedLoading) sendEventMsg(
  330. MsgEvent(
  331. MSG_EVENT_LOADING, LoadingMsg(false, null, false)
  332. )
  333. )
  334. LogUtil.i("蓝牙连接-onDisConnected : ${device?.mac} - $isActiveDisConnected")
  335. getBleDeviceByMac(device?.mac)?.let {
  336. deviceList.remove(it)
  337. it.token = null
  338. }
  339. bleDevice.mac?.let { itMac ->
  340. unregisterConnectListener(itMac)
  341. }
  342. if (!isActiveDisConnected) {
  343. // 测试模式下不重连
  344. if (isTestMode) {
  345. return
  346. }
  347. // 断开和重连之间最好间隔一段时间,否则可能会出现长时间连接不上的情况
  348. Executor.delayOnMain(300) {
  349. registerConnectListener(bleDevice.mac) { isDone, bleBean ->
  350. if (isDone && bleBean != null) {
  351. Executor.delayOnMain(300) {
  352. getCurrentStatus(6, bleBean.bleDevice)
  353. }
  354. }
  355. }
  356. }
  357. } else {
  358. ModBusController.updateKeyReadyStatus(bleDevice.mac, false, 3)
  359. }
  360. }
  361. })
  362. }
  363. }
  364. /**
  365. * 监听蓝牙设备
  366. */
  367. private fun indicate(
  368. bleBean: BleBean?,
  369. isNeedLoading: Boolean = false,
  370. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  371. ) {
  372. if (!checkProcess(bleBean?.bleDevice?.mac)) {
  373. LogUtil.e("蓝牙连接-Prepare is canceled : ${bleBean?.bleDevice?.mac}")
  374. return
  375. }
  376. if (isNeedLoading) sendEventMsg(
  377. MsgEvent(
  378. MSG_EVENT_LOADING, LoadingMsg(true, "开始监听...", null)
  379. )
  380. )
  381. bleBean?.let {
  382. var isIndicateSuccess = false
  383. BleUtil.instance?.indicate(
  384. it.bleDevice, indicateCallback = object : CustomBleIndicateCallback() {
  385. override fun onPrompt(promptStr: String?) {
  386. LogUtil.i("蓝牙连接-indicate onPrompt : $promptStr")
  387. }
  388. override fun onConnectPrompt(promptStr: String?) {
  389. LogUtil.i("蓝牙连接-indicate onConnectPrompt : $promptStr")
  390. }
  391. override fun onDisConnectPrompt(promptStr: String?) {
  392. LogUtil.i("蓝牙连接-indicate onDisConnectPrompt : $promptStr")
  393. }
  394. override fun onIndicateSuccess() {
  395. LogUtil.i("蓝牙连接-onIndicateSuccess")
  396. isIndicateSuccess = true
  397. getToken(bleBean, isNeedLoading, prepareDoneCallBack)
  398. }
  399. override fun onIndicateFailure(exception: BleException?) {
  400. if (isNeedLoading) sendEventMsg(
  401. MsgEvent(
  402. MSG_EVENT_LOADING, LoadingMsg(false, null, false)
  403. )
  404. )
  405. LogUtil.e("蓝牙连接-onIndicateFailure : ${bleBean.bleDevice.mac} - ${exception?.description}")
  406. Executor.delayOnIO(500) {
  407. if (isIndicateSuccess) {
  408. return@delayOnIO
  409. }
  410. prepareDoneCallBack?.invoke(false, null)
  411. }
  412. }
  413. override fun onCharacteristicChanged(data: ByteArray?) {
  414. LogUtil.i("蓝牙连接-onCharacteristicChanged : ${data?.toHexStrings()}")
  415. data?.let { itData ->
  416. BusinessManager.handleRsp(
  417. it,
  418. itData,
  419. isNeedLoading,
  420. prepareDoneCallBack
  421. )
  422. }
  423. }
  424. })
  425. }
  426. }
  427. /**
  428. * 获取蓝牙钥匙token
  429. */
  430. private fun getToken(
  431. bleBean: BleBean?,
  432. isNeedLoading: Boolean = false,
  433. prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
  434. ) {
  435. if (!checkProcess(bleBean?.bleDevice?.mac)) {
  436. LogUtil.e("蓝牙连接-Prepare is canceled : ${bleBean?.bleDevice?.mac}")
  437. return
  438. }
  439. if (isNeedLoading) sendEventMsg(
  440. MsgEvent(
  441. MSG_EVENT_LOADING, LoadingMsg(true, "开始获取token...", null)
  442. )
  443. )
  444. bleBean?.let {
  445. BleCmdManager.getToken(it.bleDevice.mac, object : CustomBleWriteCallback() {
  446. override fun onWriteSuccess(current: Int, total: Int, justWrite: ByteArray?) {
  447. if (isNeedLoading) sendEventMsg(
  448. MsgEvent(
  449. MSG_EVENT_LOADING, LoadingMsg(false, "token获取成功", null)
  450. )
  451. )
  452. LogUtil.i("蓝牙连接-getToken success : ${bleBean.bleDevice.mac}")
  453. }
  454. override fun onWriteFailure(exception: BleException?) {
  455. if (isNeedLoading) sendEventMsg(
  456. MsgEvent(
  457. MSG_EVENT_LOADING, LoadingMsg(false, "token获取失败", false)
  458. )
  459. )
  460. LogUtil.e("蓝牙连接-getToken fail : ${bleBean.bleDevice.mac}")
  461. prepareDoneCallBack?.invoke(false, null)
  462. }
  463. })
  464. }
  465. }
  466. /**
  467. * 对单个 MAC 做下面两步:
  468. * 1. 先尝试不充电连接,若成功就返回 true;
  469. * 2. 否则开启“充电”,等 500ms,再尝试一次连接,连接成功后断电并返回 true;否则返回 false。
  470. */
  471. suspend fun tryConnectWithOptionalCharge(mac: String, withOpenCharge: Boolean = true): Boolean =
  472. withContext(Dispatchers.IO) {
  473. // -------- 第一次尝试 --------
  474. LogUtil.i("蓝牙连接-第一次尝试")
  475. val firstTry = suspendCancellableCoroutine<Boolean> { cont ->
  476. // 1. 定义一个 flag,确保只 resume 一次
  477. var isCalled = false
  478. BusinessManager.registerConnectListener(mac, true) { isDone, _ ->
  479. if (isCalled) {
  480. return@registerConnectListener
  481. }
  482. isCalled = true
  483. if (isDone) {
  484. // 连接成功后,把电关掉(以防万一)
  485. controlKeyCharge(false, mac) { }
  486. cont.resume(true)
  487. } else {
  488. cont.resume(false)
  489. }
  490. cont.cancel()
  491. }
  492. }
  493. LogUtil.i("蓝牙连接-第一次连接:${firstTry},是否继续尝试上电连接${withOpenCharge}")
  494. if (firstTry) {
  495. return@withContext true
  496. }
  497. if (!withOpenCharge) {
  498. return@withContext false
  499. }
  500. // -------- 第二次尝试:先开电,再连 --------
  501. // 开电,并等待回调
  502. suspendCoroutine<Unit> { unitCont ->
  503. controlKeyCharge(false, mac) {
  504. ThreadUtils.runOnIO {
  505. delay(500)
  506. controlKeyCharge(true, mac) {
  507. unitCont.resume(Unit)
  508. }
  509. }
  510. }
  511. }
  512. LogUtil.i("蓝牙连接-开启充电并等待500ms")
  513. // 等 500ms 保证硬件电源稳定
  514. delay(500)
  515. // 再次注册连接监听
  516. val secondTry = suspendCancellableCoroutine<Boolean> { cont ->
  517. var isCalled = false
  518. BusinessManager.registerConnectListener(mac, true) { isDone, _ ->
  519. if (isCalled) {
  520. return@registerConnectListener
  521. }
  522. isCalled = true
  523. // 无论成功或失败,都先把电关掉
  524. controlKeyCharge(false, mac) { }
  525. cont.resume(isDone)
  526. cont.cancel()
  527. }
  528. }
  529. return@withContext secondTry
  530. }
  531. /**
  532. * 扫描在线的蓝牙钥匙并发送指令关机
  533. */
  534. suspend fun scanOnlineKeyLockMacAndSwitchModeToClose(): Boolean {
  535. return suspendCancellableCoroutine { parentCont ->
  536. BleUtil.instance?.scan(object : CustomBleScanCallback() {
  537. override fun onPrompt(promptStr: String?) {
  538. // 蓝牙未启动重试
  539. LogUtil.i("设备录入-参数:${promptStr}")
  540. BleManager.getInstance().enableBluetooth()
  541. ThreadUtils.runOnMainDelayed(300) {
  542. scanOnlineKeyLockMacAndSwitchModeToClose()
  543. }
  544. }
  545. override fun onScanStarted(success: Boolean) {
  546. LogUtil.i("设备录入-onScanStarted:${success}")
  547. if (!success) {
  548. ThreadUtils.runOnMainDelayed(300) {
  549. scanOnlineKeyLockMacAndSwitchModeToClose()
  550. }
  551. }
  552. }
  553. override fun onScanning(bleDevice: BleDevice?) {
  554. val mac = bleDevice?.mac ?: return
  555. LogUtil.i("设备录入-onScanning:$mac")
  556. }
  557. override fun onScanFinished(scanResultList: MutableList<BleDevice>?) {
  558. val devicesSnapshot = scanResultList?.toList().orEmpty()
  559. ThreadUtils.runOnIO {
  560. devicesSnapshot.forEach {
  561. val connected = tryConnectWithOptionalCharge(it.mac, false)
  562. if (connected) {
  563. val sendSuccess = sendEmptyTicketJson(it)
  564. LogUtil.i("设备录入-发送切换工作模式:${it.mac},${sendSuccess}")
  565. }
  566. }
  567. parentCont.resume(true)
  568. }
  569. }
  570. })
  571. }
  572. }
  573. /**
  574. * 发送空作业票
  575. */
  576. private suspend fun sendEmptyTicketJson(bleDevice: BleDevice): Boolean {
  577. return suspendCancellableCoroutine<Boolean> { cont ->
  578. BleCmdManager.sendWorkTicket(
  579. BusinessManager.generateEmptyTicketSendJson(),
  580. bleDevice = bleDevice,
  581. callback = object : CustomBleWriteCallback() {
  582. override fun onWriteSuccess(
  583. current: Int,
  584. total: Int,
  585. justWrite: ByteArray?
  586. ) {
  587. ThreadUtils.runOnIO {
  588. delay(3000)
  589. cont.resume(switchWorkMode(bleDevice))
  590. }
  591. }
  592. override fun onWriteFailure(exception: BleException?) {
  593. ThreadUtils.runOnMainDelayed(300) {
  594. cont.resume(sendEmptyTicketJson(bleDevice))
  595. }
  596. }
  597. })
  598. }
  599. }
  600. /**
  601. * 切换工作模式
  602. */
  603. private suspend fun switchWorkMode(bleDevice: BleDevice): Boolean {
  604. return suspendCancellableCoroutine<Boolean> { cont ->
  605. BleCmdManager.switchMode(
  606. BleConst.STATUS_WORK,
  607. bleDevice,
  608. object : CustomBleWriteCallback() {
  609. override fun onWriteSuccess(
  610. current: Int,
  611. total: Int,
  612. justWrite: ByteArray?
  613. ) {
  614. BleManager.getInstance().disconnect(bleDevice)
  615. ThreadUtils.runOnIO {
  616. delay(800)
  617. cont.resume(true)
  618. }
  619. LogUtil.i("设备录入-切换模式发送成功 : ${bleDevice.mac}")
  620. }
  621. override fun onWriteFailure(exception: BleException?) {
  622. LogUtil.e("设备录入-切换模式发送失败 : ${bleDevice.mac}")
  623. ThreadUtils.runOnMainDelayed(300) {
  624. cont.resume(sendEmptyTicketJson(bleDevice))
  625. }
  626. }
  627. })
  628. }
  629. }
  630. /**
  631. * 切换待机模式
  632. */
  633. fun switchReadyMode(bleDevice: BleDevice) {
  634. BleCmdManager.switchMode(
  635. BleConst.STATUS_READY,
  636. bleDevice,
  637. object : CustomBleWriteCallback() {
  638. override fun onWriteSuccess(
  639. current: Int,
  640. total: Int,
  641. justWrite: ByteArray?
  642. ) {
  643. BleManager.getInstance().disconnect(bleDevice)
  644. LogUtil.i("设备录入-切换模式发送成功 : ${bleDevice.mac}")
  645. }
  646. override fun onWriteFailure(exception: BleException?) {
  647. LogUtil.e("设备录入-切换模式发送失败 : ${bleDevice.mac}")
  648. }
  649. })
  650. }
  651. /**
  652. * 扫描在线的蓝牙
  653. */
  654. fun scanOnlineKeyLockMac(callback: (MutableList<BleDevice>?) -> Unit) {
  655. BleUtil.instance?.scan(object : CustomBleScanCallback() {
  656. override fun onPrompt(promptStr: String?) {
  657. // 蓝牙未启动重试
  658. LogUtil.d("设备录入-参数:${promptStr}")
  659. BleManager.getInstance().enableBluetooth()
  660. ThreadUtils.runOnMainDelayed(300) {
  661. scanOnlineKeyLockMac(callback)
  662. }
  663. }
  664. override fun onScanStarted(success: Boolean) {
  665. LogUtil.d("设备录入-onScanStarted:${success}")
  666. if (!success) {
  667. ThreadUtils.runOnMainDelayed(300) {
  668. scanOnlineKeyLockMac(callback)
  669. }
  670. }
  671. }
  672. override fun onScanning(bleDevice: BleDevice?) {
  673. val mac = bleDevice?.mac ?: return
  674. LogUtil.d("设备录入-onScanning:$mac")
  675. }
  676. override fun onScanFinished(scanResultList: MutableList<BleDevice>?) {
  677. LogUtil.d("设备录入-扫描完成:$scanResultList")
  678. callback(scanResultList)
  679. }
  680. })
  681. }
  682. // 蓝牙连接准备监听
  683. data class ConnectListener(
  684. val mac: String,
  685. val callBack: ((Boolean, BleBean?) -> Unit)? = null
  686. )
  687. }