diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt index 313308e..701a3cc 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt @@ -1,85 +1,31 @@ package com.casic.br.operationsite.test.view -import android.os.Build import android.os.Bundle -import android.util.DisplayMetrics -import android.util.Log -import android.view.Surface -import android.view.View -import androidx.camera.core.AspectRatio -import androidx.camera.core.CameraSelector -import androidx.camera.core.CameraState -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 +import android.widget.FrameLayout import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.test.R -import com.casic.br.operationsite.test.callback.OnImageCompressListener import com.casic.br.operationsite.test.databinding.ActivityDisclosureBinding -import com.casic.br.operationsite.test.extensions.combineImagePath -import com.casic.br.operationsite.test.extensions.compressImage import com.casic.br.operationsite.test.extensions.initImmersionBar -import com.casic.br.operationsite.test.extensions.upload import com.casic.br.operationsite.test.util.CurrentScene -import com.casic.br.operationsite.test.util.GlideLoadEngine import com.casic.br.operationsite.test.util.LocaleConstant import com.casic.br.operationsite.test.util.RuntimeCache +import com.casic.br.operationsite.test.util.VideoPlayerManager import com.casic.br.operationsite.test.util.tcp.SocketManager -import com.casic.br.operationsite.test.vm.UploadFileViewModel -import com.google.common.util.concurrent.ListenableFuture -import com.luck.picture.lib.basic.PictureSelector -import com.luck.picture.lib.config.SelectMimeType -import com.luck.picture.lib.entity.LocalMedia -import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.casic.br.operationsite.test.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.test.widget.BottomControlSheet import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getScreenWidth import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.ActivityStackManager -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.widget.TitleBarView -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.launch -import java.io.File -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.UUID -import java.util.concurrent.ExecutionException -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.math.abs class DisclosureActivity : KotlinBaseActivity() { - companion object { - private const val RATIO_4_3_VALUE = 4.0 / 3.0 - private const val RATIO_16_9_VALUE = 16.0 / 9.0 - } - private val kTag = "DisclosureActivity" private val context = this - private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } - private val marginOffset by lazy { 1.dp2px(this) } - private lateinit var cameraExecutor: ExecutorService - private lateinit var cameraProviderFuture: ListenableFuture - private lateinit var imageCapture: ImageCapture - private lateinit var imageAnalysis: ImageAnalysis - private lateinit var uploadFileViewModel: UploadFileViewModel - private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 - private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 - private var index = 1 + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel override fun initEvent() { binding.startCheckButton.setOnClickListener { @@ -91,46 +37,23 @@ SocketManager.get.send(LocaleConstant.START_CONSTRUCTION_COMMAND) } - binding.captureImageButton.setOnClickListener { - takePhoto() + binding.showControlViewButton.setOnClickListener { + BottomControlSheet(this).show() } - imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { - override fun onAddImageClick() { - PictureSelector.create(context).openGallery(SelectMimeType.ofImage()) - .isGif(false).isMaxSelectEnabledMask(true).setFilterMinFileSize(100) - .setMaxSelectNum(3).isDisplayCamera(false) - .setImageEngine(GlideLoadEngine.get) - .forResult(object : OnResultCallbackListener { - override fun onResult(result: ArrayList?) { - lifecycleScope.launch { - flow { - result?.forEach { - emit(it) - delay(1000) - } - }.collect { - analyticalSelectResult(it.realPath) - } - } - } + binding.restartVideoButton.setOnClickListener { + binding.rtspPlayerView.startPlayLogic() + } - override fun onCancel() { + binding.clearVideoRegionButton.setOnClickListener { + binding.regionView.clearRoutePath() + } - } - }) - } + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() - override fun onItemClick(position: Int) { - navigatePageTo(position, recyclerViewImages) - } - - override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) - recyclerViewImages.removeAt(position) - imageAdapter.notifyDataSetChanged() - } - }) +// constructionCheckViewModel.setVideoRegion(LocaleConstant.AI_BASE_IP, region) + } binding.endCheckButton.setOnClickListener { if (!SocketManager.get.nettyClient.connectStatus) { @@ -148,154 +71,30 @@ RuntimeCache.currentScene = CurrentScene.DISCLOSURE - cameraExecutor = Executors.newSingleThreadExecutor() - cameraProviderFuture = ProcessCameraProvider.getInstance(this) - cameraProviderFuture.addListener({ - try { - bindPreview(cameraProviderFuture.get()) - } catch (e: ExecutionException) { - e.printStackTrace() - } catch (e: InterruptedException) { - e.printStackTrace() - } - }, ContextCompat.getMainExecutor(this)) + //动态设置rtspPlayerView宽高 + val rtspViewParams = binding.rtspPlayerView.layoutParams as FrameLayout.LayoutParams + val videoWidth = getScreenWidth() - 20.dp2px(this) + val videoHeight = videoWidth * (9f / 16) + rtspViewParams.width = videoWidth + rtspViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = rtspViewParams - val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) - imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 2, 2) - binding.recyclerView.addItemDecoration( - RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + val regionViewParams = binding.regionView.layoutParams as FrameLayout.LayoutParams + regionViewParams.width = videoWidth + regionViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = regionViewParams + + VideoPlayerManager.setGSYVideoPlayerOptions( + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) - binding.recyclerView.adapter = imageAdapter + binding.rtspPlayerView.startPlayLogic() - uploadFileViewModel = ViewModelProvider(this)[UploadFileViewModel::class.java] - uploadFileViewModel.resultModel.observe(this) { - if (it.code == 200) { - val path = it.data.toString() - if (path.isNotBlank()) { - val map = HashMap() - map["id"] = RuntimeCache.uploadFileTaskId - map["imageId"] = UUID.randomUUID().toString() - map["scenario"] = "brief" - map["image"] = path - map["index"] = index.toString() - map["base64"] = "" - map.upload() - index++ - - val url = path.combineImagePath() - imagePaths.add(path) - recyclerViewImages.add(url) - imageAdapter.notifyDataSetChanged() - } - } - } - } - - 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) - .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) - .build() - - cameraProvider.unbindAll() - try { - val camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - imageCapture, - imageAnalysis, - cameraPreViewBuilder - ) - - cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) - camera.cameraInfo.cameraState.observe(this) { - if (it.type == CameraState.Type.OPEN) { - imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> - imageProxy.close() - } - } - } - } catch (e: Exception) { - Log.e(kTag, "Use case binding failed", e) - } - } - - private fun aspectRatio(width: Int, height: Int): Int { - val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) - return if (abs(ratio - RATIO_4_3_VALUE) <= abs(ratio - RATIO_16_9_VALUE) - ) { - AspectRatio.RATIO_4_3 - } else AspectRatio.RATIO_16_9 - } - - private fun takePhoto() { - val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" - val outputFileOptions = ImageCapture.OutputFileOptions - .Builder(File(imagePath)) - .build() - imageCapture.takePicture(outputFileOptions, cameraExecutor, - object : ImageCapture.OnImageSavedCallback { - override fun onImageSaved(results: ImageCapture.OutputFileResults) { - results.savedUri?.apply { - /** - * /storage/emulated/0/Android/data/com.casic.br.operationsite/files/Pictures/IMG20240620140715.png - * */ - Log.d(kTag, "onImageSaved: $path") - if (path.isNullOrBlank()) { - Log.d(kTag, "onImageSaved: path is null") - return@apply - } - analyticalSelectResult(path!!) - } - } - - override fun onError(error: ImageCaptureException) { - error.printStackTrace() - } - }) - } - - private fun analyticalSelectResult(result: String) { - //压缩图片后上传 - result.compressImage(this, object : OnImageCompressListener { - override fun onSuccess(file: File) { - //上传图片 - uploadFileViewModel.uploadImage(context, file) - } - - override fun onError(e: Throwable) { - e.printStackTrace() - } - }) + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] +// constructionCheckViewModel.setVideoRegionResult.observe(this) { +// if (it) { +// "区域配置成功".show(this) +// } +// } } override fun initViewBinding(): ActivityDisclosureBinding { @@ -303,18 +102,7 @@ } override fun observeRequestState() { - uploadFileViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialogHub.show(this, "图片上传中,请稍后...") - LoadState.Success -> LoadingDialogHub.dismiss() - - else -> { - "图片上传失败,请重试...".show(context) - LoadingDialogHub.dismiss() - } - } - } } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt index 313308e..701a3cc 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt @@ -1,85 +1,31 @@ package com.casic.br.operationsite.test.view -import android.os.Build import android.os.Bundle -import android.util.DisplayMetrics -import android.util.Log -import android.view.Surface -import android.view.View -import androidx.camera.core.AspectRatio -import androidx.camera.core.CameraSelector -import androidx.camera.core.CameraState -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 +import android.widget.FrameLayout import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.test.R -import com.casic.br.operationsite.test.callback.OnImageCompressListener import com.casic.br.operationsite.test.databinding.ActivityDisclosureBinding -import com.casic.br.operationsite.test.extensions.combineImagePath -import com.casic.br.operationsite.test.extensions.compressImage import com.casic.br.operationsite.test.extensions.initImmersionBar -import com.casic.br.operationsite.test.extensions.upload import com.casic.br.operationsite.test.util.CurrentScene -import com.casic.br.operationsite.test.util.GlideLoadEngine import com.casic.br.operationsite.test.util.LocaleConstant import com.casic.br.operationsite.test.util.RuntimeCache +import com.casic.br.operationsite.test.util.VideoPlayerManager import com.casic.br.operationsite.test.util.tcp.SocketManager -import com.casic.br.operationsite.test.vm.UploadFileViewModel -import com.google.common.util.concurrent.ListenableFuture -import com.luck.picture.lib.basic.PictureSelector -import com.luck.picture.lib.config.SelectMimeType -import com.luck.picture.lib.entity.LocalMedia -import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.casic.br.operationsite.test.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.test.widget.BottomControlSheet import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getScreenWidth import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.ActivityStackManager -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.widget.TitleBarView -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.launch -import java.io.File -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.UUID -import java.util.concurrent.ExecutionException -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.math.abs class DisclosureActivity : KotlinBaseActivity() { - companion object { - private const val RATIO_4_3_VALUE = 4.0 / 3.0 - private const val RATIO_16_9_VALUE = 16.0 / 9.0 - } - private val kTag = "DisclosureActivity" private val context = this - private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } - private val marginOffset by lazy { 1.dp2px(this) } - private lateinit var cameraExecutor: ExecutorService - private lateinit var cameraProviderFuture: ListenableFuture - private lateinit var imageCapture: ImageCapture - private lateinit var imageAnalysis: ImageAnalysis - private lateinit var uploadFileViewModel: UploadFileViewModel - private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 - private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 - private var index = 1 + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel override fun initEvent() { binding.startCheckButton.setOnClickListener { @@ -91,46 +37,23 @@ SocketManager.get.send(LocaleConstant.START_CONSTRUCTION_COMMAND) } - binding.captureImageButton.setOnClickListener { - takePhoto() + binding.showControlViewButton.setOnClickListener { + BottomControlSheet(this).show() } - imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { - override fun onAddImageClick() { - PictureSelector.create(context).openGallery(SelectMimeType.ofImage()) - .isGif(false).isMaxSelectEnabledMask(true).setFilterMinFileSize(100) - .setMaxSelectNum(3).isDisplayCamera(false) - .setImageEngine(GlideLoadEngine.get) - .forResult(object : OnResultCallbackListener { - override fun onResult(result: ArrayList?) { - lifecycleScope.launch { - flow { - result?.forEach { - emit(it) - delay(1000) - } - }.collect { - analyticalSelectResult(it.realPath) - } - } - } + binding.restartVideoButton.setOnClickListener { + binding.rtspPlayerView.startPlayLogic() + } - override fun onCancel() { + binding.clearVideoRegionButton.setOnClickListener { + binding.regionView.clearRoutePath() + } - } - }) - } + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() - override fun onItemClick(position: Int) { - navigatePageTo(position, recyclerViewImages) - } - - override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) - recyclerViewImages.removeAt(position) - imageAdapter.notifyDataSetChanged() - } - }) +// constructionCheckViewModel.setVideoRegion(LocaleConstant.AI_BASE_IP, region) + } binding.endCheckButton.setOnClickListener { if (!SocketManager.get.nettyClient.connectStatus) { @@ -148,154 +71,30 @@ RuntimeCache.currentScene = CurrentScene.DISCLOSURE - cameraExecutor = Executors.newSingleThreadExecutor() - cameraProviderFuture = ProcessCameraProvider.getInstance(this) - cameraProviderFuture.addListener({ - try { - bindPreview(cameraProviderFuture.get()) - } catch (e: ExecutionException) { - e.printStackTrace() - } catch (e: InterruptedException) { - e.printStackTrace() - } - }, ContextCompat.getMainExecutor(this)) + //动态设置rtspPlayerView宽高 + val rtspViewParams = binding.rtspPlayerView.layoutParams as FrameLayout.LayoutParams + val videoWidth = getScreenWidth() - 20.dp2px(this) + val videoHeight = videoWidth * (9f / 16) + rtspViewParams.width = videoWidth + rtspViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = rtspViewParams - val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) - imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 2, 2) - binding.recyclerView.addItemDecoration( - RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + val regionViewParams = binding.regionView.layoutParams as FrameLayout.LayoutParams + regionViewParams.width = videoWidth + regionViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = regionViewParams + + VideoPlayerManager.setGSYVideoPlayerOptions( + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) - binding.recyclerView.adapter = imageAdapter + binding.rtspPlayerView.startPlayLogic() - uploadFileViewModel = ViewModelProvider(this)[UploadFileViewModel::class.java] - uploadFileViewModel.resultModel.observe(this) { - if (it.code == 200) { - val path = it.data.toString() - if (path.isNotBlank()) { - val map = HashMap() - map["id"] = RuntimeCache.uploadFileTaskId - map["imageId"] = UUID.randomUUID().toString() - map["scenario"] = "brief" - map["image"] = path - map["index"] = index.toString() - map["base64"] = "" - map.upload() - index++ - - val url = path.combineImagePath() - imagePaths.add(path) - recyclerViewImages.add(url) - imageAdapter.notifyDataSetChanged() - } - } - } - } - - 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) - .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) - .build() - - cameraProvider.unbindAll() - try { - val camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - imageCapture, - imageAnalysis, - cameraPreViewBuilder - ) - - cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) - camera.cameraInfo.cameraState.observe(this) { - if (it.type == CameraState.Type.OPEN) { - imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> - imageProxy.close() - } - } - } - } catch (e: Exception) { - Log.e(kTag, "Use case binding failed", e) - } - } - - private fun aspectRatio(width: Int, height: Int): Int { - val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) - return if (abs(ratio - RATIO_4_3_VALUE) <= abs(ratio - RATIO_16_9_VALUE) - ) { - AspectRatio.RATIO_4_3 - } else AspectRatio.RATIO_16_9 - } - - private fun takePhoto() { - val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" - val outputFileOptions = ImageCapture.OutputFileOptions - .Builder(File(imagePath)) - .build() - imageCapture.takePicture(outputFileOptions, cameraExecutor, - object : ImageCapture.OnImageSavedCallback { - override fun onImageSaved(results: ImageCapture.OutputFileResults) { - results.savedUri?.apply { - /** - * /storage/emulated/0/Android/data/com.casic.br.operationsite/files/Pictures/IMG20240620140715.png - * */ - Log.d(kTag, "onImageSaved: $path") - if (path.isNullOrBlank()) { - Log.d(kTag, "onImageSaved: path is null") - return@apply - } - analyticalSelectResult(path!!) - } - } - - override fun onError(error: ImageCaptureException) { - error.printStackTrace() - } - }) - } - - private fun analyticalSelectResult(result: String) { - //压缩图片后上传 - result.compressImage(this, object : OnImageCompressListener { - override fun onSuccess(file: File) { - //上传图片 - uploadFileViewModel.uploadImage(context, file) - } - - override fun onError(e: Throwable) { - e.printStackTrace() - } - }) + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] +// constructionCheckViewModel.setVideoRegionResult.observe(this) { +// if (it) { +// "区域配置成功".show(this) +// } +// } } override fun initViewBinding(): ActivityDisclosureBinding { @@ -303,18 +102,7 @@ } override fun observeRequestState() { - uploadFileViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialogHub.show(this, "图片上传中,请稍后...") - LoadState.Success -> LoadingDialogHub.dismiss() - - else -> { - "图片上传失败,请重试...".show(context) - LoadingDialogHub.dismiss() - } - } - } } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt index 91ba0c6..e6e8d1f 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt @@ -157,7 +157,7 @@ //动态设置rtspPlayerView宽高 val params = binding.rtspPlayerView.layoutParams as LinearLayout.LayoutParams - val videoWidth = getScreenWidth() - 30.dp2px(this) + val videoWidth = getScreenWidth() - 20.dp2px(this) val videoHeight = videoWidth * (9f / 16) params.width = videoWidth params.height = videoHeight.toInt() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt index 313308e..701a3cc 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt @@ -1,85 +1,31 @@ package com.casic.br.operationsite.test.view -import android.os.Build import android.os.Bundle -import android.util.DisplayMetrics -import android.util.Log -import android.view.Surface -import android.view.View -import androidx.camera.core.AspectRatio -import androidx.camera.core.CameraSelector -import androidx.camera.core.CameraState -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 +import android.widget.FrameLayout import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.test.R -import com.casic.br.operationsite.test.callback.OnImageCompressListener import com.casic.br.operationsite.test.databinding.ActivityDisclosureBinding -import com.casic.br.operationsite.test.extensions.combineImagePath -import com.casic.br.operationsite.test.extensions.compressImage import com.casic.br.operationsite.test.extensions.initImmersionBar -import com.casic.br.operationsite.test.extensions.upload import com.casic.br.operationsite.test.util.CurrentScene -import com.casic.br.operationsite.test.util.GlideLoadEngine import com.casic.br.operationsite.test.util.LocaleConstant import com.casic.br.operationsite.test.util.RuntimeCache +import com.casic.br.operationsite.test.util.VideoPlayerManager import com.casic.br.operationsite.test.util.tcp.SocketManager -import com.casic.br.operationsite.test.vm.UploadFileViewModel -import com.google.common.util.concurrent.ListenableFuture -import com.luck.picture.lib.basic.PictureSelector -import com.luck.picture.lib.config.SelectMimeType -import com.luck.picture.lib.entity.LocalMedia -import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.casic.br.operationsite.test.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.test.widget.BottomControlSheet import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getScreenWidth import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.ActivityStackManager -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.widget.TitleBarView -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.launch -import java.io.File -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.UUID -import java.util.concurrent.ExecutionException -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.math.abs class DisclosureActivity : KotlinBaseActivity() { - companion object { - private const val RATIO_4_3_VALUE = 4.0 / 3.0 - private const val RATIO_16_9_VALUE = 16.0 / 9.0 - } - private val kTag = "DisclosureActivity" private val context = this - private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } - private val marginOffset by lazy { 1.dp2px(this) } - private lateinit var cameraExecutor: ExecutorService - private lateinit var cameraProviderFuture: ListenableFuture - private lateinit var imageCapture: ImageCapture - private lateinit var imageAnalysis: ImageAnalysis - private lateinit var uploadFileViewModel: UploadFileViewModel - private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 - private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 - private var index = 1 + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel override fun initEvent() { binding.startCheckButton.setOnClickListener { @@ -91,46 +37,23 @@ SocketManager.get.send(LocaleConstant.START_CONSTRUCTION_COMMAND) } - binding.captureImageButton.setOnClickListener { - takePhoto() + binding.showControlViewButton.setOnClickListener { + BottomControlSheet(this).show() } - imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { - override fun onAddImageClick() { - PictureSelector.create(context).openGallery(SelectMimeType.ofImage()) - .isGif(false).isMaxSelectEnabledMask(true).setFilterMinFileSize(100) - .setMaxSelectNum(3).isDisplayCamera(false) - .setImageEngine(GlideLoadEngine.get) - .forResult(object : OnResultCallbackListener { - override fun onResult(result: ArrayList?) { - lifecycleScope.launch { - flow { - result?.forEach { - emit(it) - delay(1000) - } - }.collect { - analyticalSelectResult(it.realPath) - } - } - } + binding.restartVideoButton.setOnClickListener { + binding.rtspPlayerView.startPlayLogic() + } - override fun onCancel() { + binding.clearVideoRegionButton.setOnClickListener { + binding.regionView.clearRoutePath() + } - } - }) - } + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() - override fun onItemClick(position: Int) { - navigatePageTo(position, recyclerViewImages) - } - - override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) - recyclerViewImages.removeAt(position) - imageAdapter.notifyDataSetChanged() - } - }) +// constructionCheckViewModel.setVideoRegion(LocaleConstant.AI_BASE_IP, region) + } binding.endCheckButton.setOnClickListener { if (!SocketManager.get.nettyClient.connectStatus) { @@ -148,154 +71,30 @@ RuntimeCache.currentScene = CurrentScene.DISCLOSURE - cameraExecutor = Executors.newSingleThreadExecutor() - cameraProviderFuture = ProcessCameraProvider.getInstance(this) - cameraProviderFuture.addListener({ - try { - bindPreview(cameraProviderFuture.get()) - } catch (e: ExecutionException) { - e.printStackTrace() - } catch (e: InterruptedException) { - e.printStackTrace() - } - }, ContextCompat.getMainExecutor(this)) + //动态设置rtspPlayerView宽高 + val rtspViewParams = binding.rtspPlayerView.layoutParams as FrameLayout.LayoutParams + val videoWidth = getScreenWidth() - 20.dp2px(this) + val videoHeight = videoWidth * (9f / 16) + rtspViewParams.width = videoWidth + rtspViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = rtspViewParams - val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) - imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 2, 2) - binding.recyclerView.addItemDecoration( - RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + val regionViewParams = binding.regionView.layoutParams as FrameLayout.LayoutParams + regionViewParams.width = videoWidth + regionViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = regionViewParams + + VideoPlayerManager.setGSYVideoPlayerOptions( + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) - binding.recyclerView.adapter = imageAdapter + binding.rtspPlayerView.startPlayLogic() - uploadFileViewModel = ViewModelProvider(this)[UploadFileViewModel::class.java] - uploadFileViewModel.resultModel.observe(this) { - if (it.code == 200) { - val path = it.data.toString() - if (path.isNotBlank()) { - val map = HashMap() - map["id"] = RuntimeCache.uploadFileTaskId - map["imageId"] = UUID.randomUUID().toString() - map["scenario"] = "brief" - map["image"] = path - map["index"] = index.toString() - map["base64"] = "" - map.upload() - index++ - - val url = path.combineImagePath() - imagePaths.add(path) - recyclerViewImages.add(url) - imageAdapter.notifyDataSetChanged() - } - } - } - } - - 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) - .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) - .build() - - cameraProvider.unbindAll() - try { - val camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - imageCapture, - imageAnalysis, - cameraPreViewBuilder - ) - - cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) - camera.cameraInfo.cameraState.observe(this) { - if (it.type == CameraState.Type.OPEN) { - imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> - imageProxy.close() - } - } - } - } catch (e: Exception) { - Log.e(kTag, "Use case binding failed", e) - } - } - - private fun aspectRatio(width: Int, height: Int): Int { - val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) - return if (abs(ratio - RATIO_4_3_VALUE) <= abs(ratio - RATIO_16_9_VALUE) - ) { - AspectRatio.RATIO_4_3 - } else AspectRatio.RATIO_16_9 - } - - private fun takePhoto() { - val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" - val outputFileOptions = ImageCapture.OutputFileOptions - .Builder(File(imagePath)) - .build() - imageCapture.takePicture(outputFileOptions, cameraExecutor, - object : ImageCapture.OnImageSavedCallback { - override fun onImageSaved(results: ImageCapture.OutputFileResults) { - results.savedUri?.apply { - /** - * /storage/emulated/0/Android/data/com.casic.br.operationsite/files/Pictures/IMG20240620140715.png - * */ - Log.d(kTag, "onImageSaved: $path") - if (path.isNullOrBlank()) { - Log.d(kTag, "onImageSaved: path is null") - return@apply - } - analyticalSelectResult(path!!) - } - } - - override fun onError(error: ImageCaptureException) { - error.printStackTrace() - } - }) - } - - private fun analyticalSelectResult(result: String) { - //压缩图片后上传 - result.compressImage(this, object : OnImageCompressListener { - override fun onSuccess(file: File) { - //上传图片 - uploadFileViewModel.uploadImage(context, file) - } - - override fun onError(e: Throwable) { - e.printStackTrace() - } - }) + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] +// constructionCheckViewModel.setVideoRegionResult.observe(this) { +// if (it) { +// "区域配置成功".show(this) +// } +// } } override fun initViewBinding(): ActivityDisclosureBinding { @@ -303,18 +102,7 @@ } override fun observeRequestState() { - uploadFileViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialogHub.show(this, "图片上传中,请稍后...") - LoadState.Success -> LoadingDialogHub.dismiss() - - else -> { - "图片上传失败,请重试...".show(context) - LoadingDialogHub.dismiss() - } - } - } } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt index 91ba0c6..e6e8d1f 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt @@ -157,7 +157,7 @@ //动态设置rtspPlayerView宽高 val params = binding.rtspPlayerView.layoutParams as LinearLayout.LayoutParams - val videoWidth = getScreenWidth() - 30.dp2px(this) + val videoWidth = getScreenWidth() - 20.dp2px(this) val videoHeight = videoWidth * (9f / 16) params.width = videoWidth params.height = videoHeight.toInt() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt index 3927f29..8ec8b0d 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt @@ -204,8 +204,7 @@ binding.rtspPlayerView.layoutParams = regionViewParams VideoPlayerManager.setGSYVideoPlayerOptions( - binding.rtspPlayerView, - LocaleConstant.MAIN_RTSP_URL + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) binding.rtspPlayerView.startPlayLogic() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt index 313308e..701a3cc 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt @@ -1,85 +1,31 @@ package com.casic.br.operationsite.test.view -import android.os.Build import android.os.Bundle -import android.util.DisplayMetrics -import android.util.Log -import android.view.Surface -import android.view.View -import androidx.camera.core.AspectRatio -import androidx.camera.core.CameraSelector -import androidx.camera.core.CameraState -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 +import android.widget.FrameLayout import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.test.R -import com.casic.br.operationsite.test.callback.OnImageCompressListener import com.casic.br.operationsite.test.databinding.ActivityDisclosureBinding -import com.casic.br.operationsite.test.extensions.combineImagePath -import com.casic.br.operationsite.test.extensions.compressImage import com.casic.br.operationsite.test.extensions.initImmersionBar -import com.casic.br.operationsite.test.extensions.upload import com.casic.br.operationsite.test.util.CurrentScene -import com.casic.br.operationsite.test.util.GlideLoadEngine import com.casic.br.operationsite.test.util.LocaleConstant import com.casic.br.operationsite.test.util.RuntimeCache +import com.casic.br.operationsite.test.util.VideoPlayerManager import com.casic.br.operationsite.test.util.tcp.SocketManager -import com.casic.br.operationsite.test.vm.UploadFileViewModel -import com.google.common.util.concurrent.ListenableFuture -import com.luck.picture.lib.basic.PictureSelector -import com.luck.picture.lib.config.SelectMimeType -import com.luck.picture.lib.entity.LocalMedia -import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.casic.br.operationsite.test.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.test.widget.BottomControlSheet import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getScreenWidth import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.ActivityStackManager -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.widget.TitleBarView -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.launch -import java.io.File -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.UUID -import java.util.concurrent.ExecutionException -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.math.abs class DisclosureActivity : KotlinBaseActivity() { - companion object { - private const val RATIO_4_3_VALUE = 4.0 / 3.0 - private const val RATIO_16_9_VALUE = 16.0 / 9.0 - } - private val kTag = "DisclosureActivity" private val context = this - private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } - private val marginOffset by lazy { 1.dp2px(this) } - private lateinit var cameraExecutor: ExecutorService - private lateinit var cameraProviderFuture: ListenableFuture - private lateinit var imageCapture: ImageCapture - private lateinit var imageAnalysis: ImageAnalysis - private lateinit var uploadFileViewModel: UploadFileViewModel - private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 - private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 - private var index = 1 + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel override fun initEvent() { binding.startCheckButton.setOnClickListener { @@ -91,46 +37,23 @@ SocketManager.get.send(LocaleConstant.START_CONSTRUCTION_COMMAND) } - binding.captureImageButton.setOnClickListener { - takePhoto() + binding.showControlViewButton.setOnClickListener { + BottomControlSheet(this).show() } - imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { - override fun onAddImageClick() { - PictureSelector.create(context).openGallery(SelectMimeType.ofImage()) - .isGif(false).isMaxSelectEnabledMask(true).setFilterMinFileSize(100) - .setMaxSelectNum(3).isDisplayCamera(false) - .setImageEngine(GlideLoadEngine.get) - .forResult(object : OnResultCallbackListener { - override fun onResult(result: ArrayList?) { - lifecycleScope.launch { - flow { - result?.forEach { - emit(it) - delay(1000) - } - }.collect { - analyticalSelectResult(it.realPath) - } - } - } + binding.restartVideoButton.setOnClickListener { + binding.rtspPlayerView.startPlayLogic() + } - override fun onCancel() { + binding.clearVideoRegionButton.setOnClickListener { + binding.regionView.clearRoutePath() + } - } - }) - } + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() - override fun onItemClick(position: Int) { - navigatePageTo(position, recyclerViewImages) - } - - override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) - recyclerViewImages.removeAt(position) - imageAdapter.notifyDataSetChanged() - } - }) +// constructionCheckViewModel.setVideoRegion(LocaleConstant.AI_BASE_IP, region) + } binding.endCheckButton.setOnClickListener { if (!SocketManager.get.nettyClient.connectStatus) { @@ -148,154 +71,30 @@ RuntimeCache.currentScene = CurrentScene.DISCLOSURE - cameraExecutor = Executors.newSingleThreadExecutor() - cameraProviderFuture = ProcessCameraProvider.getInstance(this) - cameraProviderFuture.addListener({ - try { - bindPreview(cameraProviderFuture.get()) - } catch (e: ExecutionException) { - e.printStackTrace() - } catch (e: InterruptedException) { - e.printStackTrace() - } - }, ContextCompat.getMainExecutor(this)) + //动态设置rtspPlayerView宽高 + val rtspViewParams = binding.rtspPlayerView.layoutParams as FrameLayout.LayoutParams + val videoWidth = getScreenWidth() - 20.dp2px(this) + val videoHeight = videoWidth * (9f / 16) + rtspViewParams.width = videoWidth + rtspViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = rtspViewParams - val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) - imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 2, 2) - binding.recyclerView.addItemDecoration( - RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + val regionViewParams = binding.regionView.layoutParams as FrameLayout.LayoutParams + regionViewParams.width = videoWidth + regionViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = regionViewParams + + VideoPlayerManager.setGSYVideoPlayerOptions( + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) - binding.recyclerView.adapter = imageAdapter + binding.rtspPlayerView.startPlayLogic() - uploadFileViewModel = ViewModelProvider(this)[UploadFileViewModel::class.java] - uploadFileViewModel.resultModel.observe(this) { - if (it.code == 200) { - val path = it.data.toString() - if (path.isNotBlank()) { - val map = HashMap() - map["id"] = RuntimeCache.uploadFileTaskId - map["imageId"] = UUID.randomUUID().toString() - map["scenario"] = "brief" - map["image"] = path - map["index"] = index.toString() - map["base64"] = "" - map.upload() - index++ - - val url = path.combineImagePath() - imagePaths.add(path) - recyclerViewImages.add(url) - imageAdapter.notifyDataSetChanged() - } - } - } - } - - 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) - .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) - .build() - - cameraProvider.unbindAll() - try { - val camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - imageCapture, - imageAnalysis, - cameraPreViewBuilder - ) - - cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) - camera.cameraInfo.cameraState.observe(this) { - if (it.type == CameraState.Type.OPEN) { - imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> - imageProxy.close() - } - } - } - } catch (e: Exception) { - Log.e(kTag, "Use case binding failed", e) - } - } - - private fun aspectRatio(width: Int, height: Int): Int { - val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) - return if (abs(ratio - RATIO_4_3_VALUE) <= abs(ratio - RATIO_16_9_VALUE) - ) { - AspectRatio.RATIO_4_3 - } else AspectRatio.RATIO_16_9 - } - - private fun takePhoto() { - val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" - val outputFileOptions = ImageCapture.OutputFileOptions - .Builder(File(imagePath)) - .build() - imageCapture.takePicture(outputFileOptions, cameraExecutor, - object : ImageCapture.OnImageSavedCallback { - override fun onImageSaved(results: ImageCapture.OutputFileResults) { - results.savedUri?.apply { - /** - * /storage/emulated/0/Android/data/com.casic.br.operationsite/files/Pictures/IMG20240620140715.png - * */ - Log.d(kTag, "onImageSaved: $path") - if (path.isNullOrBlank()) { - Log.d(kTag, "onImageSaved: path is null") - return@apply - } - analyticalSelectResult(path!!) - } - } - - override fun onError(error: ImageCaptureException) { - error.printStackTrace() - } - }) - } - - private fun analyticalSelectResult(result: String) { - //压缩图片后上传 - result.compressImage(this, object : OnImageCompressListener { - override fun onSuccess(file: File) { - //上传图片 - uploadFileViewModel.uploadImage(context, file) - } - - override fun onError(e: Throwable) { - e.printStackTrace() - } - }) + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] +// constructionCheckViewModel.setVideoRegionResult.observe(this) { +// if (it) { +// "区域配置成功".show(this) +// } +// } } override fun initViewBinding(): ActivityDisclosureBinding { @@ -303,18 +102,7 @@ } override fun observeRequestState() { - uploadFileViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialogHub.show(this, "图片上传中,请稍后...") - LoadState.Success -> LoadingDialogHub.dismiss() - - else -> { - "图片上传失败,请重试...".show(context) - LoadingDialogHub.dismiss() - } - } - } } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt index 91ba0c6..e6e8d1f 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt @@ -157,7 +157,7 @@ //动态设置rtspPlayerView宽高 val params = binding.rtspPlayerView.layoutParams as LinearLayout.LayoutParams - val videoWidth = getScreenWidth() - 30.dp2px(this) + val videoWidth = getScreenWidth() - 20.dp2px(this) val videoHeight = videoWidth * (9f / 16) params.width = videoWidth params.height = videoHeight.toInt() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt index 3927f29..8ec8b0d 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt @@ -204,8 +204,7 @@ binding.rtspPlayerView.layoutParams = regionViewParams VideoPlayerManager.setGSYVideoPlayerOptions( - binding.rtspPlayerView, - LocaleConstant.MAIN_RTSP_URL + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) binding.rtspPlayerView.startPlayLogic() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt index 0445500..59c25b2 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt @@ -174,7 +174,7 @@ //动态设置rtspPlayerView宽高 val params = binding.rtspPlayerView.layoutParams as LinearLayout.LayoutParams - val videoWidth = getScreenWidth() - 30.dp2px(this) + val videoWidth = getScreenWidth() - 20.dp2px(this) val videoHeight = videoWidth * (9f / 16) params.width = videoWidth params.height = videoHeight.toInt() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt index 313308e..701a3cc 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/DisclosureActivity.kt @@ -1,85 +1,31 @@ package com.casic.br.operationsite.test.view -import android.os.Build import android.os.Bundle -import android.util.DisplayMetrics -import android.util.Log -import android.view.Surface -import android.view.View -import androidx.camera.core.AspectRatio -import androidx.camera.core.CameraSelector -import androidx.camera.core.CameraState -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 +import android.widget.FrameLayout import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import com.casic.br.operationsite.test.R -import com.casic.br.operationsite.test.callback.OnImageCompressListener import com.casic.br.operationsite.test.databinding.ActivityDisclosureBinding -import com.casic.br.operationsite.test.extensions.combineImagePath -import com.casic.br.operationsite.test.extensions.compressImage import com.casic.br.operationsite.test.extensions.initImmersionBar -import com.casic.br.operationsite.test.extensions.upload import com.casic.br.operationsite.test.util.CurrentScene -import com.casic.br.operationsite.test.util.GlideLoadEngine import com.casic.br.operationsite.test.util.LocaleConstant import com.casic.br.operationsite.test.util.RuntimeCache +import com.casic.br.operationsite.test.util.VideoPlayerManager import com.casic.br.operationsite.test.util.tcp.SocketManager -import com.casic.br.operationsite.test.vm.UploadFileViewModel -import com.google.common.util.concurrent.ListenableFuture -import com.luck.picture.lib.basic.PictureSelector -import com.luck.picture.lib.config.SelectMimeType -import com.luck.picture.lib.entity.LocalMedia -import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter +import com.casic.br.operationsite.test.vm.ConstructionCheckViewModel +import com.casic.br.operationsite.test.widget.BottomControlSheet import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getScreenWidth import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.ActivityStackManager -import com.pengxh.kt.lite.utils.LoadState -import com.pengxh.kt.lite.utils.LoadingDialogHub import com.pengxh.kt.lite.widget.TitleBarView -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.launch -import java.io.File -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.UUID -import java.util.concurrent.ExecutionException -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import kotlin.math.abs class DisclosureActivity : KotlinBaseActivity() { - companion object { - private const val RATIO_4_3_VALUE = 4.0 / 3.0 - private const val RATIO_16_9_VALUE = 16.0 / 9.0 - } - private val kTag = "DisclosureActivity" private val context = this - private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) } - private val marginOffset by lazy { 1.dp2px(this) } - private lateinit var cameraExecutor: ExecutorService - private lateinit var cameraProviderFuture: ListenableFuture - private lateinit var imageCapture: ImageCapture - private lateinit var imageAnalysis: ImageAnalysis - private lateinit var uploadFileViewModel: UploadFileViewModel - private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 - private val recyclerViewImages: ArrayList = ArrayList() //真实图片路径 - private var index = 1 + private lateinit var constructionCheckViewModel: ConstructionCheckViewModel override fun initEvent() { binding.startCheckButton.setOnClickListener { @@ -91,46 +37,23 @@ SocketManager.get.send(LocaleConstant.START_CONSTRUCTION_COMMAND) } - binding.captureImageButton.setOnClickListener { - takePhoto() + binding.showControlViewButton.setOnClickListener { + BottomControlSheet(this).show() } - imageAdapter.setOnItemClickListener(object : EditableImageAdapter.OnItemClickListener { - override fun onAddImageClick() { - PictureSelector.create(context).openGallery(SelectMimeType.ofImage()) - .isGif(false).isMaxSelectEnabledMask(true).setFilterMinFileSize(100) - .setMaxSelectNum(3).isDisplayCamera(false) - .setImageEngine(GlideLoadEngine.get) - .forResult(object : OnResultCallbackListener { - override fun onResult(result: ArrayList?) { - lifecycleScope.launch { - flow { - result?.forEach { - emit(it) - delay(1000) - } - }.collect { - analyticalSelectResult(it.realPath) - } - } - } + binding.restartVideoButton.setOnClickListener { + binding.rtspPlayerView.startPlayLogic() + } - override fun onCancel() { + binding.clearVideoRegionButton.setOnClickListener { + binding.regionView.clearRoutePath() + } - } - }) - } + binding.setVideoRegionButton.setOnClickListener { + val region = binding.regionView.getConfirmedPoints() - override fun onItemClick(position: Int) { - navigatePageTo(position, recyclerViewImages) - } - - override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) - recyclerViewImages.removeAt(position) - imageAdapter.notifyDataSetChanged() - } - }) +// constructionCheckViewModel.setVideoRegion(LocaleConstant.AI_BASE_IP, region) + } binding.endCheckButton.setOnClickListener { if (!SocketManager.get.nettyClient.connectStatus) { @@ -148,154 +71,30 @@ RuntimeCache.currentScene = CurrentScene.DISCLOSURE - cameraExecutor = Executors.newSingleThreadExecutor() - cameraProviderFuture = ProcessCameraProvider.getInstance(this) - cameraProviderFuture.addListener({ - try { - bindPreview(cameraProviderFuture.get()) - } catch (e: ExecutionException) { - e.printStackTrace() - } catch (e: InterruptedException) { - e.printStackTrace() - } - }, ContextCompat.getMainExecutor(this)) + //动态设置rtspPlayerView宽高 + val rtspViewParams = binding.rtspPlayerView.layoutParams as FrameLayout.LayoutParams + val videoWidth = getScreenWidth() - 20.dp2px(this) + val videoHeight = videoWidth * (9f / 16) + rtspViewParams.width = videoWidth + rtspViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = rtspViewParams - val viewWidth = getScreenWidth() - (15 + 15).dp2px(this) - imageAdapter = EditableImageAdapter(this, recyclerViewImages, viewWidth, 2, 2) - binding.recyclerView.addItemDecoration( - RecyclerViewItemOffsets(marginOffset, marginOffset, marginOffset, marginOffset) + val regionViewParams = binding.regionView.layoutParams as FrameLayout.LayoutParams + regionViewParams.width = videoWidth + regionViewParams.height = videoHeight.toInt() + binding.rtspPlayerView.layoutParams = regionViewParams + + VideoPlayerManager.setGSYVideoPlayerOptions( + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) - binding.recyclerView.adapter = imageAdapter + binding.rtspPlayerView.startPlayLogic() - uploadFileViewModel = ViewModelProvider(this)[UploadFileViewModel::class.java] - uploadFileViewModel.resultModel.observe(this) { - if (it.code == 200) { - val path = it.data.toString() - if (path.isNotBlank()) { - val map = HashMap() - map["id"] = RuntimeCache.uploadFileTaskId - map["imageId"] = UUID.randomUUID().toString() - map["scenario"] = "brief" - map["image"] = path - map["index"] = index.toString() - map["base64"] = "" - map.upload() - index++ - - val url = path.combineImagePath() - imagePaths.add(path) - recyclerViewImages.add(url) - imageAdapter.notifyDataSetChanged() - } - } - } - } - - 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) - .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) - .build() - - cameraProvider.unbindAll() - try { - val camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - imageCapture, - imageAnalysis, - cameraPreViewBuilder - ) - - cameraPreViewBuilder.setSurfaceProvider(binding.cameraPreView.surfaceProvider) - camera.cameraInfo.cameraState.observe(this) { - if (it.type == CameraState.Type.OPEN) { - imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy -> - imageProxy.close() - } - } - } - } catch (e: Exception) { - Log.e(kTag, "Use case binding failed", e) - } - } - - private fun aspectRatio(width: Int, height: Int): Int { - val ratio = width.coerceAtLeast(height).toDouble() / width.coerceAtMost(height) - return if (abs(ratio - RATIO_4_3_VALUE) <= abs(ratio - RATIO_16_9_VALUE) - ) { - AspectRatio.RATIO_4_3 - } else AspectRatio.RATIO_16_9 - } - - private fun takePhoto() { - val imagePath = "/${createImageFileDir()}/IMG${timeFormat.format(Date())}.png" - val outputFileOptions = ImageCapture.OutputFileOptions - .Builder(File(imagePath)) - .build() - imageCapture.takePicture(outputFileOptions, cameraExecutor, - object : ImageCapture.OnImageSavedCallback { - override fun onImageSaved(results: ImageCapture.OutputFileResults) { - results.savedUri?.apply { - /** - * /storage/emulated/0/Android/data/com.casic.br.operationsite/files/Pictures/IMG20240620140715.png - * */ - Log.d(kTag, "onImageSaved: $path") - if (path.isNullOrBlank()) { - Log.d(kTag, "onImageSaved: path is null") - return@apply - } - analyticalSelectResult(path!!) - } - } - - override fun onError(error: ImageCaptureException) { - error.printStackTrace() - } - }) - } - - private fun analyticalSelectResult(result: String) { - //压缩图片后上传 - result.compressImage(this, object : OnImageCompressListener { - override fun onSuccess(file: File) { - //上传图片 - uploadFileViewModel.uploadImage(context, file) - } - - override fun onError(e: Throwable) { - e.printStackTrace() - } - }) + constructionCheckViewModel = ViewModelProvider(this)[ConstructionCheckViewModel::class.java] +// constructionCheckViewModel.setVideoRegionResult.observe(this) { +// if (it) { +// "区域配置成功".show(this) +// } +// } } override fun initViewBinding(): ActivityDisclosureBinding { @@ -303,18 +102,7 @@ } override fun observeRequestState() { - uploadFileViewModel.loadState.observe(this) { - when (it) { - LoadState.Loading -> LoadingDialogHub.show(this, "图片上传中,请稍后...") - LoadState.Success -> LoadingDialogHub.dismiss() - - else -> { - "图片上传失败,请重试...".show(context) - LoadingDialogHub.dismiss() - } - } - } } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt index 91ba0c6..e6e8d1f 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/EnvironmentActivity.kt @@ -157,7 +157,7 @@ //动态设置rtspPlayerView宽高 val params = binding.rtspPlayerView.layoutParams as LinearLayout.LayoutParams - val videoWidth = getScreenWidth() - 30.dp2px(this) + val videoWidth = getScreenWidth() - 20.dp2px(this) val videoHeight = videoWidth * (9f / 16) params.width = videoWidth params.height = videoHeight.toInt() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt index 3927f29..8ec8b0d 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/GuardiansActivity.kt @@ -204,8 +204,7 @@ binding.rtspPlayerView.layoutParams = regionViewParams VideoPlayerManager.setGSYVideoPlayerOptions( - binding.rtspPlayerView, - LocaleConstant.MAIN_RTSP_URL + binding.rtspPlayerView, LocaleConstant.MAIN_RTSP_URL ) binding.rtspPlayerView.startPlayLogic() diff --git a/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt b/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt index 0445500..59c25b2 100644 --- a/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt +++ b/app/src/main/java/com/casic/br/operationsite/test/view/SuppliesActivity.kt @@ -174,7 +174,7 @@ //动态设置rtspPlayerView宽高 val params = binding.rtspPlayerView.layoutParams as LinearLayout.LayoutParams - val videoWidth = getScreenWidth() - 30.dp2px(this) + val videoWidth = getScreenWidth() - 20.dp2px(this) val videoHeight = videoWidth * (9f / 16) params.width = videoWidth params.height = videoHeight.toInt() diff --git a/app/src/main/res/layout/activity_disclosure.xml b/app/src/main/res/layout/activity_disclosure.xml index 5c7c3db..c047f83 100644 --- a/app/src/main/res/layout/activity_disclosure.xml +++ b/app/src/main/res/layout/activity_disclosure.xml @@ -28,44 +28,98 @@ android:layout_weight="1" android:orientation="vertical"> -