联合支付功能调试

This commit is contained in:
2026-03-23 18:13:55 +08:00
parent bf8444e5d5
commit c4a6101a7b
13 changed files with 350 additions and 143 deletions
@@ -5,24 +5,16 @@ import android.annotation.SuppressLint
import android.app.Presentation
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Outline
import android.graphics.Point
import android.hardware.Camera
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.util.DisplayMetrics
import android.view.Display
import android.view.View
import android.view.ViewGroup
import android.view.ViewOutlineProvider
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
@@ -30,7 +22,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.arcsoft.face.ErrorInfo
import com.sw.dualscreen.BuildConfig
import com.sw.dualscreen.GlobalKey
import com.sw.dualscreen.MyApp
import com.sw.dualscreen.R
import com.sw.dualscreen.activity.MainActivity
import com.sw.dualscreen.adapter.FoodOrderAdapter
@@ -40,7 +31,6 @@ import com.sw.dualscreen.ext.format2String
import com.sw.dualscreen.ext.gone
import com.sw.dualscreen.ext.load
import com.sw.dualscreen.ext.maskName
import com.sw.dualscreen.ext.roundedDecimalPlace
import com.sw.dualscreen.ext.screenSize
import com.sw.dualscreen.ext.visible
import com.sw.dualscreen.model.response.DinnerType
@@ -66,7 +56,6 @@ 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.viewmodel.RecognizeViewModel
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel.REGISTER_STATUS_READY
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch
import timber.log.Timber
@@ -105,14 +94,14 @@ class MainScreenPresentation(
private var irFaceRectTransformer: FaceRectTransformer? = null
private var detectWeight = 0.0 //识别菜品时的重量
var lastWeight = 0.0 // 上一次的计算热量结果
var lastWeight = 0 // 上一次的计算热量结果
// private var userNutritionData: UserNutritionData? = null
private var userNutrition: UserNutrition? = null
private var dinnerTypeInfo: DinnerType? = null
private val debouncer = Debouncer(500)
private var recognitionTime: Long = 0L // 人脸识别时的时间
var recognitionWeight: Double = 0.0 // 人脸识别时的重量
var recognitionWeight: Int = 0 // 人脸识别时的重量
private var lastFaceTrackId: Int = -1 // 上一次的人脸信息
var mealPickupMode: Int = 0 // 取餐模式 0 即放即取 1 余量取餐
@@ -144,8 +133,8 @@ class MainScreenPresentation(
private var isFirstGetWeight = true
fun updateWeight(weight: Double) {
lastWeight = weight * 1000 // 将千克转成克
fun updateWeight(weight: Int) {
lastWeight = weight
Timber.tag(TAG)
.d("updateWeight lastWeight = $weight, currentStep = $currentStep, isGoStep1 = $isGoStep1")
//0-即放即取,1-余量计量
@@ -164,14 +153,14 @@ class MainScreenPresentation(
// }
// isFirstGetWeight = true
// }
if (currentStep == 2 && lastWeight <= 5 && isGoStep1) {
if (currentStep == 2 && lastWeight <= MainActivity.WEIGHT_RESET_RECOGNIZE && isGoStep1) {
//人脸识别过程中,秤上物品拿走
isGoStep1 = false
activity.runOnUiThread {
Timber.tag(TAG).e("切回step1")
step1FoodRecognizing()
}
} else if (lastWeight <= 5) {
} else if (lastWeight <= MainActivity.WEIGHT_RESET_RECOGNIZE) {
isGoStep1 = false
activity.runOnUiThread {
Timber.tag(TAG).e("切回step1")
@@ -287,6 +276,14 @@ class MainScreenPresentation(
}
}
private fun setTopInfoVisible() {
binding.llTopInfo.visible()
binding.flFoodDetail.gone()
binding.llTopInfo.updateLayoutParams {
height = activity.screenSize[1] / 2 + 120.dp
}
}
/**
* 显示识别出的菜品信息
*/
@@ -297,8 +294,7 @@ class MainScreenPresentation(
currentStep = 3
stepChangeCallback(currentStep)
binding.llTopInfo.visible()
binding.flFoodDetail.gone()
setTopInfoVisible()
//根据接口数据更新热量数据--------------------------
userViewModel.getUserNutritionData(userId = userId) { nutrition ->
activity.runOnUiThread {
@@ -491,6 +487,9 @@ class MainScreenPresentation(
* 餐品识别中
*/
fun step1FoodRecognizing() {
if (currentStep == 1) {
return
}
Timber.tag(TAG).d("main,step1,耗时:${System.currentTimeMillis() - startTime}")
startTime = System.currentTimeMillis()
jointPaymentQueryFinish = false
@@ -505,7 +504,6 @@ class MainScreenPresentation(
// }
// return
//}
currentStep = 1
LightManager.closeGreenLight()
LightManager.closeRedLight()
@@ -513,12 +511,9 @@ class MainScreenPresentation(
currentFood = null
// userNutritionData = null
userNutrition = null
recognitionWeight = 0.0
recognitionWeight = 0
stepChangeCallback(currentStep)
binding.llTopInfo.visible()
binding.flFoodDetail.gone()
setTopInfoVisible()
binding.calorieInclude.root.gone()
binding.nutritionInclude.root.gone()
@@ -537,8 +532,10 @@ class MainScreenPresentation(
binding.flRecognizeIr.gone()
pauseCamera()
activity.clearFoodList()
activity.hideSearchView()
activity.clearRecognizeFood()
currentStep = 1
stepChangeCallback(currentStep)
}
// fun foodRecSuccess(foodInfo: FoodInfo) {
@@ -560,9 +557,14 @@ class MainScreenPresentation(
/**
* 用户人脸识别中
*/
fun step2FaceRecognizing(foodInfo: FoodInfo) {
fun step2FaceRecognizing(foodInfo: FoodInfo, hideFoodDetail: Boolean = false) {
isGoStep1 = true
Timber.tag(TAG).d("main,step2,耗时:${System.currentTimeMillis() - startTime}")
if (hideFoodDetail) {
setTopInfoVisible()
}
startTime = System.currentTimeMillis()
currentStep = 2
LightManager.closeRedLight()
@@ -586,7 +588,7 @@ class MainScreenPresentation(
dinnerTypeInfo = null
// userNutritionData = null
userNutrition = null
recognitionWeight = 0.0
recognitionWeight = 0
stepChangeCallback(currentStep)
currentFood = foodInfo
@@ -668,12 +670,12 @@ class MainScreenPresentation(
// }
}
private fun calculateNutrition(weight1: Double) {
private fun calculateNutrition(value: Int) {
if (currentFood == null || userNutrition == null) {
return
}
var weight = weight1
if (weight < 0) weight = 0.0
var weight = value
if (weight < 0) weight = 0
debouncer.debounce {
Timber.tag(TAG)
.d("calculateNutrition weight = $weight, recognitionWeight = $recognitionWeight")
@@ -684,7 +686,7 @@ class MainScreenPresentation(
currentFood!!,
// userNutritionData!!,
userNutrition!!,
weight,
weight.toDouble(),
dinnerType = dinnerType ?: ""
)
// Timber.tag(TAG).d("calculateNutrition calcResultInfo = $calcResultInfo")
@@ -830,8 +832,23 @@ class MainScreenPresentation(
isRecognition = false
recognizeViewModel.onPreviewFrame(ByteArray(1382400), true)
//triggerReidentify()
}
/**
* 重置人脸跟踪状态,让已在画面中的人脸重新触发识别
* 适用场景:切换按钮后需要重新识别当前画面中的人脸
*/
fun triggerReidentify() {
// 清除UI上的人脸框
binding.dualCameraFaceRectView.clearFaceInfo()
// 清除本地跟踪数据
clearLeftFaceData()
// 重置上一次的 trackId,避免 drawPreviewInfo 中的去重逻辑拦截
lastFaceTrackId = -1
// 插入空帧,让引擎重置内部跟踪状态
// isRecognition 保持 true,相机继续送帧,下一帧真实人脸会产生新 trackId
recognizeViewModel.onPreviewFrame(ByteArray(1382400), true)
}
private var recognizeTime = 0L
private fun initArcViewModel() {
recognizeViewModel.setLiveType(livenessType)
@@ -1187,8 +1204,7 @@ class MainScreenPresentation(
}
createOrder(notEnoughOneBlock = {
if (activity.settlementMode == 0) {
binding.flFoodDetail.gone()
binding.llTopInfo.visible()
setTopInfoVisible()
}
// if (mealPickupMode == 0) {
currentStep = 2
@@ -1249,11 +1265,11 @@ class MainScreenPresentation(
//userViewModel.postUserNutritionData(listOf(userNutritionParam))
activity.createOrder(
foodInfo = currentFood!!,
foodWeight = lastWeight.roundToInt(),
eatWeight = eatWeight.roundToInt(),
eatNum = activity.getEatNum(eatWeight, currentFood!!.specWeight),
foodWeight = lastWeight,
eatWeight = eatWeight,
eatNum = activity.getEatNum(eatWeight.toDouble(), currentFood!!.specWeight),
userId = currentUserId,
isMember = isMember ,
isMember = isMember,
notEnoughOneBlock = notEnoughOneBlock,
successBlock = {
activity.runOnUiThread {
@@ -1316,11 +1332,12 @@ class MainScreenPresentation(
binding.flFoodDetail.visible()
binding.detailInclude.let {
it.root.updateLayoutParams {
height = activity.screenSize[1]/2
height = activity.screenSize[1] / 2 + 120.dp
}
it.tvFoodList.run {
if (adapter == null) {
layoutManager = LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
layoutManager =
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
adapter = foodOrderAdapter
}
}
@@ -1332,10 +1349,36 @@ class MainScreenPresentation(
}
foodOrderAdapter.notifyDataSetChanged()
binding.detailInclude.tvTotalWeight.text = "总重量:${model.eatWeightSum}"
binding.detailInclude.tvTotalCalorie.text = "总热量:${model.calorie.roundToInt()}千卡"
binding.detailInclude.tvTotalCalorie.text =
"总热量:${model.calorie.roundToInt()}千卡"
jointPaymentQueryFinish = true
}
}
}
/**
* 构造符合分辨率的 NV21 格式全黑帧
* @param width 图像宽度(如 1920
* @param height 图像高度(如 1080
* @return 合法的全黑帧字节数组
*/
private fun createBlackNV21Frame(width: Int, height: Int): ByteArray {
val frameSize = width * height
val nv21Data = ByteArray(frameSize * 3 / 2) // NV21 格式长度 = 宽×高×1.5
// Y 分量(亮度)设为 0(全黑),UV 分量设为 128(默认值)
// 1. 填充 Y 分量(前 frameSize 个字节)
// Arrays.fill(nv21Data, 0, frameSize, 0.toByte())
nv21Data.fill(0, 0, frameSize)
// 2. 填充 UV 分量(后 frameSize/2 个字节)
// Arrays.fill(nv21Data, frameSize, nv21Data.size, 128.toByte())
nv21Data.fill(128.toByte(), frameSize, nv21Data.size)
return nv21Data
}
// 调用示例:构造 1920×1080 的全黑帧(长度 1382400
// private val emptyFrame = createBlackNV21Frame(1920, 1080)
private val emptyFrame = createBlackNV21Frame(1280, 720)
}