diff --git a/app/build.gradle b/app/build.gradle index 5dc1696..6b8633d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,4 +87,12 @@ implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //视频播放器 implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer:v8.4.0-release-jitpack' + //CameraX + def camerax_version = '1.2.3' + // CameraX Camera2 extensions + implementation "androidx.camera:camera-camera2:$camerax_version" + // CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:$camerax_version" + // CameraX View class + implementation "androidx.camera:camera-view:$camerax_version" } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 5dc1696..6b8633d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,4 +87,12 @@ implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //视频播放器 implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer:v8.4.0-release-jitpack' + //CameraX + def camerax_version = '1.2.3' + // CameraX Camera2 extensions + implementation "androidx.camera:camera-camera2:$camerax_version" + // CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:$camerax_version" + // CameraX View class + implementation "androidx.camera:camera-view:$camerax_version" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index 9b9c93e..dcb946c 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -1,17 +1,168 @@ package com.casic.br.app.view +import android.annotation.SuppressLint +import android.graphics.ImageFormat +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.DisplayMetrics import android.util.Log +import android.view.Surface +import androidx.camera.core.AspectRatio +import androidx.camera.core.CameraInfo +import androidx.camera.core.CameraSelector +import androidx.camera.core.CameraState +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.core.content.ContextCompat import com.casic.br.app.R import com.casic.br.app.databinding.ActivityStartCheckBinding import com.casic.br.app.extensions.initImmersionBar import com.casic.br.app.widgets.CheckResultDialog import com.casic.br.app.widgets.SelectSceneDialog +import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.toBitmap +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import java.util.concurrent.ExecutionException +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit +import kotlin.math.abs -class StartCheckActivity : KotlinBaseActivity() { +class StartCheckActivity : KotlinBaseActivity(), Handler.Callback { private val kTag = "StartCheckActivity" + private val ratio_4_3 = 4.0 / 3.0 + private val ratio_16_9 = 16.0 / 9.0 + private val executor = ThreadPoolExecutor( + 16, 16, + 0L, TimeUnit.MILLISECONDS, + LinkedBlockingQueue(1024), + ThreadPoolExecutor.AbortPolicy() + ) + private lateinit var cameraExecutor: ExecutorService + private lateinit var cameraProviderFuture: ListenableFuture + private lateinit var imageCapture: ImageCapture + private lateinit var imageAnalysis: ImageAnalysis + private lateinit var weakReferenceHandler: WeakReferenceHandler + + override fun initOnCreate(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + // Initialize our background executor + cameraExecutor = Executors.newSingleThreadExecutor() + cameraProviderFuture = ProcessCameraProvider.getInstance(this) + // 检查 CameraProvider 可用性 + cameraProviderFuture.addListener({ + try { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + bindPreview(cameraProvider) + } catch (e: ExecutionException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + }, ContextCompat.getMainExecutor(this)) + } + + private fun bindPreview(cameraProvider: ProcessCameraProvider) { + val screenAspectRatio = if (Build.VERSION.SDK_INT >= 30) { + val metrics = windowManager.currentWindowMetrics.bounds + aspectRatio(metrics.width(), metrics.height()) + } else { + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + aspectRatio(outMetrics.widthPixels, outMetrics.heightPixels) + } + + // CameraSelector, 选择后置摄像头 + val cameraSelector = CameraSelector.Builder() + .requireLensFacing(CameraSelector.LENS_FACING_BACK) + .build() + + // Preview + val cameraPreViewBuilder = Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageCapture + imageCapture = ImageCapture.Builder() + .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageAnalysis + imageAnalysis = ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // Must unbind the use-cases before rebinding them + cameraProvider.unbindAll() + try { + val camera = cameraProvider.bindToLifecycle( + this, + cameraSelector, + imageCapture, + imageAnalysis, + cameraPreViewBuilder + ) + + // Attach the viewfinder's surface provider to preview use case + cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) + observeCameraState(camera.cameraInfo) + } catch (e: Exception) { + Log.e(kTag, "Use case binding failed", e) + } + } + + @SuppressLint("UnsafeOptInUsageError") + private fun observeCameraState(cameraInfo: CameraInfo) { + val screenWidth = getScreenWidth() + val screenHeight = getScreenHeight() + + cameraInfo.cameraState.observe(this) { cameraState -> + if (cameraState.type == CameraState.Type.OPEN) { + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + /** + * CameraX 可通过 setOutputImageFormat(int) 支持 YUV_420_888 和 RGBA_8888。默认格式为 YUV_420_888 + * + * NV12是iOS中有的模式,它的存储顺序是先存Y分量,再YV进行交替存储。 + * NV21是Android中有的模式,它的存储顺序是先存Y分量,再VU交替存储。 + * NV12和NV21格式都属于YUV420SP类型 + */ + if (imageProxy.format == ImageFormat.YUV_420_888) { + executor.execute { + val image = imageProxy.image + val bitmap = image?.toBitmap(ImageFormat.YUV_420_888) ?: return@execute + + val widthRatio = screenWidth / bitmap.width.toFloat() + val heightRatio = screenHeight / bitmap.height.toFloat() + Log.d(kTag, "observeCameraState => [${widthRatio},${heightRatio}]") + //TODO 开始调用算法检测物品 + + //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 + imageProxy.close() + } + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + + return true + } override fun initEvent() { binding.leftButton.setOnClickListener { finish() } @@ -44,10 +195,18 @@ } }).build().show() } - } - override fun initOnCreate(savedInstanceState: Bundle?) { + binding.tipsButton.setOnClickListener { + } + + binding.addButton.setOnClickListener { + + } + + binding.listButton.setOnClickListener { + + } } override fun initViewBinding(): ActivityStartCheckBinding { @@ -61,4 +220,12 @@ override fun setupTopBarLayout() { binding.rootView.initImmersionBar(this, false, R.color.themeColor) } + + private fun aspectRatio(width: Int, height: Int): Int { + val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) + return if (abs(ratio - ratio_4_3) <= abs(ratio - ratio_16_9) + ) { + AspectRatio.RATIO_4_3 + } else AspectRatio.RATIO_16_9 + } } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 5dc1696..6b8633d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,4 +87,12 @@ implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //视频播放器 implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer:v8.4.0-release-jitpack' + //CameraX + def camerax_version = '1.2.3' + // CameraX Camera2 extensions + implementation "androidx.camera:camera-camera2:$camerax_version" + // CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:$camerax_version" + // CameraX View class + implementation "androidx.camera:camera-view:$camerax_version" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index 9b9c93e..dcb946c 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -1,17 +1,168 @@ package com.casic.br.app.view +import android.annotation.SuppressLint +import android.graphics.ImageFormat +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.DisplayMetrics import android.util.Log +import android.view.Surface +import androidx.camera.core.AspectRatio +import androidx.camera.core.CameraInfo +import androidx.camera.core.CameraSelector +import androidx.camera.core.CameraState +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.core.content.ContextCompat import com.casic.br.app.R import com.casic.br.app.databinding.ActivityStartCheckBinding import com.casic.br.app.extensions.initImmersionBar import com.casic.br.app.widgets.CheckResultDialog import com.casic.br.app.widgets.SelectSceneDialog +import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.toBitmap +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import java.util.concurrent.ExecutionException +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit +import kotlin.math.abs -class StartCheckActivity : KotlinBaseActivity() { +class StartCheckActivity : KotlinBaseActivity(), Handler.Callback { private val kTag = "StartCheckActivity" + private val ratio_4_3 = 4.0 / 3.0 + private val ratio_16_9 = 16.0 / 9.0 + private val executor = ThreadPoolExecutor( + 16, 16, + 0L, TimeUnit.MILLISECONDS, + LinkedBlockingQueue(1024), + ThreadPoolExecutor.AbortPolicy() + ) + private lateinit var cameraExecutor: ExecutorService + private lateinit var cameraProviderFuture: ListenableFuture + private lateinit var imageCapture: ImageCapture + private lateinit var imageAnalysis: ImageAnalysis + private lateinit var weakReferenceHandler: WeakReferenceHandler + + override fun initOnCreate(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + // Initialize our background executor + cameraExecutor = Executors.newSingleThreadExecutor() + cameraProviderFuture = ProcessCameraProvider.getInstance(this) + // 检查 CameraProvider 可用性 + cameraProviderFuture.addListener({ + try { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + bindPreview(cameraProvider) + } catch (e: ExecutionException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + }, ContextCompat.getMainExecutor(this)) + } + + private fun bindPreview(cameraProvider: ProcessCameraProvider) { + val screenAspectRatio = if (Build.VERSION.SDK_INT >= 30) { + val metrics = windowManager.currentWindowMetrics.bounds + aspectRatio(metrics.width(), metrics.height()) + } else { + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + aspectRatio(outMetrics.widthPixels, outMetrics.heightPixels) + } + + // CameraSelector, 选择后置摄像头 + val cameraSelector = CameraSelector.Builder() + .requireLensFacing(CameraSelector.LENS_FACING_BACK) + .build() + + // Preview + val cameraPreViewBuilder = Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageCapture + imageCapture = ImageCapture.Builder() + .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageAnalysis + imageAnalysis = ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // Must unbind the use-cases before rebinding them + cameraProvider.unbindAll() + try { + val camera = cameraProvider.bindToLifecycle( + this, + cameraSelector, + imageCapture, + imageAnalysis, + cameraPreViewBuilder + ) + + // Attach the viewfinder's surface provider to preview use case + cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) + observeCameraState(camera.cameraInfo) + } catch (e: Exception) { + Log.e(kTag, "Use case binding failed", e) + } + } + + @SuppressLint("UnsafeOptInUsageError") + private fun observeCameraState(cameraInfo: CameraInfo) { + val screenWidth = getScreenWidth() + val screenHeight = getScreenHeight() + + cameraInfo.cameraState.observe(this) { cameraState -> + if (cameraState.type == CameraState.Type.OPEN) { + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + /** + * CameraX 可通过 setOutputImageFormat(int) 支持 YUV_420_888 和 RGBA_8888。默认格式为 YUV_420_888 + * + * NV12是iOS中有的模式,它的存储顺序是先存Y分量,再YV进行交替存储。 + * NV21是Android中有的模式,它的存储顺序是先存Y分量,再VU交替存储。 + * NV12和NV21格式都属于YUV420SP类型 + */ + if (imageProxy.format == ImageFormat.YUV_420_888) { + executor.execute { + val image = imageProxy.image + val bitmap = image?.toBitmap(ImageFormat.YUV_420_888) ?: return@execute + + val widthRatio = screenWidth / bitmap.width.toFloat() + val heightRatio = screenHeight / bitmap.height.toFloat() + Log.d(kTag, "observeCameraState => [${widthRatio},${heightRatio}]") + //TODO 开始调用算法检测物品 + + //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 + imageProxy.close() + } + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + + return true + } override fun initEvent() { binding.leftButton.setOnClickListener { finish() } @@ -44,10 +195,18 @@ } }).build().show() } - } - override fun initOnCreate(savedInstanceState: Bundle?) { + binding.tipsButton.setOnClickListener { + } + + binding.addButton.setOnClickListener { + + } + + binding.listButton.setOnClickListener { + + } } override fun initViewBinding(): ActivityStartCheckBinding { @@ -61,4 +220,12 @@ override fun setupTopBarLayout() { binding.rootView.initImmersionBar(this, false, R.color.themeColor) } + + private fun aspectRatio(width: Int, height: Int): Int { + val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) + return if (abs(ratio - ratio_4_3) <= abs(ratio - ratio_16_9) + ) { + AspectRatio.RATIO_4_3 + } else AspectRatio.RATIO_16_9 + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_task.xml b/app/src/main/res/drawable/ic_add_task.xml new file mode 100644 index 0000000..361a8a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_task.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/build.gradle b/app/build.gradle index 5dc1696..6b8633d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,4 +87,12 @@ implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //视频播放器 implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer:v8.4.0-release-jitpack' + //CameraX + def camerax_version = '1.2.3' + // CameraX Camera2 extensions + implementation "androidx.camera:camera-camera2:$camerax_version" + // CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:$camerax_version" + // CameraX View class + implementation "androidx.camera:camera-view:$camerax_version" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index 9b9c93e..dcb946c 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -1,17 +1,168 @@ package com.casic.br.app.view +import android.annotation.SuppressLint +import android.graphics.ImageFormat +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.DisplayMetrics import android.util.Log +import android.view.Surface +import androidx.camera.core.AspectRatio +import androidx.camera.core.CameraInfo +import androidx.camera.core.CameraSelector +import androidx.camera.core.CameraState +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.core.content.ContextCompat import com.casic.br.app.R import com.casic.br.app.databinding.ActivityStartCheckBinding import com.casic.br.app.extensions.initImmersionBar import com.casic.br.app.widgets.CheckResultDialog import com.casic.br.app.widgets.SelectSceneDialog +import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.toBitmap +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import java.util.concurrent.ExecutionException +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit +import kotlin.math.abs -class StartCheckActivity : KotlinBaseActivity() { +class StartCheckActivity : KotlinBaseActivity(), Handler.Callback { private val kTag = "StartCheckActivity" + private val ratio_4_3 = 4.0 / 3.0 + private val ratio_16_9 = 16.0 / 9.0 + private val executor = ThreadPoolExecutor( + 16, 16, + 0L, TimeUnit.MILLISECONDS, + LinkedBlockingQueue(1024), + ThreadPoolExecutor.AbortPolicy() + ) + private lateinit var cameraExecutor: ExecutorService + private lateinit var cameraProviderFuture: ListenableFuture + private lateinit var imageCapture: ImageCapture + private lateinit var imageAnalysis: ImageAnalysis + private lateinit var weakReferenceHandler: WeakReferenceHandler + + override fun initOnCreate(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + // Initialize our background executor + cameraExecutor = Executors.newSingleThreadExecutor() + cameraProviderFuture = ProcessCameraProvider.getInstance(this) + // 检查 CameraProvider 可用性 + cameraProviderFuture.addListener({ + try { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + bindPreview(cameraProvider) + } catch (e: ExecutionException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + }, ContextCompat.getMainExecutor(this)) + } + + private fun bindPreview(cameraProvider: ProcessCameraProvider) { + val screenAspectRatio = if (Build.VERSION.SDK_INT >= 30) { + val metrics = windowManager.currentWindowMetrics.bounds + aspectRatio(metrics.width(), metrics.height()) + } else { + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + aspectRatio(outMetrics.widthPixels, outMetrics.heightPixels) + } + + // CameraSelector, 选择后置摄像头 + val cameraSelector = CameraSelector.Builder() + .requireLensFacing(CameraSelector.LENS_FACING_BACK) + .build() + + // Preview + val cameraPreViewBuilder = Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageCapture + imageCapture = ImageCapture.Builder() + .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageAnalysis + imageAnalysis = ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // Must unbind the use-cases before rebinding them + cameraProvider.unbindAll() + try { + val camera = cameraProvider.bindToLifecycle( + this, + cameraSelector, + imageCapture, + imageAnalysis, + cameraPreViewBuilder + ) + + // Attach the viewfinder's surface provider to preview use case + cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) + observeCameraState(camera.cameraInfo) + } catch (e: Exception) { + Log.e(kTag, "Use case binding failed", e) + } + } + + @SuppressLint("UnsafeOptInUsageError") + private fun observeCameraState(cameraInfo: CameraInfo) { + val screenWidth = getScreenWidth() + val screenHeight = getScreenHeight() + + cameraInfo.cameraState.observe(this) { cameraState -> + if (cameraState.type == CameraState.Type.OPEN) { + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + /** + * CameraX 可通过 setOutputImageFormat(int) 支持 YUV_420_888 和 RGBA_8888。默认格式为 YUV_420_888 + * + * NV12是iOS中有的模式,它的存储顺序是先存Y分量,再YV进行交替存储。 + * NV21是Android中有的模式,它的存储顺序是先存Y分量,再VU交替存储。 + * NV12和NV21格式都属于YUV420SP类型 + */ + if (imageProxy.format == ImageFormat.YUV_420_888) { + executor.execute { + val image = imageProxy.image + val bitmap = image?.toBitmap(ImageFormat.YUV_420_888) ?: return@execute + + val widthRatio = screenWidth / bitmap.width.toFloat() + val heightRatio = screenHeight / bitmap.height.toFloat() + Log.d(kTag, "observeCameraState => [${widthRatio},${heightRatio}]") + //TODO 开始调用算法检测物品 + + //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 + imageProxy.close() + } + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + + return true + } override fun initEvent() { binding.leftButton.setOnClickListener { finish() } @@ -44,10 +195,18 @@ } }).build().show() } - } - override fun initOnCreate(savedInstanceState: Bundle?) { + binding.tipsButton.setOnClickListener { + } + + binding.addButton.setOnClickListener { + + } + + binding.listButton.setOnClickListener { + + } } override fun initViewBinding(): ActivityStartCheckBinding { @@ -61,4 +220,12 @@ override fun setupTopBarLayout() { binding.rootView.initImmersionBar(this, false, R.color.themeColor) } + + private fun aspectRatio(width: Int, height: Int): Int { + val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) + return if (abs(ratio - ratio_4_3) <= abs(ratio - ratio_16_9) + ) { + AspectRatio.RATIO_4_3 + } else AspectRatio.RATIO_16_9 + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_task.xml b/app/src/main/res/drawable/ic_add_task.xml new file mode 100644 index 0000000..361a8a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_task.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_details.xml b/app/src/main/res/drawable/ic_details.xml new file mode 100644 index 0000000..cd6dcc7 --- /dev/null +++ b/app/src/main/res/drawable/ic_details.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/build.gradle b/app/build.gradle index 5dc1696..6b8633d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,4 +87,12 @@ implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //视频播放器 implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer:v8.4.0-release-jitpack' + //CameraX + def camerax_version = '1.2.3' + // CameraX Camera2 extensions + implementation "androidx.camera:camera-camera2:$camerax_version" + // CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:$camerax_version" + // CameraX View class + implementation "androidx.camera:camera-view:$camerax_version" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index 9b9c93e..dcb946c 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -1,17 +1,168 @@ package com.casic.br.app.view +import android.annotation.SuppressLint +import android.graphics.ImageFormat +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.DisplayMetrics import android.util.Log +import android.view.Surface +import androidx.camera.core.AspectRatio +import androidx.camera.core.CameraInfo +import androidx.camera.core.CameraSelector +import androidx.camera.core.CameraState +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.core.content.ContextCompat import com.casic.br.app.R import com.casic.br.app.databinding.ActivityStartCheckBinding import com.casic.br.app.extensions.initImmersionBar import com.casic.br.app.widgets.CheckResultDialog import com.casic.br.app.widgets.SelectSceneDialog +import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.toBitmap +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import java.util.concurrent.ExecutionException +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit +import kotlin.math.abs -class StartCheckActivity : KotlinBaseActivity() { +class StartCheckActivity : KotlinBaseActivity(), Handler.Callback { private val kTag = "StartCheckActivity" + private val ratio_4_3 = 4.0 / 3.0 + private val ratio_16_9 = 16.0 / 9.0 + private val executor = ThreadPoolExecutor( + 16, 16, + 0L, TimeUnit.MILLISECONDS, + LinkedBlockingQueue(1024), + ThreadPoolExecutor.AbortPolicy() + ) + private lateinit var cameraExecutor: ExecutorService + private lateinit var cameraProviderFuture: ListenableFuture + private lateinit var imageCapture: ImageCapture + private lateinit var imageAnalysis: ImageAnalysis + private lateinit var weakReferenceHandler: WeakReferenceHandler + + override fun initOnCreate(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + // Initialize our background executor + cameraExecutor = Executors.newSingleThreadExecutor() + cameraProviderFuture = ProcessCameraProvider.getInstance(this) + // 检查 CameraProvider 可用性 + cameraProviderFuture.addListener({ + try { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + bindPreview(cameraProvider) + } catch (e: ExecutionException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + }, ContextCompat.getMainExecutor(this)) + } + + private fun bindPreview(cameraProvider: ProcessCameraProvider) { + val screenAspectRatio = if (Build.VERSION.SDK_INT >= 30) { + val metrics = windowManager.currentWindowMetrics.bounds + aspectRatio(metrics.width(), metrics.height()) + } else { + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + aspectRatio(outMetrics.widthPixels, outMetrics.heightPixels) + } + + // CameraSelector, 选择后置摄像头 + val cameraSelector = CameraSelector.Builder() + .requireLensFacing(CameraSelector.LENS_FACING_BACK) + .build() + + // Preview + val cameraPreViewBuilder = Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageCapture + imageCapture = ImageCapture.Builder() + .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageAnalysis + imageAnalysis = ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // Must unbind the use-cases before rebinding them + cameraProvider.unbindAll() + try { + val camera = cameraProvider.bindToLifecycle( + this, + cameraSelector, + imageCapture, + imageAnalysis, + cameraPreViewBuilder + ) + + // Attach the viewfinder's surface provider to preview use case + cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) + observeCameraState(camera.cameraInfo) + } catch (e: Exception) { + Log.e(kTag, "Use case binding failed", e) + } + } + + @SuppressLint("UnsafeOptInUsageError") + private fun observeCameraState(cameraInfo: CameraInfo) { + val screenWidth = getScreenWidth() + val screenHeight = getScreenHeight() + + cameraInfo.cameraState.observe(this) { cameraState -> + if (cameraState.type == CameraState.Type.OPEN) { + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + /** + * CameraX 可通过 setOutputImageFormat(int) 支持 YUV_420_888 和 RGBA_8888。默认格式为 YUV_420_888 + * + * NV12是iOS中有的模式,它的存储顺序是先存Y分量,再YV进行交替存储。 + * NV21是Android中有的模式,它的存储顺序是先存Y分量,再VU交替存储。 + * NV12和NV21格式都属于YUV420SP类型 + */ + if (imageProxy.format == ImageFormat.YUV_420_888) { + executor.execute { + val image = imageProxy.image + val bitmap = image?.toBitmap(ImageFormat.YUV_420_888) ?: return@execute + + val widthRatio = screenWidth / bitmap.width.toFloat() + val heightRatio = screenHeight / bitmap.height.toFloat() + Log.d(kTag, "observeCameraState => [${widthRatio},${heightRatio}]") + //TODO 开始调用算法检测物品 + + //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 + imageProxy.close() + } + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + + return true + } override fun initEvent() { binding.leftButton.setOnClickListener { finish() } @@ -44,10 +195,18 @@ } }).build().show() } - } - override fun initOnCreate(savedInstanceState: Bundle?) { + binding.tipsButton.setOnClickListener { + } + + binding.addButton.setOnClickListener { + + } + + binding.listButton.setOnClickListener { + + } } override fun initViewBinding(): ActivityStartCheckBinding { @@ -61,4 +220,12 @@ override fun setupTopBarLayout() { binding.rootView.initImmersionBar(this, false, R.color.themeColor) } + + private fun aspectRatio(width: Int, height: Int): Int { + val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) + return if (abs(ratio - ratio_4_3) <= abs(ratio - ratio_16_9) + ) { + AspectRatio.RATIO_4_3 + } else AspectRatio.RATIO_16_9 + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_task.xml b/app/src/main/res/drawable/ic_add_task.xml new file mode 100644 index 0000000..361a8a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_task.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_details.xml b/app/src/main/res/drawable/ic_details.xml new file mode 100644 index 0000000..cd6dcc7 --- /dev/null +++ b/app/src/main/res/drawable/ic_details.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_stop.xml b/app/src/main/res/drawable/ic_stop.xml index 5ed4acf..d0cab46 100644 --- a/app/src/main/res/drawable/ic_stop.xml +++ b/app/src/main/res/drawable/ic_stop.xml @@ -1,6 +1,6 @@ () { +class StartCheckActivity : KotlinBaseActivity(), Handler.Callback { private val kTag = "StartCheckActivity" + private val ratio_4_3 = 4.0 / 3.0 + private val ratio_16_9 = 16.0 / 9.0 + private val executor = ThreadPoolExecutor( + 16, 16, + 0L, TimeUnit.MILLISECONDS, + LinkedBlockingQueue(1024), + ThreadPoolExecutor.AbortPolicy() + ) + private lateinit var cameraExecutor: ExecutorService + private lateinit var cameraProviderFuture: ListenableFuture + private lateinit var imageCapture: ImageCapture + private lateinit var imageAnalysis: ImageAnalysis + private lateinit var weakReferenceHandler: WeakReferenceHandler + + override fun initOnCreate(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + // Initialize our background executor + cameraExecutor = Executors.newSingleThreadExecutor() + cameraProviderFuture = ProcessCameraProvider.getInstance(this) + // 检查 CameraProvider 可用性 + cameraProviderFuture.addListener({ + try { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + bindPreview(cameraProvider) + } catch (e: ExecutionException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + }, ContextCompat.getMainExecutor(this)) + } + + private fun bindPreview(cameraProvider: ProcessCameraProvider) { + val screenAspectRatio = if (Build.VERSION.SDK_INT >= 30) { + val metrics = windowManager.currentWindowMetrics.bounds + aspectRatio(metrics.width(), metrics.height()) + } else { + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + aspectRatio(outMetrics.widthPixels, outMetrics.heightPixels) + } + + // CameraSelector, 选择后置摄像头 + val cameraSelector = CameraSelector.Builder() + .requireLensFacing(CameraSelector.LENS_FACING_BACK) + .build() + + // Preview + val cameraPreViewBuilder = Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageCapture + imageCapture = ImageCapture.Builder() + .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageAnalysis + imageAnalysis = ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // Must unbind the use-cases before rebinding them + cameraProvider.unbindAll() + try { + val camera = cameraProvider.bindToLifecycle( + this, + cameraSelector, + imageCapture, + imageAnalysis, + cameraPreViewBuilder + ) + + // Attach the viewfinder's surface provider to preview use case + cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) + observeCameraState(camera.cameraInfo) + } catch (e: Exception) { + Log.e(kTag, "Use case binding failed", e) + } + } + + @SuppressLint("UnsafeOptInUsageError") + private fun observeCameraState(cameraInfo: CameraInfo) { + val screenWidth = getScreenWidth() + val screenHeight = getScreenHeight() + + cameraInfo.cameraState.observe(this) { cameraState -> + if (cameraState.type == CameraState.Type.OPEN) { + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + /** + * CameraX 可通过 setOutputImageFormat(int) 支持 YUV_420_888 和 RGBA_8888。默认格式为 YUV_420_888 + * + * NV12是iOS中有的模式,它的存储顺序是先存Y分量,再YV进行交替存储。 + * NV21是Android中有的模式,它的存储顺序是先存Y分量,再VU交替存储。 + * NV12和NV21格式都属于YUV420SP类型 + */ + if (imageProxy.format == ImageFormat.YUV_420_888) { + executor.execute { + val image = imageProxy.image + val bitmap = image?.toBitmap(ImageFormat.YUV_420_888) ?: return@execute + + val widthRatio = screenWidth / bitmap.width.toFloat() + val heightRatio = screenHeight / bitmap.height.toFloat() + Log.d(kTag, "observeCameraState => [${widthRatio},${heightRatio}]") + //TODO 开始调用算法检测物品 + + //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 + imageProxy.close() + } + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + + return true + } override fun initEvent() { binding.leftButton.setOnClickListener { finish() } @@ -44,10 +195,18 @@ } }).build().show() } - } - override fun initOnCreate(savedInstanceState: Bundle?) { + binding.tipsButton.setOnClickListener { + } + + binding.addButton.setOnClickListener { + + } + + binding.listButton.setOnClickListener { + + } } override fun initViewBinding(): ActivityStartCheckBinding { @@ -61,4 +220,12 @@ override fun setupTopBarLayout() { binding.rootView.initImmersionBar(this, false, R.color.themeColor) } + + private fun aspectRatio(width: Int, height: Int): Int { + val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) + return if (abs(ratio - ratio_4_3) <= abs(ratio - ratio_16_9) + ) { + AspectRatio.RATIO_4_3 + } else AspectRatio.RATIO_16_9 + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_task.xml b/app/src/main/res/drawable/ic_add_task.xml new file mode 100644 index 0000000..361a8a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_task.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_details.xml b/app/src/main/res/drawable/ic_details.xml new file mode 100644 index 0000000..cd6dcc7 --- /dev/null +++ b/app/src/main/res/drawable/ic_details.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_stop.xml b/app/src/main/res/drawable/ic_stop.xml index 5ed4acf..d0cab46 100644 --- a/app/src/main/res/drawable/ic_stop.xml +++ b/app/src/main/res/drawable/ic_stop.xml @@ -1,6 +1,6 @@ + + + + diff --git a/app/build.gradle b/app/build.gradle index 5dc1696..6b8633d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -87,4 +87,12 @@ implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0' //视频播放器 implementation 'com.github.CarGuo.GSYVideoPlayer:GSYVideoPlayer:v8.4.0-release-jitpack' + //CameraX + def camerax_version = '1.2.3' + // CameraX Camera2 extensions + implementation "androidx.camera:camera-camera2:$camerax_version" + // CameraX Lifecycle library + implementation "androidx.camera:camera-lifecycle:$camerax_version" + // CameraX View class + implementation "androidx.camera:camera-view:$camerax_version" } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt index 9b9c93e..dcb946c 100644 --- a/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt +++ b/app/src/main/java/com/casic/br/app/view/StartCheckActivity.kt @@ -1,17 +1,168 @@ package com.casic.br.app.view +import android.annotation.SuppressLint +import android.graphics.ImageFormat +import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.util.DisplayMetrics import android.util.Log +import android.view.Surface +import androidx.camera.core.AspectRatio +import androidx.camera.core.CameraInfo +import androidx.camera.core.CameraSelector +import androidx.camera.core.CameraState +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.core.content.ContextCompat import com.casic.br.app.R import com.casic.br.app.databinding.ActivityStartCheckBinding import com.casic.br.app.extensions.initImmersionBar import com.casic.br.app.widgets.CheckResultDialog import com.casic.br.app.widgets.SelectSceneDialog +import com.google.common.util.concurrent.ListenableFuture import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.getScreenHeight +import com.pengxh.kt.lite.extensions.getScreenWidth +import com.pengxh.kt.lite.extensions.toBitmap +import com.pengxh.kt.lite.utils.WeakReferenceHandler +import java.util.concurrent.ExecutionException +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit +import kotlin.math.abs -class StartCheckActivity : KotlinBaseActivity() { +class StartCheckActivity : KotlinBaseActivity(), Handler.Callback { private val kTag = "StartCheckActivity" + private val ratio_4_3 = 4.0 / 3.0 + private val ratio_16_9 = 16.0 / 9.0 + private val executor = ThreadPoolExecutor( + 16, 16, + 0L, TimeUnit.MILLISECONDS, + LinkedBlockingQueue(1024), + ThreadPoolExecutor.AbortPolicy() + ) + private lateinit var cameraExecutor: ExecutorService + private lateinit var cameraProviderFuture: ListenableFuture + private lateinit var imageCapture: ImageCapture + private lateinit var imageAnalysis: ImageAnalysis + private lateinit var weakReferenceHandler: WeakReferenceHandler + + override fun initOnCreate(savedInstanceState: Bundle?) { + weakReferenceHandler = WeakReferenceHandler(this) + // Initialize our background executor + cameraExecutor = Executors.newSingleThreadExecutor() + cameraProviderFuture = ProcessCameraProvider.getInstance(this) + // 检查 CameraProvider 可用性 + cameraProviderFuture.addListener({ + try { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + bindPreview(cameraProvider) + } catch (e: ExecutionException) { + e.printStackTrace() + } catch (e: InterruptedException) { + e.printStackTrace() + } + }, ContextCompat.getMainExecutor(this)) + } + + private fun bindPreview(cameraProvider: ProcessCameraProvider) { + val screenAspectRatio = if (Build.VERSION.SDK_INT >= 30) { + val metrics = windowManager.currentWindowMetrics.bounds + aspectRatio(metrics.width(), metrics.height()) + } else { + val outMetrics = DisplayMetrics() + windowManager.defaultDisplay.getMetrics(outMetrics) + aspectRatio(outMetrics.widthPixels, outMetrics.heightPixels) + } + + // CameraSelector, 选择后置摄像头 + val cameraSelector = CameraSelector.Builder() + .requireLensFacing(CameraSelector.LENS_FACING_BACK) + .build() + + // Preview + val cameraPreViewBuilder = Preview.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageCapture + imageCapture = ImageCapture.Builder() + .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // ImageAnalysis + imageAnalysis = ImageAnalysis.Builder() + .setTargetAspectRatio(screenAspectRatio) + .setTargetRotation(Surface.ROTATION_0) + .build() + + // Must unbind the use-cases before rebinding them + cameraProvider.unbindAll() + try { + val camera = cameraProvider.bindToLifecycle( + this, + cameraSelector, + imageCapture, + imageAnalysis, + cameraPreViewBuilder + ) + + // Attach the viewfinder's surface provider to preview use case + cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) + observeCameraState(camera.cameraInfo) + } catch (e: Exception) { + Log.e(kTag, "Use case binding failed", e) + } + } + + @SuppressLint("UnsafeOptInUsageError") + private fun observeCameraState(cameraInfo: CameraInfo) { + val screenWidth = getScreenWidth() + val screenHeight = getScreenHeight() + + cameraInfo.cameraState.observe(this) { cameraState -> + if (cameraState.type == CameraState.Type.OPEN) { + imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> + /** + * CameraX 可通过 setOutputImageFormat(int) 支持 YUV_420_888 和 RGBA_8888。默认格式为 YUV_420_888 + * + * NV12是iOS中有的模式,它的存储顺序是先存Y分量,再YV进行交替存储。 + * NV21是Android中有的模式,它的存储顺序是先存Y分量,再VU交替存储。 + * NV12和NV21格式都属于YUV420SP类型 + */ + if (imageProxy.format == ImageFormat.YUV_420_888) { + executor.execute { + val image = imageProxy.image + val bitmap = image?.toBitmap(ImageFormat.YUV_420_888) ?: return@execute + + val widthRatio = screenWidth / bitmap.width.toFloat() + val heightRatio = screenHeight / bitmap.height.toFloat() + Log.d(kTag, "observeCameraState => [${widthRatio},${heightRatio}]") + //TODO 开始调用算法检测物品 + + //检测完之后close就会继续生成下一帧图片,否则就会被阻塞不会继续生成下一帧 + imageProxy.close() + } + } + } + } + } + } + + override fun handleMessage(msg: Message): Boolean { + + return true + } override fun initEvent() { binding.leftButton.setOnClickListener { finish() } @@ -44,10 +195,18 @@ } }).build().show() } - } - override fun initOnCreate(savedInstanceState: Bundle?) { + binding.tipsButton.setOnClickListener { + } + + binding.addButton.setOnClickListener { + + } + + binding.listButton.setOnClickListener { + + } } override fun initViewBinding(): ActivityStartCheckBinding { @@ -61,4 +220,12 @@ override fun setupTopBarLayout() { binding.rootView.initImmersionBar(this, false, R.color.themeColor) } + + private fun aspectRatio(width: Int, height: Int): Int { + val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) + return if (abs(ratio - ratio_4_3) <= abs(ratio - ratio_16_9) + ) { + AspectRatio.RATIO_4_3 + } else AspectRatio.RATIO_16_9 + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_task.xml b/app/src/main/res/drawable/ic_add_task.xml new file mode 100644 index 0000000..361a8a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_task.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_details.xml b/app/src/main/res/drawable/ic_details.xml new file mode 100644 index 0000000..cd6dcc7 --- /dev/null +++ b/app/src/main/res/drawable/ic_details.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_stop.xml b/app/src/main/res/drawable/ic_stop.xml index 5ed4acf..d0cab46 100644 --- a/app/src/main/res/drawable/ic_stop.xml +++ b/app/src/main/res/drawable/ic_stop.xml @@ -1,6 +1,6 @@ + + + + diff --git a/app/src/main/res/layout/activity_start_check.xml b/app/src/main/res/layout/activity_start_check.xml index 581ff4a..331effa 100644 --- a/app/src/main/res/layout/activity_start_check.xml +++ b/app/src/main/res/layout/activity_start_check.xml @@ -41,8 +41,8 @@ android:layout_height="0dp" android:layout_weight="1"> - @@ -53,5 +53,29 @@ android:layout_gravity="end" android:layout_margin="@dimen/dp_10" android:src="@drawable/ic_stop" /> + + + + + + \ No newline at end of file