This commit is contained in:
2026-02-05 15:06:00 +08:00
parent e5940605c1
commit dcfb684b66
11 changed files with 2376 additions and 626 deletions
@@ -9,6 +9,10 @@ class InitActivity : BaseActivity<ActivityInitBinding>() {
override fun initialize() {
super.initialize()
binding.btnStart.setOnClickListener {
finish()
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -16,6 +16,8 @@ import com.sw.face.collect.databinding.DialogWaitingBinding
import com.sw.face.collect.view.CustomDialog
import com.sw.face.collect.R
import com.sw.face.collect.model.IActivityResult
import com.sw.face.collect.utils.PermissionHelper
import kotlin.collections.set
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
@@ -51,6 +53,14 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
}
private val permissionHelpers = mutableMapOf<Int, PermissionHelper>()
/**
* 注册PermissionHelper以便处理结果
*/
fun registerPermissionHelper(helper: PermissionHelper) {
permissionHelpers[helper.requestCode] = helper
}
/**
* 显示等待提示框
@@ -250,3 +250,4 @@ fun String.copyText(context: Context, showToast: Boolean = true) {
Toast.makeText(context, "文本已复制到剪贴板", Toast.LENGTH_SHORT).show()
}
}
@@ -0,0 +1,159 @@
package com.sw.face.collect.utils
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.provider.Settings
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import kotlin.apply
import kotlin.collections.all
import kotlin.collections.any
import kotlin.collections.forEachIndexed
class PermissionHelper private constructor(
private val context: Context,
private val permissions: Array<String>,
internal val requestCode: Int,
private val rationale: String? = null,
private val onGranted: (() -> Unit)?
) {
companion object {
/**
* 创建权限请求构建器
*/
fun with(context: Context, permissions: Array<String>, requestCode: Int): Builder {
return Builder(context, permissions, requestCode)
}
/**
* 检查是否已授予所有权限
*/
fun checkPermissions(context: Context, permissions: Array<String>): Boolean {
return permissions.all { permission ->
ContextCompat.checkSelfPermission(
context,
permission
) == PackageManager.PERMISSION_GRANTED
}
}
/**
* 处理权限请求结果(供BaseActivity/BaseFragment调用)
* @return 是否所有权限都已授予
*/
fun handlePermissionResult(
context: Context,
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray,
permissionHelper: PermissionHelper? = null
): Boolean {
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
permissionHelper?.onGranted?.invoke()
return true
}
val permanentlyDeniedPermissions = mutableListOf<String>()
permissions.forEachIndexed { index, permission ->
if (grantResults[index] != PackageManager.PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(
context as Activity,
permission
)
) {
permanentlyDeniedPermissions.add(permission)
}
}
}
return false
}
/**
* 跳转到应用设置页面
*/
fun openAppSettings(context: Context) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", context.packageName, null)
}
if (context is Activity) {
context.startActivity(intent)
} else if (context is Fragment) {
context.startActivity(intent)
}
}
}
class Builder(
private val context: Context,
private val permissions: Array<String>,
private val requestCode: Int
) {
private var rationale: String? = null
private var onGranted: (() -> Unit)? = null
/**
* 设置权限说明
*/
fun setRationale(rationale: String): Builder {
this.rationale = rationale
return this
}
/**
* 设置权限授予回调
*/
fun onGranted(callback: () -> Unit): Builder {
this.onGranted = callback
return this
}
/**
* 构建PermissionHelper实例
*/
fun build(): PermissionHelper {
return PermissionHelper(context, permissions, requestCode, rationale, onGranted)
}
}
/**
* 检查并请求权限
*/
fun checkAndRequest() {
if (checkPermissions(context, permissions)) {
onGranted?.invoke()
} else {
requestPermissions()
}
}
private fun requestPermissions() {
val activity = context as? Activity ?: return
val shouldShowRationale = permissions.any { permission ->
ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
}
if (shouldShowRationale && rationale != null) {
AlertDialog.Builder(activity)
.setTitle("权限说明")
.setMessage(rationale)
.setPositiveButton("确定") { _, _ ->
doRequestPermissions(activity)
}
.setNegativeButton("取消", null)
.show()
} else {
doRequestPermissions(activity)
}
}
private fun doRequestPermissions(activity: Activity) {
ActivityCompat.requestPermissions(activity, permissions, requestCode)
}
}
+3 -1
View File
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
@@ -23,7 +25,7 @@
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnCollectFace"
android:id="@+id/btnStart"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_margin="20dp"
+59 -19
View File
@@ -100,7 +100,7 @@
android:visibility="visible" />
<TextView
android:id="@+id/tvCountDown"
android:id="@+id/tvToInit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -111,6 +111,46 @@
android:visibility="visible"
tools:text="30s" />
<LinearLayout
android:id="@+id/llCollectButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_gravity="bottom|center_horizontal"
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/bg_collect_btn"
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/bg_collect_btn"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:id="@+id/layoutState"
android:layout_width="wrap_content"
@@ -135,26 +175,26 @@
android:textSize="26sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnCollectFace"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_margin="20dp"
android:background="@drawable/bg_collect_btn"
android:text="开始采集"
android:textColor="@color/white"
android:textSize="40sp"
android:textStyle="normal" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnCollectFace"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_margin="20dp"
android:background="@drawable/bg_collect_btn"
android:text="开始采集"
android:textColor="@color/white"
android:textSize="40sp"
android:textStyle="normal" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_collect_shape"
tools:context=".MainActivity">
<!-- <ImageView-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:src="@drawable/bg_collect_shape"/>-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="50dp"
android:gravity="center"
android:text="人脸采集"
android:textColor="@color/white"
android:textSize="40sp"
android:textStyle="bold" />
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="1dp"
app:dividerColor="#3391CEFF" />
<TextView
android:id="@+id/tvSimilarValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:textColor="@color/white"
android:layout_marginTop="20dp"
android:textSize="30sp"
android:textStyle="bold"
android:visibility="visible"
tools:text="1.0" />
<TextView
android:id="@+id/tvFaceTip"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="center"
android:gravity="center_vertical"
android:text="请正视屏幕"
android:textColor="@color/white"
android:textSize="26sp"
android:textStyle="bold"
android:visibility="visible" />
<TextView
android:id="@+id/tvToInit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold"
android:visibility="visible"
tools:text="30s" />
<!-- android:layout_width="640dp"-->
<FrameLayout
android:id="@+id/flCameraView"
android:layout_width="852dp"
android:layout_height="480dp"
android:layout_gravity="center_horizontal"
android:layout_marginVertical="50dp"
android:visibility="visible">
<androidx.cardview.widget.CardView
android:id="@+id/flFace"
android:layout_width="640dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<TextureView
android:id="@+id/dual_camera_texture_preview_rgb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
<com.sw.plate.utils.arcface.FaceRectView
android:id="@+id/dual_camera_face_rect_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.cardview.widget.CardView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:src="@drawable/bg_face_wrap3"
android:visibility="visible" />
</FrameLayout>
<LinearLayout
android:id="@+id/layoutState"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<ProgressBar
android:id="@+id/pbCollectLoading"
android:layout_width="36dp"
android:layout_height="36dp"
android:indeterminateTint="@color/white" />
<TextView
android:id="@+id/tvCollectState"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="采集中......"
android:textColor="@color/white"
android:textSize="26sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnCollectFace"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_margin="20dp"
android:background="@drawable/bg_collect_btn"
android:text="开始采集"
android:textColor="@color/white"
android:textSize="40sp"
android:textStyle="normal" />
</LinearLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/flRecognizeIr"
android:layout_width="4dp"
android:layout_height="3dp"
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>
@@ -0,0 +1,178 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_collect_shape"
tools:context=".MainActivity">
<!-- <ImageView-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:src="@drawable/bg_collect_shape"/>-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="50dp"
android:gravity="center"
android:text="人脸采集"
android:textColor="@color/white"
android:textSize="40sp"
android:textStyle="bold" />
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="1dp"
app:dividerColor="#3391CEFF" />
<!-- android:layout_width="640dp"-->
<FrameLayout
android:id="@+id/flCameraView"
android:layout_width="852dp"
android:layout_height="480dp"
android:layout_gravity="center_horizontal"
android:layout_marginVertical="50dp"
android:visibility="visible">
<androidx.cardview.widget.CardView
android:id="@+id/flFace"
android:layout_width="640dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<TextureView
android:id="@+id/dual_camera_texture_preview_rgb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
<com.sw.plate.utils.arcface.FaceRectView
android:id="@+id/dual_camera_face_rect_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.cardview.widget.CardView>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:src="@drawable/bg_face_wrap3"
android:visibility="visible" />
</FrameLayout>
<TextView
android:id="@+id/tvSimilarValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold"
android:visibility="visible"
tools:text="1.0" />
<TextView
android:id="@+id/tvFaceTip"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="center"
android:gravity="center_vertical"
android:text="请正视摄像头,保持面部居中于取景框内"
android:textColor="@color/white"
android:textSize="26sp"
android:textStyle="bold"
android:visibility="visible" />
<TextView
android:id="@+id/tvCountDown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_vertical"
android:textColor="@color/white"
android:textSize="60sp"
android:textStyle="bold"
android:visibility="visible"
tools:text="30s" />
<LinearLayout
android:id="@+id/layoutState"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<ProgressBar
android:id="@+id/pbCollectLoading"
android:layout_width="36dp"
android:layout_height="36dp"
android:indeterminateTint="@color/white" />
<TextView
android:id="@+id/tvCollectState"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="采集中......"
android:textColor="@color/white"
android:textSize="26sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnCollectFace"
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_margin="20dp"
android:background="@drawable/bg_collect_btn"
android:text="开始采集"
android:textColor="@color/white"
android:textSize="40sp"
android:textStyle="normal" />
</LinearLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/flRecognizeIr"
android:layout_width="4dp"
android:layout_height="3dp"
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>
@@ -16,6 +16,10 @@ public class CompareResult {
this.similarPass = similarPass;
}
public boolean isSimilarPass() {
return similarPass;
}
public CompareResult(FaceEntity faceEntity, float similar) {
this.faceEntity = faceEntity;
this.similar = similar;