UhfRfidManager.kt 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package xn.hxp.receiver
  2. import android.content.Context
  3. import android.content.SharedPreferences
  4. import android.view.InputDevice
  5. import android.view.KeyEvent
  6. import com.blankj.utilcode.util.LogUtils
  7. /**
  8. * 外置超高频RFID读卡器管理器(单例)
  9. * 负责:设备学习、开关管理、白名单管理、设备识别
  10. */
  11. object UhfRfidManager {
  12. private const val PREF_NAME = "uhf_rfid_config"
  13. private const val KEY_ENABLED = "uhf_enabled"
  14. private const val KEY_DEVICE_VENDOR_ID = "uhf_vendor_id"
  15. private const val KEY_DEVICE_PRODUCT_ID = "uhf_product_id"
  16. private const val KEY_DEVICE_NAME = "uhf_device_name"
  17. private const val KEY_WHITELIST = "uhf_whitelist"
  18. // 白名单业务标识
  19. const val PAGE_STORAGE_RFID = "storage_rfid" // 存储模块RFID绑定
  20. const val PAGE_LABEL_RFID = "label_rfid" // 标签管理RFID绑定/更换
  21. const val PAGE_INQUIRY = "inquiry" // 查询模块
  22. // 学习模式
  23. var isLearning = false
  24. var learningCallback: ((deviceName: String) -> Unit)? = null
  25. private fun getPrefs(context: Context): SharedPreferences {
  26. return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
  27. }
  28. fun isEnabled(context: Context): Boolean {
  29. return getPrefs(context).getBoolean(KEY_ENABLED, false)
  30. }
  31. fun setEnabled(context: Context, enabled: Boolean) {
  32. getPrefs(context).edit().putBoolean(KEY_ENABLED, enabled).apply()
  33. }
  34. fun getDeviceVendorId(context: Context): Int {
  35. return getPrefs(context).getInt(KEY_DEVICE_VENDOR_ID, -1)
  36. }
  37. fun getDeviceProductId(context: Context): Int {
  38. return getPrefs(context).getInt(KEY_DEVICE_PRODUCT_ID, -1)
  39. }
  40. fun getDeviceName(context: Context): String? {
  41. return getPrefs(context).getString(KEY_DEVICE_NAME, null)
  42. }
  43. fun saveDeviceInfo(context: Context, vendorId: Int, productId: Int, deviceName: String) {
  44. getPrefs(context).edit()
  45. .putInt(KEY_DEVICE_VENDOR_ID, vendorId)
  46. .putInt(KEY_DEVICE_PRODUCT_ID, productId)
  47. .putString(KEY_DEVICE_NAME, deviceName)
  48. .apply()
  49. LogUtils.i("UhfRfidManager: 学习设备成功 vendorId=$vendorId productId=$productId name=$deviceName")
  50. }
  51. fun hasLearnedDevice(context: Context): Boolean {
  52. return getDeviceVendorId(context) != -1 && getDeviceProductId(context) != -1
  53. }
  54. /**
  55. * 获取白名单集合
  56. */
  57. fun getWhitelist(context: Context): Set<String> {
  58. val str = getPrefs(context).getString(KEY_WHITELIST, "") ?: ""
  59. if (str.isEmpty()) return emptySet()
  60. return str.split(",").toSet()
  61. }
  62. fun saveWhitelist(context: Context, whitelist: Set<String>) {
  63. getPrefs(context).edit().putString(KEY_WHITELIST, whitelist.joinToString(",")).apply()
  64. }
  65. /**
  66. * 开始学习模式,等待外置读卡器刷卡
  67. */
  68. fun startLearning(callback: (deviceName: String) -> Unit) {
  69. isLearning = true
  70. learningCallback = callback
  71. }
  72. fun stopLearning() {
  73. isLearning = false
  74. learningCallback = null
  75. }
  76. fun isPageWhitelisted(context: Context, pageTag: String): Boolean {
  77. return getWhitelist(context).contains(pageTag)
  78. }
  79. /**
  80. * 判断KeyEvent是否来自已学习的外置超高频RFID读卡器
  81. */
  82. fun isUhfRfidEvent(context: Context, event: KeyEvent): Boolean {
  83. if (!isEnabled(context)) return false
  84. if (!hasLearnedDevice(context)) return false
  85. val device = event.device ?: return false
  86. val vendorId = getDeviceVendorId(context)
  87. val productId = getDeviceProductId(context)
  88. return device.vendorId == vendorId && device.productId == productId
  89. }
  90. /**
  91. * 学习模式下处理KeyEvent,记录设备信息
  92. * 返回true表示已消费该事件
  93. */
  94. fun handleLearningEvent(context: Context, event: KeyEvent): Boolean {
  95. if (!isLearning) return false
  96. val device = event.device ?: return false
  97. // 学习期间统一消费设备按键,避免触发页面按钮导致误操作或重启
  98. if (!isCandidateLearningDevice(device, event)) return true
  99. // 只在ACTION_DOWN时记录,避免重复
  100. if (event.action != KeyEvent.ACTION_DOWN) return true
  101. val vendorId = device.vendorId
  102. val productId = device.productId
  103. val deviceName = device.name ?: "Unknown"
  104. saveDeviceInfo(context, vendorId, productId, deviceName)
  105. isLearning = false
  106. learningCallback?.invoke(deviceName)
  107. learningCallback = null
  108. return true
  109. }
  110. /**
  111. * 允许学习的候选设备:
  112. * 1. 明确标记为 external 的输入设备
  113. * 2. 或具备 vendorId / productId 的 HID 键盘类设备
  114. *
  115. * 不再强依赖 isExternal,避免部分 Android 设备把 USB HID 识别成普通键盘导致学习失败。
  116. */
  117. private fun isCandidateLearningDevice(device: InputDevice, event: KeyEvent): Boolean {
  118. if (device.isVirtual) return false
  119. val hasVidPid = device.vendorId > 0 || device.productId > 0
  120. val keyboardLike = device.sources and InputDevice.SOURCE_KEYBOARD == InputDevice.SOURCE_KEYBOARD
  121. val validKey = event.keyCode != KeyEvent.KEYCODE_UNKNOWN
  122. return device.isExternal || (hasVidPid && keyboardLike && validKey)
  123. }
  124. }