精简了称sdk调用

This commit is contained in:
zxj
2025-08-06 14:45:07 +08:00
parent bbf2e605b5
commit 08611349aa
15 changed files with 545 additions and 101 deletions
+271
View File
@@ -0,0 +1,271 @@
{
"info": {
"_postman_id": "adfceb8d-2c35-41bf-82d9-40b87e10524d",
"name": "档口机",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "751386"
},
"item": [{
"name": "device获取token",
"request": {
"auth": {
"type": "noauth"
},
"method": "GET",
"header": [],
"url": {
"
raw": "http://device.shuziweidao.com:8889/sys/getEquipmentToken?qrcodeId=3ea47dc0-3cf0-3c2f-909c-265a9a65572e",
"protocol": "http",
"host": [
"device",
"shuziweidao",
"com"
],
"port": "8889",
"path": [
"sys",
"getEquipmentToken"
],
"query": [{
"key": "qrcodeId",
"value": "3ea47dc0-3cf0-3c2f-909c-265a9a65572e"
}
]
}
},
"response": []
}, {
"name": "获取配置信息",
"request": {
"method": "GET",
"header": [{
"key": "X-Access-Token",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NTM4NDIzNDEsInVzZXJuYW1lIjoiYWRtaW4ifQ.gcKT7BeMWNve8NydRmTTrdXW8wdS7W_Ot9kVdtllyuc",
"type": "text"
}
],
"url": {
"
raw": "http://device.shuziweidao.com:8889/equipment/stEquipment/queryByEquipmentCode?equipmentCode=3ea47dc0-3cf0-3c2f-909c-265a9a65572e",
"protocol": "http",
"host": [
"device",
"shuziweidao",
"com"
],
"port": "8889",
"path": [
"equipment",
"stEquipment",
"queryByEquipmentCode"
],
"query": [{
"key": "equipmentCode",
"value": "3ea47dc0-3cf0-3c2f-909c-265a9a65572e"
}
]
}
},
"response": []
}, {
"name": "获取业务服务器token",
"request": {
"method": "GET",
"header": [],
"url": {
"
raw": "http://192.168.1.207/gateway/local/sys/getEquipmentToken?qrcodeId=3ea47dc0-3cf0-3c2f-909c-265a9a65572e",
"protocol": "http",
"host": [
"192",
"168",
"1",
"207"
],
"path": [
"gateway",
"local",
"sys",
"getEquipmentToken"
],
"query": [{
"key": "qrcodeId",
"value": "3ea47dc0-3cf0-3c2f-909c-265a9a65572e"
}
]
}
},
"response": []
}, {
"name": "获取人脸数据",
"request": {
"method": "GET",
"header": [{
"key": "X-Access-Token",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYW50ZWVuSWQiOiIyOCIsInR5cGUiOiI0IiwidXNlcklkIjoiMDAwMDAwMDAwMDAwMDAwMDAwMSJ9.Jy7Dc2k5FlqUAmGReRn-uEg3Du5gtlyUhXKUMZLlO-E",
"type": "text"
}
],
"url": {
"raw": "http://192.168.1.207/gateway/local/stapi/cquser/getUserFaceCache/v2?pageIndex=0",
"protocol": "http",
"host": [
"192",
"168",
"1",
"207"
],
"path": [
"gateway",
"local",
"stapi",
"cquser",
"getUserFaceCache",
"v2"
],
"query": [{
"key": "pageIndex",
"value": "0"
}
]
}
},
"response": []
}, {
"name": "获取档口菜品信息",
"request": {
"method": "GET",
"header": [{
"key": "X-Access-Token",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYW50ZWVuSWQiOiIyOCIsInR5cGUiOiI0IiwidXNlcklkIjoiMDAwMDAwMDAwMDAwMDAwMDAwMSJ9.Jy7Dc2k5FlqUAmGReRn-uEg3Du5gtlyUhXKUMZLlO-E",
"type": "text"
}
],
"url": {
"
raw": "http://192.168.1.207/gateway/local/zhstapi/zhst/getRestInfoFoodsByType/stall?restId=1678234139391512577&type=0&foodName=西红柿",
"protocol": "http",
"host": [
"192",
"168",
"1",
"207"
],
"path": [
"gateway",
"local",
"zhstapi",
"zhst",
"getRestInfoFoodsByType",
"stall"
],
"query": [{
"key": "restId",
"value": "1678234139391512577"
}, {
"key": "type",
"value": "0",
"description": "0全部 1餐次"
}, {
"key": "foodName",
"value": "西红柿"
}
]
}
},
"response": []
}, {
"name": "通过用户信息获取就餐数据",
"request": {
"method": "GET",
"header": [{
"key": "X-Access-Token",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYW50ZWVuSWQiOiIyOCIsInR5cGUiOiI0IiwidXNlcklkIjoiMDAwMDAwMDAwMDAwMDAwMDAwMSJ9.Jy7Dc2k5FlqUAmGReRn-uEg3Du5gtlyUhXKUMZLlO-E",
"type": "text"
}
],
"url": {
"
raw": "http://192.168.1.207/gateway/local/zhstapi/zhst/getUserNutritionData/face?restId=1678234139391512577&userId=4958698b725b4e89a514fa8552aa5fa3&foodId=1701417944860119041",
"protocol": "http",
"host": [
"192",
"168",
"1",
"207"
],
"path": [
"gateway",
"local",
"zhstapi",
"zhst",
"getUserNutritionData",
"face"
],
"query": [{
"key": "restId",
"value": "1678234139391512577"
}, {
"key": "userId",
"value": "4958698b725b4e89a514fa8552aa5fa3"
}, {
"key": "foodId",
"value": "1701417944860119041"
}
]
}
},
"response": []
}, {
"name": "提交就餐数据",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"
raw": "http://192.168.1.207/gateway/local/zhstapi/zhst/userEatFood/doubleBalance/face/stall?restId=1678234139391512577&userId=4958698b725b4e89a514fa8552aa5fa3&foodId=1701417944860119041&faceTime&faceEndTime&eatWeight&foodWeight&deviceId",
"protocol": "http",
"host": [
"192",
"168",
"1",
"207"
],
"path": [
"gateway",
"local",
"zhstapi",
"zhst",
"userEatFood",
"doubleBalance",
"face",
"stall"
],
"body": [{
"appVersion": "1",
"deviceId": "abe60247-99d1-3c2a-9f10-c0b76f4b3f3b",
"eatWeight": 0.278,
"faceEndTime": 1754385701611,
"faceTime": 1754385694475,
"foodId": "1701417944860119041",
"foodWeight": 0.278,
"restId": "1678234139391512577",
"userId": "1937692681894932481"
}
]
}
},
"response": []
}
]
}
@@ -7,6 +7,10 @@ object GlobalData {
// var globalEquipmentCode: String = "202501171634" // var globalEquipmentCode: String = "202501171634"
var restId: String = "" var restId: String = ""
/**
* 设备id
*/
var deviceId: String = ""
/** /**
* app版本号 * app版本号
*/ */
@@ -1,6 +1,7 @@
package com.sw.dualscreen package com.sw.dualscreen
import com.sw.plate.App import com.sw.plate.App
import com.sw.plate.utils.AppUtil
import timber.log.Timber import timber.log.Timber
class MyApp : App() { class MyApp : App() {
@@ -11,5 +12,8 @@ class MyApp : App() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Timber.plant(Timber.DebugTree()) Timber.plant(Timber.DebugTree())
val deviceId = AppUtil.getUDID(this)
Timber.d("UDID = ${AppUtil.getUDID(this)}")
GlobalData.deviceId = deviceId
} }
} }
@@ -6,6 +6,7 @@ import android.graphics.Typeface
import android.hardware.display.DisplayManager import android.hardware.display.DisplayManager
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.view.View import android.view.View
import android.view.ViewOutlineProvider import android.view.ViewOutlineProvider
import android.widget.AdapterView import android.widget.AdapterView
@@ -36,7 +37,6 @@ import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.utils.GlideUtils import com.sw.dualscreen.utils.GlideUtils
import com.sw.dualscreen.view.CustomBottomSheetDialog import com.sw.dualscreen.view.CustomBottomSheetDialog
import com.sw.dualscreen.viewmodel.UserViewModel import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.AppUtil
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -56,6 +56,8 @@ class MainActivity : AppCompatActivity() {
private var imageAnalysis: ImageAnalysis? = null private var imageAnalysis: ImageAnalysis? = null
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
private var canIdentify: Boolean = false private var canIdentify: Boolean = false
private var bottomSheetDialog: CustomBottomSheetDialog? = null
private var lastWeight: Double = 0.0
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -63,7 +65,6 @@ class MainActivity : AppCompatActivity() {
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.main) setContentView(binding.main)
Timber.d("UDID = ${AppUtil.getUDID(this)}")
initView() initView()
setupSecondaryDisplay() setupSecondaryDisplay()
setupCamera() setupCamera()
@@ -84,10 +85,10 @@ class MainActivity : AppCompatActivity() {
} }
binding.previewView.clipToOutline = true binding.previewView.clipToOutline = true
binding.tvToSearch.setOnClickListener { binding.tvToSearch.setOnClickListener {
val bottomSheetDialog = CustomBottomSheetDialog.newInstance(viewModel) { bottomSheetDialog = CustomBottomSheetDialog.newInstance(viewModel) {
updateCurrentFood(it) updateCurrentFood(it)
} }
bottomSheetDialog.show(supportFragmentManager, "CustomBottomSheetDialog") bottomSheetDialog!!.show(supportFragmentManager, "CustomBottomSheetDialog")
} }
val spinnerAdapter = ArrayAdapter<String>( val spinnerAdapter = ArrayAdapter<String>(
@@ -138,7 +139,15 @@ class MainActivity : AppCompatActivity() {
binding.tvFoodName.text = foodInfo.foodName binding.tvFoodName.text = foodInfo.foodName
binding.previewView.visibility = View.GONE binding.previewView.visibility = View.GONE
binding.ivImg.visibility = View.VISIBLE binding.ivImg.visibility = View.VISIBLE
GlideUtils.loadRoundCornerImage(this, foodInfo.imgUrl, binding.ivImg, 12) val imgUrl = foodInfo.imgUrl
if (TextUtils.isEmpty(imgUrl)) {
takePhoto { imgUri ->
GlideUtils.loadRoundCornerImage(this, imgUri, binding.ivImg, 12)
presentation.updateFood(foodInfo.copy(imgUrl = imgUri.toString()))
}
} else {
GlideUtils.loadRoundCornerImage(this, foodInfo.imgUrl, binding.ivImg, 12)
}
pauseAnalysis() pauseAnalysis()
} else { } else {
binding.tvFoodName.text = "-" binding.tvFoodName.text = "-"
@@ -158,7 +167,8 @@ class MainActivity : AppCompatActivity() {
} }
} }
SensorScaleUtils.startScale { weight -> SensorScaleUtils.startScale { weight ->
// Timber.d("weight = $weight") Timber.d("registerDataChange weight = $weight")
presentation.updateWeight(weight)
if (weight > 0.0) { if (weight > 0.0) {
if (canIdentify) { if (canIdentify) {
canIdentify = false canIdentify = false
@@ -290,23 +300,30 @@ class MainActivity : AppCompatActivity() {
// 拍照功能 // 拍照功能
private fun takePhoto(callback: (Uri) -> Unit) { private fun takePhoto(callback: (Uri) -> Unit) {
Timber.d("takePhoto")
// 临时停止分析以避免干扰 // 临时停止分析以避免干扰
isAnalyzing = false isAnalyzing = false
// 创建输出选项 // 创建输出选项
val outputFileOptions = ImageCapture.OutputFileOptions.Builder( val executor = ContextCompat.getMainExecutor(this)
File( val cacheDir = cacheDir
cacheDir.path, "IMG_${System.currentTimeMillis()}.jpg" val photoFile = File.createTempFile(
) "IMG_${System.currentTimeMillis()}",
).build() ".jpg",
cacheDir
)
val cacheOutputOptions =
ImageCapture.OutputFileOptions.Builder(photoFile).build()
// 执行拍照 // 执行拍照
imageCapture?.takePicture( imageCapture?.takePicture(
outputFileOptions, cacheOutputOptions,
executor, executor,
object : ImageCapture.OnImageSavedCallback { object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
runOnUiThread { runOnUiThread {
val savedUri = outputFileResults.savedUri val savedUri = outputFileResults.savedUri
Timber.d("takePhoto savedUri = $savedUri")
ToastUtils.showToast("照片保存成功: $savedUri") ToastUtils.showToast("照片保存成功: $savedUri")
if (savedUri != null) { if (savedUri != null) {
callback(savedUri) callback(savedUri)
@@ -347,6 +364,7 @@ class MainActivity : AppCompatActivity() {
presentation.setStepChangeCallback { step -> presentation.setStepChangeCallback { step ->
if (step == 1) { if (step == 1) {
updateCurrentFood(null) updateCurrentFood(null)
bottomSheetDialog?.dismiss()
} }
} }
presentation.show() presentation.show()
@@ -14,5 +14,5 @@ data class UserNutritionParam(
val faceEndTime: Long, val faceEndTime: Long,
val eatWeight: Double, val eatWeight: Double,
val foodWeight: Double, val foodWeight: Double,
val deviceId: String = "" val deviceId: String = GlobalData.deviceId
) : Parcelable ) : Parcelable
@@ -97,6 +97,6 @@ interface ApiService {
@POST @POST
suspend fun postUserNutritionData( suspend fun postUserNutritionData(
@Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/userEatFood/doubleBalance/face/stall", @Url url: String = "${GlobalData.appBaseUrl}/zhstapi/zhst/userEatFood/doubleBalance/face/stall",
@Body param: UserNutritionParam @Body param: List<UserNutritionParam>
): ApiResponse<String> ): ApiResponse<String>
} }
@@ -19,7 +19,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewOutlineProvider import android.view.ViewOutlineProvider
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.Toast
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
@@ -32,10 +31,10 @@ import com.sw.dualscreen.databinding.PresentationSecondaryScreenBinding
import com.sw.dualscreen.ext.dp import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.ext.format2String import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.maskName import com.sw.dualscreen.ext.maskName
import com.sw.dualscreen.model.request.UserNutritionParam
import com.sw.dualscreen.model.response.DinnerTypeInfo import com.sw.dualscreen.model.response.DinnerTypeInfo
import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.FoodInfo
import com.sw.dualscreen.model.response.UserNutritionData import com.sw.dualscreen.model.response.UserNutritionData
import com.sw.dualscreen.sdk.SensorScaleUtils
import com.sw.dualscreen.utils.Debouncer import com.sw.dualscreen.utils.Debouncer
import com.sw.dualscreen.utils.GlideUtils import com.sw.dualscreen.utils.GlideUtils
import com.sw.dualscreen.viewmodel.UserViewModel import com.sw.dualscreen.viewmodel.UserViewModel
@@ -49,9 +48,11 @@ import com.sw.plate.utils.arcface.PreviewConfig
import com.sw.plate.utils.arcface.camera.CameraListener import com.sw.plate.utils.arcface.camera.CameraListener
import com.sw.plate.utils.arcface.camera.DualCameraHelper import com.sw.plate.utils.arcface.camera.DualCameraHelper
import com.sw.plate.utils.arcface.face.constants.LivenessType 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.FacePreviewInfo
import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration import com.sw.plate.utils.arcface.face.model.RecognizeConfiguration
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
@@ -67,9 +68,6 @@ class SecondaryScreenPresentation(
val recognizeViewModel: RecognizeViewModel val recognizeViewModel: RecognizeViewModel
) : Presentation(context, display), ViewTreeObserver.OnGlobalLayoutListener { ) : Presentation(context, display), ViewTreeObserver.OnGlobalLayoutListener {
private lateinit var binding: PresentationSecondaryScreenBinding private lateinit var binding: PresentationSecondaryScreenBinding
private var cameraDevice: CameraDevice? = null
// private var cameraCaptureSession: CameraCaptureSession? = null
private lateinit var cameraManager: CameraManager private lateinit var cameraManager: CameraManager
private var cameraIdList: Array<String> = arrayOf() private var cameraIdList: Array<String> = arrayOf()
@@ -77,13 +75,17 @@ class SecondaryScreenPresentation(
private var currentFood: FoodInfo? = null private var currentFood: FoodInfo? = null
private var lastFood: FoodInfo? = null private var lastFood: FoodInfo? = null
private var userNutritionData: UserNutritionData? = null private var userNutritionData: UserNutritionData? = null
private var dinnerType: DinnerTypeInfo? = null private var dinnerTypeInfo: DinnerTypeInfo? = null
private lateinit var itemUserNutritionBinding: ItemUserNutritionBinding private lateinit var itemUserNutritionBinding: ItemUserNutritionBinding
private lateinit var stepChangeCallback: (Int) -> Unit private lateinit var stepChangeCallback: (Int) -> Unit
// 上一次的计算热量结果
private var lastCalcResultInfo: UserNutritionUtils.CalcResultInfo? = null private var lastCalcResultInfo: UserNutritionUtils.CalcResultInfo? = null
private var startSensorScale: Boolean = false
private var lastWeight = 0.0 private var lastWeight = 0.0
private val debouncer = Debouncer(1000) private val debouncer = Debouncer(2000)
private var faceTime: Long = 0L // 人脸识别时的时间
private var recognitionWeight: Double = 0.0 // 人脸识别时的重量
private var lastFaceTrackId: Int = 0 // 上一次的人脸信息
// 当前步骤 // 当前步骤
var currentStep: Int = 0 var currentStep: Int = 0
@@ -104,17 +106,20 @@ class SecondaryScreenPresentation(
activity.lifecycleScope.launch { activity.lifecycleScope.launch {
viewModel.nutritionData.collect { viewModel.nutritionData.collect {
Timber.d("registerDataChange nutritionData = $it") Timber.d("registerDataChange nutritionData = $it")
if (it == null) return@collect
userNutritionData = it userNutritionData = it
if (it == null) return@collect
step3() step3()
itemUserNutritionBinding.tvUserName.text = it.userName.maskName() itemUserNutritionBinding.tvUserName.text = it.userName.maskName()
itemUserNutritionBinding.tvRecommendHeat.text = itemUserNutritionBinding.tvRecommendHeat.text =
"推荐热量:${it.recommendMin}-${it.recommendMax}" "推荐热量:${it.recommendMin}-${it.recommendMax}"
updateWeight(lastWeight)
} }
} }
activity.lifecycleScope.launch { activity.lifecycleScope.launch {
viewModel.dinnerTypeInfo.collect { viewModel.dinnerTypeInfo.drop(1).collect {
dinnerType = it Timber.d("registerDataChange dinnerTypeInfo = $it")
dinnerTypeInfo = it
} }
} }
} }
@@ -155,8 +160,14 @@ class SecondaryScreenPresentation(
fun step1() { fun step1() {
Timber.d("step1") Timber.d("step1")
currentStep = 1 currentStep = 1
//回复上一次的设置
lastWeight = 0.0
lastFood = null
lastCalcResultInfo = null
recognitionWeight = 0.0
stepChangeCallback(currentStep) stepChangeCallback(currentStep)
binding.tvFoodInfo.text = "菜品识别中" binding.tvFoodName.text = "菜品识别中"
binding.ivFaceBg.visibility = View.GONE binding.ivFaceBg.visibility = View.GONE
binding.flPreview.visibility = View.VISIBLE binding.flPreview.visibility = View.VISIBLE
binding.ivImg.visibility = View.VISIBLE binding.ivImg.visibility = View.VISIBLE
@@ -164,8 +175,6 @@ class SecondaryScreenPresentation(
pauseCamera() pauseCamera()
binding.tvBottomTip.visibility = View.VISIBLE binding.tvBottomTip.visibility = View.VISIBLE
itemUserNutritionBinding.clNutritionData.visibility = View.GONE itemUserNutritionBinding.clNutritionData.visibility = View.GONE
stopSensorScale()
viewModel.getDinnerType()
} }
/** /**
@@ -176,14 +185,15 @@ class SecondaryScreenPresentation(
currentStep = 2 currentStep = 2
stepChangeCallback(currentStep) stepChangeCallback(currentStep)
currentFood = foodInfo currentFood = foodInfo
viewModel.getDinnerType()
resumeCamera() resumeCamera()
binding.tvFoodInfo.text = foodInfo.foodName binding.tvFoodName.text = foodInfo.foodName
binding.ivImg.visibility = View.GONE binding.ivImg.visibility = View.GONE
binding.flPreview.visibility = View.GONE binding.flPreview.visibility = View.GONE
binding.flFace.visibility = View.VISIBLE binding.flFace.visibility = View.VISIBLE
binding.ivFaceBg.visibility = View.VISIBLE binding.ivFaceBg.visibility = View.GONE
binding.tvFaceTip.visibility = View.VISIBLE binding.tvFaceTip.visibility = View.VISIBLE
binding.tvBottomTip.visibility = View.VISIBLE binding.tvBottomTip.visibility = View.VISIBLE
itemUserNutritionBinding.clNutritionData.visibility = View.GONE itemUserNutritionBinding.clNutritionData.visibility = View.GONE
@@ -196,7 +206,7 @@ class SecondaryScreenPresentation(
if (currentStep == 1) { if (currentStep == 1) {
step2(foodInfo) step2(foodInfo)
} else { } else {
binding.tvFoodInfo.text = foodInfo.foodName binding.tvFoodName.text = foodInfo.foodName
GlideUtils.loadRoundCornerImage( GlideUtils.loadRoundCornerImage(
context, context,
url = currentFood!!.imgUrl, url = currentFood!!.imgUrl,
@@ -218,10 +228,7 @@ class SecondaryScreenPresentation(
ToastUtils.showToast("选中物品为空3") ToastUtils.showToast("选中物品为空3")
return return
} }
binding.tvFoodInfo.text = currentFood!!.foodName binding.tvFoodName.text = currentFood!!.foodName
pauseCamera()
startSensorScale()
GlideUtils.loadRoundCornerImage( GlideUtils.loadRoundCornerImage(
context, context,
url = currentFood!!.imgUrl, url = currentFood!!.imgUrl,
@@ -238,36 +245,40 @@ class SecondaryScreenPresentation(
itemUserNutritionBinding.clNutritionData.visibility = View.VISIBLE itemUserNutritionBinding.clNutritionData.visibility = View.VISIBLE
} }
private fun startSensorScale() { fun updateWeight(weight: Double) {
Timber.d("startSensorScale startSensorScale = $startSensorScale") Timber.d("updateWeight weight = $weight")
if (startSensorScale) return lastWeight = weight
SensorScaleUtils.startScale { weight -> Timber.d("updateWeight lastWeight = $weight")
if (currentFood == null) { if (currentFood == null) {
Timber.e("startSensorScale currentFood is null") Timber.e("updateWeight currentFood is null")
return@startScale return
} }
if (userNutritionData == null) { if (userNutritionData == null) {
Timber.e("startSensorScale userNutritionData is null") Timber.e("updateWeight userNutritionData is null")
return@startScale return
} }
if (dinnerType == null) { if (dinnerTypeInfo == null) {
Timber.e("startSensorScale dinnerType is null") Timber.e("updateWeight dinnerType is null")
return@startScale return
} }
// 重量和 当前食物都没变,则不再计算 // 重量和 当前食物都没变,则不再计算
if (weight == lastWeight && lastFood == currentFood) return@startScale if (lastFood == currentFood) {
Timber.d("registerDataChange weight = $weight") // Timber.e("updateWeight 物品未改变")
return
}
lastFood = currentFood lastFood = currentFood
lastWeight = weight
debouncer.debounce { debouncer.debounce {
val dinnerType = dinnerTypeInfo!!.dinnerType!!.dinnerType!!
Timber.d("updateWeight foodName = ${currentFood!!.foodName}, dinnerType = $dinnerType, userId = ${userNutritionData!!.userId}")
val calcResultInfo = UserNutritionUtils.calculateNutrition( val calcResultInfo = UserNutritionUtils.calculateNutrition(
currentFood!!, currentFood!!,
userNutritionData!!, userNutritionData!!,
weight, weight,
dinnerType = dinnerType!!.dinnerType!!.dinnerType!! dinnerType = dinnerType
) )
Timber.d("calcResultInfo = $calcResultInfo") Timber.d("updateWeight calcResultInfo = $calcResultInfo")
if (lastCalcResultInfo == calcResultInfo) { if (lastCalcResultInfo == calcResultInfo) {
Timber.d("updateWeight 与上次计算结果无变化")
return@debounce return@debounce
} }
lastCalcResultInfo = calcResultInfo lastCalcResultInfo = calcResultInfo
@@ -318,11 +329,6 @@ class SecondaryScreenPresentation(
) )
} }
} }
}
}
private fun stopSensorScale() {
SensorScaleUtils.closeScale()
} }
private fun openCamera() { private fun openCamera() {
@@ -338,7 +344,11 @@ class SecondaryScreenPresentation(
// 获取摄像头列表 // 获取摄像头列表
cameraIdList = cameraManager.cameraIdList cameraIdList = cameraManager.cameraIdList
if (cameraIdList.isEmpty()) { if (cameraIdList.isEmpty()) {
Toast.makeText(context, "没有可用的摄像头", Toast.LENGTH_SHORT).show() ToastUtils.showToast("没有可用的摄像头")
return
}
if (cameraIdList.size < 3) {
ToastUtils.showToast("摄像头数量异常")
return return
} }
@@ -347,27 +357,29 @@ class SecondaryScreenPresentation(
} }
val cameraId = cameraIdList.last() val cameraId = cameraIdList.last()
Timber.d("openCamera cameraId = $cameraId") Timber.d("openCamera cameraId = $cameraId")
cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() { val c1 = cameraIdList[0]
val c2 = cameraIdList[1]
val c3 = cameraIdList[2]
cameraManager.openCamera(c3, object : CameraDevice.StateCallback() {
override fun onOpened(device: CameraDevice) { override fun onOpened(device: CameraDevice) {
cameraDevice = device
// createCameraPreviewSession()
recognizeViewModel.init( recognizeViewModel.init(
PreviewConfig( PreviewConfig(
2, 4, 0, 0 c3.toInt(), c2.toInt(), 90, 90
) )
) )
initRgbCamera() initRgbCamera()
resumeCamera() // resumeCamera()
if (DualCameraHelper.hasDualCamera() && livenessType === LivenessType.IR) {
initIrCamera()
}
} }
override fun onDisconnected(device: CameraDevice) { override fun onDisconnected(device: CameraDevice) {
device.close() device.close()
cameraDevice = null
} }
override fun onError(device: CameraDevice, error: Int) { override fun onError(device: CameraDevice, error: Int) {
device.close() device.close()
cameraDevice = null
} }
}, null) }, null)
} catch (e: Exception) { } catch (e: Exception) {
@@ -383,9 +395,12 @@ class SecondaryScreenPresentation(
private var isRecognition = false private var isRecognition = false
private var rgbCameraHelper: DualCameraHelper? = null private var rgbCameraHelper: DualCameraHelper? = null
private var rgbFaceRectTransformer: FaceRectTransformer? = null private var rgbFaceRectTransformer: FaceRectTransformer? = null
private val livenessType = LivenessType.RGB private val livenessType = LivenessType.IR
private var openRectInfoDraw = false private var openRectInfoDraw = false
private var irCameraHelper: DualCameraHelper? = null
private var irFaceRectTransformer: FaceRectTransformer? = null
private fun initArcViewModel() { private fun initArcViewModel() {
recognizeViewModel.setLiveType(livenessType) recognizeViewModel.setLiveType(livenessType)
@@ -427,15 +442,18 @@ class SecondaryScreenPresentation(
}) })
recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? -> recognizeViewModel.recognizeNotice.observe(activity, Observer { notice: String? ->
Timber.i("recognizeNotice observe notice = $notice") Timber.i("recognizeNotice observe notice = $notice")
if (currentStep == 3 && notice == "leave") {
// step1()
}
}) })
recognizeViewModel.recognizeUserId.observe(activity, Observer { userId: String? -> recognizeViewModel.recognizeUserId.observe(
Timber.i("recognizeUserId observe userId = $userId") activity,
Observer { compareResult: CompareResult ->
Timber.i("recognizeUserId observe compareResult = $compareResult")
faceTime = System.currentTimeMillis()
recognitionWeight = lastWeight
lastFaceTrackId = compareResult.trackId
val faceEntity = compareResult.faceEntity
val userId = faceEntity.userName
if (userId == null) return@Observer if (userId == null) return@Observer
viewModel.getUserNutritionData(userId = userId, foodId = currentFood!!.id!!) viewModel.getUserNutritionData(userId = userId, foodId = currentFood!!.id!!)
}) })
@@ -519,12 +537,13 @@ class SecondaryScreenPresentation(
displayOrientation: Int, displayOrientation: Int,
isMirror: Boolean isMirror: Boolean
) { ) {
Timber.d("Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
activity.runOnUiThread({ activity.runOnUiThread({
val previewSizeRgb = camera.getParameters().getPreviewSize() val previewSizeRgb = camera.getParameters().getPreviewSize()
val layoutParams = adjustPreviewViewSize( val layoutParams = adjustPreviewViewSize(
binding.dualCameraTexturePreviewRgb, binding.dualCameraTexturePreviewRgb,
binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView,
previewSizeRgb, 90, 1f previewSizeRgb, displayOrientation, 1f
) )
Timber.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}") Timber.d("initRgbCamera previewSizeRgb = ${previewSizeRgb.width}-${previewSizeRgb.height}")
Timber.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}") Timber.d("initRgbCamera layoutParams = ${layoutParams.width}-${layoutParams.height}")
@@ -586,7 +605,7 @@ class SecondaryScreenPresentation(
) )
) )
.rotation(activity.windowManager.defaultDisplay.rotation) .rotation(activity.windowManager.defaultDisplay.rotation)
.additionalRotation(90) // 角度 .additionalRotation(previewConfig.rgbAdditionalDisplayOrientation) // 角度
.previewSize(recognizeViewModel.loadPreviewSize()) .previewSize(recognizeViewModel.loadPreviewSize())
.specificCameraId(previewConfig.rgbCameraId) .specificCameraId(previewConfig.rgbCameraId)
.isMirror(true) .isMirror(true)
@@ -597,12 +616,96 @@ class SecondaryScreenPresentation(
rgbCameraHelper!!.start() rgbCameraHelper!!.start()
} }
/**
* 初始化红外相机,若活体检测类型是可见光活体检测或不启用活体,则不需要启用
*/
private fun initIrCamera() {
Timber.d("initIrCamera: livenessType = $livenessType")
if (livenessType === LivenessType.RGB) {
return
}
val irCameraListener: CameraListener = object : CameraListener {
override fun onCameraOpened(
camera: Camera,
cameraId: Int,
displayOrientation: Int,
isMirror: Boolean
) {
Timber.d("IR onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
val previewSizeIr = camera.getParameters().getPreviewSize()
val layoutParams = adjustPreviewViewSize(
binding.dualCameraTexturePreviewRgb,
binding.dualCameraTexturePreviewIr, binding.dualCameraFaceRectViewIr,
previewSizeIr, displayOrientation, 0.25f
)
irFaceRectTransformer = FaceRectTransformer(
previewSizeIr.width, previewSizeIr.height,
layoutParams.width, layoutParams.height, displayOrientation, cameraId, isMirror,
ConfigUtil.isDrawIrRectHorizontalMirror(context),
ConfigUtil.isDrawIrRectVerticalMirror(context)
)
recognizeViewModel.onIrCameraOpened(camera)
recognizeViewModel.setIrFaceRectTransformer(irFaceRectTransformer)
}
override fun onPreview(nv21: ByteArray?, camera: Camera?) {
recognizeViewModel.refreshIrPreviewData(nv21)
}
override fun onCameraClosed() {
Timber.i("onCameraClosed: ")
}
override fun onCameraError(e: java.lang.Exception) {
Timber.i("onCameraError: ${e.message}")
e.printStackTrace()
}
override fun onCameraConfigurationChanged(
cameraID: Int,
displayOrientation: Int
) {
if (irFaceRectTransformer != null) {
irFaceRectTransformer!!.cameraDisplayOrientation = displayOrientation
}
Timber.i("onCameraConfigurationChanged: cameraID = $cameraID, displayOrientation = $displayOrientation")
}
}
val previewConfig = recognizeViewModel.previewConfig
irCameraHelper = DualCameraHelper.Builder()
.previewViewSize(
Point(
binding.dualCameraTexturePreviewIr.measuredWidth,
binding.dualCameraTexturePreviewIr.measuredHeight
)
)
.rotation(activity.windowManager.defaultDisplay.rotation)
.specificCameraId(previewConfig.irCameraId)
.previewOn(binding.dualCameraTexturePreviewIr)
.cameraListener(irCameraListener)
.isMirror(true)
.previewSize(recognizeViewModel.loadPreviewSize()) //相机预览大小设置,RGB与IR需使用相同大小
.additionalRotation(previewConfig.irAdditionalDisplayOrientation) //额外旋转角度
.build()
irCameraHelper!!.init()
try {
irCameraHelper!!.start()
} catch (e: RuntimeException) {
ToastUtils.showToast(e.message + context.getString(R.string.camera_error_notice))
}
}
/** /**
* 绘制RGB、IR画面的实时人脸信息 * 绘制RGB、IR画面的实时人脸信息
* *
* @param facePreviewInfoList RGB画面的实时人脸信息 * @param facePreviewInfoList RGB画面的实时人脸信息
*/ */
private fun drawPreviewInfo(facePreviewInfoList: MutableList<FacePreviewInfo?>) { private fun drawPreviewInfo(facePreviewInfoList: MutableList<FacePreviewInfo?>) {
// Timber.d("drawPreviewInfo facePreviewInfoList = ${facePreviewInfoList.size}, rgbFaceRectTransformer = ${rgbFaceRectTransformer != null}")
if (rgbFaceRectTransformer != null) { if (rgbFaceRectTransformer != null) {
val rgbDrawInfoList: MutableList<DrawInfo?>? = recognizeViewModel.getDrawInfo( val rgbDrawInfoList: MutableList<DrawInfo?>? = recognizeViewModel.getDrawInfo(
facePreviewInfoList, facePreviewInfoList,
@@ -612,6 +715,27 @@ class SecondaryScreenPresentation(
// 识别成功 // 识别成功
binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList) binding.dualCameraFaceRectView.drawRealtimeFaceInfo(rgbDrawInfoList)
} }
if (facePreviewInfoList.isEmpty() || (lastFaceTrackId != facePreviewInfoList[0]!!.trackId)) {
if (lastFaceTrackId != 0) {
Timber.i("$lastFaceTrackId 用户离开")
lastFaceTrackId = 0
postUserData()
step1()
}
}
}
fun postUserData() {
val userNutritionParam = UserNutritionParam(
userId = userNutritionData?.userId!!,
foodId = currentFood?.id!!,
faceTime = faceTime,
faceEndTime = System.currentTimeMillis(),
eatWeight = recognitionWeight - lastWeight,
foodWeight = lastWeight
)
viewModel.postUserNutritionData(listOf<UserNutritionParam>(userNutritionParam))
} }
fun openRectInfoDraw(view: View?) { fun openRectInfoDraw(view: View?) {
@@ -643,7 +767,10 @@ class SecondaryScreenPresentation(
rgbCameraHelper!!.release() rgbCameraHelper!!.release()
rgbCameraHelper = null rgbCameraHelper = null
} }
SensorScaleUtils.closeScale() if (irCameraHelper != null) {
irCameraHelper!!.release()
irCameraHelper = null
}
recognizeViewModel.destroy() recognizeViewModel.destroy()
super.onStop() super.onStop()
} }
@@ -99,7 +99,7 @@ class RemoteRepository constructor(
* 提交就餐数据 * 提交就餐数据
*/ */
suspend fun postUserNutritionData( suspend fun postUserNutritionData(
param: UserNutritionParam param: List<UserNutritionParam>
): ApiResponse<String> { ): ApiResponse<String> {
return safeApiCall { apiService.postUserNutritionData(param = param) } return safeApiCall { apiService.postUserNutritionData(param = param) }
} }
@@ -1,6 +1,5 @@
package com.sw.dualscreen.sdk package com.sw.dualscreen.sdk
import android.util.Log
import com.sw.plate.utils.ToastUtils import com.sw.plate.utils.ToastUtils
import com.wabon.wbintelligenthardwaresdk.api.SensorScale import com.wabon.wbintelligenthardwaresdk.api.SensorScale
import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult import com.wabon.wbintelligenthardwaresdk.api.SensorScale.OnScaleResult
@@ -20,7 +19,9 @@ object SensorScaleUtils {
private var mSensorScale: SensorScale? = null private var mSensorScale: SensorScale? = null
private var isOpened: Boolean = false private var isOpened: Boolean = false
private var isRead: Boolean = false private var isRead: Boolean = false
private var isZero = false
private var callback: Callback? = {} private var callback: Callback? = {}
private var lastWeight: Double? = null
private fun init() { private fun init() {
mSensorScale = SensorScale(object : OnScaleResult { mSensorScale = SensorScale(object : OnScaleResult {
@@ -36,7 +37,8 @@ object SensorScaleUtils {
} }
// Log.d(TAG, "readWeight state = ${stateStr}, weight = $value") // Log.d(TAG, "readWeight state = ${stateStr}, weight = $value")
// 只使用稳定值 // 只使用稳定值
if (state == SensorScale.STATE_STABLE) { if (state == SensorScale.STATE_STABLE && lastWeight != value) {
lastWeight = value
callback?.invoke(value) callback?.invoke(value)
} }
} }
@@ -45,11 +47,11 @@ object SensorScaleUtils {
* 读取鉴别率 * 读取鉴别率
*/ */
override fun readIdentify(rate: Int) { override fun readIdentify(rate: Int) {
Log.e(TAG, "readIdentify rate = $rate") Timber.e("readIdentify rate = $rate")
} }
override fun fail(errCode: Int) { override fun fail(errCode: Int) {
Log.e(TAG, "fail code = $errCode") Timber.e("fail code = $errCode")
} }
}) })
} }
@@ -66,9 +68,6 @@ object SensorScaleUtils {
} }
this.callback = callback this.callback = callback
init() init()
mSensorScale?.zero {
Timber.d("startScale: zero")
}
mSensorScale?.openScale(serialPort, baudRate) { open -> mSensorScale?.openScale(serialPort, baudRate) { open ->
isOpened = open isOpened = open
Timber.d("isOpened = $isOpened") Timber.d("isOpened = $isOpened")
@@ -78,6 +77,7 @@ object SensorScaleUtils {
Thread.sleep(1000) Thread.sleep(1000)
// 打开后需要等待后才能调用,否则会 1001 SDK未初始化 // 打开后需要等待后才能调用,否则会 1001 SDK未初始化
mSensorScale?.startContinuousRead() mSensorScale?.startContinuousRead()
zero()
}).start() }).start()
} }
} }
@@ -88,7 +88,7 @@ object SensorScaleUtils {
* 开启自动读取重量 * 开启自动读取重量
*/ */
fun startContinuousRead(callback: Callback?) { fun startContinuousRead(callback: Callback?) {
Log.d(TAG, "开启自动读取 = $isRead") Timber.d("开启自动读取 = $isRead")
if (isRead) { if (isRead) {
return return
} }
@@ -101,7 +101,7 @@ object SensorScaleUtils {
* 手动读取重量 * 手动读取重量
*/ */
fun readWeight(callback: Callback?) { fun readWeight(callback: Callback?) {
Log.d(TAG, "isOpened = $isOpened") Timber.d("isOpened = $isOpened")
if (!isOpened) { if (!isOpened) {
return return
} }
@@ -113,9 +113,11 @@ object SensorScaleUtils {
* 零位标定 * 零位标定
*/ */
fun zero() { fun zero() {
if (!isOpened) return Timber.d("zero isZero = $isZero")
if (isZero) return
isZero = true
mSensorScale?.zero { mSensorScale?.zero {
Log.d(TAG, "零位标定操作成功") Timber.d("零位标定操作成功")
ToastUtils.showToast("零位标定操作成功") ToastUtils.showToast("零位标定操作成功")
} }
} }
@@ -126,7 +128,7 @@ object SensorScaleUtils {
fun tare() { fun tare() {
if (!isOpened) return if (!isOpened) return
mSensorScale?.tare { mSensorScale?.tare {
Log.d(TAG, "去皮置零操作成功") Timber.d("去皮置零操作成功")
ToastUtils.showToast("去皮置零操作成功") ToastUtils.showToast("去皮置零操作成功")
} }
} }
@@ -135,7 +137,7 @@ object SensorScaleUtils {
* 停止自动读取重量 * 停止自动读取重量
*/ */
fun stopContinuousRead() { fun stopContinuousRead() {
Log.d(TAG, "isOpened = $isOpened") Timber.d("isOpened = $isOpened")
if (!isOpened) { if (!isOpened) {
return return
} }
@@ -147,7 +149,7 @@ object SensorScaleUtils {
* 关闭称重 * 关闭称重
*/ */
fun closeScale() { fun closeScale() {
Log.d(TAG, "closeScale") Timber.d("closeScale")
isOpened = false isOpened = false
mSensorScale?.closeScale() mSensorScale?.closeScale()
mSensorScale == null mSensorScale == null
@@ -68,7 +68,6 @@ abstract class BaseViewModel() : ViewModel() {
GlobalData.restId = equipmentInfo.canteenId!! GlobalData.restId = equipmentInfo.canteenId!!
} }
fun handleError(exception: Exception) { fun handleError(exception: Exception) {
Timber.d("handleError ${exception.message}") Timber.d("handleError ${exception.message}")
} }
@@ -40,7 +40,7 @@ class UserViewModel : BaseViewModel() {
val nutritionData: StateFlow<UserNutritionData?> = _nutritionData val nutritionData: StateFlow<UserNutritionData?> = _nutritionData
/** /**
* 饭点类型 * 饭点类型 早餐/午餐/晚餐
*/ */
private val _dinnerTypeInfo = MutableStateFlow<DinnerTypeInfo?>(null) private val _dinnerTypeInfo = MutableStateFlow<DinnerTypeInfo?>(null)
val dinnerTypeInfo: StateFlow<DinnerTypeInfo?> = _dinnerTypeInfo val dinnerTypeInfo: StateFlow<DinnerTypeInfo?> = _dinnerTypeInfo
@@ -201,9 +201,9 @@ class UserViewModel : BaseViewModel() {
/** /**
* 提交就餐数据 * 提交就餐数据
*/ */
fun postUserNutritionData(param: UserNutritionParam) { fun postUserNutritionData(param: List<UserNutritionParam>) {
Timber.d("postUserNutritionData param = $param") Timber.d("postUserNutritionData param = $param")
launchWithLoading { launch {
val response = repository.postUserNutritionData(param) val response = repository.postUserNutritionData(param)
if (parseResponse(response)) { if (parseResponse(response)) {
@@ -16,7 +16,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:paddingTop="1dp" android:paddingTop="1dp"
android:visibility="gone"> android:visibility="visible">
<TextureView <TextureView
android:id="@+id/dual_camera_texture_preview_rgb" android:id="@+id/dual_camera_texture_preview_rgb"
@@ -29,8 +29,25 @@
android:id="@+id/dual_camera_face_rect_view" android:id="@+id/dual_camera_face_rect_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout
android:id="@+id/fl_recognize_ir"
android:layout_width="150dp"
android:layout_height="200dp"
android:layout_gravity="bottom">
<TextureView
android:id="@+id/dual_camera_texture_preview_ir"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.sw.plate.utils.arcface.FaceRectView
android:id="@+id/dual_camera_face_rect_view_ir"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</FrameLayout>
<ImageView <ImageView
android:id="@+id/iv_face_bg" android:id="@+id/iv_face_bg"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -38,7 +55,7 @@
android:layout_gravity="center" android:layout_gravity="center"
android:background="@drawable/bg_face" android:background="@drawable/bg_face"
android:contentDescription="相机遮盖层" android:contentDescription="相机遮盖层"
android:visibility="visible" /> android:visibility="gone" />
<FrameLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -55,7 +72,7 @@
android:visibility="visible"> android:visibility="visible">
<TextView <TextView
android:id="@+id/tv_food_info" android:id="@+id/tv_food_name"
style="@style/text_title_blob_2" style="@style/text_title_blob_2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
+1
View File
@@ -2,6 +2,7 @@
<string name="app_name">档口双屏</string> <string name="app_name">档口双屏</string>
<string name="specific_engine_init_failed">%s 初始化失败,错误码:%d\n错误码常量名:%s</string> <string name="specific_engine_init_failed">%s 初始化失败,错误码:%d\n错误码常量名:%s</string>
<string name="permission_denied">权限被拒绝!</string> <string name="permission_denied">权限被拒绝!</string>
<string name="camera_error_notice">\n可能的原因:该设备不支持同时打开两个摄像头</string>
<array name="detection_method"> <array name="detection_method">
<item>即放即取</item> <item>即放即取</item>
@@ -129,7 +129,8 @@ public class DualCameraHelper implements Camera.PreviewCallback {
//相机数量为2则打开1,1则打开0,相机ID 1为前置,0为后置 //相机数量为2则打开1,1则打开0,相机ID 1为前置,0为后置
mCameraId = Camera.getNumberOfCameras() - 1; mCameraId = Camera.getNumberOfCameras() - 1;
//若指定了相机ID且该相机存在,则打开指定的相机 //若指定了相机ID且该相机存在,则打开指定的相机
if (specificCameraId != null && specificCameraId <= mCameraId) { // if (specificCameraId != null && specificCameraId <= mCameraId) {
if (specificCameraId != null) {
mCameraId = specificCameraId; mCameraId = specificCameraId;
} }
@@ -158,7 +158,7 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
private MutableLiveData<String> drawRectInfoText = new MutableLiveData<>(); private MutableLiveData<String> drawRectInfoText = new MutableLiveData<>();
private MutableLiveData<String> recognizeUserId = new MutableLiveData<>(); private MutableLiveData<CompareResult> recognizeUserId = new MutableLiveData<>();
/** /**
* 检测ir活体前,是否需要更新faceData * 检测ir活体前,是否需要更新faceData
@@ -475,7 +475,7 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
Disposable disposable = Observable.just(true).observeOn(AndroidSchedulers.mainThread()).subscribe(aBoolean -> { Disposable disposable = Observable.just(true).observeOn(AndroidSchedulers.mainThread()).subscribe(aBoolean -> {
if (similarPass) { if (similarPass) {
if (recognizeUserId != null) { if (recognizeUserId != null) {
recognizeUserId.postValue(compareResult.getFaceEntity().getUserName()); recognizeUserId.postValue(compareResult);
} }
boolean isAdded = false; boolean isAdded = false;
List<CompareResult> compareResults = compareResultList.getValue(); List<CompareResult> compareResults = compareResultList.getValue();
@@ -541,7 +541,7 @@ public class RecognizeViewModel extends ViewModel implements RecognizeCallback {
return recognizeNotice; return recognizeNotice;
} }
public MutableLiveData<String> getRecognizeUserId() { public MutableLiveData<CompareResult> getRecognizeUserId() {
return recognizeUserId; return recognizeUserId;
} }