|
@@ -0,0 +1,325 @@
|
|
|
|
|
+package com.grkj.iscs.utils.fingerprint
|
|
|
|
|
+
|
|
|
|
|
+import android.Manifest
|
|
|
|
|
+import android.content.Context
|
|
|
|
|
+import android.graphics.Bitmap
|
|
|
|
|
+import android.hardware.usb.UsbDevice
|
|
|
|
|
+import android.hardware.usb.UsbManager
|
|
|
|
|
+import android.util.Base64
|
|
|
|
|
+import android.util.Log
|
|
|
|
|
+import androidx.appcompat.app.AppCompatActivity.USB_SERVICE
|
|
|
|
|
+import com.sik.sikandroid.permission.PermissionUtils
|
|
|
|
|
+import com.sik.sikcore.SIKCore
|
|
|
|
|
+import com.sik.sikcore.activity.ActivityTracker
|
|
|
|
|
+import com.sik.sikcore.thread.ThreadUtils
|
|
|
|
|
+import com.zkteco.android.biometric.FingerprintExceptionListener
|
|
|
|
|
+import com.zkteco.android.biometric.core.device.ParameterHelper
|
|
|
|
|
+import com.zkteco.android.biometric.core.device.TransportType
|
|
|
|
|
+import com.zkteco.android.biometric.core.utils.LogHelper
|
|
|
|
|
+import com.zkteco.android.biometric.core.utils.ToolUtils
|
|
|
|
|
+import com.zkteco.android.biometric.module.fingerprintreader.FingerprintCaptureListener
|
|
|
|
|
+import com.zkteco.android.biometric.module.fingerprintreader.FingerprintSensor
|
|
|
|
|
+import com.zkteco.android.biometric.module.fingerprintreader.FingprintFactory
|
|
|
|
|
+import com.zkteco.android.biometric.module.fingerprintreader.ZKFingerService
|
|
|
|
|
+import com.zkteco.android.biometric.module.fingerprintreader.exception.FingerprintException
|
|
|
|
|
+import org.slf4j.Logger
|
|
|
|
|
+import org.slf4j.LoggerFactory
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 指纹工具
|
|
|
|
|
+ */
|
|
|
|
|
+object FingerprintUtil {
|
|
|
|
|
+ private val logger: Logger = LoggerFactory.getLogger(FingerprintUtil::class.java)
|
|
|
|
|
+ private const val REQUEST_PERMISSION_CODE = 9
|
|
|
|
|
+ private const val ZKTECO_VID: Int = 0x1b55
|
|
|
|
|
+ private const val LIVE20R_PID: Int = 0x0120
|
|
|
|
|
+ private const val LIVE10R_PID: Int = 0x0124
|
|
|
|
|
+ private const val ENROLL_COUNT: Int = 3
|
|
|
|
|
+
|
|
|
|
|
+ private var bStarted = false
|
|
|
|
|
+ private var usb_pid = 0
|
|
|
|
|
+ private var zkusbManager: ZKUSBManager? = null
|
|
|
|
|
+ private val usb_vid: Int = ZKTECO_VID
|
|
|
|
|
+ private var fingerprintSensor: FingerprintSensor? = null
|
|
|
|
|
+ private var bRegister = false
|
|
|
|
|
+ private var enroll_index = 0
|
|
|
|
|
+ private var isReseted = false
|
|
|
|
|
+ private val deviceIndex = 0
|
|
|
|
|
+ private val regtemparray = Array(3) {
|
|
|
|
|
+ ByteArray(
|
|
|
|
|
+ 2048
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private var strUid: String? = null
|
|
|
|
|
+
|
|
|
|
|
+ private var onScanListener: OnScanListener? = null
|
|
|
|
|
+
|
|
|
|
|
+ fun setScanListener(listener: OnScanListener) {
|
|
|
|
|
+ onScanListener = listener
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun init(ctx: Context) {
|
|
|
|
|
+ zkusbManager ?: let {
|
|
|
|
|
+ zkusbManager = ZKUSBManager(ctx, zkusbManagerListener)
|
|
|
|
|
+ }
|
|
|
|
|
+ zkusbManager?.registerUSBPermissionReceiver()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun unInit() {
|
|
|
|
|
+ if (bStarted) {
|
|
|
|
|
+ closeDevice()
|
|
|
|
|
+ }
|
|
|
|
|
+ zkusbManager?.unRegisterUSBPermissionReceiver()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun start() {
|
|
|
|
|
+ if (bStarted) {
|
|
|
|
|
+ logger.info("Device already connected!")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!enumSensor()) {
|
|
|
|
|
+ logger.info("Device not found!")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ tryGetUSBPermission()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun stop() {
|
|
|
|
|
+ if (!bStarted) {
|
|
|
|
|
+ logger.info("Device not connected!")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ closeDevice()
|
|
|
|
|
+ logger.info("Device closed!")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun afterGetUsbPermission() {
|
|
|
|
|
+ openDevice()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun tryGetUSBPermission() {
|
|
|
|
|
+ zkusbManager?.initUSBPermission(usb_vid, usb_pid)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ private val fingerprintCaptureListener: FingerprintCaptureListener =
|
|
|
|
|
+ object : FingerprintCaptureListener {
|
|
|
|
|
+ override fun captureOK(fpImage: ByteArray?) {
|
|
|
|
|
+ val bitmap: Bitmap = ToolUtils.renderCroppedGreyScaleBitmap(
|
|
|
|
|
+ fpImage,
|
|
|
|
|
+ fingerprintSensor?.getImageWidth()!!,
|
|
|
|
|
+ fingerprintSensor?.getImageHeight()!!
|
|
|
|
|
+ )
|
|
|
|
|
+ ThreadUtils.runOnMain {
|
|
|
|
|
+ onScanListener?.onScan(bitmap)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun captureError(e: FingerprintException?) {
|
|
|
|
|
+ // nothing to do
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun extractOK(fpTemplate: ByteArray?) {
|
|
|
|
|
+ if (bRegister) {
|
|
|
|
|
+ doRegister(fpTemplate)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ doIdentify(fpTemplate)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun extractError(i: Int) {
|
|
|
|
|
+ // nothing to do
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private val fingerprintExceptionListener: FingerprintExceptionListener =
|
|
|
|
|
+ object : FingerprintExceptionListener {
|
|
|
|
|
+ override fun onDeviceException() {
|
|
|
|
|
+ logger.error("usb exception!!!")
|
|
|
|
|
+ if (!isReseted) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ fingerprintSensor?.openAndReboot(deviceIndex)
|
|
|
|
|
+ } catch (e: FingerprintException) {
|
|
|
|
|
+ e.printStackTrace()
|
|
|
|
|
+ }
|
|
|
|
|
+ isReseted = true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private val zkusbManagerListener: ZKUSBManagerListener = object : ZKUSBManagerListener {
|
|
|
|
|
+ override fun onCheckPermission(result: Int) {
|
|
|
|
|
+ afterGetUsbPermission()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun onUSBArrived(device: UsbDevice?) {
|
|
|
|
|
+ if (bStarted) {
|
|
|
|
|
+ closeDevice()
|
|
|
|
|
+ tryGetUSBPermission()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun onUSBRemoved(device: UsbDevice?) {
|
|
|
|
|
+ logger.debug("usb removed!")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun openDevice() {
|
|
|
|
|
+ createFingerprintSensor()
|
|
|
|
|
+ bRegister = false
|
|
|
|
|
+ enroll_index = 0
|
|
|
|
|
+ isReseted = false
|
|
|
|
|
+ try {
|
|
|
|
|
+ fingerprintSensor?.open(deviceIndex)
|
|
|
|
|
+ run {
|
|
|
|
|
+ // device parameter
|
|
|
|
|
+ logger.debug("sdk version" + fingerprintSensor?.getSDK_Version())
|
|
|
|
|
+ logger.debug("firmware version" + fingerprintSensor?.getFirmwareVersion())
|
|
|
|
|
+ logger.debug("serial:" + fingerprintSensor?.getStrSerialNumber())
|
|
|
|
|
+ logger.debug("width=" + fingerprintSensor?.getImageWidth() + ", height=" + fingerprintSensor?.getImageHeight())
|
|
|
|
|
+ }
|
|
|
|
|
+ fingerprintSensor?.setFingerprintCaptureListener(
|
|
|
|
|
+ deviceIndex,
|
|
|
|
|
+ fingerprintCaptureListener
|
|
|
|
|
+ )
|
|
|
|
|
+ fingerprintSensor?.SetFingerprintExceptionListener(fingerprintExceptionListener)
|
|
|
|
|
+ fingerprintSensor?.startCapture(deviceIndex)
|
|
|
|
|
+ bStarted = true
|
|
|
|
|
+ logger.info("connect success!")
|
|
|
|
|
+ } catch (e: FingerprintException) {
|
|
|
|
|
+ e.printStackTrace()
|
|
|
|
|
+ // try to reboot the sensor
|
|
|
|
|
+ try {
|
|
|
|
|
+ fingerprintSensor?.openAndReboot(deviceIndex)
|
|
|
|
|
+ } catch (ex: FingerprintException) {
|
|
|
|
|
+ ex.printStackTrace()
|
|
|
|
|
+ }
|
|
|
|
|
+ logger.info("connect failed!")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun closeDevice() {
|
|
|
|
|
+ if (bStarted) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ fingerprintSensor?.stopCapture(deviceIndex)
|
|
|
|
|
+ fingerprintSensor?.close(deviceIndex)
|
|
|
|
|
+ } catch (e: FingerprintException) {
|
|
|
|
|
+ e.printStackTrace()
|
|
|
|
|
+ }
|
|
|
|
|
+ bStarted = false
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun enumSensor(): Boolean {
|
|
|
|
|
+ val usbManager = SIKCore.getApplication().getSystemService(USB_SERVICE) as UsbManager
|
|
|
|
|
+ for (device in usbManager.deviceList.values) {
|
|
|
|
|
+ val device_vid = device.vendorId
|
|
|
|
|
+ val device_pid = device.productId
|
|
|
|
|
+ if (device_vid == ZKTECO_VID && (device_pid == LIVE20R_PID || device_pid == LIVE10R_PID)) {
|
|
|
|
|
+ usb_pid = device_pid
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun createFingerprintSensor() {
|
|
|
|
|
+ if (null != fingerprintSensor) {
|
|
|
|
|
+ FingprintFactory.destroy(fingerprintSensor)
|
|
|
|
|
+ fingerprintSensor = null
|
|
|
|
|
+ }
|
|
|
|
|
+ // Define output log level
|
|
|
|
|
+ LogHelper.setLevel(Log.VERBOSE)
|
|
|
|
|
+ LogHelper.setNDKLogLevel(Log.ASSERT)
|
|
|
|
|
+ // Start fingerprint sensor
|
|
|
|
|
+ val deviceParams = HashMap<String?, Any?>()
|
|
|
|
|
+ //set vid
|
|
|
|
|
+ deviceParams[ParameterHelper.PARAM_KEY_VID] = usb_vid
|
|
|
|
|
+ //set pid
|
|
|
|
|
+ deviceParams[ParameterHelper.PARAM_KEY_PID] = usb_pid
|
|
|
|
|
+ fingerprintSensor = FingprintFactory.createFingerprintSensor(
|
|
|
|
|
+ SIKCore.getApplication(),
|
|
|
|
|
+ TransportType.USB,
|
|
|
|
|
+ deviceParams
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun doRegister(template: ByteArray?) {
|
|
|
|
|
+ val bufids = ByteArray(256)
|
|
|
|
|
+ var ret = ZKFingerService.identify(template, bufids, 70, 1)
|
|
|
|
|
+ if (ret > 0) {
|
|
|
|
|
+ val strRes = String(bufids).split("\t".toRegex()).dropLastWhile { it.isEmpty() }
|
|
|
|
|
+ .toTypedArray()
|
|
|
|
|
+ setResult("the finger already enroll by " + strRes[0] + ",cancel enroll")
|
|
|
|
|
+ bRegister = false
|
|
|
|
|
+ enroll_index = 0
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (enroll_index > 0 && (ZKFingerService.verify(
|
|
|
|
|
+ regtemparray.get(enroll_index - 1),
|
|
|
|
|
+ template
|
|
|
|
|
+ ).also {
|
|
|
|
|
+ ret = it
|
|
|
|
|
+ }) <= 0
|
|
|
|
|
+ ) {
|
|
|
|
|
+ setResult("please press the same finger 3 times for the enrollment, cancel enroll, socre=$ret")
|
|
|
|
|
+ bRegister = false
|
|
|
|
|
+ enroll_index = 0
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ System.arraycopy(template, 0, regtemparray.get(enroll_index), 0, 2048)
|
|
|
|
|
+ enroll_index++
|
|
|
|
|
+ if (enroll_index == ENROLL_COUNT) {
|
|
|
|
|
+ bRegister = false
|
|
|
|
|
+ enroll_index = 0
|
|
|
|
|
+ val regTemp = ByteArray(2048)
|
|
|
|
|
+ if (0 < (ZKFingerService.merge(
|
|
|
|
|
+ regtemparray.get(0),
|
|
|
|
|
+ regtemparray.get(1),
|
|
|
|
|
+ regtemparray.get(2),
|
|
|
|
|
+ regTemp
|
|
|
|
|
+ ).also {
|
|
|
|
|
+ ret = it
|
|
|
|
|
+ })
|
|
|
|
|
+ ) {
|
|
|
|
|
+ var retVal = 0
|
|
|
|
|
+ retVal = ZKFingerService.save(regTemp, strUid)
|
|
|
|
|
+ if (0 == retVal) {
|
|
|
|
|
+ val strFeature = Base64.encodeToString(regTemp, 0, ret, Base64.NO_WRAP)
|
|
|
|
|
+// dbManager.insertUser(strUid, strFeature)
|
|
|
|
|
+ setResult("enroll succ")
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setResult("enroll fail, add template fail, ret=$retVal")
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setResult("enroll fail")
|
|
|
|
|
+ }
|
|
|
|
|
+ bRegister = false
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setResult("You need to press the " + (3 - enroll_index) + " times fingerprint")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun setResult(result: String) {
|
|
|
|
|
+ logger.info(result)
|
|
|
|
|
+// val mStrText = result
|
|
|
|
|
+// runOnUiThread { mBinding?.txtResult?.setText(mStrText) }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun doIdentify(template: ByteArray?) {
|
|
|
|
|
+ val bufids = ByteArray(256)
|
|
|
|
|
+ val ret = ZKFingerService.identify(template, bufids, 70, 1)
|
|
|
|
|
+ if (ret > 0) {
|
|
|
|
|
+ val strRes = String(bufids).split("\t".toRegex()).dropLastWhile { it.isEmpty() }
|
|
|
|
|
+ .toTypedArray()
|
|
|
|
|
+ setResult("identify succ, userid:" + strRes[0].trim { it <= ' ' } + ", score:" + strRes[1].trim { it <= ' ' })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setResult("identify fail, ret=$ret")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ interface OnScanListener {
|
|
|
|
|
+ fun onScan(bitmap: Bitmap)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|