Browse Source

refactor(更新)
- 虹软不裁剪

周文健 4 tháng trước cách đây
mục cha
commit
84b03ce384
24 tập tin đã thay đổi với 319 bổ sung109 xóa
  1. 29 13
      app/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt
  2. 24 9
      app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt
  3. 17 1
      app/src/main/java/com/grkj/iscs/features/login/viewmodel/LoginViewModel.kt
  4. 28 12
      app/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt
  5. 1 0
      app/src/main/java/com/grkj/iscs/features/main/dialog/user_info/AddFingerprintDialog.kt
  6. 8 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/common/SelectMemberFragment.kt
  7. 1 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/common/SelectPointFragment.kt
  8. 90 27
      app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetFingerprintFragment.kt
  9. 2 0
      app/src/main/res/values-en/strings.xml
  10. 2 0
      app/src/main/res/values-zh/strings.xml
  11. 2 0
      app/src/main/res/values/strings.xml
  12. 2 0
      data/src/main/java/com/grkj/data/repository/IUserRepository.kt
  13. 9 1
      data/src/main/java/com/grkj/data/repository/impl/network/NetworkUserRepository.kt
  14. 24 2
      data/src/main/java/com/grkj/data/repository/impl/standard/UserRepository.kt
  15. 16 11
      shared/src/main/java/com/grkj/shared/utils/ArcSoftUtil.kt
  16. 3 33
      shared/src/main/java/com/grkj/shared/utils/BiometricVerifier.kt
  17. 6 0
      shared/src/main/java/com/grkj/shared/utils/extension/Int.kt
  18. 30 0
      shared/src/main/java/com/grkj/shared/utils/extension/Rect.kt
  19. 1 0
      shared/src/main/java/com/grkj/shared/utils/face/arcsoft/CameraHelper.java
  20. 13 0
      ui-base/src/main/java/com/grkj/ui_base/base/BaseViewModel.kt
  21. 8 0
      ui-base/src/main/java/com/grkj/ui_base/utils/fingerprint/FingerprintUtil.kt
  22. 1 0
      ui-base/src/main/res/values-en/strings.xml
  23. 1 0
      ui-base/src/main/res/values-zh/strings.xml
  24. 1 0
      ui-base/src/main/res/values/strings.xml

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

@@ -29,6 +29,7 @@ import com.grkj.ui_base.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.extension.getAppVersionName
 import com.grkj.shared.utils.extension.toByteArrays
 import com.grkj.shared.utils.extension.toHexStrings
+import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.fingerprint.FingerprintUtil
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikimage.ImageConvertUtils
@@ -146,19 +147,35 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
         FingerprintUtil.start()
         FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
             override fun onScan(bitmap: Bitmap) {
-                LoadingEvent.sendLoadingEvent(
-                    CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),
-                    true
-                )
-                viewModel.loginWithFingerprint(ImageConvertUtils.bitmapToBase64(bitmap).toString())
-                    .observe(this@LoginActivity) { isSuccess ->
-                        LoadingEvent.sendLoadingEvent()
-                        if (isSuccess) {
-                            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
-                        } else {
-                            PopTip.tip(CommonUtils.getStr(R.string.login_failed))
+                if (ISCSConfig.isNetVersion){
+                    LoadingEvent.sendLoadingEvent(
+                        CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),
+                        true
+                    )
+                    viewModel.loginWithFingerprint(ImageConvertUtils.bitmapToBase64(bitmap).toString())
+                        .observe(this@LoginActivity) { isSuccess ->
+                            LoadingEvent.sendLoadingEvent()
+                            if (isSuccess) {
+                                startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                            } else {
+                                PopTip.tip(CommonUtils.getStr(R.string.login_failed))
+                            }
                         }
-                    }
+                }
+            }
+
+            override fun onScan(temp: ByteArray?) {
+                if (!ISCSConfig.isNetVersion){
+                    viewModel.loginWithFingerprint(temp)
+                        .observe(this@LoginActivity) { isSuccess ->
+                            LoadingEvent.sendLoadingEvent()
+                            if (isSuccess) {
+                                startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                            } else {
+                                PopTip.tip(CommonUtils.getStr(R.string.login_failed))
+                            }
+                        }
+                }
             }
         })
     }
@@ -167,7 +184,6 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
         super.onStop()
         cardNo = ""
         FingerprintUtil.stop()
-        FingerprintUtil.unInit()
     }
 
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {

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

@@ -1,5 +1,6 @@
 package com.grkj.iscs.features.login.dialog
 
+import android.content.Intent
 import android.graphics.Bitmap
 import android.view.View
 import androidx.appcompat.widget.PopupMenu
@@ -7,8 +8,11 @@ import androidx.lifecycle.LifecycleOwner
 import com.grkj.data.model.res.UserInfoRes
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogLoginBinding
+import com.grkj.iscs.features.login.activity.LoginActivity
 import com.grkj.iscs.features.login.viewmodel.LoginViewModel
+import com.grkj.iscs.features.main.activity.MainActivity
 import com.grkj.shared.utils.ArcSoftUtil
+import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.fingerprint.FingerprintUtil
@@ -88,7 +92,6 @@ class LoginDialog(
 
                     1 -> {
                         FingerprintUtil.stop()
-                        FingerprintUtil.unInit()
                     }
 
                     3 -> {
@@ -124,14 +127,26 @@ class LoginDialog(
                     FingerprintUtil.start()
                     FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
                         override fun onScan(bitmap: Bitmap) {
-                            LoadingEvent.sendLoadingEvent(
-                                CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),
-                                true
-                            )
-                            viewModel.loginWithFingerprint(
-                                ImageConvertUtils.bitmapToBase64(bitmap).toString()
-                            ).observe(lifecycleOwner) {
-                                callBack?.invoke(it)
+                            if (ISCSConfig.isNetVersion){
+                                LoadingEvent.sendLoadingEvent(
+                                    CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),
+                                    true
+                                )
+                                viewModel.loginWithFingerprint(ImageConvertUtils.bitmapToBase64(bitmap).toString())
+                                    .observe(lifecycleOwner) { isSuccess ->
+                                        LoadingEvent.sendLoadingEvent()
+                                        callBack?.invoke(isSuccess)
+                                    }
+                            }
+                        }
+
+                        override fun onScan(temp: ByteArray?) {
+                            if (!ISCSConfig.isNetVersion){
+                                viewModel.loginWithFingerprint(temp)
+                                    .observe(lifecycleOwner) { isSuccess ->
+                                        LoadingEvent.sendLoadingEvent()
+                                        callBack?.invoke(isSuccess)
+                                    }
                             }
                         }
                     })

+ 17 - 1
app/src/main/java/com/grkj/iscs/features/login/viewmodel/LoginViewModel.kt

@@ -21,7 +21,9 @@ class LoginViewModel @Inject constructor(
     /**
      * 添加管理员账号
      */
-    fun insertAdminAccount(username: String = "admin", password: String = "123456"): LiveData<Boolean> {
+    fun insertAdminAccount(
+        username: String = "admin", password: String = "123456"
+    ): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             userRepository.removeAdminUser()
             userRepository.addAdminUser(username, password)
@@ -62,6 +64,20 @@ class LoginViewModel @Inject constructor(
         }
     }
 
+    /**
+     * 指纹登录
+     */
+    fun loginWithFingerprint(fingerprint: ByteArray?): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            if (fingerprint == null) {
+                emit(false)
+            } else {
+                val loginSuccess = userRepository.loginWithFingerprint(fingerprint)
+                emit(loginSuccess)
+            }
+        }
+    }
+
     /**
      * 人脸登录
      */

+ 28 - 12
app/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt

@@ -11,6 +11,7 @@ import com.grkj.iscs.databinding.DialogLoginBinding
 import com.grkj.iscs.features.login.viewmodel.LoginViewModel
 import com.grkj.shared.utils.ArcSoftUtil
 import com.grkj.ui_base.base.BaseViewModel
+import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.fingerprint.FingerprintUtil
@@ -66,7 +67,6 @@ class CheckFaceDialog(
 
                 1 -> {
                     FingerprintUtil.stop()
-                    FingerprintUtil.unInit()
                 }
             }
             customDialog.dismiss()
@@ -80,7 +80,6 @@ class CheckFaceDialog(
 
                     1 -> {
                         FingerprintUtil.stop()
-                        FingerprintUtil.unInit()
                     }
                 }
                 super.onDismiss(dialog)
@@ -105,16 +104,33 @@ class CheckFaceDialog(
                 FingerprintUtil.start()
                 FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
                     override fun onScan(bitmap: Bitmap) {
-                        LoadingEvent.sendLoadingEvent(
-                            CommonUtils.getStr(com.grkj.ui_base.R.string.doing_checking), true
-                        )
-                        viewModel.checkFinger(
-                            ImageConvertUtils.bitmapToBase64(bitmap).toString()
-                        ).observe(lifecycleOwner) {
-                            if (it) {
-                                callBack?.invoke(it)
-                            } else {
-                                PopTip.tip(R.string.verify_failed)
+                        if (ISCSConfig.isNetVersion){
+                            LoadingEvent.sendLoadingEvent(
+                                CommonUtils.getStr(com.grkj.ui_base.R.string.doing_checking), true
+                            )
+                            viewModel.checkFinger(
+                                ImageConvertUtils.bitmapToBase64(bitmap).toString()
+                            ).observe(lifecycleOwner) {
+                                if (it) {
+                                    callBack?.invoke(it)
+                                } else {
+                                    PopTip.tip(R.string.verify_failed)
+                                }
+                            }
+                        }
+                    }
+
+                    override fun onScan(temp: ByteArray?) {
+                        if (!ISCSConfig.isNetVersion){
+                            LoadingEvent.sendLoadingEvent(
+                                CommonUtils.getStr(com.grkj.ui_base.R.string.doing_checking), true
+                            )
+                            viewModel.checkFinger(temp).observe(lifecycleOwner) {
+                                if (it) {
+                                    callBack?.invoke(it)
+                                } else {
+                                    PopTip.tip(R.string.verify_failed)
+                                }
                             }
                         }
                     }

+ 1 - 0
app/src/main/java/com/grkj/iscs/features/main/dialog/user_info/AddFingerprintDialog.kt

@@ -18,6 +18,7 @@ class AddFingerprintDialog(val onCancel: () -> Unit) :
         dialog.isCancelable = false
         binding.cancel.setDebouncedClickListener {
             onCancel()
+            dialog.dismiss()
         }
     }
 

+ 8 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/common/SelectMemberFragment.kt

@@ -61,6 +61,14 @@ class SelectMemberFragment : BaseFragment<FragmentSelectMemeberBinding>() {
             navController.popBackStack()
         }
         binding.confirm.setDebouncedClickListener {
+            if (selectedLockerData.isEmpty()){
+                PopTip.tip(com.grkj.ui_base.R.string.please_select_locker)
+                return@setDebouncedClickListener
+            }
+            if (selectedColockerData.isEmpty()){
+                PopTip.tip(com.grkj.ui_base.R.string.please_select_colocker)
+                return@setDebouncedClickListener
+            }
             GlobalDataTempStore.getInstance()
                 .saveData(DataTransferConstants.KEY_SELECTED_MEMBER_LOCKER_DATA, selectedLockerData)
             GlobalDataTempStore.getInstance().saveData(

+ 1 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/common/SelectPointFragment.kt

@@ -63,6 +63,7 @@ class SelectPointFragment : BaseFragment<FragmentSelectPointBinding>() {
             if (item.isSelected) {
                 item.isSelected = false
                 selectedPointData.removeIf { it.pointId == item.pointId }
+                viewModel.pointManageData.find { it.pointId == item.pointId }?.isSelected = false
             }
             adapter.notifyDataSetChanged()
             binding.selectedPointRv.adapter?.notifyDataSetChanged()

+ 90 - 27
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetFingerprintFragment.kt

@@ -18,13 +18,20 @@ import com.grkj.iscs.databinding.ItemSetFingerprintBinding
 import com.grkj.iscs.features.main.dialog.user_info.AddFingerprintDialog
 import com.grkj.iscs.features.main.viewmodel.user_info.UserInfoViewModel
 import com.grkj.ui_base.base.BaseFragment
+import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.fingerprint.FingerprintUtil
+import com.kongzue.dialogx.dialogs.CustomDialog
+import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.extension.deleteIfExists
 import com.sik.sikcore.extension.setDebouncedClickListener
 import com.sik.sikimage.ImageConvertUtils
+import com.zkteco.android.biometric.module.fingerprintreader.FingerprintCaptureListener
+import com.zkteco.android.biometric.module.fingerprintreader.FingerprintConstant
+import com.zkteco.android.biometric.module.fingerprintreader.FingerprintSensor
+import com.zkteco.zkfinger.FingerprintService
 import dagger.hilt.android.AndroidEntryPoint
 
 /**
@@ -33,7 +40,7 @@ import dagger.hilt.android.AndroidEntryPoint
 @AndroidEntryPoint
 class SetFingerprintFragment : BaseFragment<FragmentSetFingerprintBinding>() {
     private val viewModel: UserInfoViewModel by viewModels()
-
+    private var fingerprintTempData = mutableListOf<ByteArray>()
     override fun getLayoutId(): Int {
         return R.layout.fragment_set_fingerprint
     }
@@ -43,35 +50,11 @@ class SetFingerprintFragment : BaseFragment<FragmentSetFingerprintBinding>() {
             navController.popBackStack()
         }
         binding.add.setDebouncedClickListener {
+            fingerprintTempData.clear()
             AddFingerprintDialog.show {
                 FingerprintUtil.stop()
-                FingerprintUtil.unInit()
             }.apply {
-                FingerprintUtil.init(requireContext())
-                FingerprintUtil.start()
-                FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
-                    override fun onScan(bitmap: Bitmap) {
-                        FingerprintUtil.stop()
-                        FingerprintUtil.unInit()
-                        val saveFileName =
-                            "${MainDomainData.userInfo?.userId}_fingerprint_${TimeUtils.nowString("yyyyMMddHHmmss")}"
-                        FileStorageUtils.writeText(
-                            CommonConstants.FINGERPRINT_FOLDER,
-                            saveFileName,
-                            ImageConvertUtils.bitmapToBase64(bitmap).toString()
-                        )
-                        val savePath = FileStorageUtils.getFilePath(
-                            CommonConstants.FINGERPRINT_FOLDER,
-                            saveFileName
-                        )
-                        viewModel.saveUserFingerprint(savePath)
-                            .observe(this@SetFingerprintFragment) {
-                                getData()
-                                TipDialog.showSuccess(getString(com.grkj.ui_base.R.string.save_success))
-                                this@apply.dismiss()
-                            }
-                    }
-                })
+                startCaptureFingerprint(this)
             }
         }
         binding.delete.setDebouncedClickListener {
@@ -140,6 +123,86 @@ class SetFingerprintFragment : BaseFragment<FragmentSetFingerprintBinding>() {
         setSelectAllListener()
     }
 
+    private fun startCaptureFingerprint(dialog: CustomDialog) {
+        FingerprintUtil.init(requireContext())
+        FingerprintUtil.start()
+        FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
+            override fun onScan(bitmap: Bitmap) {
+                if (ISCSConfig.isNetVersion) {
+                    FingerprintUtil.stop()
+                    val saveFileName =
+                        "${MainDomainData.userInfo?.userId}_fingerprint_${
+                            TimeUtils.nowString(
+                                "yyyyMMddHHmmss"
+                            )
+                        }"
+                    FileStorageUtils.writeText(
+                        CommonConstants.FINGERPRINT_FOLDER,
+                        saveFileName,
+                        ImageConvertUtils.bitmapToBase64(bitmap).toString()
+                    )
+                    val savePath = FileStorageUtils.getFilePath(
+                        CommonConstants.FINGERPRINT_FOLDER,
+                        saveFileName
+                    )
+                    viewModel.saveUserFingerprint(savePath)
+                        .observe(this@SetFingerprintFragment) {
+                            getData()
+                            TipDialog.showSuccess(getString(com.grkj.ui_base.R.string.save_success))
+                            dialog.dismiss()
+                        }
+                }
+
+            }
+
+            override fun onScan(temp: ByteArray?) {
+                if (!ISCSConfig.isNetVersion && temp != null) {
+                    fingerprintTempData.add(temp)
+                    logger.info("指纹数量:${fingerprintTempData.size}-${temp.size}")
+                    if (fingerprintTempData.size == 3) {
+                        val newFingerprintTemp = ByteArray(FingerprintConstant.MAX_DATA_LENGTH)
+                        val mergeCode = FingerprintService.merge(
+                            fingerprintTempData[0],
+                            fingerprintTempData[1],
+                            fingerprintTempData[2],
+                            newFingerprintTemp
+                        )
+                        logger.info("指纹模板长度:${newFingerprintTemp.size}-${mergeCode}")
+                        if (newFingerprintTemp.isNotEmpty()) {
+                            val saveFileName =
+                                "${MainDomainData.userInfo?.userId}_fingerprint_${
+                                    TimeUtils.nowString(
+                                        "yyyyMMddHHmmss"
+                                    )
+                                }"
+                            FileStorageUtils.writeBytes(
+                                CommonConstants.FINGERPRINT_FOLDER,
+                                saveFileName,
+                                newFingerprintTemp
+                            )
+                            val savePath = FileStorageUtils.getFilePath(
+                                CommonConstants.FINGERPRINT_FOLDER,
+                                saveFileName
+                            )
+                            viewModel.saveUserFingerprint(savePath)
+                                .observe(this@SetFingerprintFragment) {
+                                    FingerprintUtil.stop()
+                                    getData()
+                                    TipDialog.showSuccess(getString(com.grkj.ui_base.R.string.save_success))
+                                    dialog.dismiss()
+                                }
+                        } else {
+                            PopTip.tip(R.string.fingerprint_register_failed)
+                            fingerprintTempData.clear()
+                        }
+                    } else {
+                        PopTip.tip(R.string.please_press_the_fingerprint_again)
+                    }
+                }
+            }
+        })
+    }
+
     private fun setSelectAllListener() {
         binding.selectAll.setOnCheckedChangeListener { v, checked ->
             viewModel.sysBiometricDataVo.forEach { it.isSelected = checked }

+ 2 - 0
app/src/main/res/values-en/strings.xml

@@ -450,5 +450,7 @@
     <string name="handle_exception_failed">Handle exception failed</string>
     <string name="confirm_create_lock_job">Confirm whether to create a lock job</string>
     <string name="create_job_failed">Create job failed</string>
+    <string name="please_press_the_fingerprint_again">Please press the fingerprint again</string>
+    <string name="fingerprint_register_failed">Fingerprint input failed</string>
 
 </resources>

+ 2 - 0
app/src/main/res/values-zh/strings.xml

@@ -450,5 +450,7 @@
     <string name="handle_exception_failed">处理异常失败</string>
     <string name="confirm_create_lock_job">确认是否创建上锁作业</string>
     <string name="create_job_failed">创建作业失败</string>
+    <string name="please_press_the_fingerprint_again">请再次按压指纹</string>
+    <string name="fingerprint_register_failed">指纹录入失败</string>
 
 </resources>

+ 2 - 0
app/src/main/res/values/strings.xml

@@ -453,5 +453,7 @@
     <string name="handle_exception_failed">处理异常失败</string>
     <string name="confirm_create_lock_job">确认是否创建上锁作业</string>
     <string name="create_job_failed">创建作业失败</string>
+    <string name="please_press_the_fingerprint_again">请再次按压指纹</string>
+    <string name="fingerprint_register_failed">指纹录入失败</string>
 
 </resources>

+ 2 - 0
data/src/main/java/com/grkj/data/repository/IUserRepository.kt

@@ -32,11 +32,13 @@ interface IUserRepository {
      * 指纹登录
      */
     fun loginWithFingerprint(fingerprint: String): Boolean
+    fun loginWithFingerprint(fingerprint: ByteArray): Boolean
 
     /**
      * 检查指纹
      */
     fun checkFingerprint(fingerprint: String): Boolean
+    fun checkFingerprint(fingerprint: ByteArray): Boolean
 
     /**
      * 人脸登录

+ 9 - 1
data/src/main/java/com/grkj/data/repository/impl/network/NetworkUserRepository.kt

@@ -17,7 +17,7 @@ import javax.inject.Singleton
  * 联网版用户仓储
  */
 @Singleton
-class NetworkUserRepository @Inject constructor()  : BaseRepository(), IUserRepository{
+class NetworkUserRepository @Inject constructor() : BaseRepository(), IUserRepository {
     override fun loginWithAccount(
         username: String,
         password: String
@@ -37,10 +37,18 @@ class NetworkUserRepository @Inject constructor()  : BaseRepository(), IUserRepo
         TODO("Not yet implemented")
     }
 
+    override fun loginWithFingerprint(fingerprint: ByteArray): Boolean {
+        TODO("Not yet implemented")
+    }
+
     override fun checkFingerprint(fingerprint: String): Boolean {
         TODO("Not yet implemented")
     }
 
+    override fun checkFingerprint(fingerprint: ByteArray): Boolean {
+        TODO("Not yet implemented")
+    }
+
     override fun loginWithFace(face: String): Boolean {
         TODO("Not yet implemented")
     }

+ 24 - 2
data/src/main/java/com/grkj/data/repository/impl/standard/UserRepository.kt

@@ -20,6 +20,7 @@ import com.grkj.data.repository.BaseRepository
 import com.grkj.data.repository.IUserRepository
 import com.grkj.shared.utils.BCryptUtils
 import com.grkj.shared.utils.BiometricVerifier
+import com.sik.sikcore.extension.deleteIfExists
 import com.sik.sikcore.extension.file
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -95,6 +96,15 @@ class UserRepository @Inject constructor(
     }
 
     override fun loginWithFingerprint(fingerprint: String): Boolean {
+        val fingerprintDataList = userDao.getFingerprintData()
+        if (fingerprintDataList.isEmpty()) {
+            return false
+        }
+        var hasFingerprint = false
+        return hasFingerprint
+    }
+
+    override fun loginWithFingerprint(fingerprint: ByteArray): Boolean {
         val fingerprintDataList = userDao.getFingerprintData()
         if (fingerprintDataList.isEmpty()) {
             return false
@@ -103,7 +113,7 @@ class UserRepository @Inject constructor(
         var userId: String? = null
         for (fingerprintData in fingerprintDataList) {
             if (fingerprintData.content.isNotEmpty()) {
-                val fileData = fingerprintData.content.file().readText()
+                val fileData = fingerprintData.content.file().readBytes()
                 if (BiometricVerifier.verifyFingerprint(fingerprint, fileData)) {
                     hasFingerprint = true
                     userId = fingerprintData.userId.toString()
@@ -137,6 +147,15 @@ class UserRepository @Inject constructor(
     }
 
     override fun checkFingerprint(fingerprint: String): Boolean {
+        val fingerprintDataList = userDao.getFingerprintData()
+        if (fingerprintDataList.isEmpty()) {
+            return false
+        }
+        var hasFingerprint = false
+        return hasFingerprint
+    }
+
+    override fun checkFingerprint(fingerprint: ByteArray): Boolean {
         val fingerprintDataList = userDao.getFingerprintData()
         if (fingerprintDataList.isEmpty()) {
             return false
@@ -145,7 +164,7 @@ class UserRepository @Inject constructor(
         var userId: String? = null
         for (fingerprintData in fingerprintDataList) {
             if (fingerprintData.content.isNotEmpty()) {
-                val fileData = fingerprintData.content.file().readText()
+                val fileData = fingerprintData.content.file().readBytes()
                 if (BiometricVerifier.verifyFingerprint(fingerprint, fileData)) {
                     hasFingerprint = true
                     userId = fingerprintData.userId.toString()
@@ -344,6 +363,9 @@ class UserRepository @Inject constructor(
     }
 
     override fun deleteFaceDataByUserId(userId: Long) {
+        userDao.getFaceDataByUserId(userId).forEach {
+            it.content.deleteIfExists()
+        }
         userDao.deleteFaceDataByUserId(userId)
     }
 

+ 16 - 11
shared/src/main/java/com/grkj/shared/utils/ArcSoftUtil.kt

@@ -5,7 +5,6 @@ import android.content.Context
 import android.graphics.Bitmap
 import android.graphics.BitmapFactory
 import android.graphics.Point
-import android.graphics.Rect
 import android.hardware.Camera
 import android.util.Base64
 import android.util.DisplayMetrics
@@ -27,8 +26,6 @@ import com.grkj.shared.config.Constants
 import com.grkj.shared.utils.face.arcsoft.CameraHelper
 import com.grkj.shared.utils.face.arcsoft.CameraListener
 import com.grkj.shared.utils.face.arcsoft.NV21ToBitmap
-import com.sik.sikimage.CropImageUtils
-import com.sik.sikimage.ImageUtils
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 
@@ -41,12 +38,15 @@ object ArcSoftUtil {
     private var previewSize: Camera.Size? = null
     private val rgbCameraId = Camera.CameraInfo.CAMERA_FACING_BACK
     private var faceEngine: FaceEngine? = null
+    private val cameraWidth: Int = 640
+    private val cameraHeight: Int = 480
     private var afCode = -1
     private val processMask: Int =
         FaceEngine.ASF_AGE or FaceEngine.ASF_FACE3DANGLE or FaceEngine.ASF_GENDER or FaceEngine.ASF_LIVENESS
 
     private const val ACTION_REQUEST_PERMISSIONS: Int = 0x001
     var isActivated = false
+    private var isInit = false
 
     /**
      * 所需的所有权限信息
@@ -81,16 +81,20 @@ object ArcSoftUtil {
     }
 
     fun initEngine(context: Context) {
+        if (isInit){
+            return
+        }
         faceEngine = FaceEngine()
         afCode = faceEngine!!.init(
             context,
             DetectMode.ASF_DETECT_MODE_VIDEO,
             DetectFaceOrientPriority.valueOf("ASF_OP_0_ONLY"),
             16,
-            20,
+            1,
             FaceEngine.ASF_FACE_DETECT or FaceEngine.ASF_AGE or FaceEngine.ASF_FACE3DANGLE or FaceEngine.ASF_GENDER or FaceEngine.ASF_LIVENESS or FaceEngine.ASF_FACE_RECOGNITION
         )
         logger.info("initEngine:  init: $afCode")
+        isInit = afCode == ErrorInfo.MOK
         if (afCode != ErrorInfo.MOK) {
             logger.info("初始化失败")
         }
@@ -174,12 +178,13 @@ object ArcSoftUtil {
                     previewSize!!.width,
                     previewSize!!.height
                 )
-                val faceRect = faceInfoList[0].rect
+//                val faceRect = faceInfoList[0].rect
                 logger.debug("人脸检测结果-识别结果 : ${bitmap == null} - $faceInfoList")
-                bitmap?.let {
-                    val faceBitmap = CropImageUtils.cropBitmap(bitmap, faceRect)
-                    callBack(faceBitmap, faceInfoList.size, true)
-                } ?: callBack(null, faceInfoList.size, true)
+                callBack(bitmap, faceInfoList.size, true)
+//                bitmap?.let {
+//                    val faceBitmap = CropImageUtils.cropBitmap(bitmap, faceRect)
+//                    callBack(faceBitmap, faceInfoList.size, true)
+//                } ?: callBack(null, faceInfoList.size, true)
             }
 
             override fun onCameraClosed() {
@@ -195,7 +200,7 @@ object ArcSoftUtil {
             }
         }
         cameraHelper = CameraHelper.Builder()
-            .previewViewSize(Point(preview.measuredWidth, preview.measuredHeight))
+            .previewViewSize(Point(cameraWidth, cameraHeight))
             .rotation(windowManager.defaultDisplay.rotation)
             .specificCameraId(rgbCameraId ?: Camera.CameraInfo.CAMERA_FACING_FRONT)
             .isMirror(false)
@@ -221,7 +226,7 @@ object ArcSoftUtil {
             cameraHelper!!.release()
             cameraHelper = null
         }
-        unInitEngine()
+//        unInitEngine()
     }
 
     /**

+ 3 - 33
shared/src/main/java/com/grkj/shared/utils/BiometricVerifier.kt

@@ -1,23 +1,6 @@
 package com.grkj.shared.utils
 
-import android.content.Context
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.os.Build
-import android.util.Base64
-import androidx.annotation.RequiresApi
-import com.arcsoft.face.ErrorInfo
-import com.arcsoft.face.FaceEngine
-import com.arcsoft.face.FaceFeature
-import com.arcsoft.face.FaceInfo
-import com.arcsoft.face.FaceSimilar
-import com.arcsoft.face.enums.DetectFaceOrientPriority
-import com.arcsoft.face.enums.DetectMode
-import com.grkj.shared.config.Constants
-import com.machinezoo.sourceafis.FingerprintMatcher
-import com.machinezoo.sourceafis.FingerprintTemplate
-import com.sik.sikcore.SIKCore
-import java.util.concurrent.atomic.AtomicBoolean
+import com.zkteco.zkfinger.FingerprintService
 
 object BiometricVerifier {
 
@@ -27,21 +10,8 @@ object BiometricVerifier {
      * @param b64b 指纹2 的 Base64 图像
      * @return 两者是否认为同一人(score >= threshold)
      */
-    fun verifyFingerprint(b64a: String, b64b: String, threshold: Double = 40.0): Boolean {
-        // 1. 解码成 Bitmap
-        val bmpA = Base64.decode(b64a, Base64.DEFAULT)
-        val bmpB = Base64.decode(b64b, Base64.DEFAULT)
-
-        // 2. 构建指纹模板
-        val templateA = FingerprintTemplate()
-            .dpi(500.0) // 根据图像 DPI 调整
-            .create(bmpA)
-        val templateB = FingerprintTemplate()
-            .dpi(500.0)
-            .create(bmpB)
-
-        // 3. 比对
-        val score = FingerprintMatcher(templateA).match(templateB)
+    fun verifyFingerprint(b64a: ByteArray, b64b: ByteArray, threshold: Double = 23.0): Boolean {
+        val score = FingerprintService.verify(b64a, b64b)
         return score >= threshold
     }
 

+ 6 - 0
shared/src/main/java/com/grkj/shared/utils/extension/Int.kt

@@ -17,4 +17,10 @@ fun Int.toByteArray(capability: Int = 2): ByteArray {
         bytes[i] = ((this ushr (i * 8)) and 0xFF).toByte()  // 小端模式
     }
     return bytes
+}
+
+fun Int.pad4(): Int {
+    val rem = this % 4
+    // 如果已经是 4 的倍数,rem = 0,这里就加 0;否则加上 4 - rem
+    return this + if (rem == 0) 0 else (4 - rem)
 }

+ 30 - 0
shared/src/main/java/com/grkj/shared/utils/extension/Rect.kt

@@ -0,0 +1,30 @@
+package com.grkj.shared.utils.extension
+
+import android.graphics.Rect
+import kotlin.math.roundToInt
+
+/**
+ * 以 Rect 中心为锚点,将宽度和高度向上凑到 padW、padH 的倍数后扩展
+ *
+ * @param padW 宽度对齐像素倍数(如 4)
+ * @param padH 高度对齐像素倍数(如 2)
+ * @return     新的、已对齐且以中心为锚的 Rect
+ */
+inline fun Rect.expandToPadCenter(padW: Int = 4, padH: Int = 4): Rect {
+    val w = width()
+    val h = height()
+
+    // 向上凑整到 padW / padH 的倍数
+    val newW = ((w + padW - 1) / padW) * padW
+    val newH = ((h + padH - 1) / padH) * padH
+
+    // 计算中心点
+    val cx = centerX().toFloat()
+    val cy = centerY().toFloat()
+
+    // 以中心为锚,重新计算 left/top
+    val left = (cx - newW / 2f).roundToInt()
+    val top = (cy - newH / 2f).roundToInt()
+
+    return Rect(left, top, left + newW, top + newH)
+}

+ 1 - 0
shared/src/main/java/com/grkj/shared/utils/face/arcsoft/CameraHelper.java

@@ -15,6 +15,7 @@ import java.io.IOException;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
+import java.util.logging.Logger;
 
 /**
  * 相机辅助类,和{@link CameraListener}共同使用,获取nv21数据等操作

+ 13 - 0
ui-base/src/main/java/com/grkj/ui_base/base/BaseViewModel.kt

@@ -54,6 +54,19 @@ open class BaseViewModel constructor(
         }
     }
 
+    /**
+     * 检查指纹
+     */
+    fun checkFinger(fingerB64: ByteArray?): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            if (fingerB64 == null) {
+                emit(false)
+            } else {
+                emit(userRepository?.checkFingerprint(fingerB64) == true)
+            }
+        }
+    }
+
     /**
      * 检查卡片
      */

+ 8 - 0
ui-base/src/main/java/com/grkj/ui_base/utils/fingerprint/FingerprintUtil.kt

@@ -57,6 +57,9 @@ object FingerprintUtil {
     }
 
     fun init(ctx: Context) {
+        if (bStarted) {
+            return
+        }
         zkusbManager ?: let {
             zkusbManager = ZKUSBManager(ctx, zkusbManagerListener)
         }
@@ -118,6 +121,9 @@ object FingerprintUtil {
             }
 
             override fun extractOK(fpTemplate: ByteArray?) {
+                ThreadUtils.runOnMain {
+                    onScanListener?.onScan(fpTemplate)
+                }
                 if (bRegister) {
                     doRegister(fpTemplate)
                 } else {
@@ -318,5 +324,7 @@ object FingerprintUtil {
 
     interface OnScanListener {
         fun onScan(bitmap: Bitmap)
+
+        fun onScan(temp: ByteArray?)
     }
 }

+ 1 - 0
ui-base/src/main/res/values-en/strings.xml

@@ -371,4 +371,5 @@
     <string name="can_not_remove_current_locker">can not remove current locker</string>
     <string name="fingerprint_delete_selected_confirm_tip">Confirm to delete selected fingerprint?</string>
     <string name="doing_checking">Verifying......</string>
+    <string name="please_select_colocker">Please select Co-Locker</string>
 </resources>

+ 1 - 0
ui-base/src/main/res/values-zh/strings.xml

@@ -371,4 +371,5 @@
     <string name="can_not_remove_current_locker">无法移除当前上锁人</string>
     <string name="fingerprint_delete_selected_confirm_tip">确定要删除选中的指纹吗?</string>
     <string name="doing_checking">正在验证......</string>
+    <string name="please_select_colocker">请选择共锁人</string>
 </resources>

+ 1 - 0
ui-base/src/main/res/values/strings.xml

@@ -371,4 +371,5 @@
     <string name="can_not_remove_current_locker">无法移除当前上锁人</string>
     <string name="fingerprint_delete_selected_confirm_tip">确定要删除选中的指纹吗?</string>
     <string name="doing_checking">正在验证......</string>
+    <string name="please_select_colocker">请选择共锁人</string>
 </resources>