1428 lines
61 KiB
Kotlin
1428 lines
61 KiB
Kotlin
package com.aros.apron.activity
|
||
|
||
import android.annotation.SuppressLint
|
||
import android.graphics.Color
|
||
import android.graphics.drawable.ColorDrawable
|
||
import android.os.Build
|
||
import android.os.Bundle
|
||
import android.os.Handler
|
||
import android.os.Looper
|
||
import android.util.Log
|
||
import android.view.View
|
||
import android.view.Window
|
||
import android.view.WindowManager
|
||
import android.widget.Button
|
||
import android.widget.Toast
|
||
import android.widget.TextView
|
||
import androidx.annotation.RequiresApi
|
||
import androidx.constraintlayout.widget.ConstraintLayout
|
||
import androidx.core.view.GravityCompat
|
||
import androidx.drawerlayout.widget.DrawerLayout
|
||
import com.aros.apron.R
|
||
import com.aros.apron.base.BaseActivity
|
||
import com.aros.apron.callback.MqttCallBack
|
||
import com.aros.apron.entity.Movement
|
||
import com.aros.apron.entity.Synchronizedstatus
|
||
import com.aros.apron.manager.AlternateLandingManager
|
||
import com.aros.apron.manager.BatteryManager
|
||
import com.aros.apron.manager.CameraManager
|
||
import com.aros.apron.manager.FlightManager
|
||
import com.aros.apron.manager.FlightManager.FLAG_DOWN_LAND
|
||
import com.aros.apron.manager.FlightManager.FLAG_START_DETECT_ARUCO_ALTERNATE
|
||
import com.aros.apron.manager.FlightManager.FLAG_START_DETECT_ARUCO_APRON
|
||
import com.aros.apron.manager.FlightManager.FLAG_STOP_ARUCO
|
||
import com.aros.apron.manager.FlightTaskProgressManager
|
||
import com.aros.apron.manager.GimbalManager
|
||
import com.aros.apron.manager.LEDsSettingsManager
|
||
import com.aros.apron.manager.LTEManager
|
||
import com.aros.apron.manager.MLTEManager
|
||
import com.aros.apron.manager.MediaManager
|
||
import com.aros.apron.manager.MissionV3Manager
|
||
import com.aros.apron.manager.NavigationSatelliteSystemManager
|
||
import com.aros.apron.manager.OSDManager
|
||
import com.aros.apron.manager.PayloadWidgetManager
|
||
import com.aros.apron.manager.RTKManager
|
||
import com.aros.apron.manager.SpeakerManager
|
||
import com.aros.apron.manager.StickManager
|
||
import com.aros.apron.manager.StreamManager
|
||
import com.aros.apron.manager.WirelessLinkManager
|
||
import com.aros.apron.mix.Aprondown
|
||
import com.aros.apron.mix.Aprongim
|
||
import com.aros.apron.tools.AlternateArucoDetect
|
||
import com.aros.apron.tools.ApronArucoDetect
|
||
import com.aros.apron.tools.ApronArucoDetectPort
|
||
import com.aros.apron.tools.ApronArucodownmany
|
||
import com.aros.apron.tools.DroneHelper
|
||
import com.aros.apron.tools.LogUtil
|
||
import com.aros.apron.tools.MqttManager
|
||
import com.aros.apron.tools.PreferenceUtils
|
||
import com.aros.apron.tools.SimplePortScanner
|
||
import com.dji.wpmzsdk.manager.WPMZManager
|
||
import com.google.gson.Gson
|
||
import dji.sdk.keyvalue.key.CameraKey
|
||
import dji.sdk.keyvalue.key.DJIKey
|
||
import dji.sdk.keyvalue.key.FlightControllerKey
|
||
import dji.sdk.keyvalue.key.KeyTools
|
||
import dji.sdk.keyvalue.value.camera.CameraMode
|
||
import dji.sdk.keyvalue.value.common.CameraLensType
|
||
import dji.sdk.keyvalue.value.common.ComponentIndexType
|
||
import dji.sdk.keyvalue.value.common.EmptyMsg
|
||
import dji.sdk.keyvalue.value.flightassistant.VisionAssistDirection
|
||
import dji.sdk.keyvalue.value.flightcontroller.LEDsSettings
|
||
import dji.v5.common.callback.CommonCallbacks
|
||
import dji.v5.common.callback.CommonCallbacks.CompletionCallback
|
||
import dji.v5.common.error.IDJIError
|
||
import dji.v5.common.utils.GeoidManager
|
||
import dji.v5.manager.KeyManager
|
||
import dji.v5.manager.datacenter.MediaDataCenter
|
||
import dji.v5.manager.interfaces.ICameraStreamManager
|
||
import dji.v5.manager.interfaces.ICameraStreamManager.AvailableCameraUpdatedListener
|
||
import dji.v5.network.DJINetworkManager
|
||
import dji.v5.network.IDJINetworkStatusListener
|
||
import dji.v5.utils.common.JsonUtil
|
||
import dji.v5.utils.common.LogPath
|
||
import dji.v5.utils.common.LogUtils
|
||
import dji.v5.ux.accessory.RTKStartServiceHelper.startRtkService
|
||
import dji.v5.ux.cameracore.widget.autoexposurelock.AutoExposureLockWidget
|
||
import dji.v5.ux.cameracore.widget.cameracontrols.CameraControlsWidget
|
||
import dji.v5.ux.cameracore.widget.cameracontrols.lenscontrol.LensControlWidget
|
||
import dji.v5.ux.cameracore.widget.focusexposureswitch.FocusExposureSwitchWidget
|
||
import dji.v5.ux.cameracore.widget.focusmode.FocusModeWidget
|
||
import dji.v5.ux.cameracore.widget.fpvinteraction.FPVInteractionWidget
|
||
import dji.v5.ux.core.base.SchedulerProvider.io
|
||
import dji.v5.ux.core.base.SchedulerProvider.ui
|
||
import dji.v5.ux.core.communication.BroadcastValues
|
||
import dji.v5.ux.core.communication.GlobalPreferenceKeys
|
||
import dji.v5.ux.core.communication.ObservableInMemoryKeyedStore
|
||
import dji.v5.ux.core.communication.UXKeys
|
||
import dji.v5.ux.core.extension.hide
|
||
import dji.v5.ux.core.extension.toggleVisibility
|
||
import dji.v5.ux.core.panel.systemstatus.SystemStatusListPanelWidget
|
||
import dji.v5.ux.core.panel.topbar.TopBarPanelWidget
|
||
import dji.v5.ux.core.util.CameraUtil
|
||
import dji.v5.ux.core.util.DataProcessor
|
||
import dji.v5.ux.core.util.ViewUtil
|
||
import dji.v5.ux.core.widget.fpv.FPVStreamSourceListener
|
||
import dji.v5.ux.core.widget.fpv.FPVWidget
|
||
import dji.v5.ux.core.widget.hsi.HorizontalSituationIndicatorWidget
|
||
import dji.v5.ux.core.widget.hsi.PrimaryFlightDisplayWidget
|
||
import dji.v5.ux.core.widget.setting.SettingWidget
|
||
import dji.v5.ux.gimbal.GimbalFineTuneWidget
|
||
import dji.v5.ux.training.simulatorcontrol.SimulatorControlWidget
|
||
import dji.v5.ux.training.simulatorcontrol.SimulatorControlWidget.UIState.VisibilityUpdated
|
||
import dji.v5.ux.visualcamera.CameraNDVIPanelWidget
|
||
import dji.v5.ux.visualcamera.CameraVisiblePanelWidget
|
||
import dji.v5.ux.visualcamera.zoom.FocalZoomWidget
|
||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||
import io.reactivex.rxjava3.functions.Consumer
|
||
import org.eclipse.paho.client.mqttv3.MqttException
|
||
import org.greenrobot.eventbus.Subscribe
|
||
import org.greenrobot.eventbus.ThreadMode
|
||
import org.opencv.objdetect.Dictionary
|
||
import org.opencv.objdetect.Objdetect
|
||
import java.util.concurrent.TimeUnit
|
||
|
||
|
||
open class MainActivity : BaseActivity() {
|
||
|
||
|
||
companion object {
|
||
// 如果不需要改变 isAppStarted 的值,可以直接这样声明
|
||
var isAppStarted: Boolean = false
|
||
var streamReceive: Boolean = false
|
||
|
||
var isscousse: Boolean=false;
|
||
private var instance: MainActivity? = null
|
||
|
||
fun getInstance(): MainActivity? {
|
||
return instance
|
||
}
|
||
|
||
private var vtxHeartbeatHandler: Handler? = null
|
||
private var lastVtxFrameTime: Long = 0
|
||
private var lastPortToastTime: Long = 0
|
||
private var lastFpvToastTime: Long = 0
|
||
private const val TOAST_INTERVAL_MS = 3000L
|
||
private const val VTX_HEARTBEAT_TIMEOUT = 2000L // 3秒没有收到帧就认为图传异常
|
||
private var isVtxHeartbeatRunning = false
|
||
|
||
fun startVtxHeartbeat() {
|
||
if (isVtxHeartbeatRunning) return
|
||
|
||
isVtxHeartbeatRunning = true
|
||
lastVtxFrameTime = System.currentTimeMillis()
|
||
|
||
vtxHeartbeatHandler = Handler(Looper.getMainLooper())
|
||
vtxHeartbeatHandler?.post(object : Runnable {
|
||
override fun run() {
|
||
val currentTime = System.currentTimeMillis()
|
||
val timeSinceLastFrame = currentTime - lastVtxFrameTime
|
||
|
||
if (timeSinceLastFrame > VTX_HEARTBEAT_TIMEOUT) {
|
||
//LogUtil.log("MainActivity", "图传心跳超时,设置图传状态为false")
|
||
Movement.getInstance().isVtx = false
|
||
}
|
||
|
||
if (isVtxHeartbeatRunning) {
|
||
vtxHeartbeatHandler?.postDelayed(this, 1000) // 每秒检查一次
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
fun stopVtxHeartbeat() {
|
||
isVtxHeartbeatRunning = false
|
||
vtxHeartbeatHandler?.removeCallbacksAndMessages(null)
|
||
vtxHeartbeatHandler = null
|
||
}
|
||
|
||
fun updateVtxHeartbeat() {
|
||
lastVtxFrameTime = System.currentTimeMillis()
|
||
}
|
||
|
||
@JvmStatic
|
||
fun setStartArucoType(type: Int) {
|
||
instance?.startArucoType = type
|
||
}
|
||
}
|
||
|
||
protected var primaryFpvWidget: FPVWidget? = null
|
||
protected var fpvInteractionWidget: FPVInteractionWidget? = null
|
||
protected var secondaryFPVWidget: FPVWidget? = null
|
||
protected var systemStatusListPanelWidget: SystemStatusListPanelWidget? = null
|
||
protected var simulatorControlWidget: SimulatorControlWidget? = null
|
||
protected var lensControlWidget: LensControlWidget? = null
|
||
protected var autoExposureLockWidget: AutoExposureLockWidget? = null
|
||
protected var focusModeWidget: FocusModeWidget? = null
|
||
protected var focusExposureSwitchWidget: FocusExposureSwitchWidget? = null
|
||
protected var cameraControlsWidget: CameraControlsWidget? = null
|
||
protected var horizontalSituationIndicatorWidget: HorizontalSituationIndicatorWidget? = null
|
||
protected var pfvFlightDisplayWidget: PrimaryFlightDisplayWidget? = null
|
||
protected var ndviCameraPanel: CameraNDVIPanelWidget? = null
|
||
protected var visualCameraPanel: CameraVisiblePanelWidget? = null
|
||
protected var focalZoomWidget: FocalZoomWidget? = null
|
||
protected var settingWidget: SettingWidget? = null
|
||
protected var topBarPanel: TopBarPanelWidget? = null
|
||
protected var fpvParentView: ConstraintLayout? = null
|
||
|
||
|
||
private var mDrawerLayout: DrawerLayout? = null
|
||
private var gimbalAdjustDone: TextView? = null
|
||
private var btn_test: Button? = null
|
||
private var btn_test1: Button? = null
|
||
private var btn_test2: Button? = null
|
||
private var btn_test3: Button? = null
|
||
|
||
private var gimbalFineTuneWidget: GimbalFineTuneWidget? = null
|
||
private var lastDevicePosition = ComponentIndexType.UNKNOWN
|
||
private var lastLensType = CameraLensType.UNKNOWN
|
||
|
||
private var compositeDisposable: CompositeDisposable? = null
|
||
private val cameraSourceProcessor = DataProcessor.create(
|
||
CameraSource(
|
||
ComponentIndexType.UNKNOWN,
|
||
CameraLensType.UNKNOWN
|
||
)
|
||
)
|
||
private val networkStatusListener =
|
||
IDJINetworkStatusListener { isNetworkAvailable: Boolean ->
|
||
if (isNetworkAvailable) {
|
||
LogUtils.d(TAG, "isNetworkAvailable=" + true)
|
||
startRtkService(false)
|
||
}
|
||
}
|
||
|
||
private val availableCameraUpdatedListener: AvailableCameraUpdatedListener =
|
||
object : AvailableCameraUpdatedListener {
|
||
override fun onAvailableCameraUpdated(availableCameraList: List<ComponentIndexType>) {
|
||
runOnUiThread {
|
||
updateFPVWidgetSource(availableCameraList)
|
||
}
|
||
}
|
||
|
||
override fun onCameraStreamEnableUpdate(cameraStreamEnableMap: Map<ComponentIndexType, Boolean>) {
|
||
//
|
||
}
|
||
}
|
||
|
||
|
||
private var cameraManager: ICameraStreamManager =
|
||
MediaDataCenter.getInstance().cameraStreamManager
|
||
|
||
private var startArucoType = 0 //1执行机库二维码识别 2执行备降点二维码识别 3扫到任何码触发刹停
|
||
private var dictionary: Dictionary? = null
|
||
override fun useEventBus(): Boolean {
|
||
return true
|
||
}
|
||
|
||
|
||
override fun onResume() {
|
||
super.onResume()
|
||
|
||
dictionary = Objdetect.getPredefinedDictionary(Objdetect.DICT_6X6_250)
|
||
|
||
compositeDisposable = CompositeDisposable()
|
||
// 延迟订阅 RxJava 流,避免在初始 layout 阶段触发大量 widget 更新导致 ANR
|
||
Handler(Looper.getMainLooper()).postDelayed({
|
||
if (compositeDisposable == null) return@postDelayed
|
||
compositeDisposable!!.add(
|
||
systemStatusListPanelWidget!!.closeButtonPressed()
|
||
.observeOn(AndroidSchedulers.mainThread())
|
||
.subscribe { pressed: Boolean ->
|
||
if (pressed) {
|
||
systemStatusListPanelWidget!!.hide()
|
||
}
|
||
})
|
||
compositeDisposable!!.add(
|
||
simulatorControlWidget!!.getUIStateUpdates()
|
||
.observeOn(AndroidSchedulers.mainThread())
|
||
.subscribe { simulatorControlWidgetState: SimulatorControlWidget.UIState? ->
|
||
if (simulatorControlWidgetState is VisibilityUpdated) {
|
||
if ((simulatorControlWidgetState as VisibilityUpdated).isVisible) {
|
||
hideOtherPanels(simulatorControlWidget!!)
|
||
}
|
||
}
|
||
})
|
||
compositeDisposable!!.add(
|
||
cameraSourceProcessor.toFlowable()
|
||
.observeOn(io())
|
||
.throttleLast(500, TimeUnit.MILLISECONDS)
|
||
.subscribeOn(io())
|
||
.subscribe(Consumer { result: CameraSource ->
|
||
runOnUiThread {
|
||
onCameraSourceUpdated(
|
||
result.devicePosition,
|
||
result.lensType
|
||
)
|
||
}
|
||
})
|
||
)
|
||
compositeDisposable!!.add(
|
||
ObservableInMemoryKeyedStore.getInstance()
|
||
.addObserver(UXKeys.create(GlobalPreferenceKeys.GIMBAL_ADJUST_CLICKED))
|
||
.observeOn(ui())
|
||
.subscribe { broadcastValues: BroadcastValues? ->
|
||
isGimableAdjustClicked(
|
||
broadcastValues!!
|
||
)
|
||
})
|
||
}, 500)
|
||
ViewUtil.setKeepScreen(this, true)
|
||
}
|
||
|
||
override fun onPause() {
|
||
// 在后台线程 dispose RxJava 订阅,避免阻塞主线程导致 ANR
|
||
// DJI UX widget 的 unregisterReactions() 会同步清理 RxJava 队列,可能耗时很长
|
||
val disposable = compositeDisposable
|
||
if (disposable != null && !disposable.isDisposed) {
|
||
Thread {
|
||
try {
|
||
disposable.dispose()
|
||
} catch (e: Exception) {
|
||
LogUtil.log(TAG, "dispose compositeDisposable error: ${e.message}")
|
||
}
|
||
}.start()
|
||
compositeDisposable = null
|
||
}
|
||
super.onPause()
|
||
ViewUtil.setKeepScreen(this, false)
|
||
}
|
||
|
||
//endregion
|
||
private fun hideOtherPanels(widget: View?) {
|
||
val panels = arrayOf<View>(
|
||
simulatorControlWidget!!
|
||
)
|
||
for (panel in panels) {
|
||
if (widget !== panel) {
|
||
panel.visibility = View.GONE
|
||
}
|
||
}
|
||
}
|
||
|
||
private fun updateFPVWidgetSource(availableCameraList: List<ComponentIndexType>?) {
|
||
LogUtils.i(TAG, JsonUtil.toJson(availableCameraList))
|
||
if (availableCameraList == null) {
|
||
return
|
||
}
|
||
val cameraList = java.util.ArrayList(availableCameraList)
|
||
|
||
//没有数据
|
||
if (cameraList.isEmpty()) {
|
||
secondaryFPVWidget!!.visibility = View.GONE
|
||
return
|
||
}
|
||
|
||
//仅一路数据
|
||
if (cameraList.size == 1) {
|
||
primaryFpvWidget!!.updateVideoSource(availableCameraList[0])
|
||
secondaryFPVWidget!!.visibility = View.GONE
|
||
return
|
||
}
|
||
|
||
//大于两路数据ort1
|
||
val primarySource = getSuitableSource(cameraList, ComponentIndexType.PORT_1)
|
||
primaryFpvWidget!!.updateVideoSource(primarySource!!)
|
||
cameraList.remove(primarySource)
|
||
|
||
val secondarySource = getSuitableSource(cameraList, ComponentIndexType.FPV)
|
||
secondaryFPVWidget!!.updateVideoSource(secondarySource!!)
|
||
|
||
secondaryFPVWidget!!.visibility = View.VISIBLE
|
||
|
||
|
||
}
|
||
|
||
private fun getSuitableSource(
|
||
cameraList: List<ComponentIndexType>,
|
||
defaultSource: ComponentIndexType
|
||
): ComponentIndexType? {
|
||
if (cameraList.contains(ComponentIndexType.LEFT_OR_MAIN)) {
|
||
return ComponentIndexType.LEFT_OR_MAIN
|
||
} else if (cameraList.contains(ComponentIndexType.RIGHT)) {
|
||
return ComponentIndexType.RIGHT
|
||
} else if (cameraList.contains(ComponentIndexType.UP)) {
|
||
return ComponentIndexType.UP
|
||
} else if (cameraList.contains(ComponentIndexType.PORT_1)) {
|
||
return ComponentIndexType.PORT_1
|
||
} else if (cameraList.contains(ComponentIndexType.PORT_2)) {
|
||
return ComponentIndexType.PORT_2
|
||
} else if (cameraList.contains(ComponentIndexType.PORT_3)) {
|
||
return ComponentIndexType.PORT_3
|
||
} else if (cameraList.contains(ComponentIndexType.PORT_4)) {
|
||
return ComponentIndexType.PORT_4
|
||
} else if (cameraList.contains(ComponentIndexType.VISION_ASSIST)) {
|
||
return ComponentIndexType.VISION_ASSIST
|
||
}
|
||
return defaultSource
|
||
}
|
||
|
||
private fun onCameraSourceUpdated(
|
||
devicePosition: ComponentIndexType,
|
||
lensType: CameraLensType
|
||
) {
|
||
LogUtils.i(LogPath.SAMPLE, "onCameraSourceUpdated", devicePosition, lensType)
|
||
if (devicePosition == lastDevicePosition && lensType == lastLensType) {
|
||
return
|
||
}
|
||
lastDevicePosition = devicePosition
|
||
lastLensType = lensType
|
||
updateViewVisibility(devicePosition, lensType)
|
||
updateInteractionEnabled()
|
||
//如果无需使能或者显示的,也就没有必要切换了。
|
||
if (fpvInteractionWidget!!.isInteractionEnabled) {
|
||
fpvInteractionWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (lensControlWidget!!.visibility == View.VISIBLE) {
|
||
lensControlWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (ndviCameraPanel!!.visibility == View.VISIBLE) {
|
||
ndviCameraPanel!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (visualCameraPanel!!.visibility == View.VISIBLE) {
|
||
visualCameraPanel!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (autoExposureLockWidget!!.visibility == View.VISIBLE) {
|
||
autoExposureLockWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (focusModeWidget!!.visibility == View.VISIBLE) {
|
||
focusModeWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (focusExposureSwitchWidget!!.visibility == View.VISIBLE) {
|
||
focusExposureSwitchWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (cameraControlsWidget!!.visibility == View.VISIBLE) {
|
||
cameraControlsWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (focalZoomWidget!!.visibility == View.VISIBLE) {
|
||
focalZoomWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
if (horizontalSituationIndicatorWidget!!.visibility == View.VISIBLE) {
|
||
horizontalSituationIndicatorWidget!!.updateCameraSource(devicePosition, lensType)
|
||
}
|
||
}
|
||
|
||
private fun updateViewVisibility(
|
||
devicePosition: ComponentIndexType,
|
||
lensType: CameraLensType
|
||
) {
|
||
//只在fpv下显示
|
||
pfvFlightDisplayWidget!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.VISIBLE else View.INVISIBLE
|
||
|
||
//fpv下不显示
|
||
lensControlWidget!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
ndviCameraPanel!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
visualCameraPanel!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
autoExposureLockWidget!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
focusModeWidget!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
focusExposureSwitchWidget!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
cameraControlsWidget!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
focalZoomWidget!!.visibility =
|
||
if (CameraUtil.isFPVTypeView(devicePosition)) View.INVISIBLE else View.VISIBLE
|
||
horizontalSituationIndicatorWidget!!.setSimpleModeEnable(
|
||
CameraUtil.isFPVTypeView(
|
||
devicePosition
|
||
)
|
||
)
|
||
|
||
//只在部分len下显示
|
||
ndviCameraPanel!!.visibility =
|
||
if (CameraUtil.isSupportForNDVI(lensType)) View.VISIBLE else View.INVISIBLE
|
||
}
|
||
|
||
/**
|
||
* Swap the video sources of the FPV and secondary FPV widgets.
|
||
*/
|
||
fun swapVideoSource() {
|
||
|
||
val primarySource = primaryFpvWidget!!.widgetModel.getCameraIndex()
|
||
val secondarySource = secondaryFPVWidget!!.widgetModel.getCameraIndex()
|
||
//两个source都存在的情况下才进行切换
|
||
if (primarySource != ComponentIndexType.UNKNOWN && secondarySource != ComponentIndexType.UNKNOWN) {
|
||
primaryFpvWidget!!.updateVideoSource(secondarySource)
|
||
secondaryFPVWidget!!.updateVideoSource(primarySource)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 强制刷新两个FPVWidget的视频流(重新向MediaDataCenter注册)
|
||
* 用于起飞/航线执行后视频流卡死的场景
|
||
*/
|
||
fun refreshVideoStream() {
|
||
val primarySource = primaryFpvWidget?.widgetModel?.getCameraIndex()
|
||
val secondarySource = secondaryFPVWidget?.widgetModel?.getCameraIndex()
|
||
if (primarySource != null && primarySource != ComponentIndexType.UNKNOWN) {
|
||
primaryFpvWidget?.updateVideoSource(primarySource)
|
||
}
|
||
if (secondarySource != null && secondarySource != ComponentIndexType.UNKNOWN) {
|
||
secondaryFPVWidget?.updateVideoSource(secondarySource)
|
||
}
|
||
LogUtil.log(TAG, "强制刷新视频流: primary=$primarySource, secondary=$secondarySource")
|
||
}
|
||
|
||
/**
|
||
* 智能刷新视频流:有云台(secondary)就模拟点击切换,没有就直接刷新当前流
|
||
* 兼容只有FPV没有云台的设备
|
||
*/
|
||
fun smartRefreshVideoStream() {
|
||
val secondarySource = secondaryFPVWidget?.widgetModel?.getCameraIndex()
|
||
if (secondarySource != null && secondarySource != ComponentIndexType.UNKNOWN) {
|
||
// 有云台:模拟真实点击,触发 swapVideoSource()
|
||
secondaryFPVWidget?.post {
|
||
secondaryFPVWidget?.performClick()
|
||
}
|
||
//LogUtil.log(TAG, "智能刷新:有云台,模拟点击 FPV Widget")
|
||
} else {
|
||
// 没有云台:直接刷新当前流
|
||
primaryFpvWidget?.post {
|
||
refreshVideoStream()
|
||
}
|
||
//LogUtil.log(TAG, "智能刷新:无云台,直接刷新主视频流")
|
||
}
|
||
}
|
||
|
||
private fun updateInteractionEnabled() {
|
||
fpvInteractionWidget!!.isInteractionEnabled = !CameraUtil.isFPVTypeView(
|
||
primaryFpvWidget!!.widgetModel.getCameraIndex()
|
||
)
|
||
}
|
||
|
||
private data class CameraSource(
|
||
val devicePosition: ComponentIndexType,
|
||
val lensType: CameraLensType
|
||
)
|
||
|
||
override fun onBackPressed() {
|
||
if (mDrawerLayout!!.isDrawerOpen(GravityCompat.END)) {
|
||
mDrawerLayout!!.closeDrawers()
|
||
} else {
|
||
super.onBackPressed()
|
||
}
|
||
}
|
||
|
||
@RequiresApi(Build.VERSION_CODES.O)
|
||
override fun onCreate(savedInstanceState: Bundle?) {
|
||
super.onCreate(savedInstanceState)
|
||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||
// window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||
window.setFlags(
|
||
WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||
)
|
||
setContentView(R.layout.activity_main)
|
||
isAppStarted = true
|
||
instance = this
|
||
|
||
|
||
// mapWidget = findViewById<MapWidget>(R.id.widget_map)
|
||
// mapWidget?.initMapLibreMap(applicationContext, OnMapReadyListener { map: DJIMap ->
|
||
// val uiSetting = map.uiSettings
|
||
// uiSetting?.setZoomControlsEnabled(false)
|
||
//
|
||
// mapWidget?.onCreate(savedInstanceState)
|
||
GeoidManager.getInstance().init(this)
|
||
WPMZManager.getInstance().init(this)
|
||
MqttManager.getInstance().needConnect()
|
||
|
||
initView()
|
||
|
||
// 后台线程初始化 DJI 相关模块,避免阻塞主线程导致 ANR
|
||
Thread {
|
||
initDJIManager()
|
||
}.start()
|
||
|
||
|
||
}
|
||
|
||
|
||
private fun initView() {
|
||
fpvParentView = findViewById(R.id.fpv_holder)
|
||
mDrawerLayout = findViewById(R.id.root_view)
|
||
topBarPanel = findViewById(R.id.panel_top_bar)
|
||
settingWidget = topBarPanel?.settingWidget
|
||
primaryFpvWidget = findViewById(R.id.widget_primary_fpv)
|
||
fpvInteractionWidget = findViewById(R.id.widget_fpv_interaction)
|
||
secondaryFPVWidget = findViewById(R.id.widget_secondary_fpv)
|
||
systemStatusListPanelWidget = findViewById(R.id.widget_panel_system_status_list)
|
||
simulatorControlWidget = findViewById(R.id.widget_simulator_control)
|
||
lensControlWidget = findViewById<LensControlWidget>(R.id.widget_lens_control)
|
||
ndviCameraPanel = findViewById(R.id.panel_ndvi_camera)
|
||
visualCameraPanel = findViewById(R.id.panel_visual_camera)
|
||
autoExposureLockWidget = findViewById(R.id.widget_auto_exposure_lock)
|
||
focusModeWidget = findViewById(R.id.widget_focus_mode)
|
||
focusExposureSwitchWidget = findViewById(R.id.widget_focus_exposure_switch)
|
||
pfvFlightDisplayWidget = findViewById(R.id.widget_fpv_flight_display_widget)
|
||
focalZoomWidget = findViewById(R.id.widget_focal_zoom)
|
||
cameraControlsWidget = findViewById(R.id.widget_camera_controls)
|
||
horizontalSituationIndicatorWidget =
|
||
findViewById(R.id.widget_horizontal_situation_indicator)
|
||
// gimbalAdjustDone = findViewById<TextView>( R.id.fpv_gimbal_ok_btn)
|
||
gimbalFineTuneWidget = findViewById(R.id.setting_menu_gimbal_fine_tune)
|
||
btn_test = findViewById(R.id.btn_test)
|
||
btn_test1 = findViewById(R.id.btn_test1)
|
||
btn_test2 = findViewById(R.id.btn_test2)
|
||
// btn_test3 = findViewById(R.id.btn_test3)
|
||
btn_test?.setOnClickListener {
|
||
// if(cameraMode == 3){
|
||
// //退出回放模式
|
||
// MediaManager.getInstance().disablePlayback();
|
||
// }
|
||
KeyManager.getInstance().setValue<CameraMode?>(
|
||
KeyTools.createKey<CameraMode?>(CameraKey.KeyCameraMode, ComponentIndexType.PORT_1),
|
||
CameraMode.find(12),
|
||
object : CompletionCallback {
|
||
override fun onSuccess() {
|
||
OSDManager.getInstance().pushFlightAttitude()
|
||
}
|
||
|
||
override fun onFailure(error: IDJIError) {
|
||
|
||
}
|
||
})
|
||
|
||
}
|
||
btn_test1?.setOnClickListener {
|
||
KeyManager.getInstance().performAction<EmptyMsg?>(
|
||
KeyTools.createKey<EmptyMsg?, EmptyMsg?>(
|
||
CameraKey.KeyStartShootPhoto,
|
||
ComponentIndexType.PORT_1
|
||
),
|
||
object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg?> {
|
||
override fun onSuccess(emptyMsg: EmptyMsg?) {
|
||
LogUtil.log(TAG, "拍照成功")
|
||
}
|
||
|
||
override fun onFailure(error: IDJIError) {
|
||
LogUtil.log(TAG, "拍照失败:" + Gson().toJson(error))
|
||
}
|
||
})
|
||
|
||
}
|
||
btn_test2?.setOnClickListener {
|
||
StickManager.getInstance().enableVirtualStick1()
|
||
|
||
}
|
||
// btn_test3?.setOnClickListener {
|
||
// StreamManager.getInstance().startstream()
|
||
//
|
||
// }
|
||
|
||
|
||
initClickListener()
|
||
MediaDataCenter.getInstance().cameraStreamManager.addAvailableCameraUpdatedListener(
|
||
availableCameraUpdatedListener
|
||
)
|
||
|
||
primaryFpvWidget?.setOnFPVStreamSourceListener(object : FPVStreamSourceListener {
|
||
override fun onStreamSourceUpdated(
|
||
devicePosition: ComponentIndexType,
|
||
lensType: CameraLensType
|
||
) {
|
||
cameraSourceProcessor.onNext(
|
||
CameraSource(devicePosition, lensType)
|
||
)
|
||
}
|
||
})
|
||
|
||
//小surfaceView放置在顶部,避免被大的遮挡
|
||
secondaryFPVWidget?.setSurfaceViewZOrderOnTop(true)
|
||
secondaryFPVWidget?.setSurfaceViewZOrderMediaOverlay(true)
|
||
|
||
|
||
window.setBackgroundDrawable(ColorDrawable(Color.BLACK))
|
||
|
||
//实现RTK监测网络,并自动重连机制
|
||
DJINetworkManager.getInstance().addNetworkStatusListener(networkStatusListener)
|
||
|
||
|
||
}
|
||
|
||
private fun isGimableAdjustClicked(broadcastValues: BroadcastValues) {
|
||
if (mDrawerLayout!!.isDrawerOpen(GravityCompat.END)) {
|
||
mDrawerLayout!!.closeDrawers()
|
||
}
|
||
horizontalSituationIndicatorWidget!!.visibility = View.GONE
|
||
if (gimbalFineTuneWidget != null) {
|
||
gimbalFineTuneWidget!!.visibility = View.VISIBLE
|
||
}
|
||
}
|
||
|
||
private fun initClickListener() {
|
||
secondaryFPVWidget!!.setOnClickListener { v: View? -> swapVideoSource() }
|
||
if (settingWidget != null) {
|
||
settingWidget!!.setOnClickListener { v: View? -> toggleRightDrawer() }
|
||
}
|
||
|
||
// Setup top bar state callbacks
|
||
val systemStatusWidget = topBarPanel!!.systemStatusWidget
|
||
systemStatusWidget?.setOnClickListener { v: View? -> systemStatusListPanelWidget!!.toggleVisibility() }
|
||
val simulatorIndicatorWidget = topBarPanel!!.simulatorIndicatorWidget
|
||
simulatorIndicatorWidget?.setOnClickListener { v: View? -> simulatorControlWidget!!.toggleVisibility() }
|
||
// gimbalAdjustDone!!.setOnClickListener { view: View? ->
|
||
// horizontalSituationIndicatorWidget!!.visibility = View.VISIBLE
|
||
// if (gimbalFineTuneWidget != null) {
|
||
// gimbalFineTuneWidget!!.visibility = View.GONE
|
||
// }
|
||
// }
|
||
}
|
||
|
||
private fun toggleRightDrawer() {
|
||
mDrawerLayout!!.openDrawer(GravityCompat.END)
|
||
}
|
||
|
||
|
||
override fun onDestroy() {
|
||
|
||
super.onDestroy()
|
||
isAppStarted = false
|
||
stopVtxHeartbeat()
|
||
try {
|
||
if (MqttManager.getInstance().mqttAndroidClient != null && MqttManager.getInstance().mqttAndroidClient.isConnected) {
|
||
MqttManager.getInstance().mqttAndroidClient.unregisterResources()
|
||
MqttManager.getInstance().mqttAndroidClient.disconnect() //断开连接
|
||
}
|
||
} catch (e: MqttException) {
|
||
e.printStackTrace()
|
||
}
|
||
MediaDataCenter.getInstance().cameraStreamManager.removeAvailableCameraUpdatedListener(
|
||
availableCameraUpdatedListener
|
||
)
|
||
DJINetworkManager.getInstance().removeNetworkStatusListener(networkStatusListener)
|
||
}
|
||
|
||
private var initTimes = 0
|
||
|
||
private fun initDJIManager() {
|
||
// 在后台线程中轮询等待飞控/相机连接,避免阻塞主线程
|
||
var isFlightControllerConnect =
|
||
KeyManager.getInstance().getValue(DJIKey.create(FlightControllerKey.KeyConnection))
|
||
var isCameraConnect =
|
||
KeyManager.getInstance()
|
||
.getValue(KeyTools.createKey(CameraKey.KeyConnection, ComponentIndexType.PORT_1))
|
||
|
||
val cameraLocationType = PreferenceUtils.getInstance().cameraLocationType
|
||
|
||
// 根据 cameraLocationType 轮询等待连接
|
||
while (true) {
|
||
val flightConnected =
|
||
isFlightControllerConnect != null && isFlightControllerConnect == true
|
||
val cameraConnected = isCameraConnect != null && isCameraConnect == true
|
||
|
||
val shouldInit = when (cameraLocationType) {
|
||
3 -> flightConnected
|
||
1, 2, 4, 5 -> flightConnected && cameraConnected
|
||
else -> flightConnected && cameraConnected
|
||
}
|
||
|
||
if (shouldInit) break
|
||
|
||
try {
|
||
Thread.sleep(1000)
|
||
} catch (e: InterruptedException) {
|
||
Thread.currentThread().interrupt()
|
||
return
|
||
}
|
||
|
||
isFlightControllerConnect =
|
||
KeyManager.getInstance().getValue(DJIKey.create(FlightControllerKey.KeyConnection))
|
||
isCameraConnect =
|
||
KeyManager.getInstance()
|
||
.getValue(
|
||
KeyTools.createKey(
|
||
CameraKey.KeyConnection,
|
||
ComponentIndexType.PORT_1
|
||
)
|
||
)
|
||
}
|
||
|
||
// 飞控/相机连接后,在主线程执行初始化
|
||
runOnUiThread {
|
||
when (cameraLocationType) {
|
||
3 -> initForCameraLocationType3()
|
||
4, 5 -> initForCameraLocationType4Or5()
|
||
else -> initForCameraLocationTypeDefault()
|
||
}
|
||
}
|
||
}
|
||
|
||
private fun initForCameraLocationType3() {
|
||
initTimes++
|
||
LogUtil.log(TAG, "下视觉初始化$initTimes")
|
||
cameraManager.setKeepAliveDecoding(true)
|
||
FlightManager.getInstance().initFlightInfo()
|
||
BatteryManager.getInstance().initBatteryInfo()
|
||
StickManager.getInstance().initStickInfo()
|
||
GimbalManager.getInstance().initGimbalInfo()
|
||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||
OSDManager.getInstance().initOsd()
|
||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||
MediaManager.getInstance().init()
|
||
StreamManager.getInstance().initStreamManager()
|
||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||
RTKManager.getInstance().initRTKInfo()
|
||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||
LTEManager.getInstance().initLTEInfo()
|
||
WirelessLinkManager.getInstance().initWirelessLink()
|
||
CameraManager.getInstance().initCameraInfo()
|
||
GeoidManager.getInstance().init(this)
|
||
MissionV3Manager.getInstance().initMissionManager()
|
||
enableStream()
|
||
initFpvStream()
|
||
startVtxHeartbeat()
|
||
SpeakerManager.getInstance().addMegaphoneInfoListener()
|
||
GimbalManager.getInstance().setmode()
|
||
PayloadWidgetManager.getInstance().initPayloadInfo()
|
||
|
||
if (PreferenceUtils.getInstance().lteEnable) {
|
||
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
|
||
MLTEManager.getInstance().initLTEManager()
|
||
Handler().postDelayed(Runnable {
|
||
MLTEManager.getInstance().setLTEEnhancedTransmissionType()
|
||
}, 3000)
|
||
|
||
}
|
||
|
||
|
||
|
||
LogUtil.log("qwq", "lteEnable" + PreferenceUtils.getInstance().lteEnable)
|
||
|
||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||
|
||
Handler(Looper.getMainLooper()).postDelayed({
|
||
when (PreferenceUtils.getInstance().customStreamType) {
|
||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||
}
|
||
SimplePortScanner.getInstance().startScan()
|
||
}, 5000)
|
||
|
||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||
}
|
||
|
||
private fun initForCameraLocationType4Or5() {
|
||
initTimes++
|
||
cameraManager.setKeepAliveDecoding(true)
|
||
LogUtil.log(TAG, "云台初始化$initTimes")
|
||
FlightManager.getInstance().initFlightInfo()
|
||
BatteryManager.getInstance().initBatteryInfo()
|
||
StickManager.getInstance().initStickInfo()
|
||
GimbalManager.getInstance().initGimbalInfo()
|
||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||
OSDManager.getInstance().initOsd()
|
||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||
MediaManager.getInstance().init()
|
||
StreamManager.getInstance().initStreamManager()
|
||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||
RTKManager.getInstance().initRTKInfo()
|
||
LTEManager.getInstance().initLTEInfo()
|
||
|
||
|
||
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
|
||
if (PreferenceUtils.getInstance().lteEnable) {
|
||
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
|
||
MLTEManager.getInstance().initLTEManager()
|
||
Handler().postDelayed(Runnable {
|
||
MLTEManager.getInstance().setLTEEnhancedTransmissionType()
|
||
}, 3000)
|
||
|
||
}
|
||
|
||
WirelessLinkManager.getInstance().initWirelessLink()
|
||
CameraManager.getInstance().initCameraInfo()
|
||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||
MissionV3Manager.getInstance().initMissionManager()
|
||
enableStream()
|
||
initMixedStream()
|
||
startVtxHeartbeat()
|
||
SpeakerManager.getInstance().addMegaphoneInfoListener()
|
||
GeoidManager.getInstance().init(this)
|
||
GimbalManager.getInstance().setmode()
|
||
PayloadWidgetManager.getInstance().initPayloadInfo()
|
||
|
||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||
|
||
Handler(Looper.getMainLooper()).postDelayed({
|
||
when (PreferenceUtils.getInstance().customStreamType) {
|
||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||
}
|
||
SimplePortScanner.getInstance().startScan()
|
||
}, 5000)
|
||
|
||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||
}
|
||
|
||
private fun initForCameraLocationTypeDefault() {
|
||
initTimes++
|
||
cameraManager.setKeepAliveDecoding(true)
|
||
LogUtil.log(TAG, "云台初始化$initTimes")
|
||
FlightManager.getInstance().initFlightInfo()
|
||
BatteryManager.getInstance().initBatteryInfo()
|
||
StickManager.getInstance().initStickInfo()
|
||
GimbalManager.getInstance().initGimbalInfo()
|
||
AlternateLandingManager.getInstance().initAlterLandingInfo()
|
||
OSDManager.getInstance().initOsd()
|
||
FlightTaskProgressManager.getInstance().initFlightTaskProgress()
|
||
MediaManager.getInstance().init()
|
||
StreamManager.getInstance().initStreamManager()
|
||
LEDsSettingsManager.getInstance().initLEDsInfo()
|
||
RTKManager.getInstance().initRTKInfo()
|
||
LTEManager.getInstance().initLTEInfo()
|
||
WirelessLinkManager.getInstance().initWirelessLink()
|
||
CameraManager.getInstance().initCameraInfo()
|
||
NavigationSatelliteSystemManager.getInstance().initNavigationSatelliteSystem()
|
||
NavigationSatelliteSystemManager.getInstance().setNavigationSatelliteSystem()
|
||
MissionV3Manager.getInstance().initMissionManager()
|
||
enableStream()
|
||
initCameraStream()
|
||
startVtxHeartbeat()
|
||
|
||
|
||
SpeakerManager.getInstance().addMegaphoneInfoListener()
|
||
GeoidManager.getInstance().init(this)
|
||
GimbalManager.getInstance().setmode()
|
||
PayloadWidgetManager.getInstance().initPayloadInfo()
|
||
|
||
|
||
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
|
||
|
||
if (PreferenceUtils.getInstance().lteEnable) {
|
||
// LogUtil.log("qwq","lteEnable"+PreferenceUtils.getInstance().lteEnable)
|
||
MLTEManager.getInstance().initLTEManager()
|
||
Handler().postDelayed(Runnable {
|
||
MLTEManager.getInstance().setLTEEnhancedTransmissionType()
|
||
}, 3000)
|
||
|
||
}
|
||
|
||
|
||
LogUtil.log(TAG, "自定义推流方式:" + PreferenceUtils.getInstance().customStreamType)
|
||
|
||
Handler(Looper.getMainLooper()).postDelayed({
|
||
when (PreferenceUtils.getInstance().customStreamType) {
|
||
1 -> StreamManager.getInstance().startLiveWithRTSP()
|
||
2 -> StreamManager.getInstance().startLiveWithCustom()
|
||
else -> StreamManager.getInstance().startLiveWithCustom()
|
||
}
|
||
SimplePortScanner.getInstance().startScan()
|
||
}, 5000)
|
||
|
||
LogUtil.log(TAG, "推流类型:" + PreferenceUtils.getInstance().customStreamType)
|
||
}
|
||
|
||
private fun enableStream() {
|
||
cameraManager.enableStream(ComponentIndexType.PORT_1, true);
|
||
cameraManager.enableStream(ComponentIndexType.FPV, true);
|
||
}
|
||
|
||
@SuppressLint("SuspiciousIndentation")
|
||
private fun initMixedStream() {
|
||
// 初始化融合视觉降落识别器
|
||
//val mixedLanding = MixedVisionLanding.getInstance()
|
||
// 为 PORT_1(云台相机)添加帧监听器
|
||
cameraManager.addFrameListener(
|
||
ComponentIndexType.PORT_1,
|
||
ICameraStreamManager.FrameFormat.YUV420_888
|
||
) { frameData, _, _, width, height, _ ->
|
||
// LogUtil.log(TAG,"port监听回调了addFrameListener")
|
||
// runOnUiThread {
|
||
// val now = System.currentTimeMillis()
|
||
// if (now - lastPortToastTime >= TOAST_INTERVAL_MS) {
|
||
// lastPortToastTime = now
|
||
// Toast.makeText(this, "port监听回调了addFrameListener", Toast.LENGTH_SHORT).show()
|
||
// }
|
||
// }
|
||
|
||
Movement.getInstance().isVtx = true
|
||
updateVtxHeartbeat()
|
||
streamReceive = true
|
||
|
||
// 使用融合视觉识别器处理云台相机帧
|
||
//mixedLanding.processGimbalFrame(height, width, frameData, dictionary)
|
||
//使用云台
|
||
synchronized(Synchronizedstatus.LOCK_OBJ) {
|
||
if (!Synchronizedstatus.isIsruningframe() && Synchronizedstatus.isAprongim() && Synchronizedstatus.isSwitchtime()) {
|
||
try {
|
||
Synchronizedstatus.setIsruningframe(true)
|
||
|
||
if(!isscousse){
|
||
isscousse=true;
|
||
LogUtil.log(TAG,"mix视频帧回调了")
|
||
}
|
||
|
||
if (startArucoType == 1) {
|
||
Aprongim.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 2) {
|
||
AlternateArucoDetect.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 3) {
|
||
Aprongim.getInstance()?.detectForceTriggerTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
}
|
||
} finally {
|
||
Synchronizedstatus.setIsruningframe(false)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 为 FPV(下视相机)添加帧监听器
|
||
cameraManager.addFrameListener(
|
||
ComponentIndexType.FPV,
|
||
ICameraStreamManager.FrameFormat.YUV420_888
|
||
) { frameData, _, _, width, height, _ ->
|
||
|
||
//LogUtil.log(TAG,"fpv监听回调了addFrameListener")
|
||
// runOnUiThread {
|
||
// val now = System.currentTimeMillis()
|
||
// if (now - lastFpvToastTime >= TOAST_INTERVAL_MS) {
|
||
// lastFpvToastTime = now
|
||
// Toast.makeText(this, "fpv监听回调了addFrameListener", Toast.LENGTH_SHORT).show()
|
||
// }
|
||
// }
|
||
Movement.getInstance().isVtx = true
|
||
updateVtxHeartbeat()
|
||
streamReceive = true
|
||
// 使用融合视觉识别器处理下视相机帧
|
||
//mixedLanding.processDownwardFrame(height, width, frameData, dictionary)
|
||
//使用下视觉
|
||
synchronized(Synchronizedstatus.LOCK_OBJ) {
|
||
if (!Synchronizedstatus.isIsruningframe() && !Synchronizedstatus.isAprongim() && Synchronizedstatus.isSwitchtime()) {
|
||
try {
|
||
Synchronizedstatus.setIsruningframe(true)
|
||
|
||
|
||
|
||
if (startArucoType == 1) {
|
||
Aprondown.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 2) {
|
||
AlternateArucoDetect.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 3) {
|
||
Aprondown.getInstance()?.detectForceTriggerTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
}
|
||
} finally {
|
||
Synchronizedstatus.setIsruningframe(false)
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
@SuppressLint("SuspiciousIndentation")
|
||
private fun initFpvStream() {
|
||
cameraManager.addFrameListener(
|
||
ComponentIndexType.FPV,
|
||
ICameraStreamManager.FrameFormat.YUV420_888
|
||
) { frameData, _, _, width, height, _ ->
|
||
Movement.getInstance().isVtx = true
|
||
updateVtxHeartbeat()
|
||
streamReceive = true
|
||
// DualCaptureHelper.getInstance().onFrame(height, width, frameData)
|
||
// if (shouldExecute) {
|
||
// if (startArucoType == 1&& ApronArucoStatus.getInstance().canProcess(ApronArucoStatus.CameraSource.DOWNWARD)) {
|
||
synchronized(Synchronizedstatus.LOCK_OBJ) {
|
||
if (!Synchronizedstatus.isIsruningframe()) {
|
||
try {
|
||
Synchronizedstatus.setIsruningframe(true)
|
||
|
||
if(!isscousse){
|
||
isscousse=true;
|
||
LogUtil.log(TAG,"port视频帧回调了")
|
||
}
|
||
|
||
if (startArucoType == 1) {
|
||
ApronArucoDetect.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 2) {
|
||
AlternateArucoDetect.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 3) {
|
||
ApronArucoDetect.getInstance()?.detectForceTriggerTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
}
|
||
} finally {
|
||
Synchronizedstatus.setIsruningframe(false)
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
@SuppressLint("SuspiciousIndentation")
|
||
private fun initCameraStream() {
|
||
cameraManager.addFrameListener(
|
||
ComponentIndexType.PORT_1,
|
||
ICameraStreamManager.FrameFormat.YUV420_888
|
||
) { frameData, _, _, width, height, _ ->
|
||
Movement.getInstance().isVtx = true
|
||
updateVtxHeartbeat()
|
||
streamReceive = true
|
||
// DualCaptureHelper.getInstance().onFrame(height, width, frameData)
|
||
// if (shouldExecute) {
|
||
// if (startArucoType == 1&& ApronArucoStatus.getInstance().canProcess(ApronArucoStatus.CameraSource.DOWNWARD)) {
|
||
synchronized(Synchronizedstatus.LOCK_OBJ) {
|
||
if (!Synchronizedstatus.isIsruningframe()) {
|
||
try {
|
||
Synchronizedstatus.setIsruningframe(true)
|
||
|
||
if(!isscousse){
|
||
isscousse=true;
|
||
LogUtil.log(TAG,"fpv视频帧回调了")
|
||
}
|
||
|
||
if (startArucoType == 1) {
|
||
ApronArucoDetectPort.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 2) {
|
||
AlternateArucoDetect.getInstance()?.detectArucoTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
} else if (startArucoType == 3) {
|
||
ApronArucoDetectPort.getInstance()?.detectForceTriggerTags(
|
||
height,
|
||
width,
|
||
frameData,
|
||
dictionary
|
||
)
|
||
}
|
||
} finally {
|
||
Synchronizedstatus.setIsruningframe(false)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// private val mLoaderCallback: BaseLoaderCallback = object : BaseLoaderCallback(this) {
|
||
// override fun onManagerConnected(status: Int) {
|
||
// if (status == SUCCESS) {
|
||
// LogUtil.log(TAG,"Version Name="+BuildConfig.VERSION_NAME)
|
||
// ApronArucoDetect.getInstance().init()
|
||
//
|
||
// } else {
|
||
// super.onManagerConnected(status)
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||
fun onEvent(message: String?) {
|
||
when (message) {
|
||
FLAG_START_DETECT_ARUCO_APRON -> {
|
||
MediaDataCenter.getInstance().getCameraStreamManager().setVisionAssistViewDirection(
|
||
VisionAssistDirection.DOWN,
|
||
object : CompletionCallback {
|
||
override fun onSuccess() {
|
||
LogUtil.log(TAG, "下视开启成功")
|
||
}
|
||
|
||
override fun onFailure(idjiError: IDJIError) {
|
||
LogUtil.log(TAG, "下视开启失败")
|
||
}
|
||
})
|
||
|
||
val leDsSettings = LEDsSettings()
|
||
leDsSettings.setNavigationLEDsOn(false)
|
||
leDsSettings.setStatusIndicatorLEDsOn(true)
|
||
leDsSettings.setFrontLEDsOn(true)
|
||
KeyManager.getInstance().setValue<LEDsSettings?>(
|
||
KeyTools.createKey<LEDsSettings?>(FlightControllerKey.KeyLEDsSettings),
|
||
leDsSettings,
|
||
object : CompletionCallback {
|
||
override fun onSuccess() {
|
||
LogUtil.log(TAG, "夜航灯关闭成功")
|
||
}
|
||
|
||
override fun onFailure(idjiError: IDJIError) {
|
||
LogUtil.log(TAG, "夜航灯关闭失败")
|
||
}
|
||
})
|
||
|
||
KeyManager.getInstance().performAction<EmptyMsg>(
|
||
KeyTools.createKey<EmptyMsg, EmptyMsg>(FlightControllerKey.KeyStopAutoLanding),
|
||
object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg?> {
|
||
override fun onSuccess(emptyMsg: EmptyMsg?) {
|
||
LogUtil.log(TAG, "取消降落,识别机库二维码")
|
||
if (PreferenceUtils.getInstance().cameraLocationType == 3) {
|
||
Handler().postDelayed(Runnable {
|
||
if (!ApronArucoDetect.getInstance().isTriggerSuccess) {
|
||
LogUtil.log(TAG, "图传异常:飞往备降点")
|
||
//测试图传丢失
|
||
AlternateLandingManager.getInstance().startTaskProcess(null)
|
||
}
|
||
}, 6000)
|
||
} else if (PreferenceUtils.getInstance().cameraLocationType == 4 || PreferenceUtils.getInstance().cameraLocationType == 5) {
|
||
Handler().postDelayed(Runnable {
|
||
if (!Aprongim.getInstance().isTriggerSuccess) {
|
||
LogUtil.log(TAG, "图传异常:飞往备降点"+ Movement.getInstance().isVtx)
|
||
//测试图传丢失
|
||
AlternateLandingManager.getInstance().startTaskProcess(null)
|
||
}
|
||
}, 6000)
|
||
} else {
|
||
Handler().postDelayed(Runnable {
|
||
if (!ApronArucoDetectPort.getInstance().isTriggerSuccess) {
|
||
LogUtil.log(TAG, "图传异常:飞往备降点")
|
||
//测试图传丢失
|
||
AlternateLandingManager.getInstance().startTaskProcess(null)
|
||
}
|
||
}, 6000)
|
||
}
|
||
if (startArucoType == 1) {
|
||
return
|
||
}
|
||
startArucoType = 1
|
||
ApronArucoDetect.getInstance().setDetectedBigMarkers()
|
||
ApronArucoDetectPort.getInstance().setDetectedBigMarkers()
|
||
Aprongim.getInstance().setDetectedBigMarkers()
|
||
Aprondown.getInstance().setDetectedBigMarkers()
|
||
|
||
|
||
DroneHelper.getInstance().setGimbalPitchDegree()
|
||
//每次触发识别二维码时,为避免获取控制权失败,使多次获取控制权
|
||
DroneHelper.getInstance().isVirtualStickEnable = false
|
||
DroneHelper.getInstance().setVerticalModeToVelocity()
|
||
}
|
||
|
||
override fun onFailure(error: IDJIError) {
|
||
if (startArucoType == 1) {
|
||
return
|
||
}
|
||
startArucoType = 1
|
||
LogUtil.log(TAG, "取消降落,识别机库二维码失败:" + Gson().toJson(error))
|
||
ApronArucoDetect.getInstance().setDetectedBigMarkers()
|
||
ApronArucoDetectPort.getInstance().setDetectedBigMarkers()
|
||
Aprongim.getInstance().setDetectedBigMarkers()
|
||
Aprondown.getInstance().setDetectedBigMarkers()
|
||
|
||
|
||
DroneHelper.getInstance().setGimbalPitchDegree()
|
||
//每次触发识别二维码时,为避免获取控制权失败,使多次获取控制权
|
||
DroneHelper.getInstance().isVirtualStickEnable = false
|
||
DroneHelper.getInstance().setVerticalModeToVelocity()
|
||
}
|
||
})
|
||
}
|
||
|
||
FLAG_START_DETECT_ARUCO_ALTERNATE ->
|
||
KeyManager.getInstance().performAction<EmptyMsg>(
|
||
KeyTools.createKey<EmptyMsg, EmptyMsg>(FlightControllerKey.KeyStopAutoLanding),
|
||
object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg?> {
|
||
override fun onSuccess(emptyMsg: EmptyMsg?) {
|
||
LogUtil.log(TAG, "取消降落,识别备降点二维码")
|
||
if (PreferenceUtils.getInstance().cameraLocationType == 3) {
|
||
Handler().postDelayed(Runnable {
|
||
if (!ApronArucoDetect.getInstance().isTriggerSuccess) {
|
||
LogUtil.log(TAG, "图传异常:飞往备降点")
|
||
//测试图传丢失
|
||
AlternateLandingManager.getInstance().startTaskProcess(null)
|
||
}
|
||
}, 6000)
|
||
} else if (PreferenceUtils.getInstance().cameraLocationType == 4 || PreferenceUtils.getInstance().cameraLocationType == 5) {
|
||
Handler().postDelayed(Runnable {
|
||
if (!Aprongim.getInstance().isTriggerSuccess) {
|
||
LogUtil.log(TAG, "备降点图传异常:飞往备降点")
|
||
AlternateLandingManager.getInstance().startTaskProcess(null)
|
||
}
|
||
}, 6000)
|
||
|
||
} else {
|
||
Handler().postDelayed(Runnable {
|
||
if (!ApronArucoDetectPort.getInstance().isTriggerSuccess) {
|
||
LogUtil.log(TAG, "图传异常:飞往备降点")
|
||
//测试图传丢失
|
||
AlternateLandingManager.getInstance().startTaskProcess(null)
|
||
}
|
||
}, 6000)
|
||
}
|
||
if (startArucoType == 2) {
|
||
return
|
||
}
|
||
startArucoType = 2
|
||
DroneHelper.getInstance().setGimbalPitchDegree()
|
||
//每次触发识别二维码时,为避免获取控制权失败,使多次获取控制权
|
||
DroneHelper.getInstance().isVirtualStickEnable = false
|
||
DroneHelper.getInstance().setVerticalModeToVelocity()
|
||
}
|
||
|
||
override fun onFailure(error: IDJIError) {
|
||
if (startArucoType == 2) {
|
||
return
|
||
}
|
||
startArucoType = 2
|
||
LogUtil.log(
|
||
TAG,
|
||
"取消降落,识别备降点二维码失败:" + Gson().toJson(error)
|
||
)
|
||
DroneHelper.getInstance().setGimbalPitchDegree()
|
||
//每次触发识别二维码时,为避免获取控制权失败,使多次获取控制权
|
||
DroneHelper.getInstance().isVirtualStickEnable = false
|
||
DroneHelper.getInstance().setVerticalModeToVelocity()
|
||
}
|
||
})
|
||
|
||
FLAG_DOWN_LAND -> {
|
||
//重置降落变量
|
||
ApronArucoDetect.getInstance().setStartAruco(false);
|
||
ApronArucoDetectPort.getInstance().setStartAruco(false);
|
||
Aprongim.getInstance().setStartAruco(false);
|
||
Aprondown.getInstance().setStartAruco(false);
|
||
|
||
|
||
KeyManager.getInstance().performAction<EmptyMsg>(
|
||
KeyTools.createKey<EmptyMsg, EmptyMsg>(FlightControllerKey.KeyStartAutoLanding),
|
||
object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg?> {
|
||
override fun onSuccess(emptyMsg: EmptyMsg?) {
|
||
startArucoType = 0
|
||
LogUtil.log(TAG, "自动降落调用成功")
|
||
}
|
||
|
||
override fun onFailure(error: IDJIError) {
|
||
LogUtil.log(TAG, "自动降落调用失败${error.description()}")
|
||
}
|
||
})
|
||
}
|
||
|
||
|
||
FLAG_STOP_ARUCO ->
|
||
startArucoType = 0
|
||
|
||
"REFRESH_VIDEO_SOURCE" -> {
|
||
// 智能刷新:有云台模拟点击,没有云台直接刷新
|
||
smartRefreshVideoStream()
|
||
}
|
||
|
||
MqttCallBack.FLAG_RESET_CLEAN_MODE ->
|
||
setViewVisibilityWithCleanMode()
|
||
}
|
||
}
|
||
|
||
|
||
private fun setViewVisibilityWithCleanMode() {
|
||
if (PreferenceUtils.getInstance().isCleanMode) {
|
||
fpvInteractionWidget?.visibility = View.GONE
|
||
horizontalSituationIndicatorWidget?.visibility = View.GONE
|
||
gimbalFineTuneWidget?.visibility = View.GONE
|
||
ndviCameraPanel?.visibility = View.GONE
|
||
visualCameraPanel?.visibility = View.GONE
|
||
autoExposureLockWidget?.visibility = View.GONE
|
||
focusModeWidget?.visibility = View.GONE
|
||
focusExposureSwitchWidget?.visibility = View.GONE
|
||
cameraControlsWidget?.visibility = View.GONE
|
||
focalZoomWidget?.visibility = View.GONE
|
||
// returnHomeWidget?.visibility = View.GONE
|
||
// takeOffWidget?.visibility = View.GONE
|
||
// lensControlWidget?.visibility = View.GONE
|
||
simulatorControlWidget?.visibility = View.GONE
|
||
pfvFlightDisplayWidget?.visibility = View.GONE
|
||
systemStatusListPanelWidget?.visibility = View.GONE
|
||
topBarPanel?.visibility = View.GONE
|
||
}
|
||
}
|
||
|
||
}
|