diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 6c74be6..5203b9e 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -48,7 +48,14 @@ dependencies {
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
- implementation("com.squareup.okhttp3:okhttp:4.12.0")
- // 可选:协程扩展支持
- implementation("com.squareup.okhttp3:okhttp-coroutines:4.12.0")
+
+
+ // CameraX 用于相机预览
+ implementation("androidx.camera:camera-camera2:1.3.0")
+ implementation("androidx.camera:camera-lifecycle:1.3.0")
+ implementation("androidx.camera:camera-view:1.3.0")
+ // Google ML Kit 人脸检测
+ implementation("com.google.mlkit:face-detection:16.1.5")
+ // 图形绘制库(绘制人脸框)
+ implementation("com.github.bumptech.glide:glide:4.15.1")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4b7d2ba..5ca0a3c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,12 @@
+
+
+
+
-
-
@@ -26,6 +26,25 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt b/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt
index 999f9b3..6b49f2d 100644
--- a/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/home/HomeActivity.kt
@@ -5,17 +5,75 @@ import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
+import androidx.fragment.app.Fragment
import com.example.defenseapplication.R
+import com.example.defenseapplication.databinding.HomeActivityBinding
+import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
class HomeActivity : AppCompatActivity() {
+ // ViewBinding 核心对象
+ private lateinit var binding: HomeActivityBinding
+
+ // 定义两个 Fragment
+ private val homeMenuFragment = HomeMenuFragment()
+ private val personalFragment = PersonalFragment()
+
+ // 当前显示的 Fragment
+ private var currentFragment: Fragment = homeMenuFragment
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContentView(R.layout.home_activity)
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
- val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
- insets
+
+ // 初始化 ViewBinding
+ binding = HomeActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ // 默认显示首页
+ switchFragment(homeMenuFragment)
+ // 第一次加载,只 add 首页
+ supportFragmentManager.beginTransaction()
+ .add(R.id.fragment_container, homeMenuFragment)
+ .commit()
+ // ========== 首页点击 ==========
+ binding.tabHome.setOnClickListener {
+ switchFragment(homeMenuFragment)
+ // 切换图标 + 文字颜色
+ binding.ivHome.setImageResource(R.drawable.home_checked)
+ binding.tvHome.setTextColor(resources.getColor(R.color.ic_selected))
+
+ binding.ivProfile.setImageResource(R.drawable.profile)
+ binding.tvProfile.setTextColor(resources.getColor(R.color.ic_normal))
+ }
+
+ // ========== 个人点击 ==========
+ binding.tabProfile.setOnClickListener {
+ switchFragment(personalFragment)
+ // 切换图标 + 文字颜色
+ binding.ivHome.setImageResource(R.drawable.home)
+ binding.tvHome.setTextColor(resources.getColor(R.color.ic_normal))
+
+ binding.ivProfile.setImageResource(R.drawable.profile_checked)
+ binding.tvProfile.setTextColor(resources.getColor(R.color.ic_selected))
}
}
+
+ /**
+ * 切换 Fragment 的方法
+ */
+ private fun switchFragment(fragment: Fragment) {
+ if (currentFragment == fragment) return
+
+ val transaction = supportFragmentManager.beginTransaction()
+
+ // 如果没添加过,才 add
+ if (!fragment.isAdded) {
+ transaction.add(R.id.fragment_container, fragment)
+ }
+
+ // 隐藏当前,显示目标
+ transaction.hide(currentFragment)
+ transaction.show(fragment)
+ transaction.commit()
+
+ currentFragment = fragment
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt b/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt
index 48df419..88e5b3a 100644
--- a/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt
+++ b/app/src/main/java/com/example/defenseapplication/home/HomeMenuFragment.kt
@@ -6,55 +6,24 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.defenseapplication.R
+import com.example.defenseapplication.databinding.HomeMenuFragmentBinding
-// TODO: Rename parameter arguments, choose names that match
-// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
-private const val ARG_PARAM1 = "param1"
-private const val ARG_PARAM2 = "param2"
-
-/**
- * A simple [Fragment] subclass.
- * Use the [HomeMenuFragment.newInstance] factory method to
- * create an instance of this fragment.
- */
class HomeMenuFragment : Fragment() {
- // TODO: Rename and change types of parameters
- private var param1: String? = null
- private var param2: String? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- arguments?.let {
- param1 = it.getString(ARG_PARAM1)
- param2 = it.getString(ARG_PARAM2)
- }
- }
+ // ViewBinding
+ private var _binding: HomeMenuFragmentBinding? = null
+ private val binding get() = _binding!!
override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
+ inflater: LayoutInflater,
+ container: ViewGroup?,
savedInstanceState: Bundle?
- ): View? {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.home_menu_fragment, container, false)
+ ): View {
+ _binding = HomeMenuFragmentBinding.inflate(inflater, container, false)
+ return binding.root
}
- companion object {
- /**
- * Use this factory method to create a new instance of
- * this fragment using the provided parameters.
- *
- * @param param1 Parameter 1.
- * @param param2 Parameter 2.
- * @return A new instance of fragment HomeMenuFragment.
- */
- // TODO: Rename and change types and number of parameters
- @JvmStatic
- fun newInstance(param1: String, param2: String) =
- HomeMenuFragment().apply {
- arguments = Bundle().apply {
- putString(ARG_PARAM1, param1)
- putString(ARG_PARAM2, param2)
- }
- }
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null // 避免内存泄漏
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt b/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt
index ff2b8db..94415df 100644
--- a/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt
+++ b/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt
@@ -6,55 +6,24 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.defenseapplication.R
+import com.example.defenseapplication.databinding.PersonalFragmentBinding
-// TODO: Rename parameter arguments, choose names that match
-// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
-private const val ARG_PARAM1 = "param1"
-private const val ARG_PARAM2 = "param2"
-
-/**
- * A simple [Fragment] subclass.
- * Use the [PersonalFragment.newInstance] factory method to
- * create an instance of this fragment.
- */
class PersonalFragment : Fragment() {
- // TODO: Rename and change types of parameters
- private var param1: String? = null
- private var param2: String? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- arguments?.let {
- param1 = it.getString(ARG_PARAM1)
- param2 = it.getString(ARG_PARAM2)
- }
- }
+ // ViewBinding
+ private var _binding: PersonalFragmentBinding? = null
+ private val binding get() = _binding!!
override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
+ inflater: LayoutInflater,
+ container: ViewGroup?,
savedInstanceState: Bundle?
- ): View? {
- // Inflate the layout for this fragment
- return inflater.inflate(R.layout.personal_fragment, container, false)
+ ): View {
+ _binding = PersonalFragmentBinding.inflate(inflater, container, false)
+ return binding.root
}
- companion object {
- /**
- * Use this factory method to create a new instance of
- * this fragment using the provided parameters.
- *
- * @param param1 Parameter 1.
- * @param param2 Parameter 2.
- * @return A new instance of fragment PersonalFragment.
- */
- // TODO: Rename and change types and number of parameters
- @JvmStatic
- fun newInstance(param1: String, param2: String) =
- PersonalFragment().apply {
- arguments = Bundle().apply {
- putString(ARG_PARAM1, param1)
- putString(ARG_PARAM2, param2)
- }
- }
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null // 避免内存泄漏
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt b/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt
index a407e76..6932a27 100644
--- a/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/login/FaceLoginActivity.kt
@@ -1,21 +1,39 @@
package com.example.defenseapplication.login
+import android.content.Intent
import android.os.Bundle
+import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
+import com.example.defenseapplication.databinding.FaceLoginActivityBinding
class FaceLoginActivity : AppCompatActivity() {
+
+ private lateinit var binding: FaceLoginActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContentView(R.layout.face_login_activity)
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
- val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
- insets
+ binding = FaceLoginActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ setupListeners()
+ }
+
+ private fun setupListeners() {
+ // 返回按钮
+ binding.backIcon.setOnClickListener {
+ finish()
+ }
+
+ // 继续按钮
+ binding.btnStartVerification.setOnClickListener {
+ val intent= Intent(this, FaceVerificationActivity::class.java)
+ startActivity(intent)
+ Toast.makeText(this, "跳转到人脸识别页面", Toast.LENGTH_SHORT).show()
+
+
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/login/FaceVerificationActivity.kt b/app/src/main/java/com/example/defenseapplication/login/FaceVerificationActivity.kt
index 79bc325..4584335 100644
--- a/app/src/main/java/com/example/defenseapplication/login/FaceVerificationActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/login/FaceVerificationActivity.kt
@@ -1,21 +1,110 @@
package com.example.defenseapplication.login
+import android.Manifest
+import android.content.pm.PackageManager
import android.os.Bundle
-import androidx.activity.enableEdgeToEdge
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowInsetsCompat
-import com.example.defenseapplication.R
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageAnalysis
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import com.example.defenseapplication.databinding.FaceVerificationActivityBinding
+import com.example.defenseapplication.view.FaceAnalyzer
+import com.google.mlkit.vision.face.FaceDetection
+import com.google.mlkit.vision.face.FaceDetectorOptions
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
class FaceVerificationActivity : AppCompatActivity() {
+
+ private lateinit var binding: FaceVerificationActivityBinding
+ private lateinit var cameraExecutor: ExecutorService
+ private var faceDetector: com.google.mlkit.vision.face.FaceDetector? = null
+
+ companion object {
+ private const val REQUEST_CAMERA_PERMISSION = 100
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContentView(R.layout.face_verification_activity)
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
- val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
- insets
+ // 使用标准 ViewBinding
+ binding = FaceVerificationActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ // 初始化人脸检测器(选项可自行调整)
+ val options = FaceDetectorOptions.Builder()
+ .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
+ .setContourMode(FaceDetectorOptions.CONTOUR_MODE_NONE)
+ .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_NONE)
+ .build()
+ faceDetector = FaceDetection.getClient(options)
+
+ cameraExecutor = Executors.newSingleThreadExecutor()
+
+ // 检查并请求权限
+ checkCameraPermissionAndStart()
+ }
+
+ private fun checkCameraPermissionAndStart() {
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
+ == PackageManager.PERMISSION_GRANTED) {
+ startCamera()
+ } else {
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.CAMERA),
+ REQUEST_CAMERA_PERMISSION
+ )
}
}
+
+ private fun startCamera() {
+ val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
+ cameraProviderFuture.addListener({
+ val cameraProvider = cameraProviderFuture.get()
+
+ // 预览用例
+ val preview = Preview.Builder().build().also {
+ it.setSurfaceProvider(binding.previewView.surfaceProvider)
+ }
+
+ // 分析用例(人脸检测)
+ val imageAnalysis = ImageAnalysis.Builder()
+ .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
+ .build()
+ imageAnalysis.setAnalyzer(cameraExecutor, FaceAnalyzer(faceDetector, binding.overlay))
+
+ // 选择后置摄像头
+ val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+ // 绑定到生命周期
+ cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis)
+
+ }, ContextCompat.getMainExecutor(this))
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == REQUEST_CAMERA_PERMISSION) {
+ if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ startCamera()
+ } else {
+ Toast.makeText(this, "需要相机权限才能进行人脸验证", Toast.LENGTH_SHORT).show()
+ finish()
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ cameraExecutor.shutdown()
+ faceDetector?.close()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/login/ForgetPasswordActivity.kt b/app/src/main/java/com/example/defenseapplication/login/ForgetPasswordActivity.kt
index d49b835..49cd003 100644
--- a/app/src/main/java/com/example/defenseapplication/login/ForgetPasswordActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/login/ForgetPasswordActivity.kt
@@ -12,7 +12,6 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ForgetPasswordActivityBinding
-import com.example.defenseapplication.okhttp.OkHttpClientManager
import java.util.regex.Pattern
import kotlin.random.Random
@@ -79,20 +78,6 @@ class ForgetPasswordActivity : AppCompatActivity() {
isSendingCode = true
binding.sendCodeBtn.isEnabled = false
- OkHttpClientManager.postForm(
- url = "https://httpbin.org/post",
- params = mapOf("phone" to phoneNumber)
- ) { result ->
- result.onSuccess {
- verifyCode = (100000 + Random.nextInt(900000)).toString()
- startCountDown()
- Toast.makeText(this, "验证码已发送(演示码:$verifyCode)", Toast.LENGTH_SHORT).show()
- }.onFailure {
- Toast.makeText(this@ForgetPasswordActivity, "发送失败,请重试", Toast.LENGTH_SHORT).show()
- resetSendButton()
- }
- isSendingCode = false
- }
}
/**
@@ -181,20 +166,7 @@ class ForgetPasswordActivity : AppCompatActivity() {
}
""".trimIndent()
- OkHttpClientManager.postJson(
- url = "https://httpbin.org/post",
- json = requestJson
- ) { result ->
- result.onSuccess {
- Toast.makeText(this, "密码重置成功,请重新登录", Toast.LENGTH_LONG).show()
- finish()
- }.onFailure {
- Toast.makeText(this, "网络异常,请重试", Toast.LENGTH_SHORT).show()
- }
- binding.btnNext.isEnabled = true
- binding.btnNext.text = "确定"
- }
}
override fun onDestroy() {
diff --git a/app/src/main/java/com/example/defenseapplication/login/RegisterActivity.kt b/app/src/main/java/com/example/defenseapplication/login/RegisterActivity.kt
index 5556164..038e9a6 100644
--- a/app/src/main/java/com/example/defenseapplication/login/RegisterActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/login/RegisterActivity.kt
@@ -1,6 +1,8 @@
package com.example.defenseapplication.login
+import android.content.Intent
import android.os.Bundle
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.RegisterActivityBinding
@@ -31,6 +33,9 @@ class RegisterActivity : AppCompatActivity() {
// 下一步按钮
binding.btnNext.setOnClickListener {
if (!isLoading) {
+ val intent= Intent(this, FaceLoginActivity::class.java)
+ startActivity(intent)
+ Toast.makeText(this, "跳转到人脸页面", Toast.LENGTH_SHORT).show()
//performRegistration()
}
}
diff --git a/app/src/main/java/com/example/defenseapplication/login/RegisterSuccessActivity.kt b/app/src/main/java/com/example/defenseapplication/login/RegisterSuccessActivity.kt
index 0b04e1d..144840a 100644
--- a/app/src/main/java/com/example/defenseapplication/login/RegisterSuccessActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/login/RegisterSuccessActivity.kt
@@ -1,21 +1,63 @@
package com.example.defenseapplication.login
+import android.content.Intent
import android.os.Bundle
+import android.os.CountDownTimer
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.example.defenseapplication.R
+import com.example.defenseapplication.databinding.RegisterSuccessActivityBinding
+import com.example.defenseapplication.home.HomeActivity
class RegisterSuccessActivity : AppCompatActivity() {
+
+ private lateinit var binding: RegisterSuccessActivityBinding
+ private var countDownTimer: CountDownTimer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContentView(R.layout.register_success_activity)
- ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
- val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
- v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
- insets
+ binding = RegisterSuccessActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ // 返回按钮
+ binding.backIcon.setOnClickListener {
+ finish()
}
+ // 点击按钮:取消倒计时并立即跳转
+ binding.btnEnter.setOnClickListener {
+ cancelTimer()
+ jumpToPlatform()
+ }
+ // 启动3秒倒计时,自动跳转
+ startAutoJumpTimer()
+ }
+
+ private fun startAutoJumpTimer() {
+ countDownTimer = object : CountDownTimer(3000L, 1000L) {
+ override fun onTick(millisUntilFinished: Long) {
+ val seconds = (millisUntilFinished / 1000).toInt()
+ binding.btnEnter.text = "进入平台(${seconds}S)"
+ }
+
+ override fun onFinish() {
+ binding.btnEnter.text = "进入平台(0S)"
+ jumpToPlatform()
+ }
+ }.start()
+ }
+
+ private fun cancelTimer() {
+ countDownTimer?.cancel()
+ countDownTimer = null
+ }
+
+ private fun jumpToPlatform() {
+ startActivity(Intent(this, HomeActivity::class.java))
+ finish()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ cancelTimer()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/view/FaceAnalyzer.kt b/app/src/main/java/com/example/defenseapplication/view/FaceAnalyzer.kt
index 167987b..d64d385 100644
--- a/app/src/main/java/com/example/defenseapplication/view/FaceAnalyzer.kt
+++ b/app/src/main/java/com/example/defenseapplication/view/FaceAnalyzer.kt
@@ -1,4 +1,44 @@
package com.example.defenseapplication.view
-class FaceAnalyzer {
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import androidx.camera.core.ExperimentalGetImage
+import androidx.camera.core.ImageAnalysis
+import androidx.camera.core.ImageProxy
+import com.google.mlkit.vision.common.InputImage
+import com.google.mlkit.vision.face.FaceDetector
+/*
+* 人脸分析器
+* */
+@ExperimentalGetImage
+class FaceAnalyzer(
+ private val detector: FaceDetector?,
+ private val overlayView: FaceOverlayView
+) : ImageAnalysis.Analyzer {
+
+ override fun analyze(imageProxy: ImageProxy) {
+ if (detector == null) {
+ imageProxy.close()
+ return
+ }
+ val mediaImage = imageProxy.image ?: run {
+ imageProxy.close()
+ return
+ }
+ val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
+
+ detector.process(image)
+ .addOnSuccessListener { faces ->
+ Handler(Looper.getMainLooper()).post {
+ overlayView.setFaces(faces)
+ }
+ }
+ .addOnFailureListener { e ->
+ Log.e("FaceAnalyzer", "人脸检测失败", e)
+ }
+ .addOnCompleteListener {
+ imageProxy.close()
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt b/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt
index 8f7c0f9..d894c7d 100644
--- a/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt
+++ b/app/src/main/java/com/example/defenseapplication/view/FaceOverlayView.kt
@@ -1,2 +1,36 @@
package com.example.defenseapplication.view
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+import com.google.mlkit.vision.face.Face
+
+class FaceOverlayView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
+ private val paint = Paint().apply {
+ color = Color.GREEN
+ style = Paint.Style.STROKE
+ strokeWidth = 4f
+ }
+ private val textPaint = Paint().apply {
+ color = Color.YELLOW
+ textSize = 40f
+ }
+ private var faces = mutableListOf()
+
+ fun setFaces(faces: List) {
+ this.faces = faces.toMutableList()
+ invalidate() // 触发 onDraw
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ for (face in faces) {
+ val rect = face.boundingBox
+ canvas.drawRect(rect, paint)
+ canvas.drawText("Face", rect.left.toFloat(), rect.top - 10f, textPaint)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/face_login_gray_bg.xml b/app/src/main/res/drawable/face_login_gray_bg.xml
index 6dbb0ba..75474a3 100644
--- a/app/src/main/res/drawable/face_login_gray_bg.xml
+++ b/app/src/main/res/drawable/face_login_gray_bg.xml
@@ -1,6 +1,6 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
index ae83cfa..5f67492 100644
--- a/app/src/main/res/layout/activity_login.xml
+++ b/app/src/main/res/layout/activity_login.xml
@@ -25,7 +25,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="智能防御机"
- android:textSize="28sp"
+ android:textSize="26dp"
android:textStyle="bold"
android:textColor="@color/black"
app:layout_constraintTop_toBottomOf="@id/logoFrame"
@@ -86,8 +86,8 @@
android:paddingEnd="16dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/face_verification_activity.xml b/app/src/main/res/layout/face_verification_activity.xml
index b07ec1a..af7d02a 100644
--- a/app/src/main/res/layout/face_verification_activity.xml
+++ b/app/src/main/res/layout/face_verification_activity.xml
@@ -7,4 +7,14 @@
android:layout_height="match_parent"
tools:context=".login.FaceVerificationActivity">
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/forget_password_activity.xml b/app/src/main/res/layout/forget_password_activity.xml
index 4ade768..dd30e22 100644
--- a/app/src/main/res/layout/forget_password_activity.xml
+++ b/app/src/main/res/layout/forget_password_activity.xml
@@ -20,8 +20,8 @@
android:paddingEnd="16dp">
@@ -214,8 +214,8 @@
diff --git a/app/src/main/res/layout/home_activity.xml b/app/src/main/res/layout/home_activity.xml
index d27c75c..72ae279 100644
--- a/app/src/main/res/layout/home_activity.xml
+++ b/app/src/main/res/layout/home_activity.xml
@@ -7,4 +7,73 @@
android:layout_height="match_parent"
tools:context=".home.HomeActivity">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/home_menu_fragment.xml b/app/src/main/res/layout/home_menu_fragment.xml
index c494a26..2acd362 100644
--- a/app/src/main/res/layout/home_menu_fragment.xml
+++ b/app/src/main/res/layout/home_menu_fragment.xml
@@ -1,14 +1,13 @@
-
-
-
-
\ No newline at end of file
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="首页 Fragment"
+ android:textSize="20sp"/>
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/personal_fragment.xml b/app/src/main/res/layout/personal_fragment.xml
index e6b85bd..9cee5d9 100644
--- a/app/src/main/res/layout/personal_fragment.xml
+++ b/app/src/main/res/layout/personal_fragment.xml
@@ -1,14 +1,14 @@
-
-
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="个人 Fragment"
+ android:textSize="20sp"/>
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/register_activity.xml b/app/src/main/res/layout/register_activity.xml
index 364cffb..775dc2e 100644
--- a/app/src/main/res/layout/register_activity.xml
+++ b/app/src/main/res/layout/register_activity.xml
@@ -20,8 +20,8 @@
android:paddingEnd="16dp">
+ app:layout_constraintTop_toTopOf="@id/backIcon"
+ app:layout_constraintVertical_bias="0.518" />
@@ -49,7 +50,7 @@
android:layout_height="wrap_content"
android:text="注册用户"
android:textColor="@color/black"
- android:textSize="20dp"
+ android:textSize="24dp"
android:textStyle="bold"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
@@ -71,8 +72,8 @@
+xmlns:app="http://schemas.android.com/apk/res-auto"
+xmlns:tools="http://schemas.android.com/tools"
+android:background="@color/login_background"
+android:id="@+id/main"
+android:padding="16dp"
+android:layout_width="match_parent"
+android:layout_height="match_parent"
+tools:context=".login.RegisterSuccessActivity">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 93a63ad..8109c71 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -6,5 +6,9 @@
#999999
#EDF4FF
#E34D59
+ #666666
+ #F0F0F0
+ #000000
+ #999999
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 55b8f47..591fafc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,5 @@
DefenseApplication
+
+ Hello blank fragment
\ No newline at end of file