[3.3.0][M1] 360环视需求代码提交

This commit is contained in:
renwj
2023-06-13 16:39:27 +08:00
parent 59dd44a14b
commit dd9a4667df
37 changed files with 1388 additions and 231 deletions

View File

@@ -56,6 +56,7 @@ import com.zhidao.support.adas.high.common.Constants
import com.zhidao.support.adas.high.common.Constants.IPC_CONNECTION_STATUS
import com.zhidao.support.adas.high.common.CupidLogUtils
import com.zhidao.support.adas.high.common.MessageType
import com.zhjt.mogo.adas.data.AdasConstants
import com.zhjt.mogo.adas.data.bean.MogoReport
import com.zhjt.mogo.adas.data.sweeper.bootable.SweeperBootable
import com.zhjt.mogo.adas.data.sweeper.task.SweeperTask
@@ -559,7 +560,7 @@ class MoGoAutopilotControlProvider :
/**
* 获取全部参数
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq)}
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq, AdasParam)}
*
* @return boolean
*/
@@ -569,12 +570,12 @@ class MoGoAutopilotControlProvider :
/**
* 参数获取请求
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq)}
* 结果回调{@link OnAdasListener#onGetParamResp(MessagePad.Header, MessagePad.SetParamReq, AdasParam)}
*
* @param paramType 参数类型{@link com.zhidao.support.adas.high.common.Constants.PARAM_TYPE}
* @param paramType 参数类型:libraries/mogo-adas-data/src/main/proto/personal/adas_constants.proto
* @return boolean
*/
override fun sendGetParamReq(paramType: Int): Boolean {
override fun sendGetParamReq(paramType: AdasConstants.MapSystemParamType): Boolean {
return AdasManager.getInstance().sendGetParamReq(paramType)
}

View File

@@ -60,7 +60,7 @@ import com.mogo.eagle.core.utilcode.mogo.logger.Logger
import com.mogo.support.obu.ObuScene
import com.zhidao.support.adas.high.AdasManager
import com.zhidao.support.adas.high.OnAdasListener
import com.zhidao.support.adas.high.bean.AdasParam
import com.zhjt.mogo.adas.data.bean.AdasParam
import com.zhidao.support.adas.high.common.ProtocolStatus
import com.zhjt.mogo.adas.data.bean.AutopilotStatistics
import com.zhjt.mogo.adas.data.sweeper.SweeperCloudTask
@@ -796,6 +796,7 @@ class MoGoAdasListenerImpl : OnAdasListener {
* @param adasParam 解析后的配置参数
*/
override fun onGetParamResp(header: MessagePad.Header, getParamResp: MessagePad.SetParamReq, adasParam: AdasParam) {
CallerAutopilotGetParamResponseDispatcher.dispatchResponse(header, getParamResp, adasParam)
}
/**

View File

@@ -20,6 +20,7 @@ import com.mogo.eagle.core.function.api.devatools.apm.*
import com.mogo.eagle.core.function.api.devatools.strict.*
import com.mogo.eagle.core.function.call.map.*
import com.mogo.eagle.core.function.api.devatools.download.*
import com.mogo.eagle.core.function.api.lookaround.*
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.w
import com.tencent.matrix.Matrix
@@ -42,6 +43,7 @@ import com.zhjt.mogo_core_function_devatools.funcconfig.FuncConfigCenter.Compani
import com.zhjt.mogo_core_function_devatools.funcconfig.FuncConfigImpl
import com.zhjt.mogo_core_function_devatools.koom.KoomInitTask
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchManager
import com.zhjt.mogo_core_function_devatools.lookaround.*
import com.zhjt.mogo_core_function_devatools.matrix.DynamicConfigImpl
import com.zhjt.mogo_core_function_devatools.mofang.MoFangManager.Companion.moFangManager
import com.zhjt.mogo_core_function_devatools.monitor.MonitorManager
@@ -72,6 +74,9 @@ class DevaToolsProvider : IDevaToolsProvider {
private val strictModeProvider by lazy { StrictModeProviderImpl() }
private val lookAroundDataProvider by lazy { MoGoLookAroundProviderImpl() }
@Volatile
private var mDockerVersion: String? = null
@@ -105,6 +110,7 @@ class DevaToolsProvider : IDevaToolsProvider {
// 监听弱网
WeakNetworkStrategy.startListen()
}
lookAroundDataProvider.init(mContext!!)
}
override fun checkMonitorDb() {
@@ -356,4 +362,6 @@ class DevaToolsProvider : IDevaToolsProvider {
return upgradeManager.upgradeProvider()
}
override fun strict(): IStrictModeProvider = strictModeProvider
override fun lookAroundDataProvider(): IMoGoLookAroundProvider = lookAroundDataProvider
}

View File

@@ -0,0 +1,160 @@
package com.zhjt.mogo_core_function_devatools.lookaround
import android.content.*
import android.graphics.BitmapFactory
import android.util.*
import androidx.core.util.Pools
import com.mogo.eagle.core.data.config.*
import com.mogo.eagle.core.function.api.autopilot.*
import com.mogo.eagle.core.function.api.lookaround.*
import com.mogo.eagle.core.function.api.lookaround.data.*
import com.mogo.eagle.core.function.call.autopilot.*
import com.mogo.eagle.core.utilcode.mogo.*
import com.zhjt.mogo.adas.data.*
import com.zhjt.mogo.adas.data.bean.*
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
import kotlinx.coroutines.flow.*
import mogo.telematics.pad.MessagePad.Header
import mogo.telematics.pad.MessagePad.SetParamReq
import java.util.concurrent.atomic.AtomicInteger
import kotlin.concurrent.*
internal class MoGoLookAroundProviderImpl: IMoGoLookAroundProvider, IMoGoSweeperFutianBackCameraVideoListener, IMoGoRoboBusJinlvM1StitchedVideoListener, IMoGoGetParamResponseListener {
companion object {
private const val TAG = "MoGoLookAroundProvider"
}
@OptIn(ExperimentalCoroutinesApi::class)
private var channel: Channel<LookAroundData> = Channel(CONFLATED)
get() {
return if (field.isClosedForReceive || field.isClosedForSend) {
Channel(CONFLATED)
} else {
field
}
}
private val pool by lazy { Pools.SynchronizedPool<LookAroundData>(10) }
private val bitmapWidth by lazy { AtomicInteger(0) }
private val bitmapHeight by lazy { AtomicInteger(0) }
//276,319,147,366
private val targetX by lazy { AtomicInteger(0) }
private val targetY by lazy { AtomicInteger(0) }
private val targetWidth by lazy { AtomicInteger(0) }
private val targetHeight by lazy { AtomicInteger(0) }
private val scope by lazy { CoroutineScope(Dispatchers.IO + SupervisorJob()) }
@Volatile
private var job: Job? = null
override fun init(ctx: Context) {
CallerSweeperFutianBackCameraVideoListenerManager.addListener(TAG, this)
CallerRoboBusJinlvM1StitchedVideoListenerManager.addListener(TAG, this)
CallerAutopilotGetParamResponseDispatcher.addListener(TAG, this)
if (AppIdentityModeUtils.isM1(FunctionBuildConfig.appIdentityMode)) {
sendReqForParamPeriod()
}
}
private fun sendReqForParamPeriod() {
scope.launch {
while (targetX.get() == 0 || targetY.get() == 0) {
CallerAutoPilotControlManager.sendGetParamReq(AdasConstants.MapSystemParamType.M1_STITCHED_VIDEO_SELF_VEHICLE_PARAM)
delay(2000)
}
}.also {
job = it
}
}
@OptIn(ExperimentalCoroutinesApi::class)
override fun flow(): Flow<LookAroundData> = channelFlow {
val iterator = this@MoGoLookAroundProviderImpl.channel.iterator()
while (iterator.hasNext()) {
send(iterator.next())
}
}.flowOn(Dispatchers.IO)
override fun onRoboBusJinlvM1StitchedVideo(data: ByteArray) {
if (bitmapWidth.get() == 0 || bitmapHeight.get() == 0) {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeByteArray(data,0 , data.size, options)
bitmapWidth.set(options.outWidth)
bitmapHeight.set(options.outHeight)
}
Log.d(TAG, "-- onRoboBusJinlvM1StitchedVideo -- bitmap:[${bitmapWidth.get()}, ${bitmapHeight.get()}] -- data: ${data.size}")
var old = pool.acquire()
try {
if (old == null) {
old = LookAroundData(data, bitmapWidth.get(), bitmapHeight.get(), targetX.get(), targetY.get(), targetWidth.get(), targetHeight.get())
} else {
old.data = data
old.bitmapWidth = bitmapWidth.get()
old.bitmapHeight = bitmapHeight.get()
old.targetX = targetX.get()
old.targetY = targetY.get()
old.targetWidth = targetWidth.get()
old.targetHeight = targetHeight.get()
}
channel.trySend(old)
} finally {
if (old != null) {
pool.release(old)
}
}
}
override fun onSweeperFutianBackCameraVideo(data: ByteArray) {
if (bitmapWidth.get() == 0 || bitmapHeight.get() == 0) {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeByteArray(data,0 , data.size, options)
bitmapWidth.set(options.outWidth)
bitmapHeight.set(options.outHeight)
}
Log.d(TAG, "-- onSweeperFutianBackCameraVideo -- bitmap:[${bitmapWidth.get()}, ${bitmapHeight.get()}] -- data: ${data.size}")
var old = pool.acquire()
try {
if (old == null) {
old = LookAroundData(data, bitmapWidth.get(), bitmapHeight.get(), targetX.get(), targetY.get(), targetWidth.get(), targetHeight.get())
} else {
old.data = data
old.bitmapWidth = bitmapWidth.get()
old.bitmapHeight = bitmapHeight.get()
old.targetX = targetX.get()
old.targetY = targetY.get()
old.targetWidth = targetWidth.get()
old.targetHeight = targetHeight.get()
}
channel.trySend(old)
} finally {
if (old != null) {
pool.release(old)
}
}
}
override fun onGetParamResp(header: Header, getParamResp: SetParamReq, adasParam: AdasParam) {
Log.d(TAG, "-- onGetParamResp -- 1 --")
val parse = adasParam.m1StitchedVideoSelfVehicleParamParse
if (parse != null) {
targetX.set(parse.x)
targetY.set(parse.y)
targetWidth.set(parse.width)
targetHeight.set(parse.height)
Log.d(TAG, "-- onGetParamResp -- 2 --:[x: ${parse.x}, y: ${parse.y}, width: ${parse.width}, height: ${parse.height}]")
}
}
}

View File

@@ -8,16 +8,13 @@ import androidx.lifecycle.*
import androidx.lifecycle.Lifecycle.Event
import androidx.lifecycle.Lifecycle.Event.ON_CREATE
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
import com.mogo.eagle.core.function.call.autopilot.*
import com.mogo.eagle.core.utilcode.kotlin.*
import com.mogo.eagle.core.utilcode.mogo.logger.*
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_DEVA
import com.mogo.eagle.core.utilcode.util.*
import com.zhjt.mogo_core_function_devatools.status.entity.CanStatus
import com.zhjt.mogo_core_function_devatools.status.entity.GpsStatus
import com.zhjt.mogo_core_function_devatools.status.entity.IpcStatus
//import com.zhjt.mogo_core_function_devatools.status.entity.NetStatus
import com.zhjt.mogo_core_function_devatools.status.entity.RTKStatus
import com.zhjt.mogo_core_function_devatools.status.entity.Status
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus
@@ -26,13 +23,11 @@ import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
import com.zhjt.mogo_core_function_devatools.status.flow.can.CanImpl
import com.zhjt.mogo_core_function_devatools.status.flow.gps.GpsImpl
import com.zhjt.mogo_core_function_devatools.status.flow.ipc.IpcImpl
//import com.zhjt.mogo_core_function_devatools.status.flow.nets.NetsImpl
import com.zhjt.mogo_core_function_devatools.status.flow.rtk.RTKImpl
import com.zhjt.mogo_core_function_devatools.status.flow.trace.TracingImpl
import com.zhjt.mogo_core_function_devatools.status.ui.StatusView
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import mogo_msg.MogoReportMsg
import java.lang.ref.*
import java.util.concurrent.*
@@ -42,52 +37,14 @@ object StatusManager {
private const val TAG = "StatusManager"
private lateinit var model: StatusModel
// private var timer: Job? = null
private var hasInit = false
private val listeners by lazy { CopyOnWriteArrayList<IStatusListener>() }
private var container: WeakReference<ViewGroup>? = null
// private val listener = object : IMoGoAutopilotStatusListener {
// override fun onAutopilotGuardian(guardianInfo: MogoReportMsg.MogoReportMessage?) {
// super.onAutopilotGuardian(guardianInfo)
// guardianInfo?.code?.takeIf {
// CallerLogger.d("$M_DEVA$TAG", "-- onAutopilotGuardian ---: code: $it")
// it.contains("RTK_STATUS", true) || it.contains("CAN", true) || it == "ILCT_RTK_OR_SLAM_CHANGE"
// }?.run {
// CallerLogger.d("$M_DEVA$TAG", "-- onAutopilotGuardian trigger req ---: code: $this")
// req()
// }
// }
// }
// private val appStateListener = object : IAppStateListener {
//
// override fun onAppStateChanged(isForeground: Boolean) {
// if (isForeground) {
// req()
// } else {
// timer?.cancel()
// }
// }
// }
private val flows: ArrayList<IFlow<out Status>> by lazy {
ArrayList()
}
// private fun req() {
// timer?.cancel()
// model.viewModelScope.launch(Dispatchers.IO) {
// CallerAutoPilotManager.sendStatusQueryReq()
// while (true) {
// delay(60000) //一分钟主动请求一次
// CallerAutoPilotManager.sendStatusQueryReq()
// }
// }.also {
// timer = it
// }
// }
fun init(ctx: Context) {
if (hasInit) {
return
@@ -109,14 +66,10 @@ object StatusManager {
private fun onCreate(ctx: Context) {
val values = model.status.value?.second ?: throw IllegalStateException("state is not right.")
// CallerAutoPilotStatusListenerManager.addListener(TAG, listener)
// AppStateManager.registerAppStateListener(appStateListener)
// req()
values.map {
when (it) {
is CanStatus -> CanImpl(ctx)
is IpcStatus -> IpcImpl(ctx)
// is NetStatus -> NetsImpl(ctx)
is GpsStatus -> GpsImpl(ctx)
is TracingStatus -> TracingImpl(ctx)
is RTKStatus -> RTKImpl(ctx)
@@ -138,16 +91,6 @@ object StatusManager {
}
}
fun registerListener(listener: IStatusListener) {
listeners.add(listener)
}
fun unRegisterListener(listener: IStatusListener) {
listeners.remove(listener)
}
fun show(container: ViewGroup) {
if (container.childCount > 0) {
if (container.visibility != View.VISIBLE) {
@@ -166,9 +109,6 @@ object StatusManager {
private fun onDestroy(ctx: Context) {
hasInit = false
// CallerAutoPilotStatusListenerManager.removeListener(TAG)
// AppStateManager.unRegisterAppStateListener(appStateListener)
// timer?.cancel()
flows.forEach {
it.onDestroy()
}

View File

@@ -23,7 +23,6 @@ internal class StatusModel : ViewModel() {
it += CanStatus(false)
it += TracingStatus(UNKNOWN)
it += RTKStatus("", -1)
// it += NetStatus(false)
it += GpsStatus(enabled = false, isGranted = false)
})
}

View File

@@ -3,7 +3,10 @@ package com.mogo.eagle.core.function.hmi.ui
import android.content.Context
import android.text.TextUtils
import android.util.*
import android.view.ViewGroup
import android.view.*
import android.view.ViewGroup.LayoutParams
import android.widget.FrameLayout
import androidx.core.view.*
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.alibaba.android.arouter.facade.annotation.Route
@@ -22,9 +25,10 @@ import com.mogo.eagle.core.data.biz.notice.NoticeNormalData
import com.mogo.eagle.core.data.biz.notice.NoticeTrafficStylePushData
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoHmiProvider
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener
import com.mogo.eagle.core.function.call.hmi.CallerHmiViewControlListenerManager
import com.mogo.eagle.core.function.call.hmi.*
import com.mogo.eagle.core.function.call.v2x.CallerV2XWarningListenerManager
import com.mogo.eagle.core.function.hmi.ui.camera.RoadVideoDialog
import com.mogo.eagle.core.function.hmi.ui.lookaround.*
import com.mogo.eagle.core.function.hmi.ui.notice.DispatchDialogManager
import com.mogo.eagle.core.function.hmi.ui.notice.NoticeCheckDialog
import com.mogo.eagle.core.function.hmi.ui.notice.traffic.NoticeTrafficDialog
@@ -35,15 +39,17 @@ import com.mogo.eagle.core.function.hmi.ui.tools.ModifyBindingCarDialog
import com.mogo.eagle.core.function.hmi.ui.tools.ToBindingCarDialog
import com.mogo.eagle.core.function.hmi.ui.tools.UpgradeAppDialog
import com.mogo.eagle.core.function.hmi.ui.widget.StatusBarView
import com.mogo.eagle.core.utilcode.floating.*
import com.mogo.eagle.core.utilcode.kotlin.safeCancel
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_HMI
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.eagle.core.utilcode.util.*
import com.zhjt.service_biz.BizConfig
import kotlinx.coroutines.*
import kotlinx.coroutines.selects.*
import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicReference
/**
@@ -62,6 +68,11 @@ class MoGoHmiProvider : IMoGoHmiProvider {
private var lastShowV2XJob: Job? = null
private var context: Context? = null
/**
* 360环视窗口引用
*/
private val lookAround by lazy { AtomicReference<MoGoPopWindow>() }
private val scope by lazy { CoroutineScope(Dispatchers.Default + SupervisorJob()) }
override fun init(context: Context?) {
@@ -312,4 +323,38 @@ class MoGoHmiProvider : IMoGoHmiProvider {
}
}
override fun show360LookAround() {
val activity = AppStateManager.currentActivity() ?: return
val old = lookAround.get()
if (old != null && old.isShowing()) {
return
}
old?.hide()
MoGoPopWindow.Builder()
.attachToActivity(activity)
.contentView(M1LookAroundView(activity))
.draggable(true)
.isDismissOnTouchOutside(false)
.gravityInActivity(Gravity.CENTER)
.width(700)
.height(1400)
.onDismissed {
lookAround.set(null)
}
.build().also {
lookAround.set(it)
}.show()
}
override fun hide360LookAround() {
val old = lookAround.get()
if (old == null || !old.isShowing()) {
return
}
old.hide()
}
override fun is360LookAroundShowing(): Boolean {
return lookAround.get()?.isShowing() ?: false
}
}

View File

@@ -0,0 +1,347 @@
package com.mogo.eagle.core.function.hmi.ui.lookaround
import android.content.*
import android.graphics.*
import android.graphics.Paint.Style.STROKE
import android.os.Handler
import android.os.HandlerThread
import android.os.SystemClock
import android.util.*
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.widget.Toast
import com.mogo.eagle.core.function.api.autopilot.*
import com.mogo.eagle.core.function.api.lookaround.data.*
import com.mogo.eagle.core.function.call.autopilot.*
import com.mogo.eagle.core.function.call.devatools.*
import com.mogo.eagle.core.utilcode.kotlin.*
import com.mogo.eagle.core.utilcode.util.ThreadUtils
import com.mogo.eagle.core.utilcode.util.Utils
import kotlinx.coroutines.*
import kotlinx.coroutines.Runnable
import kotlinx.coroutines.flow.*
import java.util.concurrent.atomic.AtomicReference
import kotlin.math.*
class M1LookAroundView: SurfaceView, SurfaceHolder.Callback, Runnable, IMoGoChassisSteeringStateListener {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
companion object {
private const val TAG = "M1LookAroundView"
private const val BROKE_LINE_LENGTH = 40f
private const val VEHICLE_STEERING_RATIO = 21
}
init {
holder.addCallback(this)
}
private val handler by lazy { AtomicReference<Handler>() }
private val bitmapPaint by lazy { Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG).also { it.xfermode = null } }
private val routerPaint = Paint().also {
it.color = Color.RED
it.isAntiAlias = true
it.style = STROKE
it.strokeWidth = 5f
}
private val brokePaint = Paint().also {
it.color = Color.RED
it.isAntiAlias = true
it.style = STROKE
it.strokeJoin = Paint.Join.ROUND
it.strokeWidth = 5f
}
private val brokePath by lazy { Path() }
private val routerPath = Path()
private val innerRect by lazy { RectF() }
private val outerRect by lazy { RectF() }
/**
* 方向盘转角
*/
@Volatile
private var steering: Float = 0f
@Volatile
private var surfaceWidth = 0
@Volatile
private var surfaceHeight = 0
@Volatile
private var isSurfaceValid = false
@Volatile
private var data: LookAroundData? = null
override fun surfaceCreated(holder: SurfaceHolder?) {
val old = handler.get()
if (old == null) {
handler.set(HandlerThread("look-around-drawer").let { it.start(); Handler(it.looper) })
} else {
old.looper.quitSafely()
handler.set(HandlerThread("look-around-drawer").let { it.start(); Handler(it.looper) })
}
handler.get()?.removeCallbacks(this)
handler.get()?.post(this)
isSurfaceValid = true
}
override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) {
this.surfaceWidth = width
this.surfaceHeight = height
}
override fun surfaceDestroyed(holder: SurfaceHolder?) {
isSurfaceValid = false
}
override fun run() {
var isTimedBlock = false
try {
Log.d(TAG, "--- 1 ---")
if (!isSurfaceValid) {
isTimedBlock = true
return
}
if (this.surfaceWidth <= 0 || this.surfaceHeight <= 0) {
Log.d(TAG, "--- 2 ---")
isTimedBlock = true
return
}
Log.d(TAG, "--- 3 ---")
val data = this.data ?: return
val targetX = data.targetX
val targetY = data.targetY
val targetWidth = data.targetWidth
val targetHeight = data.targetHeight
val bitmapWidth = data.bitmapWidth
val bitmapHeight = data.bitmapHeight
val scaleX = this.surfaceWidth * 1.0f / bitmapWidth
val scaleY = this.surfaceHeight * 1.0f / bitmapHeight
val bytes = data.data
if (bytes == null) {
isTimedBlock = true
Log.d(TAG, "--- 4 ---")
return
}
Log.d(TAG, "--- 5 ---")
val canvas = holder.lockCanvas()
try {
if (canvas == null) {
Log.d(TAG, "--- 6 ---")
isTimedBlock = true
return
}
//1. 绘制图片
var startTime = SystemClock.elapsedRealtime()
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
Log.d(TAG, "--- cost for decode bitmap: ${SystemClock.elapsedRealtime() - startTime}ms.")
if (bitmap == null) {
Log.d(TAG, "--- 7 ---")
isTimedBlock = true
return
}
try {
startTime = SystemClock.elapsedRealtime()
canvas.save()
canvas.scale(scaleX, scaleY)
canvas.drawBitmap(bitmap, 0f, 0f, bitmapPaint)
} finally {
canvas.restore()
if (!bitmap.isRecycled) {
bitmap.recycle()
}
Log.d(TAG, "--- draw decoded bitmap cost: ${SystemClock.elapsedRealtime() - startTime}ms.")
}
//2. 绘制车的信息
Log.d(TAG, "--- 8 ---")
val newTargetX = targetX * scaleX
val newTargetY = targetY * scaleY
val newTargetWidth = targetWidth * scaleX
val newTargetHeight = targetHeight * scaleY
try {
//2.1 绘制车前的转向角
canvas.save()
var steering = this.steering
if (abs(steering) < 1) {
steering = 0f
}
if (steering == 0f) {
canvas.translate(newTargetX + newTargetWidth * 0.5f, newTargetY)
routerPath.reset()
val halfX = newTargetWidth * 0.5f
var startX = - halfX
val startY= 0f
routerPath.moveTo(startX, startY)
var endX = startX
val endY = - newTargetY
routerPath.lineTo(endX, endY)
canvas.drawPath(routerPath, routerPaint)
startX += newTargetWidth
endX += newTargetWidth
routerPath.reset()
routerPath.moveTo(startX, startY)
routerPath.lineTo(endX, endY)
canvas.drawPath(routerPath, routerPaint)
} else {
val outerAngle = abs(steering * 1.0 / VEHICLE_STEERING_RATIO)
val radians = Math.toRadians(outerAngle)
val d = (newTargetHeight / tan(radians)).toFloat()
if (steering < 0) {
// 左打轮
// 将坐标原点平移到圆心
canvas.translate(newTargetX - (d - newTargetWidth), newTargetY + newTargetHeight)
//外圆半径
val outerR = (newTargetHeight / sin(radians)).toFloat()
//内圆半径
val innerR = sqrt((newTargetHeight * 1.0).pow(2.0) + ((d - newTargetWidth) * 1.0).pow(2.0)).toFloat()
val innerAngle = Math.toDegrees(asin(newTargetHeight / innerR) * 1.0)
outerRect.set(-outerR, -outerR, outerR, outerR)
innerRect.set(-innerR, -innerR, innerR, innerR)
canvas.drawArc(outerRect, -outerAngle.toFloat(), -60f, false, routerPaint)
canvas.drawArc(innerRect, -innerAngle.toFloat(), -60f, false, routerPaint)
}
if (steering > 0) {
//右打轮
// 将坐标原点平移到圆心
canvas.translate(newTargetX + d, newTargetY + newTargetHeight)
//外圆半径
val outerR = (newTargetHeight / sin(radians)).toFloat()
//内圆半径
val innerR = sqrt((newTargetHeight * 1.0).pow(2.0) + ((d - newTargetWidth) * 1.0).pow(2.0)).toFloat()
val innerAngle = Math.toDegrees(asin(newTargetHeight / innerR) * 1.0)
outerRect.set(-outerR, -outerR, outerR, outerR)
innerRect.set(-innerR, -innerR, innerR, innerR)
canvas.drawArc(outerRect, 180f + outerAngle.toFloat(), 60f, false, routerPaint)
canvas.drawArc(innerRect, 180f + innerAngle.toFloat(), 60f, false, routerPaint)
}
}
} finally {
canvas.restore()
}
try {
//2.2 绘制车周围盲区标定
canvas.save()
canvas.translate(newTargetX + newTargetWidth * 0.5f, newTargetY)
Log.d(TAG, "--- 9 ---:[$targetX:$newTargetX, $targetY:$newTargetY, $targetWidth:$newTargetWidth, $targetHeight:$newTargetHeight]")
val halfTargetWidth = newTargetWidth * 0.5f
var startX = -halfTargetWidth
var startY = BROKE_LINE_LENGTH
var endX = startX
var endY = 0f
// 绘制左上角
brokePath.reset()
brokePath.moveTo(startX, startY)
brokePath.lineTo(endX, endY)
endX += BROKE_LINE_LENGTH
brokePath.lineTo(endX, endY)
canvas.drawPath(brokePath, brokePaint)
// 绘制右上角
startX = halfTargetWidth - BROKE_LINE_LENGTH
startY = 0f
endX = halfTargetWidth
endY = 0f
brokePath.reset()
brokePath.moveTo(startX, startY)
brokePath.lineTo(endX, endY)
endY += BROKE_LINE_LENGTH
brokePath.lineTo(endX, endY)
canvas.drawPath(brokePath, brokePaint)
//绘制左下角
startX = -halfTargetWidth
startY = newTargetHeight - BROKE_LINE_LENGTH
endX = startX
endY = newTargetHeight
brokePath.reset()
brokePath.moveTo(startX, startY)
brokePath.lineTo(endX, endY)
endX += BROKE_LINE_LENGTH
brokePath.lineTo(endX, endY)
canvas.drawPath(brokePath, brokePaint)
//绘制右下角
startX = halfTargetWidth - BROKE_LINE_LENGTH
startY = newTargetHeight
endX = halfTargetWidth
endY = startY
brokePath.reset()
brokePath.moveTo(startX, startY)
brokePath.lineTo(endX, endY)
endY -= BROKE_LINE_LENGTH
brokePath.lineTo(endX, endY)
canvas.drawPath(brokePath, brokePaint)
} finally {
canvas.restore()
}
} finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas)
}
}
} finally {
if (isTimedBlock) {
try {
Thread.sleep(2000)
} catch (ignore: Exception) { }
}
handler.get().post(this)
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
CallerChassisSteeringStateListenerManager.addListener(TAG, this)
Log.d(TAG, "--- 发起订阅 ---")
CallerAutoPilotControlManager.setIsSubscribeM1StitchedVideo(true)
scope.launch(ThreadUtils.getCpuPool().asCoroutineDispatcher()) {
CallerDevaToolsManager.lookAroundProvider()?.flow()?.also { flow ->
flow.onEach {
Log.d(TAG, "-- onEach ---:$it")
if (it.isValid()) {
data = it
}
}.collect()
}
}
// 订阅后5秒内未收到有效数据, 提示用户当前MAP版本不支持
scope.launch {
delay(5000)
val d = data
if (d == null || !d.isValid()) {
Toast.makeText(Utils.getApp(), "当前MAP版本不支持360环视请升级MAP版本", Toast.LENGTH_SHORT).show()
}
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
CallerChassisSteeringStateListenerManager.removeListener(TAG)
Log.d(TAG, "--- 取消订阅 ---")
CallerAutoPilotControlManager.setIsSubscribeM1StitchedVideo(false)
handler.get()?.looper?.quitSafely()
}
override fun onAutopilotSteeringData(steering: Float) {
Log.d(TAG, "--- onAutopilotSteeringData --: steering: $steering")
this.steering = steering
}
}

View File

@@ -223,6 +223,23 @@ internal class SOPSettingView @JvmOverloads constructor(
FunctionBuildConfig.isNewV2NData = isChecked
}
// M1 360度环视
tbNew360LookAround?.also {
if (!AppIdentityModeUtils.isM1(FunctionBuildConfig.appIdentityMode)) {
it.isEnabled = false
} else {
it.isEnabled = true
it.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
CallerHmiManager.showM1360LookAround()
} else {
CallerHmiManager.hidM1360LookAround()
}
}
it.isChecked = CallerHmiManager.isM1360LookAroundShowing()
}
}
//变道绕障的目标障碍物速度阈值
tvSpeed.text = "${FunctionBuildConfig.detouringSpeed} m/s"
ivSpeedReduce.setOnClickListener {

View File

@@ -1,87 +0,0 @@
package com.mogo.eagle.core.function.hmi.ui.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.mogo.eagle.core.function.api.autopilot.IMoGoSweeperFutianBackCameraVideoListener;
import com.mogo.eagle.core.function.call.autopilot.CallerSweeperFutianBackCameraVideoListenerManager;
import com.mogo.eagle.core.utilcode.mogo.glide.GlideApp;
import com.mogo.eagle.core.utilcode.util.ThreadUtils;
/**
* 清扫车摄像头展示View
*/
public class SweeperVideoView extends AppCompatImageView implements IMoGoSweeperFutianBackCameraVideoListener {
private static final String TAG = SweeperVideoView.class.getSimpleName();
private final RequestOptions requestOptions = new RequestOptions()
.priority(Priority.HIGH)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.dontAnimate();
public SweeperVideoView(@NonNull Context context) {
super(context);
}
public SweeperVideoView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public SweeperVideoView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
CallerSweeperFutianBackCameraVideoListenerManager.INSTANCE.addListener(TAG, this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
CallerSweeperFutianBackCameraVideoListenerManager.INSTANCE.removeListener(this);
}
private final CustomTarget<Bitmap> target = new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
//回调内容
if (!resource.isRecycled()) {
SweeperVideoView.this.setImageBitmap(resource);
}
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
//这个方法在target被回收时调用如果在除了imageView以外的地方引用了imageView中的bitmap在这里清除引用以避免崩溃
}
};
@Override
public void onSweeperFutianBackCameraVideo(@NonNull byte[] data) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
GlideApp.with(SweeperVideoView.this)
.asBitmap()
.load(data)
.placeholder(SweeperVideoView.this.getDrawable())
.apply(requestOptions)
.into(target);
}
});
}
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mogo.eagle.core.function.hmi.ui.widget.MogoVideoView
android:id="@+id/mogo_video_view"
android:layout_width="0dip"
android:layout_height="0dip"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<com.mogo.eagle.core.function.hmi.ui.lookaround.BezierView
android:id="@+id/mogo_bezier_view"
android:layout_width="0dip"
android:layout_height="0dip"
android:background="@android:color/transparent"
app:layout_constraintTop_toTopOf="@+id/mogo_video_view"
app:layout_constraintBottom_toBottomOf="@+id/mogo_video_view"
app:layout_constraintStart_toStartOf="@+id/mogo_video_view"
app:layout_constraintEnd_toEndOf="@+id/mogo_video_view"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -261,6 +261,19 @@
app:layout_constraintRight_toLeftOf="@id/verticalGuideLine"
/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/tbNew360LookAround"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="360环视"
android:paddingTop="25dp"
android:paddingBottom="25dp"
android:scaleY="1.2"
android:scaleX="1.2"
app:layout_constraintTop_toBottomOf="@id/tbIPCReport"
app:layout_constraintLeft_toRightOf="@+id/verticalGuideLine"
app:layout_constraintRight_toRightOf="parent" />
<TextView
android:id="@+id/tvSpeedThresholdTitle"
android:layout_width="wrap_content"