Newer
Older
Endoscope / app / src / main / java / com / casic / endoscope / view / MainActivity.kt
package com.casic.endoscope.view

import android.annotation.SuppressLint
import android.graphics.PixelFormat
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.util.Log
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.View
import androidx.lifecycle.lifecycleScope
import com.casic.endoscope.adapter.CameraPointAdapter
import com.casic.endoscope.bean.CameraPointBean
import com.casic.endoscope.databinding.ActivityMainBinding
import com.casic.endoscope.extensions.createHorizontalCommand
import com.casic.endoscope.extensions.createImageFileDir
import com.casic.endoscope.extensions.createVerticalCommand
import com.casic.endoscope.extensions.createVideoFileDir
import com.casic.endoscope.extensions.getChannel
import com.casic.endoscope.extensions.toTime
import com.casic.endoscope.utils.DataBaseManager
import com.casic.endoscope.utils.ProjectConstant
import com.casic.endoscope.utils.hk.MessageCodeHub
import com.casic.endoscope.utils.hk.SDKGuider
import com.casic.endoscope.widgets.AddCameraPointDialog
import com.gyf.immersionbar.ImmersionBar
import com.hikvision.netsdk.HCNetSDK
import com.hikvision.netsdk.NET_DVR_JPEGPARA
import com.hikvision.netsdk.NET_DVR_PREVIEWINFO
import com.hikvision.netsdk.NET_DVR_SERIALSTART_V40
import com.hikvision.netsdk.PTZCommand
import com.pengxh.kt.lite.base.KotlinBaseActivity
import com.pengxh.kt.lite.extensions.getStatusBarHeight
import com.pengxh.kt.lite.extensions.navigatePageTo
import com.pengxh.kt.lite.extensions.show
import com.pengxh.kt.lite.utils.WeakReferenceHandler
import com.pengxh.kt.lite.widget.SteeringWheelView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.Timer
import java.util.TimerTask

@SuppressLint("all")
class MainActivity : KotlinBaseActivity<ActivityMainBinding>(), SurfaceHolder.Callback,
    Handler.Callback {

    private val kTag = "MainActivity"
    private val context = this@MainActivity
    private val hkSDK by lazy { HCNetSDK.getInstance() }
    private val timeFormat by lazy { SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA) }
    private val selectedSpeed = 7
    private val messageCode = 2024021901
    private var clickTime = 0L
    private var previewHandle = -1
    private var selectChannel = -1
    private var returnUserId = -1
    private var aChannelNum = 0
    private var startAChannel = 0
    private var dChannelNum = 0
    private var startDChannel = 0
    private var isPreviewSuccess = false

    //手指是否已经从方向控制盘抬起
    private var isActionUp = true

    //焦距按钮是否已松开
    private var isScaleButtonUp = true

    //是否拍照成功
    private var isCaptureSuccess = true

    private var timer: Timer? = null
    private var timerTask: TimerTask? = null
    private var seconds = 0L
    private var dataBeans: MutableList<CameraPointBean> = ArrayList()
    private var selectedItems: MutableList<CameraPointBean> = ArrayList()
    private lateinit var weakReferenceHandler: WeakReferenceHandler
    private lateinit var dataAdapter: CameraPointAdapter

    override fun initViewBinding(): ActivityMainBinding {
        return ActivityMainBinding.inflate(layoutInflater)
    }

    override fun initOnCreate(savedInstanceState: Bundle?) {
        weakReferenceHandler = WeakReferenceHandler(this)

        dataBeans = DataBaseManager.get.loadAllCameraPoint()

        //显示数据
        weakReferenceHandler.sendEmptyMessage(messageCode)
    }

    override fun handleMessage(msg: Message): Boolean {
        if (msg.what == messageCode) {
            //绑定数据
            dataAdapter = CameraPointAdapter(this, dataBeans)
            binding.recyclerView.adapter = dataAdapter
            dataAdapter.setOnItemCheckedListener(object : CameraPointAdapter.OnItemCheckedListener {
                override fun onItemChecked(position: Int, items: ArrayList<CameraPointBean>) {
                    selectedItems = items
                }
            })
        }
        return true
    }

    override fun initEvent() {
        binding.openAlbumButton.setOnClickListener {
            if (isPreviewSuccess) {
                "设备预览画面中,无法切换".show(this)
                return@setOnClickListener
            }
            navigatePageTo<AlbumActivity>()
        }

        //单张拍照
        binding.imageButton.setOnClickListener {
            if (isPreviewSuccess) {
                binding.imageButton.isEnabled = false

                val strJpeg = NET_DVR_JPEGPARA()
                strJpeg.wPicQuality = 1
                strJpeg.wPicSize = 2

                val imagePath = "/${createImageFileDir()}/${timeFormat.format(Date())}.png"
                hkSDK.NET_DVR_CaptureJPEGPicture(
                    returnUserId, selectChannel, strJpeg, imagePath
                )

                if (MessageCodeHub.getErrorCode() == 0) {
                    "画面抓取成功".show(this)
                    binding.imageButton.isEnabled = true
                }
            } else {
                "摄像头预览未打开,无法拍照".show(this)
            }
        }

        //视频录制
        binding.videoButton.setOnClickListener {
            if (isPreviewSuccess) {
                val videoPath = "/${createVideoFileDir()}/${timeFormat.format(Date())}.mp4"
                hkSDK.NET_DVR_SaveRealData(returnUserId, videoPath)
                binding.videoStateView.visibility = View.VISIBLE
            } else {
                "摄像头预览未打开,无法录制视频".show(this)
            }
        }

        binding.videoButton.setOnLongClickListener {
            //停止视频抓取
            hkSDK.NET_DVR_StopSaveRealData(returnUserId)
            binding.videoStateView.visibility = View.INVISIBLE
            "视频录制成功".show(this)
            true
        }

        //连续拍照
        binding.multipleImageButton.setOnClickListener {
            if (dataBeans.isEmpty()) {
                "请先设置连续拍照步骤".show(this)
                return@setOnClickListener
            }
            if (isPreviewSuccess) {
                lifecycleScope.launch(Dispatchers.IO) {
                    dataBeans.forEach {
                        //再拍照
                        if (isCaptureSuccess) {
                            isCaptureSuccess = false

                            //先执行角度
                            executeAngle(it.hAngle, it.vAngle)

                            withContext(Dispatchers.Main) {
                                "抓取步骤${it.step}画面".show(context)
                            }

                            val strJpeg = NET_DVR_JPEGPARA()
                            strJpeg.wPicQuality = 1
                            strJpeg.wPicSize = 2

                            val imagePath =
                                "/${createImageFileDir()}/${timeFormat.format(Date())}.png"
                            hkSDK.NET_DVR_CaptureJPEGPicture(
                                returnUserId, selectChannel, strJpeg, imagePath
                            )

                            isCaptureSuccess = MessageCodeHub.getErrorCode() == 0
                        }
                    }
                    withContext(Dispatchers.Main) {
                        "连续抓取画面完成".show(context)
                    }
                }
            } else {
                "摄像头预览未打开,无法拍照".show(this)
            }
        }

        binding.addButton.setOnClickListener {
            val step = if (dataBeans.isEmpty()) {
                0
            } else {
                dataBeans.last().step
            }
            AddCameraPointDialog.Builder()
                .setContext(this)
                .setLastStep(step)
                .setNegativeButton("取消")
                .setPositiveButton("添加")
                .setOnDialogButtonClickListener(object :
                    AddCameraPointDialog.OnDialogButtonClickListener {
                    override fun onConfirmClick(step: Int, hAngle: Int, vAngle: Int) {
                        DataBaseManager.get.cacheCameraPoint(step, hAngle, vAngle)
                        dataBeans = DataBaseManager.get.loadAllCameraPoint()
                        dataAdapter.setRefreshData(dataBeans)
                    }

                    override fun onCancelClick() {

                    }
                }).build().show()
        }

        binding.deleteButton.setOnClickListener {
            if (selectedItems.isEmpty()) {
                "请先选择要删除的步骤".show(this)
                return@setOnClickListener
            }
            DataBaseManager.get.deleteCameraPoints(selectedItems)
            dataBeans = DataBaseManager.get.loadAllCameraPoint()
            dataAdapter.setRefreshData(dataBeans)
            selectedItems.clear()
        }

        binding.steeringWheelView.setOnWheelTouchListener(object :
            SteeringWheelView.OnWheelTouchListener {
            override fun onCenterClicked() {
                if (!isPreviewSuccess) {
                    val deviceItem = SDKGuider.sdkGuider.devManageGuider.DeviceItem()
                    deviceItem.szDevName = ""
                    deviceItem.devNetInfo = SDKGuider.sdkGuider.devManageGuider.DevNetInfo(
                        ProjectConstant.HK_NET_IP,
                        ProjectConstant.HK_NET_PORT,
                        ProjectConstant.HK_NET_USERNAME,
                        ProjectConstant.HK_NET_PASSWORD
                    )
                    if (deviceItem.szDevName.isEmpty()) {
                        deviceItem.szDevName = deviceItem.devNetInfo.szIp
                    }
                    val loginV40Jna = SDKGuider.sdkGuider.devManageGuider.login_v40_jna(
                        deviceItem.szDevName, deviceItem.devNetInfo
                    )
                    if (loginV40Jna) {
                        //配置设备通道
                        try {
                            val deviceInfo = SDKGuider.sdkGuider.devManageGuider.devList[0]
                            returnUserId = deviceInfo.szUserId

                            aChannelNum =
                                deviceInfo.deviceInfoV40_jna.struDeviceV30.byChanNum.toInt()
                            startAChannel =
                                deviceInfo.deviceInfoV40_jna.struDeviceV30.byStartChan.toInt()

                            dChannelNum = deviceInfo.deviceInfoV40_jna.struDeviceV30.byIPChanNum +
                                    deviceInfo.deviceInfoV40_jna.struDeviceV30.byHighDChanNum * 256
                            startDChannel =
                                deviceInfo.deviceInfoV40_jna.struDeviceV30.byStartChan.toInt()

                            var iAnalogStartChan = startAChannel
                            var iDigitalStartChan = startDChannel

                            val channelList = ArrayList<String>()

                            for (i in 0 until aChannelNum) {
                                channelList.add("ACamera_$iAnalogStartChan")
                                iAnalogStartChan++
                            }

                            for (i in 0 until dChannelNum) {
                                channelList.add("DCamera_$iDigitalStartChan")
                                iDigitalStartChan++
                            }
                            selectChannel = Integer.valueOf(channelList[0].getChannel())

                            val streamList = ArrayList<String>()
                            streamList.add("main_stream")
                            streamList.add("sub_stream")
                            streamList.add("third_stream")

                            //开始预览
                            if (previewHandle != -1) {
                                SDKGuider.sdkGuider.devPreviewGuider.RealPlay_Stop_jni(previewHandle)
                            }
                            val strutPlayInfo = NET_DVR_PREVIEWINFO()
                            strutPlayInfo.lChannel = selectChannel
                            strutPlayInfo.dwStreamType = 1
                            strutPlayInfo.bBlocked = 1
                            strutPlayInfo.hHwnd = binding.surfaceView.holder
                            previewHandle = SDKGuider.sdkGuider.devPreviewGuider.RealPlay_V40_jni(
                                returnUserId, strutPlayInfo, null
                            )
                            if (previewHandle < 0) {
                                Log.d(kTag, "initEvent: Err:${MessageCodeHub.getErrorCode()}")
                                return
                            }
                            isPreviewSuccess = true
                            "预览开启成功".show(context)
                            //开始计时
                            timer = Timer()
                            timerTask = object : TimerTask() {
                                override fun run() {
                                    seconds++
                                    lifecycleScope.launch(Dispatchers.Main) {
                                        binding.runningTimeView.text = seconds.toTime()
                                    }
                                }
                            }
                            timer?.schedule(timerTask, 0, 1000)
                        } catch (e: IndexOutOfBoundsException) {
                            e.printStackTrace()
                            "设备未正常连接,无法开启预览".show(context)
                        }
                    }
                } else {
                    if (!SDKGuider.sdkGuider.devPreviewGuider.RealPlay_Stop_jni(previewHandle)) {
                        return
                    }
                    previewHandle = -1
                    isPreviewSuccess = false
                    "预览关闭成功".show(context)
                    //停止计时
                    timerTask?.cancel()
                    timer?.cancel()
                }
            }

            override fun onLeftTurn() {
                if (isPreviewSuccess && isActionUp) {
                    hkSDK.NET_DVR_PTZControlWithSpeed(
                        previewHandle, PTZCommand.PAN_LEFT, 0, selectedSpeed
                    )
                    isActionUp = false
                }
            }

            override fun onTopTurn() {
                if (isPreviewSuccess && isActionUp) {
                    hkSDK.NET_DVR_PTZControlWithSpeed(
                        previewHandle, PTZCommand.TILT_UP, 0, selectedSpeed
                    )
                    isActionUp = false
                }
            }

            override fun onRightTurn() {
                if (isPreviewSuccess && isActionUp) {
                    hkSDK.NET_DVR_PTZControlWithSpeed(
                        previewHandle, PTZCommand.PAN_RIGHT, 0, selectedSpeed
                    )
                    isActionUp = false
                }
            }

            override fun onBottomTurn() {
                if (isPreviewSuccess && isActionUp) {
                    hkSDK.NET_DVR_PTZControlWithSpeed(
                        previewHandle, PTZCommand.TILT_DOWN, 0, selectedSpeed
                    )
                    isActionUp = false
                }
            }

            override fun onActionTurnUp(dir: SteeringWheelView.Direction) {
                when (dir) {
                    SteeringWheelView.Direction.LEFT -> {
                        hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.PAN_LEFT, 1)
                        isActionUp = true
                    }

                    SteeringWheelView.Direction.TOP -> {
                        hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.TILT_UP, 1)
                        isActionUp = true
                    }

                    SteeringWheelView.Direction.RIGHT -> {
                        hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.PAN_RIGHT, 1)
                        isActionUp = true
                    }

                    SteeringWheelView.Direction.BOTTOM -> {
                        hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.TILT_DOWN, 1)
                        isActionUp = true
                    }
                }
            }
        })

        binding.upScaleButton.setOnTouchListener { _, event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    if (isPreviewSuccess && isScaleButtonUp) {
                        hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_IN, 0)
                        isScaleButtonUp = false
                    }
                }

                MotionEvent.ACTION_UP -> {
                    isScaleButtonUp = true
                    hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_IN, 1)
                }
            }
            false
        }

        binding.downScaleButton.setOnTouchListener { _, event ->
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    if (isPreviewSuccess && isScaleButtonUp) {
                        hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_OUT, 0)
                        isScaleButtonUp = false
                    }
                }

                MotionEvent.ACTION_UP -> {
                    isScaleButtonUp = true
                    hkSDK.NET_DVR_PTZControl(previewHandle, PTZCommand.ZOOM_OUT, 1)
                }
            }
            false
        }
    }

    /**
     * 角度执行
     * */
    private fun executeAngle(horizontal: Int, vertical: Int) {
        //建立透明通道
        val serialStart = NET_DVR_SERIALSTART_V40()
        //串口类型:1- 232 串口,2- 485 串口
        serialStart.dwSerialPort = 2
        //串口编号
        serialStart.wPort = 0
        val serialHandle = hkSDK.NET_DVR_SerialStart_V40(
            returnUserId, serialStart
        ) { _, _, _, _ -> }

        //向透明通道发送数据,水平和垂直需要分开发送
        hkSDK.NET_DVR_SerialSend(
            serialHandle,
            1,
            horizontal.createHorizontalCommand(),
            horizontal.createHorizontalCommand().size
        )
        try {
            Thread.sleep(50)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        hkSDK.NET_DVR_SerialSend(
            serialHandle,
            1,
            vertical.createVerticalCommand(),
            vertical.createVerticalCommand().size
        )

        try {
            Thread.sleep(50)
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        //关闭通道
        hkSDK.NET_DVR_SerialStop(serialHandle)
    }

    override fun observeRequestState() {

    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        binding.surfaceView.holder.setFormat(PixelFormat.TRANSLUCENT)
        if (-1 == previewHandle) {
            return
        }
        val surface = holder.surface
        if (surface.isValid) {
            if (-1 == SDKGuider.sdkGuider.devPreviewGuider.RealPlaySurfaceChanged_jni(
                    previewHandle, 0, holder
                )
            ) {
                Log.d(kTag, "surfaceCreated: ${MessageCodeHub.getErrorCode()}")
            }
        }
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {

    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        if (-1 == previewHandle) {
            return
        }
        if (holder.surface.isValid) {
            if (-1 == SDKGuider.sdkGuider.devPreviewGuider.RealPlaySurfaceChanged_jni(
                    previewHandle, 0, null
                )
            ) {
                Log.d(kTag, "surfaceDestroyed: ${MessageCodeHub.getErrorCode()}")
            }
        }
    }

    override fun setupTopBarLayout() {
        ImmersionBar.with(this).statusBarDarkFont(false).init()
        //根据不同设备状态栏高度设置statusBarView高度
        val statusBarHeight = getStatusBarHeight()
        binding.rootView.setPadding(0, statusBarHeight, 0, 0)
        binding.rootView.requestLayout()
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (System.currentTimeMillis() - clickTime > 2000) {
                "再按一次退出应用".show(this)
                clickTime = System.currentTimeMillis()
                return true
            } else {
                super.onKeyDown(keyCode, event)
            }
        }
        return super.onKeyDown(keyCode, event)
    }
}