diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0fa65d..7df3629 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,10 @@ android:name=".view.TaskDetailActivity" android:screenOrientation="landscape" /> + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0fa65d..7df3629 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,10 @@ android:name=".view.TaskDetailActivity" android:screenOrientation="landscape" /> + diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt index 4d41ff1..983505d 100644 --- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt +++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt @@ -263,6 +263,10 @@ } binding.deleteTaskButton.setOnClickListener { + if (selectedItems.isEmpty()) { + "请先勾选要批量删除的任务".show(requireContext()) + return@setOnClickListener + } val ids = ArrayList() selectedItems.forEach { task -> ids.add(task.id) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0fa65d..7df3629 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,10 @@ android:name=".view.TaskDetailActivity" android:screenOrientation="landscape" /> + diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt index 4d41ff1..983505d 100644 --- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt +++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt @@ -263,6 +263,10 @@ } binding.deleteTaskButton.setOnClickListener { + if (selectedItems.isEmpty()) { + "请先勾选要批量删除的任务".show(requireContext()) + return@setOnClickListener + } val ids = ArrayList() selectedItems.forEach { task -> ids.add(task.id) diff --git a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt index a2a0c30..82e7be5 100644 --- a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt @@ -1,6 +1,8 @@ package com.casic.br.ktd.view +import android.content.res.Configuration import android.os.Bundle +import android.util.Log import android.view.View import androidx.lifecycle.ViewModelProvider import com.amap.api.maps.CoordinateConverter @@ -19,10 +21,18 @@ import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.PageNavigationManager import com.pengxh.kt.lite.vm.LoadState +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack +import com.shuyu.gsyvideoplayer.utils.OrientationUtils class AlarmDetailActivity : KotlinBaseActivity() { + private val kTag = "AlarmDetailActivity" private lateinit var alarmViewModel: AlarmViewModel + private lateinit var orientationUtils: OrientationUtils + private var isPlay = false + private var isPause = false override fun initEvent() { @@ -32,6 +42,10 @@ PageNavigationManager.addActivity(this) val alarmId = intent.getStringExtra(Constant.INTENT_PARAM)!! + orientationUtils = OrientationUtils(this, binding.videoPlayerView) + //初始化不打开外部的旋转 + orientationUtils.isEnable = false + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] alarmViewModel.getAlarmDetail(alarmId) alarmViewModel.alarmDetail.observe(this) { @@ -87,6 +101,39 @@ } else { binding.emptyImageView.visibility = View.GONE binding.videoPlayerView.visibility = View.VISIBLE + + val videoPath = model.alarmVideo.combineImagePath() + Log.d(kTag, "initOnCreate => $videoPath") + val videoOption = GSYVideoOptionBuilder() + videoOption.setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setAutoFullWithSize(true) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setUrl(videoPath) + .setCacheWithPlay(false) + .setVideoTitle(model.taskName) + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onPrepared(url: String, vararg objects: Any) { + super.onPrepared(url, *objects) + //开始播放了才能旋转和全屏 + orientationUtils.isEnable = true + isPlay = true + } + + override fun onQuitFullscreen(url: String, vararg objects: Any) { + super.onQuitFullscreen(url, *objects) + orientationUtils.backToProtVideo() + } + }).setLockClickListener { _, lock -> + orientationUtils.isEnable = !lock + }.build(binding.videoPlayerView) + binding.videoPlayerView.fullscreenButton.setOnClickListener { + //直接横屏 + orientationUtils.resolveByClick() + binding.videoPlayerView.startWindowFullscreen(this, true, true) + } } } } @@ -112,4 +159,46 @@ override fun setupTopBarLayout() { ImmersionBar.with(this).statusBarDarkFont(true).init() } + + override fun onBackPressed() { + orientationUtils.backToProtVideo() + if (GSYVideoManager.backFromWindowFull(this)) { + return + } + super.onBackPressed() + } + + override fun onPause() { + binding.videoPlayerView.currentPlayer.onVideoPause() + super.onPause() + isPause = true + } + + override fun onResume() { + binding.videoPlayerView.currentPlayer.onVideoResume(false) + super.onResume() + isPause = false + } + + override fun onDestroy() { + if (isPlay) { + binding.videoPlayerView.currentPlayer.release() + } + orientationUtils.releaseListener() + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + //如果旋转了就全屏 + if (isPlay && !isPause) { + binding.videoPlayerView.onConfigurationChanged( + this, + newConfig, + orientationUtils, + true, + true + ) + } + } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0fa65d..7df3629 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,10 @@ android:name=".view.TaskDetailActivity" android:screenOrientation="landscape" /> + diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt index 4d41ff1..983505d 100644 --- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt +++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt @@ -263,6 +263,10 @@ } binding.deleteTaskButton.setOnClickListener { + if (selectedItems.isEmpty()) { + "请先勾选要批量删除的任务".show(requireContext()) + return@setOnClickListener + } val ids = ArrayList() selectedItems.forEach { task -> ids.add(task.id) diff --git a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt index a2a0c30..82e7be5 100644 --- a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt @@ -1,6 +1,8 @@ package com.casic.br.ktd.view +import android.content.res.Configuration import android.os.Bundle +import android.util.Log import android.view.View import androidx.lifecycle.ViewModelProvider import com.amap.api.maps.CoordinateConverter @@ -19,10 +21,18 @@ import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.PageNavigationManager import com.pengxh.kt.lite.vm.LoadState +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack +import com.shuyu.gsyvideoplayer.utils.OrientationUtils class AlarmDetailActivity : KotlinBaseActivity() { + private val kTag = "AlarmDetailActivity" private lateinit var alarmViewModel: AlarmViewModel + private lateinit var orientationUtils: OrientationUtils + private var isPlay = false + private var isPause = false override fun initEvent() { @@ -32,6 +42,10 @@ PageNavigationManager.addActivity(this) val alarmId = intent.getStringExtra(Constant.INTENT_PARAM)!! + orientationUtils = OrientationUtils(this, binding.videoPlayerView) + //初始化不打开外部的旋转 + orientationUtils.isEnable = false + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] alarmViewModel.getAlarmDetail(alarmId) alarmViewModel.alarmDetail.observe(this) { @@ -87,6 +101,39 @@ } else { binding.emptyImageView.visibility = View.GONE binding.videoPlayerView.visibility = View.VISIBLE + + val videoPath = model.alarmVideo.combineImagePath() + Log.d(kTag, "initOnCreate => $videoPath") + val videoOption = GSYVideoOptionBuilder() + videoOption.setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setAutoFullWithSize(true) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setUrl(videoPath) + .setCacheWithPlay(false) + .setVideoTitle(model.taskName) + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onPrepared(url: String, vararg objects: Any) { + super.onPrepared(url, *objects) + //开始播放了才能旋转和全屏 + orientationUtils.isEnable = true + isPlay = true + } + + override fun onQuitFullscreen(url: String, vararg objects: Any) { + super.onQuitFullscreen(url, *objects) + orientationUtils.backToProtVideo() + } + }).setLockClickListener { _, lock -> + orientationUtils.isEnable = !lock + }.build(binding.videoPlayerView) + binding.videoPlayerView.fullscreenButton.setOnClickListener { + //直接横屏 + orientationUtils.resolveByClick() + binding.videoPlayerView.startWindowFullscreen(this, true, true) + } } } } @@ -112,4 +159,46 @@ override fun setupTopBarLayout() { ImmersionBar.with(this).statusBarDarkFont(true).init() } + + override fun onBackPressed() { + orientationUtils.backToProtVideo() + if (GSYVideoManager.backFromWindowFull(this)) { + return + } + super.onBackPressed() + } + + override fun onPause() { + binding.videoPlayerView.currentPlayer.onVideoPause() + super.onPause() + isPause = true + } + + override fun onResume() { + binding.videoPlayerView.currentPlayer.onVideoResume(false) + super.onResume() + isPause = false + } + + override fun onDestroy() { + if (isPlay) { + binding.videoPlayerView.currentPlayer.release() + } + orientationUtils.releaseListener() + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + //如果旋转了就全屏 + if (isPlay && !isPause) { + binding.videoPlayerView.onConfigurationChanged( + this, + newConfig, + orientationUtils, + true, + true + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt index 811e69d..b25a889 100644 --- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt @@ -7,6 +7,8 @@ import android.graphics.Color import android.graphics.PixelFormat import android.os.Bundle +import android.os.CountDownTimer +import android.os.Environment import android.os.Handler import android.os.Message import android.util.Log @@ -127,6 +129,9 @@ //甲烷浓度阈值 private var gasAlarmRule = 1000 + //是否正在抓取视频 + private var isRecordingVideo = false + override fun initViewBinding(): ActivityInspectionBinding { return ActivityInspectionBinding.inflate(layoutInflater) } @@ -204,20 +209,39 @@ lng = aMapLocation.latitude.toString() address = aMapLocation.address speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat() - alarmViewModel.addAlarm( - taskId, - deviceId, - "甲烷浓度超过阈值", - lat, - lng, - System.currentTimeMillis().timestampToCompleteDate(), - gasAlarmRule.toString(), - it.data, - "0", - "1", - "", - dataModel?.methane.toString(), - ) + + if (it.data.endsWith(".png")) { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + it.data, + "0", + "1", + "", + dataModel?.methane.toString(), + ) + } else { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + "", + "0", + "1", + it.data, + dataModel?.methane.toString(), + ) + isRecordingVideo = false + } } }, true ) @@ -606,8 +630,8 @@ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt() startAChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() - dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + - deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 + dChannelNum = + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 startDChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() var iAnalogStartChan = startAChannel @@ -655,7 +679,9 @@ //打开激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.OPEN_SENSOR_COMMAND, LocaleConstant.OPEN_SENSOR_COMMAND.size ) @@ -748,6 +774,31 @@ } /** + * 视频抓取,抓取15s的视频 + * */ + private fun recordVideo() { + if (!isRecordingVideo) { + isRecordingVideo = true + val videoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4" + Log.d(kTag, "开始抓取视频 => $videoPath") + hkSDK.NET_DVR_SaveRealData(returnUserId, videoPath) + object : CountDownTimer(15 * 1000, 1000) { + override fun onTick(l: Long) { + + } + + override fun onFinish() { + //停止视频抓取 + hkSDK.NET_DVR_StopSaveRealData(returnUserId) + + //海康视频不能直接播放,需要转码。服务器转码 + fileViewModel.uploadFile(File(videoPath), FileType.VIDEO) + } + }.start() + } + } + + /** * 画面抓取 * */ private fun captureImage(isAutoCapture: Boolean) { @@ -770,7 +821,9 @@ private fun stopPreview() { //关闭激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.CLOSE_SENSOR_COMMAND, LocaleConstant.CLOSE_SENSOR_COMMAND.size ) @@ -835,9 +888,9 @@ if (dataModel!!.methane >= gasAlarmRule) { isAlarm = "1" - captureImage(true) + recordVideo() - //TODO 抓取报警时候的视频并上传 + captureImage(true) } /***折线图**************************************************************************/ @@ -924,4 +977,13 @@ super.onSaveInstanceState(outState) binding.mapView.onSaveInstanceState(outState) } + + //扩展函数 + private fun Context.createVideoFileDir(): File { + val videoDir = File(this.getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + if (!videoDir.exists()) { + videoDir.mkdir() + } + return videoDir + } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0fa65d..7df3629 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,10 @@ android:name=".view.TaskDetailActivity" android:screenOrientation="landscape" /> + diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt index 4d41ff1..983505d 100644 --- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt +++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt @@ -263,6 +263,10 @@ } binding.deleteTaskButton.setOnClickListener { + if (selectedItems.isEmpty()) { + "请先勾选要批量删除的任务".show(requireContext()) + return@setOnClickListener + } val ids = ArrayList() selectedItems.forEach { task -> ids.add(task.id) diff --git a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt index a2a0c30..82e7be5 100644 --- a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt @@ -1,6 +1,8 @@ package com.casic.br.ktd.view +import android.content.res.Configuration import android.os.Bundle +import android.util.Log import android.view.View import androidx.lifecycle.ViewModelProvider import com.amap.api.maps.CoordinateConverter @@ -19,10 +21,18 @@ import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.PageNavigationManager import com.pengxh.kt.lite.vm.LoadState +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack +import com.shuyu.gsyvideoplayer.utils.OrientationUtils class AlarmDetailActivity : KotlinBaseActivity() { + private val kTag = "AlarmDetailActivity" private lateinit var alarmViewModel: AlarmViewModel + private lateinit var orientationUtils: OrientationUtils + private var isPlay = false + private var isPause = false override fun initEvent() { @@ -32,6 +42,10 @@ PageNavigationManager.addActivity(this) val alarmId = intent.getStringExtra(Constant.INTENT_PARAM)!! + orientationUtils = OrientationUtils(this, binding.videoPlayerView) + //初始化不打开外部的旋转 + orientationUtils.isEnable = false + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] alarmViewModel.getAlarmDetail(alarmId) alarmViewModel.alarmDetail.observe(this) { @@ -87,6 +101,39 @@ } else { binding.emptyImageView.visibility = View.GONE binding.videoPlayerView.visibility = View.VISIBLE + + val videoPath = model.alarmVideo.combineImagePath() + Log.d(kTag, "initOnCreate => $videoPath") + val videoOption = GSYVideoOptionBuilder() + videoOption.setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setAutoFullWithSize(true) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setUrl(videoPath) + .setCacheWithPlay(false) + .setVideoTitle(model.taskName) + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onPrepared(url: String, vararg objects: Any) { + super.onPrepared(url, *objects) + //开始播放了才能旋转和全屏 + orientationUtils.isEnable = true + isPlay = true + } + + override fun onQuitFullscreen(url: String, vararg objects: Any) { + super.onQuitFullscreen(url, *objects) + orientationUtils.backToProtVideo() + } + }).setLockClickListener { _, lock -> + orientationUtils.isEnable = !lock + }.build(binding.videoPlayerView) + binding.videoPlayerView.fullscreenButton.setOnClickListener { + //直接横屏 + orientationUtils.resolveByClick() + binding.videoPlayerView.startWindowFullscreen(this, true, true) + } } } } @@ -112,4 +159,46 @@ override fun setupTopBarLayout() { ImmersionBar.with(this).statusBarDarkFont(true).init() } + + override fun onBackPressed() { + orientationUtils.backToProtVideo() + if (GSYVideoManager.backFromWindowFull(this)) { + return + } + super.onBackPressed() + } + + override fun onPause() { + binding.videoPlayerView.currentPlayer.onVideoPause() + super.onPause() + isPause = true + } + + override fun onResume() { + binding.videoPlayerView.currentPlayer.onVideoResume(false) + super.onResume() + isPause = false + } + + override fun onDestroy() { + if (isPlay) { + binding.videoPlayerView.currentPlayer.release() + } + orientationUtils.releaseListener() + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + //如果旋转了就全屏 + if (isPlay && !isPause) { + binding.videoPlayerView.onConfigurationChanged( + this, + newConfig, + orientationUtils, + true, + true + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt index 811e69d..b25a889 100644 --- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt @@ -7,6 +7,8 @@ import android.graphics.Color import android.graphics.PixelFormat import android.os.Bundle +import android.os.CountDownTimer +import android.os.Environment import android.os.Handler import android.os.Message import android.util.Log @@ -127,6 +129,9 @@ //甲烷浓度阈值 private var gasAlarmRule = 1000 + //是否正在抓取视频 + private var isRecordingVideo = false + override fun initViewBinding(): ActivityInspectionBinding { return ActivityInspectionBinding.inflate(layoutInflater) } @@ -204,20 +209,39 @@ lng = aMapLocation.latitude.toString() address = aMapLocation.address speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat() - alarmViewModel.addAlarm( - taskId, - deviceId, - "甲烷浓度超过阈值", - lat, - lng, - System.currentTimeMillis().timestampToCompleteDate(), - gasAlarmRule.toString(), - it.data, - "0", - "1", - "", - dataModel?.methane.toString(), - ) + + if (it.data.endsWith(".png")) { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + it.data, + "0", + "1", + "", + dataModel?.methane.toString(), + ) + } else { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + "", + "0", + "1", + it.data, + dataModel?.methane.toString(), + ) + isRecordingVideo = false + } } }, true ) @@ -606,8 +630,8 @@ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt() startAChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() - dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + - deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 + dChannelNum = + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 startDChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() var iAnalogStartChan = startAChannel @@ -655,7 +679,9 @@ //打开激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.OPEN_SENSOR_COMMAND, LocaleConstant.OPEN_SENSOR_COMMAND.size ) @@ -748,6 +774,31 @@ } /** + * 视频抓取,抓取15s的视频 + * */ + private fun recordVideo() { + if (!isRecordingVideo) { + isRecordingVideo = true + val videoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4" + Log.d(kTag, "开始抓取视频 => $videoPath") + hkSDK.NET_DVR_SaveRealData(returnUserId, videoPath) + object : CountDownTimer(15 * 1000, 1000) { + override fun onTick(l: Long) { + + } + + override fun onFinish() { + //停止视频抓取 + hkSDK.NET_DVR_StopSaveRealData(returnUserId) + + //海康视频不能直接播放,需要转码。服务器转码 + fileViewModel.uploadFile(File(videoPath), FileType.VIDEO) + } + }.start() + } + } + + /** * 画面抓取 * */ private fun captureImage(isAutoCapture: Boolean) { @@ -770,7 +821,9 @@ private fun stopPreview() { //关闭激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.CLOSE_SENSOR_COMMAND, LocaleConstant.CLOSE_SENSOR_COMMAND.size ) @@ -835,9 +888,9 @@ if (dataModel!!.methane >= gasAlarmRule) { isAlarm = "1" - captureImage(true) + recordVideo() - //TODO 抓取报警时候的视频并上传 + captureImage(true) } /***折线图**************************************************************************/ @@ -924,4 +977,13 @@ super.onSaveInstanceState(outState) binding.mapView.onSaveInstanceState(outState) } + + //扩展函数 + private fun Context.createVideoFileDir(): File { + val videoDir = File(this.getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + if (!videoDir.exists()) { + videoDir.mkdir() + } + return videoDir + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt index e90c1ee..4b03815 100644 --- a/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt @@ -19,6 +19,7 @@ import com.casic.br.ktd.widgets.DateRangeActionSheet import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.WeakReferenceHandler @@ -175,8 +176,7 @@ taskDetailAdapter.setOnClickedListener(object : TaskDetailAdapter.OnClickedListener { override fun onShowTextClicked(item: TaskDetailModel.DataModel.RowsModel) { - //TODO 播放视频 - item.taskId.show(this@TaskDetailActivity) + navigatePageTo(item.taskId) } }) } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0fa65d..7df3629 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,10 @@ android:name=".view.TaskDetailActivity" android:screenOrientation="landscape" /> + diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt index 4d41ff1..983505d 100644 --- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt +++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt @@ -263,6 +263,10 @@ } binding.deleteTaskButton.setOnClickListener { + if (selectedItems.isEmpty()) { + "请先勾选要批量删除的任务".show(requireContext()) + return@setOnClickListener + } val ids = ArrayList() selectedItems.forEach { task -> ids.add(task.id) diff --git a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt index a2a0c30..82e7be5 100644 --- a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt @@ -1,6 +1,8 @@ package com.casic.br.ktd.view +import android.content.res.Configuration import android.os.Bundle +import android.util.Log import android.view.View import androidx.lifecycle.ViewModelProvider import com.amap.api.maps.CoordinateConverter @@ -19,10 +21,18 @@ import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.PageNavigationManager import com.pengxh.kt.lite.vm.LoadState +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack +import com.shuyu.gsyvideoplayer.utils.OrientationUtils class AlarmDetailActivity : KotlinBaseActivity() { + private val kTag = "AlarmDetailActivity" private lateinit var alarmViewModel: AlarmViewModel + private lateinit var orientationUtils: OrientationUtils + private var isPlay = false + private var isPause = false override fun initEvent() { @@ -32,6 +42,10 @@ PageNavigationManager.addActivity(this) val alarmId = intent.getStringExtra(Constant.INTENT_PARAM)!! + orientationUtils = OrientationUtils(this, binding.videoPlayerView) + //初始化不打开外部的旋转 + orientationUtils.isEnable = false + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] alarmViewModel.getAlarmDetail(alarmId) alarmViewModel.alarmDetail.observe(this) { @@ -87,6 +101,39 @@ } else { binding.emptyImageView.visibility = View.GONE binding.videoPlayerView.visibility = View.VISIBLE + + val videoPath = model.alarmVideo.combineImagePath() + Log.d(kTag, "initOnCreate => $videoPath") + val videoOption = GSYVideoOptionBuilder() + videoOption.setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setAutoFullWithSize(true) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setUrl(videoPath) + .setCacheWithPlay(false) + .setVideoTitle(model.taskName) + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onPrepared(url: String, vararg objects: Any) { + super.onPrepared(url, *objects) + //开始播放了才能旋转和全屏 + orientationUtils.isEnable = true + isPlay = true + } + + override fun onQuitFullscreen(url: String, vararg objects: Any) { + super.onQuitFullscreen(url, *objects) + orientationUtils.backToProtVideo() + } + }).setLockClickListener { _, lock -> + orientationUtils.isEnable = !lock + }.build(binding.videoPlayerView) + binding.videoPlayerView.fullscreenButton.setOnClickListener { + //直接横屏 + orientationUtils.resolveByClick() + binding.videoPlayerView.startWindowFullscreen(this, true, true) + } } } } @@ -112,4 +159,46 @@ override fun setupTopBarLayout() { ImmersionBar.with(this).statusBarDarkFont(true).init() } + + override fun onBackPressed() { + orientationUtils.backToProtVideo() + if (GSYVideoManager.backFromWindowFull(this)) { + return + } + super.onBackPressed() + } + + override fun onPause() { + binding.videoPlayerView.currentPlayer.onVideoPause() + super.onPause() + isPause = true + } + + override fun onResume() { + binding.videoPlayerView.currentPlayer.onVideoResume(false) + super.onResume() + isPause = false + } + + override fun onDestroy() { + if (isPlay) { + binding.videoPlayerView.currentPlayer.release() + } + orientationUtils.releaseListener() + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + //如果旋转了就全屏 + if (isPlay && !isPause) { + binding.videoPlayerView.onConfigurationChanged( + this, + newConfig, + orientationUtils, + true, + true + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt index 811e69d..b25a889 100644 --- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt @@ -7,6 +7,8 @@ import android.graphics.Color import android.graphics.PixelFormat import android.os.Bundle +import android.os.CountDownTimer +import android.os.Environment import android.os.Handler import android.os.Message import android.util.Log @@ -127,6 +129,9 @@ //甲烷浓度阈值 private var gasAlarmRule = 1000 + //是否正在抓取视频 + private var isRecordingVideo = false + override fun initViewBinding(): ActivityInspectionBinding { return ActivityInspectionBinding.inflate(layoutInflater) } @@ -204,20 +209,39 @@ lng = aMapLocation.latitude.toString() address = aMapLocation.address speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat() - alarmViewModel.addAlarm( - taskId, - deviceId, - "甲烷浓度超过阈值", - lat, - lng, - System.currentTimeMillis().timestampToCompleteDate(), - gasAlarmRule.toString(), - it.data, - "0", - "1", - "", - dataModel?.methane.toString(), - ) + + if (it.data.endsWith(".png")) { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + it.data, + "0", + "1", + "", + dataModel?.methane.toString(), + ) + } else { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + "", + "0", + "1", + it.data, + dataModel?.methane.toString(), + ) + isRecordingVideo = false + } } }, true ) @@ -606,8 +630,8 @@ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt() startAChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() - dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + - deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 + dChannelNum = + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 startDChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() var iAnalogStartChan = startAChannel @@ -655,7 +679,9 @@ //打开激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.OPEN_SENSOR_COMMAND, LocaleConstant.OPEN_SENSOR_COMMAND.size ) @@ -748,6 +774,31 @@ } /** + * 视频抓取,抓取15s的视频 + * */ + private fun recordVideo() { + if (!isRecordingVideo) { + isRecordingVideo = true + val videoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4" + Log.d(kTag, "开始抓取视频 => $videoPath") + hkSDK.NET_DVR_SaveRealData(returnUserId, videoPath) + object : CountDownTimer(15 * 1000, 1000) { + override fun onTick(l: Long) { + + } + + override fun onFinish() { + //停止视频抓取 + hkSDK.NET_DVR_StopSaveRealData(returnUserId) + + //海康视频不能直接播放,需要转码。服务器转码 + fileViewModel.uploadFile(File(videoPath), FileType.VIDEO) + } + }.start() + } + } + + /** * 画面抓取 * */ private fun captureImage(isAutoCapture: Boolean) { @@ -770,7 +821,9 @@ private fun stopPreview() { //关闭激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.CLOSE_SENSOR_COMMAND, LocaleConstant.CLOSE_SENSOR_COMMAND.size ) @@ -835,9 +888,9 @@ if (dataModel!!.methane >= gasAlarmRule) { isAlarm = "1" - captureImage(true) + recordVideo() - //TODO 抓取报警时候的视频并上传 + captureImage(true) } /***折线图**************************************************************************/ @@ -924,4 +977,13 @@ super.onSaveInstanceState(outState) binding.mapView.onSaveInstanceState(outState) } + + //扩展函数 + private fun Context.createVideoFileDir(): File { + val videoDir = File(this.getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + if (!videoDir.exists()) { + videoDir.mkdir() + } + return videoDir + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt index e90c1ee..4b03815 100644 --- a/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt @@ -19,6 +19,7 @@ import com.casic.br.ktd.widgets.DateRangeActionSheet import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.WeakReferenceHandler @@ -175,8 +176,7 @@ taskDetailAdapter.setOnClickedListener(object : TaskDetailAdapter.OnClickedListener { override fun onShowTextClicked(item: TaskDetailModel.DataModel.RowsModel) { - //TODO 播放视频 - item.taskId.show(this@TaskDetailActivity) + navigatePageTo(item.taskId) } }) } diff --git a/app/src/main/java/com/casic/br/ktd/view/VideoPlayerActivity.kt b/app/src/main/java/com/casic/br/ktd/view/VideoPlayerActivity.kt new file mode 100644 index 0000000..9b04bb6 --- /dev/null +++ b/app/src/main/java/com/casic/br/ktd/view/VideoPlayerActivity.kt @@ -0,0 +1,89 @@ +package com.casic.br.ktd.view + +import android.content.res.Configuration +import android.os.Bundle +import com.casic.br.ktd.databinding.ActivityVideoPlayerBinding +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.utils.Constant +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.utils.OrientationUtils + +class VideoPlayerActivity : KotlinBaseActivity() { + + private lateinit var orientationUtils: OrientationUtils + private var isPlay = false + private var isPause = false + + override fun initEvent() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val params = window.attributes + params.width = (getScreenWidth() * 0.8).toInt() + params.height = (getScreenHeight() * 0.8).toInt() + window.attributes = params + + orientationUtils = OrientationUtils(this, binding.videoPlayerView) + //初始化不打开外部的旋转 + orientationUtils.isEnable = false + + val taskId = intent.getStringExtra(Constant.INTENT_PARAM) + } + + override fun initViewBinding(): ActivityVideoPlayerBinding { + return ActivityVideoPlayerBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + + } + + override fun setupTopBarLayout() { + + } + + override fun onBackPressed() { + orientationUtils.backToProtVideo() + if (GSYVideoManager.backFromWindowFull(this)) { + return + } + super.onBackPressed() + } + + override fun onPause() { + binding.videoPlayerView.currentPlayer.onVideoPause() + super.onPause() + isPause = true + } + + override fun onResume() { + binding.videoPlayerView.currentPlayer.onVideoResume(false) + super.onResume() + isPause = false + } + + override fun onDestroy() { + if (isPlay) { + binding.videoPlayerView.currentPlayer.release() + } + orientationUtils.releaseListener() + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + //如果旋转了就全屏 + if (isPlay && !isPause) { + binding.videoPlayerView.onConfigurationChanged( + this, + newConfig, + orientationUtils, + true, + true + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0fa65d..7df3629 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,6 +57,10 @@ android:name=".view.TaskDetailActivity" android:screenOrientation="landscape" /> + diff --git a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt index 4d41ff1..983505d 100644 --- a/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt +++ b/app/src/main/java/com/casic/br/ktd/fragment/TaskPageFragment.kt @@ -263,6 +263,10 @@ } binding.deleteTaskButton.setOnClickListener { + if (selectedItems.isEmpty()) { + "请先勾选要批量删除的任务".show(requireContext()) + return@setOnClickListener + } val ids = ArrayList() selectedItems.forEach { task -> ids.add(task.id) diff --git a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt index a2a0c30..82e7be5 100644 --- a/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/AlarmDetailActivity.kt @@ -1,6 +1,8 @@ package com.casic.br.ktd.view +import android.content.res.Configuration import android.os.Bundle +import android.util.Log import android.view.View import androidx.lifecycle.ViewModelProvider import com.amap.api.maps.CoordinateConverter @@ -19,10 +21,18 @@ import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.PageNavigationManager import com.pengxh.kt.lite.vm.LoadState +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder +import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack +import com.shuyu.gsyvideoplayer.utils.OrientationUtils class AlarmDetailActivity : KotlinBaseActivity() { + private val kTag = "AlarmDetailActivity" private lateinit var alarmViewModel: AlarmViewModel + private lateinit var orientationUtils: OrientationUtils + private var isPlay = false + private var isPause = false override fun initEvent() { @@ -32,6 +42,10 @@ PageNavigationManager.addActivity(this) val alarmId = intent.getStringExtra(Constant.INTENT_PARAM)!! + orientationUtils = OrientationUtils(this, binding.videoPlayerView) + //初始化不打开外部的旋转 + orientationUtils.isEnable = false + alarmViewModel = ViewModelProvider(this)[AlarmViewModel::class.java] alarmViewModel.getAlarmDetail(alarmId) alarmViewModel.alarmDetail.observe(this) { @@ -87,6 +101,39 @@ } else { binding.emptyImageView.visibility = View.GONE binding.videoPlayerView.visibility = View.VISIBLE + + val videoPath = model.alarmVideo.combineImagePath() + Log.d(kTag, "initOnCreate => $videoPath") + val videoOption = GSYVideoOptionBuilder() + videoOption.setIsTouchWiget(true) + .setRotateViewAuto(false) + .setLockLand(false) + .setAutoFullWithSize(true) + .setShowFullAnimation(false) + .setNeedLockFull(true) + .setUrl(videoPath) + .setCacheWithPlay(false) + .setVideoTitle(model.taskName) + .setVideoAllCallBack(object : GSYSampleCallBack() { + override fun onPrepared(url: String, vararg objects: Any) { + super.onPrepared(url, *objects) + //开始播放了才能旋转和全屏 + orientationUtils.isEnable = true + isPlay = true + } + + override fun onQuitFullscreen(url: String, vararg objects: Any) { + super.onQuitFullscreen(url, *objects) + orientationUtils.backToProtVideo() + } + }).setLockClickListener { _, lock -> + orientationUtils.isEnable = !lock + }.build(binding.videoPlayerView) + binding.videoPlayerView.fullscreenButton.setOnClickListener { + //直接横屏 + orientationUtils.resolveByClick() + binding.videoPlayerView.startWindowFullscreen(this, true, true) + } } } } @@ -112,4 +159,46 @@ override fun setupTopBarLayout() { ImmersionBar.with(this).statusBarDarkFont(true).init() } + + override fun onBackPressed() { + orientationUtils.backToProtVideo() + if (GSYVideoManager.backFromWindowFull(this)) { + return + } + super.onBackPressed() + } + + override fun onPause() { + binding.videoPlayerView.currentPlayer.onVideoPause() + super.onPause() + isPause = true + } + + override fun onResume() { + binding.videoPlayerView.currentPlayer.onVideoResume(false) + super.onResume() + isPause = false + } + + override fun onDestroy() { + if (isPlay) { + binding.videoPlayerView.currentPlayer.release() + } + orientationUtils.releaseListener() + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + //如果旋转了就全屏 + if (isPlay && !isPause) { + binding.videoPlayerView.onConfigurationChanged( + this, + newConfig, + orientationUtils, + true, + true + ) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt index 811e69d..b25a889 100644 --- a/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/InspectionActivity.kt @@ -7,6 +7,8 @@ import android.graphics.Color import android.graphics.PixelFormat import android.os.Bundle +import android.os.CountDownTimer +import android.os.Environment import android.os.Handler import android.os.Message import android.util.Log @@ -127,6 +129,9 @@ //甲烷浓度阈值 private var gasAlarmRule = 1000 + //是否正在抓取视频 + private var isRecordingVideo = false + override fun initViewBinding(): ActivityInspectionBinding { return ActivityInspectionBinding.inflate(layoutInflater) } @@ -204,20 +209,39 @@ lng = aMapLocation.latitude.toString() address = aMapLocation.address speed = decimalFormat.format(aMapLocation.speed * 3.6).toFloat() - alarmViewModel.addAlarm( - taskId, - deviceId, - "甲烷浓度超过阈值", - lat, - lng, - System.currentTimeMillis().timestampToCompleteDate(), - gasAlarmRule.toString(), - it.data, - "0", - "1", - "", - dataModel?.methane.toString(), - ) + + if (it.data.endsWith(".png")) { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + it.data, + "0", + "1", + "", + dataModel?.methane.toString(), + ) + } else { + alarmViewModel.addAlarm( + taskId, + deviceId, + "甲烷浓度超过阈值", + lat, + lng, + System.currentTimeMillis().timestampToCompleteDate(), + gasAlarmRule.toString(), + "", + "0", + "1", + it.data, + dataModel?.methane.toString(), + ) + isRecordingVideo = false + } } }, true ) @@ -606,8 +630,8 @@ aChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byChanNum.toInt() startAChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() - dChannelNum = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + - deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 + dChannelNum = + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byIPChanNum + deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256 startDChannel = deviceInfo.m_struDeviceInfoV40_jna.struDeviceV30.byStartChan.toInt() var iAnalogStartChan = startAChannel @@ -655,7 +679,9 @@ //打开激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.OPEN_SENSOR_COMMAND, LocaleConstant.OPEN_SENSOR_COMMAND.size ) @@ -748,6 +774,31 @@ } /** + * 视频抓取,抓取15s的视频 + * */ + private fun recordVideo() { + if (!isRecordingVideo) { + isRecordingVideo = true + val videoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4" + Log.d(kTag, "开始抓取视频 => $videoPath") + hkSDK.NET_DVR_SaveRealData(returnUserId, videoPath) + object : CountDownTimer(15 * 1000, 1000) { + override fun onTick(l: Long) { + + } + + override fun onFinish() { + //停止视频抓取 + hkSDK.NET_DVR_StopSaveRealData(returnUserId) + + //海康视频不能直接播放,需要转码。服务器转码 + fileViewModel.uploadFile(File(videoPath), FileType.VIDEO) + } + }.start() + } + } + + /** * 画面抓取 * */ private fun captureImage(isAutoCapture: Boolean) { @@ -770,7 +821,9 @@ private fun stopPreview() { //关闭激光传感器 SDKGuider.sdkGuider.devPassThroughGuider.NET_DVR_SendToSerialPort_jni( - returnUserId, 2, 1, + returnUserId, + 2, + 1, LocaleConstant.CLOSE_SENSOR_COMMAND, LocaleConstant.CLOSE_SENSOR_COMMAND.size ) @@ -835,9 +888,9 @@ if (dataModel!!.methane >= gasAlarmRule) { isAlarm = "1" - captureImage(true) + recordVideo() - //TODO 抓取报警时候的视频并上传 + captureImage(true) } /***折线图**************************************************************************/ @@ -924,4 +977,13 @@ super.onSaveInstanceState(outState) binding.mapView.onSaveInstanceState(outState) } + + //扩展函数 + private fun Context.createVideoFileDir(): File { + val videoDir = File(this.getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + if (!videoDir.exists()) { + videoDir.mkdir() + } + return videoDir + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt b/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt index e90c1ee..4b03815 100644 --- a/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt +++ b/app/src/main/java/com/casic/br/ktd/view/TaskDetailActivity.kt @@ -19,6 +19,7 @@ import com.casic.br.ktd.widgets.DateRangeActionSheet import com.gyf.immersionbar.ImmersionBar import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show import com.pengxh.kt.lite.utils.Constant import com.pengxh.kt.lite.utils.WeakReferenceHandler @@ -175,8 +176,7 @@ taskDetailAdapter.setOnClickedListener(object : TaskDetailAdapter.OnClickedListener { override fun onShowTextClicked(item: TaskDetailModel.DataModel.RowsModel) { - //TODO 播放视频 - item.taskId.show(this@TaskDetailActivity) + navigatePageTo(item.taskId) } }) } diff --git a/app/src/main/java/com/casic/br/ktd/view/VideoPlayerActivity.kt b/app/src/main/java/com/casic/br/ktd/view/VideoPlayerActivity.kt new file mode 100644 index 0000000..9b04bb6 --- /dev/null +++ b/app/src/main/java/com/casic/br/ktd/view/VideoPlayerActivity.kt @@ -0,0 +1,89 @@ +package com.casic.br.ktd.view + +import android.content.res.Configuration +import android.os.Bundle +import com.casic.br.ktd.databinding.ActivityVideoPlayerBinding +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.utils.Constant +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.utils.OrientationUtils + +class VideoPlayerActivity : KotlinBaseActivity() { + + private lateinit var orientationUtils: OrientationUtils + private var isPlay = false + private var isPause = false + + override fun initEvent() { + + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val params = window.attributes + params.width = (getScreenWidth() * 0.8).toInt() + params.height = (getScreenHeight() * 0.8).toInt() + window.attributes = params + + orientationUtils = OrientationUtils(this, binding.videoPlayerView) + //初始化不打开外部的旋转 + orientationUtils.isEnable = false + + val taskId = intent.getStringExtra(Constant.INTENT_PARAM) + } + + override fun initViewBinding(): ActivityVideoPlayerBinding { + return ActivityVideoPlayerBinding.inflate(layoutInflater) + } + + override fun observeRequestState() { + + } + + override fun setupTopBarLayout() { + + } + + override fun onBackPressed() { + orientationUtils.backToProtVideo() + if (GSYVideoManager.backFromWindowFull(this)) { + return + } + super.onBackPressed() + } + + override fun onPause() { + binding.videoPlayerView.currentPlayer.onVideoPause() + super.onPause() + isPause = true + } + + override fun onResume() { + binding.videoPlayerView.currentPlayer.onVideoResume(false) + super.onResume() + isPause = false + } + + override fun onDestroy() { + if (isPlay) { + binding.videoPlayerView.currentPlayer.release() + } + orientationUtils.releaseListener() + super.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + //如果旋转了就全屏 + if (isPlay && !isPause) { + binding.videoPlayerView.onConfigurationChanged( + this, + newConfig, + orientationUtils, + true, + true + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_video_player.xml b/app/src/main/res/layout/activity_video_player.xml new file mode 100644 index 0000000..c33aa1c --- /dev/null +++ b/app/src/main/res/layout/activity_video_player.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file