人脸识别+采集分开处理
This commit is contained in:
@@ -39,6 +39,9 @@ import com.sw.platecabinet.MyApp
|
|||||||
import com.sw.platecabinet.R
|
import com.sw.platecabinet.R
|
||||||
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
|
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
|
||||||
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||||
|
import com.sw.platecabinet.ext.clickWithDebounce
|
||||||
|
import com.sw.platecabinet.ext.gone
|
||||||
|
import com.sw.platecabinet.ext.visible
|
||||||
import com.sw.platecabinet.model.response.EquipmentUserInfo
|
import com.sw.platecabinet.model.response.EquipmentUserInfo
|
||||||
import com.sw.platecabinet.model.response.UserFaceModel
|
import com.sw.platecabinet.model.response.UserFaceModel
|
||||||
import com.sw.platecabinet.utils.BitmapSaver
|
import com.sw.platecabinet.utils.BitmapSaver
|
||||||
@@ -148,7 +151,21 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
soundMap[COLLECT_SUCCESS] = R.raw.collect_success
|
soundMap[COLLECT_SUCCESS] = R.raw.collect_success
|
||||||
soundMap[RECOGNIZE_SUCCESS] = R.raw.recognize_success
|
soundMap[RECOGNIZE_SUCCESS] = R.raw.recognize_success
|
||||||
soundMap[NO_PLATE_REMIND] = R.raw.no_plate_remind
|
soundMap[NO_PLATE_REMIND] = R.raw.no_plate_remind
|
||||||
SoundPoolUtil.getInstance().loadR(this, soundMap);
|
SoundPoolUtil.getInstance().loadR(this, soundMap)
|
||||||
|
|
||||||
|
binding.btnCollect.clickWithDebounce {
|
||||||
|
//先重置,后采集
|
||||||
|
resetRecognizeState()
|
||||||
|
//采集数据按钮
|
||||||
|
retryFailCount = 0
|
||||||
|
isCollectFace = true
|
||||||
|
collectFace()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnRetry.clickWithDebounce {
|
||||||
|
//重新识别按钮
|
||||||
|
resetRecognizeState()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -187,6 +204,17 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
private val regDebouncer = Debouncer(3000)
|
private val regDebouncer = Debouncer(3000)
|
||||||
private var registerHandler: RegisterCallbackHandler? = null
|
private var registerHandler: RegisterCallbackHandler? = null
|
||||||
|
|
||||||
|
private fun isFitData(userFaceInfo: UserFaceInfo?): Boolean {
|
||||||
|
if (userFaceInfo == null) return false
|
||||||
|
val headBmp = userFaceInfo.headBmp
|
||||||
|
if (headBmp == null) return false
|
||||||
|
if (headBmp.width <= 200 || headBmp.height <= 200) {
|
||||||
|
loadLogInfo("collectFace,isFitData:拿到人脸提取特征数据照片过小-----------")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private fun initArcViewModel() {
|
private fun initArcViewModel() {
|
||||||
recognizeViewModel.setLiveType(livenessType)
|
recognizeViewModel.setLiveType(livenessType)
|
||||||
recognizeViewModel.prepareRegister()
|
recognizeViewModel.prepareRegister()
|
||||||
@@ -195,14 +223,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
if (!isCollectFace) {
|
if (!isCollectFace) {
|
||||||
return@setCallback
|
return@setCallback
|
||||||
}
|
}
|
||||||
if (this.userFaceInfo == null && userFaceInfo != null) {
|
if (this.userFaceInfo == null && isFitData(userFaceInfo)) {
|
||||||
recognizeViewModel.updateRegisterStatus(RecognizeViewModel.REGISTER_STATUS_DONE)
|
recognizeViewModel.updateRegisterStatus(RecognizeViewModel.REGISTER_STATUS_DONE)
|
||||||
this.userFaceInfo = userFaceInfo
|
this.userFaceInfo = userFaceInfo
|
||||||
getFaceDataBlock { faceData, headBmp ->
|
getFaceDataBlock()
|
||||||
isCollecting.set(false)
|
|
||||||
isCollectFace = false
|
|
||||||
sendFaceData(faceData, headBmp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,11 +271,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
|
|
||||||
recognizeViewModel.recognizeUserId.observe(this, Observer { result: CompareResult? ->
|
recognizeViewModel.recognizeUserId.observe(this, Observer { result: CompareResult? ->
|
||||||
loadLogInfo("collectFace,recognizeUserId observe userId = ${result?.faceEntity?.userName}")
|
loadLogInfo("collectFace,recognizeUserId observe userId = ${result?.faceEntity?.userName}")
|
||||||
if (faceUseSwitch) {
|
loadFaceRecognizeResult3(result)
|
||||||
loadFaceRecognizeResult2(result)
|
|
||||||
return@Observer
|
|
||||||
}
|
|
||||||
loadFaceRecognizeResult(result)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
recognizeViewModel.drawRectInfoText.observe(this, Observer { info ->
|
recognizeViewModel.drawRectInfoText.observe(this, Observer { info ->
|
||||||
@@ -288,6 +308,81 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
private val openPlateDebouncer = Debouncer(5000)
|
private val openPlateDebouncer = Debouncer(5000)
|
||||||
private val isCollecting = AtomicBoolean(false)
|
private val isCollecting = AtomicBoolean(false)
|
||||||
|
|
||||||
|
private fun loadFaceRecognizeResult3(result: CompareResult?) {
|
||||||
|
val similar = result?.similar ?: return
|
||||||
|
|
||||||
|
binding.tvSimilarValue.text = "$similar,${retryFailCount}次"
|
||||||
|
loadLogInfo(
|
||||||
|
"collectFace,recognizeUserId 阈值 success=$faceSuccessThreshold, " +
|
||||||
|
"fail=$faceFailThreshold, similar=$similar, retry=$retryFailCount"
|
||||||
|
)
|
||||||
|
if (similar >= faceSuccessThreshold) {
|
||||||
|
val userId = result.faceEntity?.userName
|
||||||
|
if (userId.isNullOrBlank()) {
|
||||||
|
loadLogInfo("collectFace,recognizeUserId 识别成功但 userId 为空,忽略")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loadLogInfo(
|
||||||
|
"collectFace,recognizeUserId 识别成功 userId=$userId, time=${DateTimeUtils.getDateTimeString()}"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 成功后必须重置状态
|
||||||
|
retryFailCount = 0
|
||||||
|
isCollecting.set(false)
|
||||||
|
isCollectFace = false
|
||||||
|
currentUserId = userId
|
||||||
|
|
||||||
|
// 防抖,防止重复开闸
|
||||||
|
openPlateDebouncer.debounce {
|
||||||
|
openPlate(userId)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCollectFace) {
|
||||||
|
loadLogInfo("collectFace,recognizeUserId 正在采集中,忽略失败结果 similar=$similar")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (similar <= faceFailThreshold || retryFailCount >= maxFailCount) {
|
||||||
|
if (retryFailCount >= maxFailCount) {
|
||||||
|
loadLogInfo(
|
||||||
|
"collectFace,recognizeUserId 识别失败,开始采集 similar=$similar, " +
|
||||||
|
"retry=$retryFailCount, time=${DateTimeUtils.getDateTimeString()}"
|
||||||
|
)
|
||||||
|
if (!isCollecting.compareAndSet(false, true)) {
|
||||||
|
loadLogInfo("collectFace 已在采集中,忽略重复触发")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
recognizeFail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
retryFailCount++
|
||||||
|
loadLogInfo("collectFace,recognizeUserId 中间态重试,retryFailCount=$retryFailCount")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recognizeFail() {
|
||||||
|
countDownTimer?.cancel()
|
||||||
|
binding.tvToInit.text = ""
|
||||||
|
binding.tvSimilarValue.text = ""
|
||||||
|
binding.llCollectButton.visible()
|
||||||
|
binding.btnCollect.run {
|
||||||
|
visible()
|
||||||
|
if (tag == "1") {
|
||||||
|
binding.btnRetry.gone()
|
||||||
|
text = "重新采集"
|
||||||
|
tag = "1"
|
||||||
|
} else {
|
||||||
|
binding.btnRetry.visible()
|
||||||
|
"新用户采集"
|
||||||
|
tag = "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据相似度similar>设定阈值0.8作为识别成功判断,
|
* 根据相似度similar>设定阈值0.8作为识别成功判断,
|
||||||
* 如果similar<0.3作为识别失败判断,
|
* 如果similar<0.3作为识别失败判断,
|
||||||
@@ -352,38 +447,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
loadLogInfo("collectFace,recognizeUserId 中间态重试,retryFailCount=$retryFailCount")
|
loadLogInfo("collectFace,recognizeUserId 中间态重试,retryFailCount=$retryFailCount")
|
||||||
}
|
}
|
||||||
|
|
||||||
// private fun loadFaceRecognizeResult2(result: CompareResult?) {
|
|
||||||
//
|
|
||||||
// if(isCollectFace){
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val similar = result?.similar ?: 0f
|
|
||||||
// binding.tvSimilarValue.text = "$similar,${retryFailCount}次"
|
|
||||||
// loadLogInfo("collectFace,recognizeUserId 人脸识别配置阈值为:${faceSuccessThreshold},失败阈值为:${faceFailThreshold},相似度为:${similar},失败次数为:${retryFailCount}")
|
|
||||||
// if (similar > faceSuccessThreshold) {
|
|
||||||
// loadLogInfo("collectFace,recognizeUserId 相似度为:${similar},识别成功时间:${DateTimeUtils.getDateTimeString()}")
|
|
||||||
// //大 于识别阈值,作为识别成功判断
|
|
||||||
// currentUserId = result?.faceEntity?.userName
|
|
||||||
// Debouncer(5000).debounce { openPlate(currentUserId) }
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// loadLogInfo("collectFace,recognizeUserId 人脸识别相似度为:${similar},失败次数为:${retryFailCount}")
|
|
||||||
// if (similar < faceFailThreshold || retryFailCount >= maxFailCount) {
|
|
||||||
// //相似度低于识别错误阈值进行采集、识别失败次数大于等于最大失败次数,作为识别失败判断
|
|
||||||
// if (isCollectFace.not()) {
|
|
||||||
// //非采集中
|
|
||||||
// loadLogInfo("collectFace,recognizeUserId 未识别到人脸信息,相似度为:${similar},开始采集时间:${DateTimeUtils.getDateTimeString()}")
|
|
||||||
// isCollectFace = true
|
|
||||||
// collectFace()
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// //满足similar >= faceFailThreshold && similar <= successThreshold时进行重试
|
|
||||||
// retryFailCount++
|
|
||||||
// loadLogInfo("collectFace,recognizeUserId 人脸识别失败次数为:${retryFailCount}")
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据相似度similar>设定阈值0.8作为识别是否成功来加载人脸识别结果
|
* 根据相似度similar>设定阈值0.8作为识别是否成功来加载人脸识别结果
|
||||||
*/
|
*/
|
||||||
@@ -449,6 +512,9 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
Debouncer(5000).debounce {
|
Debouncer(5000).debounce {
|
||||||
//打开柜子
|
//打开柜子
|
||||||
PlateUtils.open(this, item.equipmentBoxCode, false)
|
PlateUtils.open(this, item.equipmentBoxCode, false)
|
||||||
|
|
||||||
|
countDownTimer?.cancel()
|
||||||
|
goInitActivity()
|
||||||
}
|
}
|
||||||
currentPlateInfo = item
|
currentPlateInfo = item
|
||||||
MyApp.plateList = items
|
MyApp.plateList = items
|
||||||
@@ -600,6 +666,9 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
currentPlateInfo = null
|
currentPlateInfo = null
|
||||||
currentUserId = null
|
currentUserId = null
|
||||||
userFaceInfo = null
|
userFaceInfo = null
|
||||||
|
binding.btnCollect.tag = ""
|
||||||
|
binding.tvSimilarValue.text = ""
|
||||||
|
retryFailCount = 0
|
||||||
}
|
}
|
||||||
recognizeViewModel.clearLeftFace(facePreviewInfoList)
|
recognizeViewModel.clearLeftFace(facePreviewInfoList)
|
||||||
}
|
}
|
||||||
@@ -680,13 +749,13 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 临时用户id
|
* 临时用户id
|
||||||
*/
|
*/
|
||||||
private var tempUserId: String = ""
|
private var tempUserId: String = ""
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
registerHandler = RegisterCallbackHandler()
|
|
||||||
try {
|
try {
|
||||||
if (isFirstOpen) {
|
if (isFirstOpen) {
|
||||||
goInitActivity()
|
goInitActivity()
|
||||||
@@ -695,26 +764,32 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
}, 1000)
|
}, 1000)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
retryFailCount = 0
|
resetRecognizeState()
|
||||||
binding.tvSimilarValue.text = ""
|
|
||||||
isCollecting.set(false)
|
|
||||||
isCollectFace = false
|
|
||||||
plateEnable = true
|
|
||||||
collectCount = 0
|
|
||||||
tempUserId = "${System.currentTimeMillis()}"
|
|
||||||
resumeCamera()
|
|
||||||
userViewModel.resetUserInfo()
|
|
||||||
countDownTimer?.let {
|
|
||||||
it.cancel()
|
|
||||||
it.start()
|
|
||||||
}
|
|
||||||
// initFaceScheduler()
|
|
||||||
// checkFaceState()
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置识别状态
|
||||||
|
*/
|
||||||
|
private fun resetRecognizeState() {
|
||||||
|
binding.llCollectButton.gone()
|
||||||
|
retryFailCount = 0
|
||||||
|
binding.tvSimilarValue.text = ""
|
||||||
|
isCollecting.set(false)
|
||||||
|
isCollectFace = false
|
||||||
|
plateEnable = true
|
||||||
|
collectCount = 0
|
||||||
|
tempUserId = "${System.currentTimeMillis()}"
|
||||||
|
resumeCamera()
|
||||||
|
registerHandler = RegisterCallbackHandler()
|
||||||
|
countDownTimer?.let {
|
||||||
|
it.cancel()
|
||||||
|
it.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var isFirstOpen = true
|
private var isFirstOpen = true
|
||||||
|
|
||||||
protected override fun onPause() {
|
protected override fun onPause() {
|
||||||
@@ -742,7 +817,11 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
goInitActivity()
|
if (facePreviewInfoList.isNullOrEmpty()) {
|
||||||
|
goInitActivity()
|
||||||
|
} else {
|
||||||
|
recognizeFail()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -813,16 +892,22 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFaceDataBlock(block: (String, Bitmap) -> Unit) {
|
private fun getFaceDataBlock() {
|
||||||
if (userFaceInfo == null || userFaceInfo?.faceFeature?.featureData == null) {
|
if (userFaceInfo?.faceFeature?.featureData == null) {
|
||||||
|
loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据为null-----------")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val faceData: String? = Base64.encode(userFaceInfo?.faceFeature?.featureData)
|
val faceData: String? = Base64.encode(userFaceInfo?.faceFeature?.featureData)
|
||||||
if (faceData.isNullOrBlank()) {
|
if (faceData.isNullOrBlank()) {
|
||||||
|
loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据Base64编码为空")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据时间:${DateTimeUtils.getDateTimeString()}-----------")
|
loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据时间:${DateTimeUtils.getDateTimeString()}-----------")
|
||||||
block(faceData, userFaceInfo!!.headBmp)
|
val headBmp = userFaceInfo!!.headBmp
|
||||||
|
//block(faceData, headBmp)
|
||||||
|
isCollecting.set(false)
|
||||||
|
isCollectFace = false
|
||||||
|
sendFaceData(faceData, headBmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,946 @@
|
|||||||
|
//package com.sw.platecabinet.activity
|
||||||
|
//
|
||||||
|
//import android.Manifest
|
||||||
|
//import android.content.Intent
|
||||||
|
//import android.graphics.Bitmap
|
||||||
|
//import android.graphics.Point
|
||||||
|
//import android.hardware.Camera
|
||||||
|
//import android.os.Build
|
||||||
|
//import android.os.CountDownTimer
|
||||||
|
//import android.util.DisplayMetrics
|
||||||
|
//import android.view.View
|
||||||
|
//import android.view.ViewGroup
|
||||||
|
//import android.view.ViewTreeObserver
|
||||||
|
//import androidx.annotation.RequiresApi
|
||||||
|
//import androidx.lifecycle.Observer
|
||||||
|
//import com.arcsoft.face.ErrorInfo
|
||||||
|
//import com.google.gson.Gson
|
||||||
|
//import com.sw.inbound.utils.DateTimeUtils
|
||||||
|
//import com.sw.plate.utils.Base64
|
||||||
|
//import com.sw.plate.utils.ToastUtils
|
||||||
|
//import com.sw.plate.utils.arcface.ConfigUtil
|
||||||
|
//import com.sw.plate.utils.arcface.ErrorCodeUtil
|
||||||
|
//import com.sw.plate.utils.arcface.FaceRectTransformer
|
||||||
|
//import com.sw.plate.utils.arcface.FaceRectView
|
||||||
|
//import com.sw.plate.utils.arcface.FaceRectView.DrawInfo
|
||||||
|
//import com.sw.plate.utils.arcface.PreviewConfig
|
||||||
|
//import com.sw.plate.utils.arcface.camera.CameraListener
|
||||||
|
//import com.sw.plate.utils.arcface.camera.DualCameraHelper
|
||||||
|
//import com.sw.plate.utils.arcface.face.constants.LivenessType
|
||||||
|
//import com.sw.plate.utils.arcface.face.model.CompareResult
|
||||||
|
//import com.sw.plate.utils.arcface.face.model.FacePreviewInfo
|
||||||
|
//import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration
|
||||||
|
//import com.sw.plate.utils.arcface.facedb.FaceDatabase
|
||||||
|
//import com.sw.plate.utils.arcface.facedb.entity.FaceEntity
|
||||||
|
//import com.sw.plate.utils.arcface.model.UserFaceInfo
|
||||||
|
//import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
|
||||||
|
//import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel.REGISTER_STATUS_READY
|
||||||
|
//import com.sw.platecabinet.MyApp
|
||||||
|
//import com.sw.platecabinet.R
|
||||||
|
//import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
|
||||||
|
//import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||||
|
//import com.sw.platecabinet.model.response.EquipmentUserInfo
|
||||||
|
//import com.sw.platecabinet.model.response.UserFaceModel
|
||||||
|
//import com.sw.platecabinet.utils.BitmapSaver
|
||||||
|
//import com.sw.platecabinet.utils.Debouncer
|
||||||
|
//import com.sw.platecabinet.utils.LogFileUtil
|
||||||
|
//import com.sw.platecabinet.utils.PermissionHelper
|
||||||
|
//import com.sw.platecabinet.utils.PlateUtils
|
||||||
|
//import com.sw.platecabinet.utils.RegisterCallbackHandler
|
||||||
|
//import com.sw.platecabinet.utils.SoundPoolUtil
|
||||||
|
//import com.sw.platecabinet.utils.SpTool
|
||||||
|
//import org.greenrobot.eventbus.EventBus
|
||||||
|
//import org.greenrobot.eventbus.Subscribe
|
||||||
|
//import org.greenrobot.eventbus.ThreadMode
|
||||||
|
//import timber.log.Timber
|
||||||
|
//import java.io.File
|
||||||
|
//import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * 人脸识别
|
||||||
|
// */
|
||||||
|
//class LoginByFaceActivityBak : BaseActivity<ActivityLoginFaceBinding>(),
|
||||||
|
// ViewTreeObserver.OnGlobalLayoutListener {
|
||||||
|
// // private val recognizeViewModel by viewModels<RecognizeViewModel>()
|
||||||
|
// private var countDownTimer: CountDownTimer? = null
|
||||||
|
//
|
||||||
|
// private val CAMERA_PERMISSION_REQUEST_CODE = 100
|
||||||
|
// private val REQUIRED_PERMISSIONS: Array<String> = arrayOf(
|
||||||
|
// Manifest.permission.CAMERA,
|
||||||
|
// Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
|
// Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// override fun inflateViewBinding(): ActivityLoginFaceBinding {
|
||||||
|
// return ActivityLoginFaceBinding.inflate(layoutInflater)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun inflateTitleBinding(): ItemTitleTimeBinding {
|
||||||
|
// return binding.includeHeader
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// companion object {
|
||||||
|
// private const val TAG = "LoginByFaceActivity"
|
||||||
|
// private var instance: LoginByFaceActivityBak? = null
|
||||||
|
//
|
||||||
|
// private const val COLLECT_SUCCESS = "collect_success"
|
||||||
|
// private const val RECOGNIZE_SUCCESS = "recognize_success"
|
||||||
|
// private const val NO_PLATE_REMIND = "no_plate_remind";
|
||||||
|
//
|
||||||
|
// fun goInitActivity() {
|
||||||
|
// instance?.goInitActivity()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//// private var logList: MutableList<String> = mutableListOf()
|
||||||
|
//// private val logAdapter by lazy { LogAdapter(logList) }
|
||||||
|
//
|
||||||
|
// override fun initialize() {
|
||||||
|
// instance = this
|
||||||
|
// userViewModel.activeEngine()
|
||||||
|
//// addSocketListener()
|
||||||
|
// initCountTime()
|
||||||
|
// initArcViewModel()
|
||||||
|
// initArcView()
|
||||||
|
// openRectInfoDraw = true
|
||||||
|
// recognizeViewModel.setDrawRectInfoTextValue(true)
|
||||||
|
// //viewModel.generateToken()
|
||||||
|
//
|
||||||
|
//// binding.llToPwd.setOnClickListener {
|
||||||
|
//// val intent = Intent(this, LoginByPwdActivity::class.java)
|
||||||
|
//// startActivity(intent)
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
//// TaskManager.startTask()
|
||||||
|
//
|
||||||
|
// EventBus.getDefault().register(this)
|
||||||
|
//
|
||||||
|
//// binding.btnCollectFace.setOnClickListener { collectFace() }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//// binding.rvLogInfo.let {
|
||||||
|
//// it.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true)
|
||||||
|
//// it.adapter = logAdapter
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// binding.btnLogState.let {
|
||||||
|
//// it.tag = false
|
||||||
|
//// it.setImageResource(R.drawable.ic_log_show)
|
||||||
|
//// it.setOnClickListener { v ->
|
||||||
|
//// binding.rvLogInfo.run {
|
||||||
|
//// val state = it.tag.toString().toBooleanStrictOrNull() ?: false
|
||||||
|
//// if (state) visible() else gone()
|
||||||
|
//// }
|
||||||
|
//// val state = it.tag.toString().toBooleanStrictOrNull() ?: false
|
||||||
|
//// it.tag = state
|
||||||
|
//// it.setImageResource(
|
||||||
|
//// if (state) R.drawable.ic_log_hide else R.drawable.ic_log_show
|
||||||
|
//// )
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
// //开启人脸增量数据定时任务
|
||||||
|
// startFaceTask {
|
||||||
|
// loadLogInfo("collectFace增量接口数据用户id:${Gson().toJson(it)}")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// val soundMap = hashMapOf<String, Int>()
|
||||||
|
// soundMap[COLLECT_SUCCESS] = R.raw.collect_success
|
||||||
|
// soundMap[RECOGNIZE_SUCCESS] = R.raw.recognize_success
|
||||||
|
// soundMap[NO_PLATE_REMIND] = R.raw.no_plate_remind
|
||||||
|
// SoundPoolUtil.getInstance().loadR(this, soundMap);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private fun checkCameraPermission() {
|
||||||
|
// Timber.i("checkCameraPermission")
|
||||||
|
// val permissionHelper =
|
||||||
|
// PermissionHelper.with(this, REQUIRED_PERMISSIONS, CAMERA_PERMISSION_REQUEST_CODE)
|
||||||
|
// .onGranted {
|
||||||
|
// loadLogInfo("checkCameraPermission 权限已允许")
|
||||||
|
// // 权限已授予
|
||||||
|
// recognizeViewModel.init()
|
||||||
|
// initRgbCamera()
|
||||||
|
// resumeCamera()
|
||||||
|
// }
|
||||||
|
// .build()
|
||||||
|
// registerPermissionHelper(permissionHelper)
|
||||||
|
// permissionHelper.checkAndRequest()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
// fun getFaceEntity(insertEntity: FaceEntity) {
|
||||||
|
// Timber.tag("performSync").e("-time=%s", insertEntity.registerTime)
|
||||||
|
// recognizeViewModel.addFace(insertEntity)
|
||||||
|
// Timber.tag("performSync over").e("-time=%s", insertEntity.registerTime)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onLeftDoubleClick() {
|
||||||
|
// finish()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private var isRecognition = false
|
||||||
|
// private var rgbCameraHelper: DualCameraHelper? = null
|
||||||
|
// private var rgbFaceRectTransformer: FaceRectTransformer? = null
|
||||||
|
// private val livenessType = LivenessType.RGB
|
||||||
|
// private var openRectInfoDraw = false
|
||||||
|
// private val regDebouncer = Debouncer(3000)
|
||||||
|
// private var registerHandler: RegisterCallbackHandler? = null
|
||||||
|
//
|
||||||
|
// private fun initArcViewModel() {
|
||||||
|
// recognizeViewModel.setLiveType(livenessType)
|
||||||
|
// recognizeViewModel.prepareRegister()
|
||||||
|
// recognizeViewModel.setOnRegisterFinishedCallback { facePreviewInfo, userFaceInfo ->
|
||||||
|
// registerHandler?.setCallback {
|
||||||
|
// if (!isCollectFace) {
|
||||||
|
// return@setCallback
|
||||||
|
// }
|
||||||
|
// if (this.userFaceInfo == null && userFaceInfo != null) {
|
||||||
|
// recognizeViewModel.updateRegisterStatus(RecognizeViewModel.REGISTER_STATUS_DONE)
|
||||||
|
// this.userFaceInfo = userFaceInfo
|
||||||
|
// getFaceDataBlock { faceData, headBmp ->
|
||||||
|
// isCollecting.set(false)
|
||||||
|
// isCollectFace = false
|
||||||
|
// sendFaceData(faceData, headBmp)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// recognizeViewModel.ftInitCode.observe(this, Observer { ftInitCode: Int? ->
|
||||||
|
// if (ftInitCode != ErrorInfo.MOK) {
|
||||||
|
// val error: String? = getString(
|
||||||
|
// R.string.specific_engine_init_failed, "ftEngine",
|
||||||
|
// ftInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(ftInitCode!!)
|
||||||
|
// )
|
||||||
|
// Timber.e("ftInitCode observe = $error")
|
||||||
|
// ToastUtils.showToast(error)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// recognizeViewModel.frInitCode.observe(this, Observer { frInitCode: Int? ->
|
||||||
|
// if (frInitCode != ErrorInfo.MOK) {
|
||||||
|
// val error: String? = getString(
|
||||||
|
// R.string.specific_engine_init_failed, "frEngine",
|
||||||
|
// frInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(frInitCode!!)
|
||||||
|
// )
|
||||||
|
// Timber.e("frInitCode observe = $error")
|
||||||
|
// ToastUtils.showToast(error)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// recognizeViewModel.flInitCode.observe(this, Observer { flInitCode: Int? ->
|
||||||
|
// if (flInitCode != ErrorInfo.MOK) {
|
||||||
|
// val error: String? = getString(
|
||||||
|
// R.string.specific_engine_init_failed, "flEngine",
|
||||||
|
// flInitCode, ErrorCodeUtil.arcFaceErrorCodeToFieldName(flInitCode!!)
|
||||||
|
// )
|
||||||
|
// Timber.e("flInitCode observe = $error")
|
||||||
|
// ToastUtils.showToast(error)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// recognizeViewModel.recognizeConfiguration
|
||||||
|
// .observe(this, Observer { recognizeConfiguration: RecognizeConfiguration? ->
|
||||||
|
// Timber.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
|
||||||
|
// })
|
||||||
|
// recognizeViewModel.recognizeNotice.observe(this, Observer { notice: String? ->
|
||||||
|
// Timber.i("recognizeNotice observe notice = $notice")
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// recognizeViewModel.recognizeUserId.observe(this, Observer { result: CompareResult? ->
|
||||||
|
// loadLogInfo("collectFace,recognizeUserId observe userId = ${result?.faceEntity?.userName}")
|
||||||
|
// if (faceUseSwitch) {
|
||||||
|
// loadFaceRecognizeResult2(result)
|
||||||
|
// return@Observer
|
||||||
|
// }
|
||||||
|
// loadFaceRecognizeResult(result)
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// recognizeViewModel.drawRectInfoText.observe(this, Observer { info ->
|
||||||
|
// Timber.i("drawRectInfoText observe info = $info")
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 人脸识别开关,true-loadFaceRecognizeResult2,false-loadFaceRecognizeResult
|
||||||
|
// */
|
||||||
|
// private var faceUseSwitch = true
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 识别失败重试次数
|
||||||
|
// */
|
||||||
|
// private var retryFailCount = 0
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 识别失败最大次数
|
||||||
|
// */
|
||||||
|
// private val maxFailCount = 5
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 人脸失败阈值
|
||||||
|
// */
|
||||||
|
// private val faceFailThreshold = 0.3
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 配置阈值,默认值为0.8
|
||||||
|
// */
|
||||||
|
// private val faceSuccessThreshold by lazy { ConfigUtil.getRecognizeThreshold(this) }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private val openPlateDebouncer = Debouncer(5000)
|
||||||
|
// private val isCollecting = AtomicBoolean(false)
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 根据相似度similar>设定阈值0.8作为识别成功判断,
|
||||||
|
// * 如果similar<0.3作为识别失败判断,
|
||||||
|
// * 如果similar>=0.3&&similar<=0.8时,暂时不作为失败情况,再识别5次如果similar<0.8则作为识别失败处理
|
||||||
|
// */
|
||||||
|
// private fun loadFaceRecognizeResult2(result: CompareResult?) {
|
||||||
|
// // 无有效结果直接忽略
|
||||||
|
// val similar = result?.similar ?: return
|
||||||
|
//
|
||||||
|
// binding.tvSimilarValue.text = "$similar,${retryFailCount}次"
|
||||||
|
// loadLogInfo(
|
||||||
|
// "collectFace,recognizeUserId 阈值 success=$faceSuccessThreshold, " +
|
||||||
|
// "fail=$faceFailThreshold, similar=$similar, retry=$retryFailCount"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// if (similar >= faceSuccessThreshold) {
|
||||||
|
// val userId = result.faceEntity?.userName
|
||||||
|
// if (userId.isNullOrBlank()) {
|
||||||
|
// loadLogInfo("collectFace,recognizeUserId 识别成功但 userId 为空,忽略")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// loadLogInfo(
|
||||||
|
// "collectFace,recognizeUserId 识别成功 userId=$userId, time=${DateTimeUtils.getDateTimeString()}"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// // 成功后必须重置状态
|
||||||
|
// retryFailCount = 0
|
||||||
|
// isCollecting.set(false)
|
||||||
|
// isCollectFace = false
|
||||||
|
// currentUserId = userId
|
||||||
|
//
|
||||||
|
// // 防抖,防止重复开闸
|
||||||
|
// openPlateDebouncer.debounce {
|
||||||
|
// openPlate(userId)
|
||||||
|
// }
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (isCollectFace) {
|
||||||
|
// loadLogInfo("collectFace,recognizeUserId 正在采集中,忽略失败结果 similar=$similar")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (similar <= faceFailThreshold || retryFailCount >= maxFailCount) {
|
||||||
|
// loadLogInfo(
|
||||||
|
// "collectFace,recognizeUserId 识别失败,开始采集 similar=$similar, " +
|
||||||
|
// "retry=$retryFailCount, time=${DateTimeUtils.getDateTimeString()}"
|
||||||
|
// )
|
||||||
|
// if (!isCollecting.compareAndSet(false, true)) {
|
||||||
|
// loadLogInfo("collectFace 已在采集中,忽略重复触发")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// retryFailCount = 0
|
||||||
|
// isCollectFace = true
|
||||||
|
// collectFace()//采集人脸
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// retryFailCount++
|
||||||
|
// loadLogInfo("collectFace,recognizeUserId 中间态重试,retryFailCount=$retryFailCount")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//// private fun loadFaceRecognizeResult2(result: CompareResult?) {
|
||||||
|
////
|
||||||
|
//// if(isCollectFace){
|
||||||
|
//// return
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// val similar = result?.similar ?: 0f
|
||||||
|
//// binding.tvSimilarValue.text = "$similar,${retryFailCount}次"
|
||||||
|
//// loadLogInfo("collectFace,recognizeUserId 人脸识别配置阈值为:${faceSuccessThreshold},失败阈值为:${faceFailThreshold},相似度为:${similar},失败次数为:${retryFailCount}")
|
||||||
|
//// if (similar > faceSuccessThreshold) {
|
||||||
|
//// loadLogInfo("collectFace,recognizeUserId 相似度为:${similar},识别成功时间:${DateTimeUtils.getDateTimeString()}")
|
||||||
|
//// //大 于识别阈值,作为识别成功判断
|
||||||
|
//// currentUserId = result?.faceEntity?.userName
|
||||||
|
//// Debouncer(5000).debounce { openPlate(currentUserId) }
|
||||||
|
//// return
|
||||||
|
//// }
|
||||||
|
//// loadLogInfo("collectFace,recognizeUserId 人脸识别相似度为:${similar},失败次数为:${retryFailCount}")
|
||||||
|
//// if (similar < faceFailThreshold || retryFailCount >= maxFailCount) {
|
||||||
|
//// //相似度低于识别错误阈值进行采集、识别失败次数大于等于最大失败次数,作为识别失败判断
|
||||||
|
//// if (isCollectFace.not()) {
|
||||||
|
//// //非采集中
|
||||||
|
//// loadLogInfo("collectFace,recognizeUserId 未识别到人脸信息,相似度为:${similar},开始采集时间:${DateTimeUtils.getDateTimeString()}")
|
||||||
|
//// isCollectFace = true
|
||||||
|
//// collectFace()
|
||||||
|
//// return
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// //满足similar >= faceFailThreshold && similar <= successThreshold时进行重试
|
||||||
|
//// retryFailCount++
|
||||||
|
//// loadLogInfo("collectFace,recognizeUserId 人脸识别失败次数为:${retryFailCount}")
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 根据相似度similar>设定阈值0.8作为识别是否成功来加载人脸识别结果
|
||||||
|
// */
|
||||||
|
// private fun loadFaceRecognizeResult(result: CompareResult?) {
|
||||||
|
// val similar = result?.similar ?: 0f
|
||||||
|
// binding.tvSimilarValue.text = "$similar"
|
||||||
|
// val similarPass = result?.isSimilarPass ?: false
|
||||||
|
// if (similarPass.not()) {
|
||||||
|
// loadLogInfo("collectFace,recognizeUserId 未识别到人脸信息,开始采集")
|
||||||
|
// isCollectFace = true
|
||||||
|
// collectFace()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// currentUserId = result?.faceEntity?.userName
|
||||||
|
// if (tempUserId != currentUserId) {
|
||||||
|
// SoundPoolUtil.getInstance().play("success", 0)
|
||||||
|
// }
|
||||||
|
//// plateEnable = true
|
||||||
|
// Debouncer(5000).debounce { openPlate(currentUserId) }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 查询餐盘数据
|
||||||
|
// */
|
||||||
|
// private fun getPlateData(block: (List<EquipmentUserInfo>) -> Unit) {
|
||||||
|
// MyApp.plateList?.let {
|
||||||
|
// block(it)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private var currentPlateInfo: EquipmentUserInfo? = null
|
||||||
|
// private var plateEnable = false
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 打开餐盘柜
|
||||||
|
// */
|
||||||
|
// private fun openPlate(userId: String?) {
|
||||||
|
// if (plateEnable.not()) return
|
||||||
|
// loadLogInfo("collectFace,openPlate: userId=$userId")
|
||||||
|
// getPlateData { items ->
|
||||||
|
// loadLogInfo("collectFace,openPlate: items:${Gson().toJson(items)}")
|
||||||
|
// // 未查询到当前用户,查询第一个未绑定的餐盘
|
||||||
|
// val item = items.firstOrNull { it.plateNumber.isNullOrEmpty().not() }
|
||||||
|
// loadLogInfo("collectFace,openPlate: item2:${item}")
|
||||||
|
// if (item == null) {
|
||||||
|
// //暂无餐盘
|
||||||
|
// loadLogInfo("collectFace,openPlate: 暂无餐盘,请联系管理人员,isCollectFace=$isCollectFace")
|
||||||
|
// //ToastUtils.showToast("暂无餐盘,请联系管理人员")
|
||||||
|
// SoundPoolUtil.getInstance().play(NO_PLATE_REMIND, 0)
|
||||||
|
// goInitActivity()
|
||||||
|
// return@getPlateData
|
||||||
|
// }
|
||||||
|
//// if (tempUserId != currentUserId) {
|
||||||
|
// SoundPoolUtil.getInstance().play(RECOGNIZE_SUCCESS, 0)
|
||||||
|
//// } else {
|
||||||
|
//// SoundPoolUtil.getInstance().play(COLLECT_SUCCESS, 0)
|
||||||
|
//// }
|
||||||
|
// loadLogInfo("collectFace,openPlate: item3:${item}")
|
||||||
|
// item.faceId = userId
|
||||||
|
// item.updateTime = DateTimeUtils.getDateTimeString()
|
||||||
|
// item.plateNumber = null
|
||||||
|
// plateEnable = false
|
||||||
|
// Debouncer(5000).debounce {
|
||||||
|
// //打开柜子
|
||||||
|
// PlateUtils.open(this, item.equipmentBoxCode, false)
|
||||||
|
// }
|
||||||
|
// currentPlateInfo = item
|
||||||
|
// MyApp.plateList = items
|
||||||
|
// SpTool.savePlateData(items)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//// private val debouncer by lazy { Debouncer(3000) }
|
||||||
|
//
|
||||||
|
// private fun initArcView() {
|
||||||
|
// //在布局结束后才做初始化操作
|
||||||
|
// binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this)
|
||||||
|
// recognizeViewModel.getCompareResultList().getValue()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onDestroy() {
|
||||||
|
// loadLogInfo("onDestroy")
|
||||||
|
// instance = null
|
||||||
|
// if (rgbCameraHelper != null) {
|
||||||
|
// rgbCameraHelper!!.release()
|
||||||
|
// rgbCameraHelper = null
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// recognizeViewModel.destroy()
|
||||||
|
//
|
||||||
|
// EventBus.getDefault().unregister(this)
|
||||||
|
// super.onDestroy()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 调整View的宽高,使预览显示正常且采集框固定为380x380
|
||||||
|
// *
|
||||||
|
// * @param rgbPreview RGB预览View
|
||||||
|
// * @param previewView 显示预览数据的view
|
||||||
|
// * @param faceRectView 画框的view (380x380)
|
||||||
|
// * @param previewSize 预览大小
|
||||||
|
// * @param displayOrientation 相机旋转角度
|
||||||
|
// * @param scale 缩放比例
|
||||||
|
// * @return 调整后的LayoutParams
|
||||||
|
// */
|
||||||
|
// private fun adjustPreviewViewSize(
|
||||||
|
// rgbPreview: View,
|
||||||
|
// previewView: View,
|
||||||
|
// faceRectView: FaceRectView,
|
||||||
|
// previewSize: Camera.Size,
|
||||||
|
// displayOrientation: Int,
|
||||||
|
// scale: Float
|
||||||
|
// ): ViewGroup.LayoutParams {
|
||||||
|
// val layoutParams = previewView.layoutParams
|
||||||
|
// val measuredWidth = previewView.measuredWidth
|
||||||
|
// val measuredHeight = previewView.measuredHeight
|
||||||
|
// var ratio = (previewSize.height.toFloat()) / previewSize.width.toFloat()
|
||||||
|
// if (ratio > 1) {
|
||||||
|
// ratio = 1 / ratio
|
||||||
|
// }
|
||||||
|
// if (displayOrientation % 180 == 0) {
|
||||||
|
// layoutParams.width = measuredWidth
|
||||||
|
// layoutParams.height = (measuredWidth * ratio).toInt()
|
||||||
|
// } else {
|
||||||
|
// layoutParams.height = measuredHeight
|
||||||
|
// layoutParams.width = (measuredHeight * ratio).toInt()
|
||||||
|
// }
|
||||||
|
// if (scale < 1f) {
|
||||||
|
// val rgbParam = rgbPreview.getLayoutParams()
|
||||||
|
// layoutParams.width = (rgbParam.width * scale).toInt()
|
||||||
|
// layoutParams.height = (rgbParam.height * scale).toInt()
|
||||||
|
// } else {
|
||||||
|
// layoutParams.width = (layoutParams.width * scale).toInt()
|
||||||
|
// layoutParams.height = (layoutParams.height * scale).toInt()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// val metrics = DisplayMetrics()
|
||||||
|
// windowManager.defaultDisplay.getMetrics(metrics)
|
||||||
|
//
|
||||||
|
// if (layoutParams.width >= metrics.widthPixels) {
|
||||||
|
// val viewRatio = layoutParams.width / (metrics.widthPixels.toFloat())
|
||||||
|
// layoutParams.width = (layoutParams.width / viewRatio).toInt()
|
||||||
|
// layoutParams.height = (layoutParams.height / viewRatio).toInt()
|
||||||
|
// }
|
||||||
|
// if (layoutParams.height >= metrics.heightPixels) {
|
||||||
|
// val viewRatio = layoutParams.height / (metrics.heightPixels.toFloat())
|
||||||
|
// layoutParams.width = (layoutParams.width / viewRatio).toInt()
|
||||||
|
// layoutParams.height = (layoutParams.height / viewRatio).toInt()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// previewView.setLayoutParams(layoutParams)
|
||||||
|
// faceRectView.setLayoutParams(layoutParams)
|
||||||
|
// return layoutParams
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun initRgbCamera() {
|
||||||
|
// val cameraListener: CameraListener = object : CameraListener {
|
||||||
|
// override fun onCameraOpened(
|
||||||
|
// camera: Camera,
|
||||||
|
// cameraId: Int,
|
||||||
|
// displayOrientation: Int,
|
||||||
|
// isMirror: Boolean
|
||||||
|
// ) {
|
||||||
|
// loadLogInfo("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
|
||||||
|
// runOnUiThread({
|
||||||
|
// val previewSizeRgb = camera.getParameters().getPreviewSize()
|
||||||
|
// val layoutParams = adjustPreviewViewSize(
|
||||||
|
// binding.dualCameraTexturePreviewRgb,
|
||||||
|
// binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView,
|
||||||
|
// previewSizeRgb, displayOrientation, 0.6f
|
||||||
|
// )
|
||||||
|
// loadLogInfo("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}")
|
||||||
|
// loadLogInfo("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}")
|
||||||
|
// loadLogInfo(
|
||||||
|
// "initRgbCamera isMirror = ${isMirror}, isDrawRgbRectHorizontalMirror = ${
|
||||||
|
// ConfigUtil.isDrawRgbRectHorizontalMirror(
|
||||||
|
// context
|
||||||
|
// )
|
||||||
|
// }, isDrawRgbRectVerticalMirror = ${
|
||||||
|
// ConfigUtil.isDrawRgbRectVerticalMirror(
|
||||||
|
// context
|
||||||
|
// )
|
||||||
|
// }"
|
||||||
|
// )
|
||||||
|
// rgbFaceRectTransformer = FaceRectTransformer(
|
||||||
|
// previewSizeRgb.width,
|
||||||
|
// previewSizeRgb.height,
|
||||||
|
// layoutParams.width,
|
||||||
|
// layoutParams.height,
|
||||||
|
// 90,
|
||||||
|
// cameraId,
|
||||||
|
// isMirror,
|
||||||
|
// true,
|
||||||
|
// true
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// recognizeViewModel.onRgbCameraOpened(camera)
|
||||||
|
// recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @RequiresApi(api = Build.VERSION_CODES.Q)
|
||||||
|
// override fun onPreview(nv21: ByteArray?, camera: Camera?) {
|
||||||
|
// if (!isRecognition) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// binding.dualCameraFaceRectView.clearFaceInfo()
|
||||||
|
// facePreviewInfoList = recognizeViewModel.onPreviewFrame(nv21, true)
|
||||||
|
// if (facePreviewInfoList != null && rgbFaceRectTransformer != null) {
|
||||||
|
// drawPreviewInfo(facePreviewInfoList)
|
||||||
|
// }
|
||||||
|
// if (facePreviewInfoList.isNullOrEmpty()) {
|
||||||
|
// currentPlateInfo = null
|
||||||
|
// currentUserId = null
|
||||||
|
// userFaceInfo = null
|
||||||
|
// }
|
||||||
|
// recognizeViewModel.clearLeftFace(facePreviewInfoList)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onCameraClosed() {
|
||||||
|
// Timber.i("initRgbCamera onCameraClosed: ")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onCameraError(e: java.lang.Exception) {
|
||||||
|
// Timber.i("initRgbCamera onCameraError: %s", e.message)
|
||||||
|
// e.printStackTrace()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) {
|
||||||
|
// Timber.i("initRgbCamera onCameraConfigurationChanged: threadName = ${Thread.currentThread().name}")
|
||||||
|
// if (rgbFaceRectTransformer != null) {
|
||||||
|
// rgbFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation
|
||||||
|
// }
|
||||||
|
// Timber.i("initRgbCamera onCameraConfigurationChanged: $cameraID $displayOrientation")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// val previewConfig: PreviewConfig = recognizeViewModel.previewConfig
|
||||||
|
// rgbCameraHelper = DualCameraHelper.Builder()
|
||||||
|
// .previewViewSize(
|
||||||
|
// Point(
|
||||||
|
// binding.dualCameraTexturePreviewRgb.measuredWidth,
|
||||||
|
// binding.dualCameraTexturePreviewRgb.measuredHeight
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// .rotation(windowManager.defaultDisplay.rotation)
|
||||||
|
// .additionalRotation(0) // 角度
|
||||||
|
// .previewSize(recognizeViewModel.loadPreviewSize())
|
||||||
|
// .specificCameraId(previewConfig.rgbCameraId)
|
||||||
|
// .isMirror(true)
|
||||||
|
// .previewOn(binding.dualCameraTexturePreviewRgb)
|
||||||
|
// .cameraListener(cameraListener)
|
||||||
|
// .build()
|
||||||
|
// rgbCameraHelper!!.init()
|
||||||
|
// rgbCameraHelper!!.start()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 绘制RGB、IR画面的实时人脸信息
|
||||||
|
// *
|
||||||
|
// * @param facePreviewInfoList RGB画面的实时人脸信息
|
||||||
|
// */
|
||||||
|
// private fun drawPreviewInfo(facePreviewInfoList: MutableList<FacePreviewInfo>?) {
|
||||||
|
// if (rgbFaceRectTransformer != null) {
|
||||||
|
// val rgbDrawInfoList: MutableList<DrawInfo>? = recognizeViewModel.getDrawInfo(
|
||||||
|
// facePreviewInfoList, LivenessType.RGB, openRectInfoDraw
|
||||||
|
// )
|
||||||
|
// // 识别成功
|
||||||
|
// binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun openRectInfoDraw(view: View?) {
|
||||||
|
// openRectInfoDraw = !openRectInfoDraw
|
||||||
|
// recognizeViewModel.setDrawRectInfoTextValue(openRectInfoDraw)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// override fun onGlobalLayout() {
|
||||||
|
// loadLogInfo("onGlobalLayout")
|
||||||
|
// binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this)
|
||||||
|
// // 请求权限
|
||||||
|
// checkCameraPermission()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun resumeCamera() {
|
||||||
|
// isRecognition = true
|
||||||
|
// if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) {
|
||||||
|
// loadLogInfo("collectFace,resumeCamera: ")
|
||||||
|
// rgbCameraHelper!!.start()
|
||||||
|
// } else {
|
||||||
|
// recognizeViewModel.onPreviewFrame(ByteArray(1382400), true)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 临时用户id
|
||||||
|
// */
|
||||||
|
// private var tempUserId: String = ""
|
||||||
|
// override fun onResume() {
|
||||||
|
// super.onResume()
|
||||||
|
// registerHandler = RegisterCallbackHandler()
|
||||||
|
// try {
|
||||||
|
// if (isFirstOpen) {
|
||||||
|
// goInitActivity()
|
||||||
|
// binding.root.postDelayed({
|
||||||
|
// isFirstOpen = false
|
||||||
|
// }, 1000)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// retryFailCount = 0
|
||||||
|
// binding.tvSimilarValue.text = ""
|
||||||
|
// isCollecting.set(false)
|
||||||
|
// isCollectFace = false
|
||||||
|
// plateEnable = true
|
||||||
|
// collectCount = 0
|
||||||
|
// tempUserId = "${System.currentTimeMillis()}"
|
||||||
|
// resumeCamera()
|
||||||
|
// userViewModel.resetUserInfo()
|
||||||
|
// countDownTimer?.let {
|
||||||
|
// it.cancel()
|
||||||
|
// it.start()
|
||||||
|
// }
|
||||||
|
//// initFaceScheduler()
|
||||||
|
//// checkFaceState()
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// e.printStackTrace()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private var isFirstOpen = true
|
||||||
|
//
|
||||||
|
// protected override fun onPause() {
|
||||||
|
// pauseCamera()
|
||||||
|
// super.onPause()
|
||||||
|
// countDownTimer?.cancel()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun pauseCamera() {
|
||||||
|
// isRecognition = false
|
||||||
|
// recognizeViewModel.onPreviewFrame(ByteArray(1382400), true)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
|
||||||
|
// super.handleLoginSuccess(equipmentUserInfo, isAdmin)
|
||||||
|
//// goInitActivity()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private val totalTimeInMillis = 15 * 1000L
|
||||||
|
// fun initCountTime() {
|
||||||
|
// countDownTimer = object : CountDownTimer(totalTimeInMillis, 1000) {
|
||||||
|
// override fun onTick(millisUntilFinished: Long) {
|
||||||
|
// loadLogInfo("initCountTime onTick = ${(millisUntilFinished / 1000).toInt()}")
|
||||||
|
// binding.tvToInit.text = "${(millisUntilFinished / 1000).toInt() + 1}"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onFinish() {
|
||||||
|
// goInitActivity()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// fun goInitActivity() {
|
||||||
|
// val intent = Intent(context, InitActivity::class.java)
|
||||||
|
// startActivity(intent)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 采集人脸
|
||||||
|
// */
|
||||||
|
// private fun collectFace() {
|
||||||
|
// loadLogInfo("collectFace: -----------1,开始采集人脸,开始时间:${DateTimeUtils.getDateTimeString()}----------")
|
||||||
|
// if (isFirstOpen) return
|
||||||
|
// loadLogInfo("collectFace: ----------2,isFirstOpen=false-----------")
|
||||||
|
// loadLogInfo("collectFace: ----------4,检测到人脸信息-----------")
|
||||||
|
// currentUserId = null
|
||||||
|
// userFaceInfo = null
|
||||||
|
// recognizeViewModel.updateRegisterStatus(REGISTER_STATUS_READY)
|
||||||
|
// loadLogInfo("collectFace: ----------5,人脸采集中-----------")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private val uploadFaceDebouncer = Debouncer(10000)
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 改为上传人脸数据,不需要发生人脸数据到收银端
|
||||||
|
// */
|
||||||
|
// private fun sendFaceData(faceData: String, headBmp: Bitmap) {
|
||||||
|
// loadLogInfo("collectFace,sendFaceData: ----------11,发送人脸数据-----------")
|
||||||
|
//
|
||||||
|
// val imageFile = BitmapSaver.saveToAppFilesDir(
|
||||||
|
// headBmp, this, "IMG_CROP_${System.currentTimeMillis()}.jpg"
|
||||||
|
// )
|
||||||
|
// loadLogInfo("collectFace,sendFaceData:${imageFile?.absolutePath}")
|
||||||
|
// if (imageFile == null) {
|
||||||
|
// ToastUtils.showToast("获取人脸照片失败")
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// uploadFaceDebouncer.debounce {
|
||||||
|
// addUserFace(faceData, imageFile)
|
||||||
|
// }
|
||||||
|
//// // 给某个客户端发送
|
||||||
|
//// val jsonObject = JSONObject().also {
|
||||||
|
//// it.put("type", "faceFeature")
|
||||||
|
//// it.put("content", faceData)
|
||||||
|
//// }
|
||||||
|
//// tcpClient?.send(jsonObject)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun addUserFace(faceData: String, imageFile: File) {
|
||||||
|
// settingViewModel.addUserFace(faceData, imageFile) { status, faceModel ->
|
||||||
|
// loadLogInfo("collectFace,saveFaceInfo: ----------12,人脸数据发送完成时间:${DateTimeUtils.getDateTimeString()},结果:$status-----------")
|
||||||
|
// if (status.not()) {
|
||||||
|
// ToastUtils.showToast("新增数据失败")
|
||||||
|
// loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据失败,faceData=${faceData}")
|
||||||
|
// return@addUserFace
|
||||||
|
// }
|
||||||
|
// if (faceModel == null) {
|
||||||
|
// ToastUtils.showToast("新增数据成功,但未拿到接口数据")
|
||||||
|
// loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据成功但接口返回为null,faceData=${faceData}")
|
||||||
|
// return@addUserFace
|
||||||
|
// }
|
||||||
|
// Thread {
|
||||||
|
// saveFaceInfo(faceModel)
|
||||||
|
// uploadFaceDebouncer.reset()
|
||||||
|
// }.start()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private fun getFaceDataBlock(block: (String, Bitmap) -> Unit) {
|
||||||
|
// if (userFaceInfo == null || userFaceInfo?.faceFeature?.featureData == null) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// val faceData: String? = Base64.encode(userFaceInfo?.faceFeature?.featureData)
|
||||||
|
// if (faceData.isNullOrBlank()) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据时间:${DateTimeUtils.getDateTimeString()}-----------")
|
||||||
|
// block(faceData, userFaceInfo!!.headBmp)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 加载日志
|
||||||
|
// * @param msg 日志内容
|
||||||
|
// */
|
||||||
|
// private fun loadLogInfo(msg: String) {
|
||||||
|
// Timber.tag(TAG).d(msg)
|
||||||
|
// LogFileUtil.saveLog(msg)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private var facePreviewInfoList: MutableList<FacePreviewInfo>? = null
|
||||||
|
// private var userFaceInfo: UserFaceInfo? = null
|
||||||
|
//
|
||||||
|
// private var currentUserId: String? = null
|
||||||
|
//
|
||||||
|
// private fun saveFaceInfo(faceModel: UserFaceModel) {
|
||||||
|
// try {
|
||||||
|
// loadLogInfo("collectFace,saveFaceInfo: ----------8,保存人脸取特征数据-----------")
|
||||||
|
// val faceDao = FaceDatabase.getInstance(this).faceDao()
|
||||||
|
// val faceEntity = FaceEntity(
|
||||||
|
// faceModel.userId,
|
||||||
|
// null,
|
||||||
|
// Base64.decode(faceModel.faceFeatureStr)
|
||||||
|
// ).also {
|
||||||
|
// //1-会员、2-临时用户
|
||||||
|
// it.userType = if (faceModel.isMember) "1" else "2"
|
||||||
|
// }
|
||||||
|
// faceDao.insert(faceEntity)
|
||||||
|
// loadLogInfo("collectFace,saveFaceInfo: ----------10,人脸数据保存完成-----------")
|
||||||
|
// recognizeViewModel.refreshFaceList()
|
||||||
|
// loadLogInfo("collectFace,saveFaceInfo: ----------11,刷新人脸数据-----------")
|
||||||
|
// runOnUiThread { recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) }
|
||||||
|
// loadLogInfo("---------------------------------")
|
||||||
|
// collectCount = 0
|
||||||
|
// } catch (e: Exception) {
|
||||||
|
// e.printStackTrace()
|
||||||
|
// loadLogInfo("collectFace,saveFaceInfo: ----------13,人脸采集异常:${e.message}-----------")
|
||||||
|
// collectCount++
|
||||||
|
// loadLogInfo("collectFace,saveFaceInfo: ----------14,${collectCount}次人脸采集异常:${e.message}-----------")
|
||||||
|
// ToastUtils.showToast("人脸采集异常:${e.message}")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private var collectCount = 0
|
||||||
|
//
|
||||||
|
//// private var tcpClient: TcpClient? = null
|
||||||
|
////
|
||||||
|
//// private fun addSocketListener() {
|
||||||
|
////// val ipAddress = NetworkUtils.getIPAddress(true)
|
||||||
|
////// loadLogInfo( "addSocketListener,ipAddress: $ipAddress");
|
||||||
|
//// tcpClient = TcpClient(
|
||||||
|
//// "192.168.1.95",
|
||||||
|
//// 5000,
|
||||||
|
//// GlobalData.deviceId, // clientId
|
||||||
|
//// 5000, // connectTimeoutMs
|
||||||
|
//// 10 * 1000, // heartbeatIntervalMs
|
||||||
|
//// 30 * 1000 // heartbeatTimeoutMs
|
||||||
|
//// )
|
||||||
|
////
|
||||||
|
//// tcpClient?.setListener(object : TcpClientListenerImpl() {
|
||||||
|
//// override fun onSendSuccess(json: JSONObject?) {
|
||||||
|
//// super.onSendSuccess(json)
|
||||||
|
//// loadLogInfo("collectFace,TcpClientListener发送成功:$json")
|
||||||
|
////// toast("发送成功")
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// override fun onSendFailed(json: JSONObject?, e: java.lang.Exception?) {
|
||||||
|
//// super.onSendFailed(json, e)
|
||||||
|
//// ToastUtils.showToast("发送失败${e?.message}")
|
||||||
|
//// loadLogInfo("collectFace,TcpClientListener人脸数据发送失败:${e?.message}")
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// override fun onMessage(json: JSONObject?) {
|
||||||
|
//// super.onMessage(json)
|
||||||
|
//// loadLogInfo("collectFace,TcpClientListener收到消息:$json")
|
||||||
|
//// val type = json?.getInt("type")
|
||||||
|
//// // 根据服务端消息类型处理删除新增临时用户人脸数据---------------------
|
||||||
|
//// when (type) {
|
||||||
|
//// LanServer.TYPE_ADD_FACE_DATA -> {
|
||||||
|
//// //采集设备id自己生成,不接收服务端的,在本地只判断是否存在同一人脸数据
|
||||||
|
//// loadLogInfo("collectFace,TcpClientListener收到消息,新增用户:采集设备id自己生成,不接收服务端的,在本地只判断是否存在同一人脸数据")
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// LanServer.TYPE_CLEAR_FACE_DATA -> {
|
||||||
|
//// clearFaceData()
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// else -> {}
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//// })
|
||||||
|
//// tcpClient?.start()
|
||||||
|
////
|
||||||
|
//// try {
|
||||||
|
//// LanServer.getInstance().let {
|
||||||
|
//// it.setListener(object : LanServerListenerImpl() {
|
||||||
|
//// override fun onMessageReceived(clientId: String?, message: JSONObject?) {
|
||||||
|
//// super.onMessageReceived(clientId, message)
|
||||||
|
//// ToastUtils.showToast("收到消息clientId=$clientId")
|
||||||
|
//// }
|
||||||
|
//// })
|
||||||
|
//// it.start()
|
||||||
|
//// }
|
||||||
|
//// } catch (e: Exception) {
|
||||||
|
//// e.printStackTrace()
|
||||||
|
//// }
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
// private fun clearFaceData() {
|
||||||
|
// Thread {
|
||||||
|
// val faceDao = FaceDatabase.getInstance(this).faceDao()
|
||||||
|
// faceDao.deleteTempUserFaceData()
|
||||||
|
// recognizeViewModel.refreshFaceList()
|
||||||
|
// loadLogInfo("collectFace,TcpClientListener收到消息,已删除并刷新人脸数据")
|
||||||
|
// }.start()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private var isCollectFace = false
|
||||||
|
//
|
||||||
|
//}
|
||||||
@@ -70,3 +70,14 @@ fun View.clickWithCoroutines(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun View.clickWithDebounce(delay: Long = 500, action: () -> Unit) {
|
||||||
|
var job: Job? = null
|
||||||
|
setOnClickListener {
|
||||||
|
job?.cancel()
|
||||||
|
job = CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
delay(delay)
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -105,6 +105,46 @@
|
|||||||
android:textSize="36sp"
|
android:textSize="36sp"
|
||||||
tools:text="30" />
|
tools:text="30" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llCollectButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginBottom="100dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/btnRetry"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:text="再次重试"
|
||||||
|
android:textColor="#FFCC99"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginVertical="10dp"
|
||||||
|
android:paddingHorizontal="45dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@drawable/btn_outline"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/btnCollect"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:text="新用户采集"
|
||||||
|
android:textColor="#FFCC99"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginVertical="10dp"
|
||||||
|
android:paddingHorizontal="45dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@drawable/btn_outline"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- <LinearLayout-->
|
<!-- <LinearLayout-->
|
||||||
<!-- android:layout_width="wrap_content"-->
|
<!-- android:layout_width="wrap_content"-->
|
||||||
<!-- android:layout_height="wrap_content"-->
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
|||||||
Reference in New Issue
Block a user