实现了双屏摄像头显示,添加了部分代码

This commit is contained in:
zxj
2025-07-31 11:40:56 +08:00
parent 56e0a85a4c
commit de4c5f1c75
86 changed files with 3446 additions and 809 deletions
@@ -6,10 +6,14 @@ import android.hardware.display.DisplayManager
import android.os.Bundle
import android.view.View
import android.view.ViewOutlineProvider
import android.widget.AdapterView
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
@@ -17,14 +21,23 @@ import com.google.common.util.concurrent.ListenableFuture
import com.sw.dualscreen.databinding.ActivityMainBinding
import com.sw.dualscreen.ext.dp
import com.sw.dualscreen.presentation.SecondaryScreenPresentation
import com.sw.dualscreen.viewmodel.MyViewModel
import com.sw.dualscreen.view.CustomBottomSheetDialog
import com.sw.dualscreen.viewmodel.UserViewModel
import com.sw.plate.utils.AppUtil
import com.sw.plate.utils.ToastUtils
import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel
import timber.log.Timber
import java.io.File
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
private val viewModel = MyViewModel()
private val viewModel by viewModels<UserViewModel>()
private lateinit var imageCapture: ImageCapture
private var isAnalyzing = true // 控制是否进行图像分析
private lateinit var presentation: SecondaryScreenPresentation
private val executor = Executors.newSingleThreadExecutor()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -32,51 +45,136 @@ class MainActivity : AppCompatActivity() {
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.main)
Timber.d("UDID = ${AppUtil.getUDID(this)}")
initView()
startCamera()
setupSecondaryDisplay()
setupCamera()
initData()
}
private fun initData() {
viewModel.getEquipmentToken()
}
private fun initView() {
viewModel.activeEngine()
binding.previewView.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
// outline.setRoundRect(0, 0, view.width, view.height, 12f.dp)
outline.setRoundRect(0, 0, view.width, view.height, 280f.dp)
outline.setRoundRect(0, 0, view.width, view.height, 12f.dp)
}
}
binding.previewView.clipToOutline = true
binding.tvToSearch.setOnClickListener {
val bottomSheetDialog = CustomBottomSheetDialog.newInstance()
bottomSheetDialog.show(supportFragmentManager, "CustomBottomSheetDialog")
}
binding.spinner.setItems(arrayOf("即放即取", "持续取餐"))
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
}
private fun startCamera() {
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
private fun setupCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider = cameraProviderFuture.get()
// 创建预览用例
// 1. 创建预览用例
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(binding.previewView.surfaceProvider)
}
// 选择后置摄像头
// 2. 创建图像分析用例(用于副屏显示)
val imageAnalysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
// .setTargetResolution(Size(640, 480)) // 降低分辨率减轻负担
.build()
.also { analysis ->
analysis.setAnalyzer(executor) { imageProxy ->
if (isAnalyzing) {
val bitmap = imageProxy.toBitmap()
runOnUiThread {
presentation.updateImage(bitmap) // 更新副屏
}
}
imageProxy.close() // 必须关闭以释放资源
}
}
// 3. 创建拍照用例
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
// .setTargetResolution(Size(1920, 1080)) // 设置拍照分辨率
.build()
// 4. 选择摄像头
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
// 解绑所有用例
cameraProvider.unbindAll()
// 绑定到生命周期
// 绑定三个用例到生命周期
cameraProvider.bindToLifecycle(
this, cameraSelector, preview
this, cameraSelector, preview, imageAnalysis, imageCapture
)
} catch (exc: Exception) {
Timber.e(exc, "Use case binding failed")
Timber.e(exc.message)
}
}, ContextCompat.getMainExecutor(this))
}
// 拍照功能
private fun takePhoto() {
// 临时停止分析以避免干扰
isAnalyzing = false
// 创建输出选项
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(
File(
cacheDir.path, "IMG_${System.currentTimeMillis()}.jpg"
)
).build()
// 执行拍照
imageCapture.takePicture(
outputFileOptions,
executor,
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
runOnUiThread {
ToastUtils.showToast("照片保存成功: ${outputFileResults.savedUri}")
}
// 恢复图像分析
isAnalyzing = true
}
override fun onError(exception: ImageCaptureException) {
Timber.e("拍照失败: ${exception.message}")
runOnUiThread {
ToastUtils.showToast("拍照失败: ${exception.message}")
}
// 恢复图像分析
isAnalyzing = true
}
}
)
}
private fun setupSecondaryDisplay() {
val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val displays = displayManager.displays
@@ -85,7 +183,7 @@ class MainActivity : AppCompatActivity() {
if (displays.size > 1) {
val secondaryDisplay = displays[1]
// 创建副屏的Presentation
val presentation =
presentation =
SecondaryScreenPresentation(
activity = this,
this,