From 082011a939c0e06b4af0e15a3cd5fccd85242250 Mon Sep 17 00:00:00 2001
From: zxj <275873859@qq.com>
Date: Thu, 24 Jul 2025 08:40:36 +0800
Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BA=86=E9=A4=90=E7=9B=98?=
=?UTF-8?q?=E5=9C=A8=E4=B8=8D=E5=90=8C=E8=AE=BE=E5=A4=87=E6=8F=90=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/src/main/AndroidManifest.xml | 6 +
.../java/com/sw/platecabinet/GlobalData.kt | 4 +-
.../sw/platecabinet/activity/BaseActivity.kt | 5 +-
.../activity/LoginByFaceActivity.kt | 18 +--
.../sw/platecabinet/utils/DateTimeUtils.kt | 7 +
.../sw/platecabinet/utils/PermissionHelper.kt | 4 +-
.../com/sw/platecabinet/utils/ThreadUtils.kt | 124 ++++++++++++++++++
.../viewmodel/SettingViewModel.kt | 23 +++-
.../platecabinet/viewmodel/UserViewModel.kt | 28 ++--
.../main/res/layout/activity_login_face.xml | 5 +-
app/src/main/res/layout/dialog_waiting.xml | 1 +
.../layout/fragment_plate_cabinet_full.xml | 1 +
.../main/res/layout/fragment_plate_open.xml | 1 +
.../main/res/layout/fragment_setting_list.xml | 1 +
.../utils/arcface/FaceRectTransformer.java | 2 +-
.../plate/utils/arcface/face/FaceHelper.java | 1 +
.../utils/arcface/faceserver/FaceServer.java | 2 +-
17 files changed, 198 insertions(+), 35 deletions(-)
create mode 100644 app/src/main/java/com/sw/platecabinet/utils/ThreadUtils.kt
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 12b6289..67ce82d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -8,6 +8,12 @@
+
+
: AppCompatActivity() {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
context = this
- disableSystemUICompletely()
+// disableSystemUICompletely()
// 确保内容延伸到导航栏区域
- WindowCompat.setDecorFitsSystemWindows(window, false)
+// WindowCompat.setDecorFitsSystemWindows(window, false)
binding = inflateViewBinding()
headerBinding = inflateTitleBinding()
diff --git a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt
index 4ee8b93..8f4770a 100644
--- a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt
+++ b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt
@@ -60,8 +60,8 @@ class LoginByFaceActivity : BaseActivity(),
}
override fun initialize() {
- // 请求权限
- checkCameraPermission()
+
+// viewModel.activeEngine()
initArcViewModel()
initArcView()
openRectInfoDraw = true
@@ -88,9 +88,11 @@ class LoginByFaceActivity : BaseActivity(),
}
private fun checkCameraPermission() {
+ Timber.i("checkCameraPermission")
val permissionHelper =
PermissionHelper.with(this, REQUIRED_PERMISSIONS, CAMERA_PERMISSION_REQUEST_CODE)
.onGranted {
+ Timber.d("checkCameraPermission 权限已允许")
// 权限已授予
recognizeViewModel.init()
initRgbCamera()
@@ -175,12 +177,14 @@ class LoginByFaceActivity : BaseActivity(),
/**
- * 调整View的宽高,使2个预览同时显示
+ * 调整View的宽高,使预览显示正常且采集框固定为380x380
*
+ * @param rgbPreview RGB预览View
* @param previewView 显示预览数据的view
- * @param faceRectView 画框的view
+ * @param faceRectView 画框的view (380x380)
* @param previewSize 预览大小
* @param displayOrientation 相机旋转角度
+ * @param scale 缩放比例
* @return 调整后的LayoutParams
*/
private fun adjustPreviewViewSize(
@@ -345,10 +349,8 @@ class LoginByFaceActivity : BaseActivity(),
override fun onGlobalLayout() {
binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this)
- recognizeViewModel.init()
- initRgbCamera()
- resumeCamera()
- // countDownTimer.start();
+ // 请求权限
+ checkCameraPermission()
}
diff --git a/app/src/main/java/com/sw/platecabinet/utils/DateTimeUtils.kt b/app/src/main/java/com/sw/platecabinet/utils/DateTimeUtils.kt
index d8ee539..673eb9d 100644
--- a/app/src/main/java/com/sw/platecabinet/utils/DateTimeUtils.kt
+++ b/app/src/main/java/com/sw/platecabinet/utils/DateTimeUtils.kt
@@ -19,6 +19,13 @@ object DateTimeUtils {
return SimpleDateFormat("yyyy年M月d日 EEEE", Locale.CHINA).format(date)
}
+ /**
+ * 获取标准时间格式
+ */
+ fun getDateTimeString(date: Date = Date()): String {
+ return SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(date)
+ }
+
/**
* 获取带时间的完整中文格式(示例:2025年6月11日 星期三 14:30)
*/
diff --git a/app/src/main/java/com/sw/platecabinet/utils/PermissionHelper.kt b/app/src/main/java/com/sw/platecabinet/utils/PermissionHelper.kt
index a8f635b..13129da 100644
--- a/app/src/main/java/com/sw/platecabinet/utils/PermissionHelper.kt
+++ b/app/src/main/java/com/sw/platecabinet/utils/PermissionHelper.kt
@@ -30,7 +30,7 @@ class PermissionHelper private constructor(
/**
* 检查是否已授予所有权限
*/
- fun areAllPermissionsGranted(context: Context, permissions: Array): Boolean {
+ fun checkPermissions(context: Context, permissions: Array): Boolean {
return permissions.all { permission ->
ContextCompat.checkSelfPermission(
context,
@@ -121,7 +121,7 @@ class PermissionHelper private constructor(
* 检查并请求权限
*/
fun checkAndRequest() {
- if (areAllPermissionsGranted(context, permissions)) {
+ if (checkPermissions(context, permissions)) {
onGranted?.invoke()
} else {
requestPermissions()
diff --git a/app/src/main/java/com/sw/platecabinet/utils/ThreadUtils.kt b/app/src/main/java/com/sw/platecabinet/utils/ThreadUtils.kt
new file mode 100644
index 0000000..9fed1bd
--- /dev/null
+++ b/app/src/main/java/com/sw/platecabinet/utils/ThreadUtils.kt
@@ -0,0 +1,124 @@
+package com.sw.platecabinet.utils
+
+import android.os.Handler
+import android.os.Looper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * 多功能线程工具类
+ * 结合协程、Handler和线程池实现线程切换
+ */
+object ThreadUtils : CoroutineScope {
+ // 主线程Handler
+ private val mainHandler by lazy { Handler(Looper.getMainLooper()) }
+
+ // 后台线程池(IO密集型任务)
+ private val ioThreadPool: ExecutorService by lazy {
+ Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2)
+ }
+
+ // CPU密集型线程池
+ private val cpuThreadPool: ExecutorService by lazy {
+ Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
+ }
+
+ // 协程Job管理
+ private val job = Job()
+
+ override val coroutineContext: CoroutineContext
+ get() = Dispatchers.Main + job
+
+ // ========== Handler相关方法 ==========
+
+ /**
+ * 在主线程执行任务
+ * @param delayMillis 延迟时间(毫秒)
+ */
+ fun runOnUiThread(delayMillis: Long = 0, block: () -> Unit) {
+ if (delayMillis > 0) {
+ mainHandler.postDelayed(block, delayMillis)
+ } else {
+ if (isOnMainThread()) {
+ block()
+ } else {
+ mainHandler.post(block)
+ }
+ }
+ }
+
+ /**
+ * 移除主线程任务
+ */
+ fun removeUiThreadTask(block: () -> Unit) {
+ mainHandler.removeCallbacks(block)
+ }
+
+ // ========== 线程池相关方法 ==========
+
+ /**
+ * 在IO线程执行任务
+ */
+ fun runOnIoThread(block: () -> Unit) {
+ ioThreadPool.execute(block)
+ }
+
+ /**
+ * 在CPU计算线程执行任务
+ */
+ fun runOnCpuThread(block: () -> Unit) {
+ cpuThreadPool.execute(block)
+ }
+
+ // ========== 协程相关方法 ==========
+
+ /**
+ * 启动协程(默认在主线程)
+ */
+ fun launch(block: suspend CoroutineScope.() -> Unit): Job {
+ return launch(coroutineContext, block = block)
+ }
+
+ /**
+ * 在IO线程启动协程
+ */
+ fun launchOnIo(block: suspend CoroutineScope.() -> Unit): Job {
+ return launch(Dispatchers.IO, block = block)
+ }
+
+ /**
+ * 切换到主线程(协程环境)
+ */
+ suspend fun switchToMain(block: suspend CoroutineScope.() -> T): T {
+ return withContext(Dispatchers.Main, block)
+ }
+
+ /**
+ * 切换到IO线程(协程环境)
+ */
+ suspend fun switchToIo(block: suspend CoroutineScope.() -> T): T {
+ return withContext(Dispatchers.IO, block)
+ }
+
+ /**
+ * 是否在主线程
+ */
+ fun isOnMainThread(): Boolean {
+ return Looper.myLooper() == Looper.getMainLooper()
+ }
+
+ /**
+ * 释放资源
+ */
+ fun release() {
+ job.cancel()
+ ioThreadPool.shutdown()
+ cpuThreadPool.shutdown()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/sw/platecabinet/viewmodel/SettingViewModel.kt b/app/src/main/java/com/sw/platecabinet/viewmodel/SettingViewModel.kt
index c31061b..0618be8 100644
--- a/app/src/main/java/com/sw/platecabinet/viewmodel/SettingViewModel.kt
+++ b/app/src/main/java/com/sw/platecabinet/viewmodel/SettingViewModel.kt
@@ -1,5 +1,6 @@
package com.sw.platecabinet.viewmodel
+import com.sw.inbound.utils.DateTimeUtils
import com.sw.plate.utils.ToastUtils
import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.GlobalData.globalEquipmentCode
@@ -43,7 +44,7 @@ class SettingViewModel : BaseViewModel() {
EquipmentParam(appVersion = GlobalData.appVersion, equipmentCode = equipmentCode)
val response = repository.getEquipmentList(param)
if (parseResponse(response)) {
- _equipmentList.value = response.data?.plus(response.data) ?: emptyList()
+ _equipmentList.value = response.data ?: emptyList()
}
}
}
@@ -94,6 +95,13 @@ class SettingViewModel : BaseViewModel() {
)
val response = repository.bindEquipment(bindParam)
if (parseResponse(response)) {
+ val userInfo = response.data
+ userInfo?.let {
+ if (it.isOtherEquipment()) {
+ ToastUtils.showToast("餐盘已在${it.equipmentName}绑定")
+ return@launchWithLoading
+ }
+ }
_bindStateChange.value = true to ErrorInfo()
} else {
_bindStateChange.value = true to ErrorInfo(response.code, response.msg.toString())
@@ -132,15 +140,20 @@ class SettingViewModel : BaseViewModel() {
)
val response = repository.findByPlateNumber(bindParam)
if (response.code == 200) {
- if (response.data?.isOtherEquipment() == true) {
- ToastUtils.showToast("")
- return@launchWithLoading
+ val userInfo = response.data
+ userInfo?.let {
+ if (it.isOtherEquipment()) {
+ ToastUtils.showToast("餐盘已在${it.equipmentName}绑定")
+ return@launchWithLoading
+ }
}
+
_currentUserInfo.value = response.data
} else {
_currentUserInfo.value = EquipmentUserInfo(
plateNumber = plateNumber,
- equipmentCode = equipmentCode
+ equipmentCode = equipmentCode,
+ updateTime = DateTimeUtils.getDateTimeString()
)
}
}
diff --git a/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt b/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt
index b1445fb..6a902e1 100644
--- a/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt
+++ b/app/src/main/java/com/sw/platecabinet/viewmodel/UserViewModel.kt
@@ -13,6 +13,7 @@ import com.sw.platecabinet.GlobalKey
import com.sw.platecabinet.model.request.LoginParam
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.UserFaceModel
+import com.sw.platecabinet.utils.ThreadUtils
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import timber.log.Timber
@@ -63,7 +64,8 @@ class UserViewModel : BaseViewModel() {
/**
* 激活人脸识别引擎
*/
- private fun activeEngine() {
+ fun activeEngine() {
+ Timber.d("activeEngine")
var appId = "Hkz1rBk6PZXbS8KwKr67K2eZtsz8bRoMHLg64bUdgCZj"
var sdkKey = "AabXs3sHM8UhhE7oCGf4LVMLrdkGb1nJNksbjjTdVt7k"
var activeKey = "085F-118G-Q391-53YL"
@@ -75,23 +77,27 @@ class UserViewModel : BaseViewModel() {
object : FaceApi.ActiveCallback {
override fun onSuccess(activeCode: Int) {
Timber.d("activeEngine activeCode = $activeCode")
- when (activeCode) {
- ErrorInfo.MOK -> {
- ToastUtils.showToast("激活引擎成功")
- }
+ ThreadUtils.launch {
+ when (activeCode) {
+ ErrorInfo.MOK -> {
+ ToastUtils.showToast("激活引擎成功")
+ }
- ErrorInfo.MERR_ASF_ALREADY_ACTIVATED -> {
- ToastUtils.showToast("引擎已激活,无需再次激活")
- }
+ ErrorInfo.MERR_ASF_ALREADY_ACTIVATED -> {
+// ToastUtils.showToast("引擎已激活,无需再次激活")
+ }
- else -> {
- ToastUtils.showToast("激活引擎失败($activeCode)")
+ else -> {
+ ToastUtils.showToast("激活引擎失败($activeCode)")
+ }
}
}
}
override fun onFail(e: Exception?) {
- ToastUtils.showToast("激活引擎异常,${e?.message}")
+ ThreadUtils.launch {
+ ToastUtils.showToast("激活引擎异常,${e?.message}")
+ }
}
})
}
diff --git a/app/src/main/res/layout/activity_login_face.xml b/app/src/main/res/layout/activity_login_face.xml
index 8e1dd43..ef23d7b 100644
--- a/app/src/main/res/layout/activity_login_face.xml
+++ b/app/src/main/res/layout/activity_login_face.xml
@@ -5,8 +5,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#14141E"
- android:orientation="vertical"
android:fitsSystemWindows="false"
+ android:orientation="vertical"
tools:context=".activity.LoginByFaceActivity">
+ android:layout_height="match_parent"
+ android:layout_margin="10dp" />
diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceRectTransformer.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceRectTransformer.java
index f1c7295..58c9d5d 100644
--- a/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceRectTransformer.java
+++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/FaceRectTransformer.java
@@ -77,7 +77,7 @@ public class FaceRectTransformer {
rect.bottom *= verticalRatio;
Rect newRect = new Rect();
- L.e("cameraDisplayOrientation" + cameraDisplayOrientation + "===" + cameraId);
+ L.e("cameraDisplayOrientation " + cameraDisplayOrientation + " === " + cameraId);
switch (cameraDisplayOrientation) {
case 0:
if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java
index bf51353..3f78375 100644
--- a/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java
+++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/face/FaceHelper.java
@@ -610,6 +610,7 @@ public class FaceHelper implements FaceListener {
@Override
public void onError(Throwable e) {
+ Log.e(TAG, "retryRecognizeDelayed e = " + e);
e.printStackTrace();
}
diff --git a/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java b/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java
index 7baf8e7..e414751 100644
--- a/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java
+++ b/lib_face/src/main/java/com/sw/plate/utils/arcface/faceserver/FaceServer.java
@@ -584,7 +584,7 @@ public class FaceServer {
}
}
} catch (IllegalArgumentException exception) {
- Log.i(TAG, "exception:" + exception.getMessage());
+ Log.i(TAG, "searchFaceFeature exception:" + exception.getMessage());
}
return null;
}