[8.0.0]车龙事件进MogoMind

This commit is contained in:
xuxinchao
2025-05-09 17:11:01 +08:00
parent df6ddef79f
commit 72647f150f
8 changed files with 470 additions and 0 deletions

View File

@@ -51,6 +51,7 @@ class AiView @JvmOverloads constructor(
private var roadV2NEventModel:RoadV2NEventViewModel ?= null
private var roadCrossRoamModel:RoadCrossRoamViewModel ?= null
private var automaticExplorationModel:AutomaticExplorationViewModel ?= null
private var ndeViewModel: NDEViewModel ?= null
private var aiAnimator: BigFrameAnimatorContainer?=null
private var aiAnimatorBg: BigFrameAnimatorContainer?=null
@@ -240,6 +241,10 @@ class AiView @JvmOverloads constructor(
ViewModelProvider(it)[AutomaticExplorationViewModel::class.java]
}
automaticExplorationModel?.init()
ndeViewModel = findViewTreeViewModelStoreOwner()?.let{
ViewModelProvider(it)[NDEViewModel::class.java]
}
ndeViewModel?.init()
}
private fun startListInfo(){

View File

@@ -0,0 +1,83 @@
package com.mogo.och.unmanned.passenger.ui.aiview
import androidx.lifecycle.ViewModel
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
import com.mogo.och.unmanned.passenger.ui.aiview.bean.AIMessage
import mogo.telematics.pad.MessagePad.TrackedObject
class NDEViewModel: ViewModel(), IMoGoAutopilotIdentifyListener {
companion object{
private const val TAG = "NDEViewModel"
}
private var lastMap2 = HashMap<Int, String>()
private var lastTime = 0L
fun init(){
CallerAutopilotIdentifyListenerManager.addListener(TAG, this)
}
override fun onAutopilotIdentifyDataUpdate(trafficData: List<TrackedObject>?){
super.onAutopilotIdentifyDataUpdate(trafficData)
handleCheLong(trafficData)
}
private fun handleCheLong(trafficData: List<TrackedObject>?) {
var hasCheLong = false
var isNewData = false
val roadMsgList = ArrayList<AIMessage.RoadMsg>()
val curMap = HashMap<Int, String>()
if (lastTime > 0 && System.currentTimeMillis() - lastTime > 60000) {
lastMap2.clear()// 清除上次车龙事件的缓存
}
var lastLocStr: String? = ""
trafficData?.forEach { obj ->
if (obj.type == 707) {// 当前方向所有车道
if (obj.polygonCount > 1) {// 当次数据有车龙事件
lastLocStr = lastMap2[obj.laneNum]
// 1. 上次无车龙但此次有车龙,认为是新车龙事件
// 2. 两次都有车龙,则判断车龙的长度是否相同
if (lastLocStr == null || lastLocStr == "0" || lastLocStr != "${obj.polygonList[0]}-${obj.polygonList[obj.polygonCount - 1]}") {
isNewData = true
}
hasCheLong = true
// key: 车道号value: 非0代表有车龙且首、尾两个点可计算车龙长度
curMap[obj.laneNum] =
"${obj.polygonList[0]}-${obj.polygonList[obj.polygonCount - 1]}"
} else {// 当次没有车龙
if (lastMap2[obj.laneNum] != null && lastMap2[obj.laneNum] != "0") {// 3. 上次有车龙,这次无车龙
isNewData = true
}
// key: 车道号value: 0代表无车龙
curMap[obj.laneNum] = "0"
}
// 保存所有车道信息
roadMsgList.add(
AIMessage.RoadMsg(
obj.arrowType,
laneNum = obj.laneNum,
isRecommend = obj.suggestedLanes,
isCheLong = obj.polygonCount > 1
)
)
}
}
if (isNewData) {
// 清除上次车道信息
lastMap2.clear()
if (hasCheLong) {
// 缓存当次车龙事件所有车道信息
lastMap2.putAll(curMap)
lastTime = System.currentTimeMillis()
val sortedList = roadMsgList.sortedWith(compareByDescending { it.laneNum })
val ndeEvent = AIMessage.NDEData(System.currentTimeMillis().toString(),"路口车龙","前方路口有车龙",sortedList)
AIMessageManager.post(ndeEvent)
}
}
}
}

View File

@@ -25,6 +25,7 @@ class AIMessageAdapter : ListAdapter<AIMessage, MessageViewHolder>(MessageDiffCa
AIMessage.TYPE_ROAD_CROSS -> RoadCrossRoamViewHolder(inflater.inflate(R.layout.item_ai_road_cross_roam,parent,false))
AIMessage.TYPE_AUTOMATIC_EXPLORATION -> AutomaticExplorationViewHolder(inflater.inflate(R.layout.item_ai_automatic_exploration,parent,false))
AIMessage.TYPE_EVALUATE -> EvaluateViewViewHolder(inflater.inflate(R.layout.taxi_p_evaluate,parent,false))
AIMessage.TYPE_NDE -> NDEViewHolder(inflater.inflate(R.layout.item_ai_nde_event,parent,false))
else -> throw IllegalArgumentException("Invalid view type")
}
}
@@ -42,6 +43,7 @@ class AIMessageAdapter : ListAdapter<AIMessage, MessageViewHolder>(MessageDiffCa
is AIMessage.RoadCrossRoam -> AIMessage.TYPE_ROAD_CROSS
is AIMessage.AutomaticExploration -> AIMessage.TYPE_AUTOMATIC_EXPLORATION
is AIMessage.EvaluateData -> AIMessage.TYPE_EVALUATE
is AIMessage.NDEData -> AIMessage.TYPE_NDE
else -> AIMessage.TYPE_EVENT
}
}

View File

@@ -23,6 +23,7 @@ import com.mogo.commons.voice.AIAssist
import com.mogo.eagle.core.data.notice.AutoExplorationEntity
import com.mogo.eagle.core.data.v2x.RoadV2NEventType
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager
import com.mogo.eagle.core.function.hmi.ui.msgbox.adapter.PassengerNDERoadAdapter
import com.mogo.eagle.core.function.hmi.ui.notice.exploration.AutomaticExplorationAdapter
import com.mogo.eagle.core.function.hmi.ui.v2n.RoadV2NEventLivePlayView
import com.mogo.eagle.core.function.view.MapRoamView
@@ -412,6 +413,27 @@ class EvaluateViewViewHolder(binding: View) : MessageViewHolder(binding) {
}
}
class NDEViewHolder(binding: View) : MessageViewHolder(binding){
private var tvNdeTitle: TextView = binding.findViewById(R.id.tvNdeTitle)
private var tvNdeContent: TextView = binding.findViewById(R.id.tvNdeContent)
private var rvNdeList: RecyclerView = binding.findViewById(R.id.rvNdeList)
override fun bind(item: AIMessage, onItemClickListener: OnItemClickListener?) {
if(item is AIMessage.NDEData){
tvNdeTitle.text = item.title
tvNdeContent.text = item.desc
val linearLayoutManager = LinearLayoutManager(itemView.context)
linearLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
val ndeRoadAdapter = AINDERoadAdapter(itemView.context)
rvNdeList.adapter = ndeRoadAdapter
rvNdeList.layoutManager = linearLayoutManager
ndeRoadAdapter.setData(item.roadList)
}
}
}
private class NoScrollLayoutManager(context: Context?) : LinearLayoutManager(context) {
override fun canScrollVertically(): Boolean {
return false

View File

@@ -0,0 +1,237 @@
package com.mogo.och.unmanned.passenger.ui.aiview.adapter
import android.content.Context
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.mogo.och.unmanned.passenger.ui.aiview.bean.AIMessage
import com.mogo.och.unmanned.taxi.passenger.R
class AINDERoadAdapter(private val context: Context): RecyclerView.Adapter<AINDERoadAdapter.AIRoadHolder>() {
private var roadList: List<AIMessage.RoadMsg>?= null
fun setData(list: List<AIMessage.RoadMsg>){
roadList = list
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AIRoadHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_ai_nde_road, parent, false)
return AIRoadHolder(view)
}
override fun onBindViewHolder(holder: AIRoadHolder, position: Int) {
roadList?.let{
val roadMsg = it[position]
if(it.size < 3){
//设置item宽度为最大宽度180dp
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 180f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
}else if(it.size == 3){
//设置item宽度为最大宽度180dp
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 120f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
}else if(it.size == 4){
//设置item宽度为最大宽度180dp
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
}else{
val params = ConstraintLayout.LayoutParams(
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90f,
context.resources.displayMetrics).toInt(),
ConstraintLayout.LayoutParams.WRAP_CONTENT)
holder.clRoadLayout.layoutParams = params
}
when(roadMsg.arrowType){
//直行
201->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward
))
}
//直行或左转
202->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_or_turn_left
))
}
//直行或右转
203->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_or_turn_right
))
}
//直行或掉头
204->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_or_reverse
))
}
//左转
205->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_left
))
}
//左转或掉头
206->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_left_or_reverse
))
}
//左弯或向左合流
207->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_or_merge_left
))
}
//右转
208->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_right
))
}
//右转或向右合流
209->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_or_merge_right
))
}
//左右转弯
210->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_left_or_right
))
}
//掉头
211->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_reverse
))
}
//禁止左转
212->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_turn_left
))
}
//禁止右转
213->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_turn_right
))
}
//禁止掉头
214->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_reverse
))
}
//直行或左转或右转
215->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_turn_left_right
))
}
//直行或掉头或左转
216->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_forward_turn_left_reverse
))
}
//右转或掉头
217->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_turn_right_or_reverse
))
}
//禁止右转或向右合流
218->{
holder.ivRoadType.setImageDrawable(
ContextCompat.getDrawable(
context,
R.drawable.icon_road_prohibit_turn_or_merge_right
))
}
}
//是否是推荐车道
if(roadMsg.isRecommend){
holder.tvRoadStatus.text = context.getString(R.string.nde_road_recommend)
holder.tvRoadStatus.setTextColor(context.getColor(R.color.msg_nde_road_recommend))
holder.clRoadLayout.background = ContextCompat.getDrawable(
context,
R.drawable.bg_nde_road_recommend
)
}
//是否有车龙,代表拥堵、行驶缓慢
if(roadMsg.isCheLong){
holder.tvRoadStatus.text = context.getString(R.string.nde_road_slow)
holder.tvRoadStatus.setTextColor(context.getColor(R.color.msg_nde_road_slow))
}
if(position == it.lastIndex){
holder.viewDivider.visibility = View.INVISIBLE
}
}
}
override fun getItemCount() = roadList?.size ?: 0
class AIRoadHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
var clRoadLayout: ConstraintLayout = itemView.findViewById(R.id.clRoadLayout)
var ivRoadType: ImageView = itemView.findViewById(R.id.ivRoadType)
var tvRoadStatus: TextView = itemView.findViewById(R.id.tvRoadStatus)
var viewDivider: View = itemView.findViewById(R.id.viewDivider)
}
}

View File

@@ -26,6 +26,7 @@ sealed class AIMessage(
const val TYPE_ROAD_CROSS = 8
const val TYPE_AUTOMATIC_EXPLORATION = 9
const val TYPE_EVALUATE = 10
const val TYPE_NDE = 11
}
data class Scan(
@@ -167,4 +168,18 @@ sealed class AIMessage(
var isFirst:Boolean = true
): AIMessage(id,title)
data class NDEData(
override val id: String,
override val title: String,
var desc: String,
var roadList: List<RoadMsg>
):AIMessage(id,title)
data class RoadMsg(
var arrowType: Int, // 车道类型如直行201(详情参考文件message_pad.proto)
var laneNum: Int,// 车道号
var isRecommend: Boolean,// 是否是推荐车道
var isCheLong: Boolean// 是否有车龙,代表拥堵、行驶缓慢
)
}

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<com.mogo.och.common.module.wigets.OCHBorderShadowLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/dp_799"
android:layout_height="@dimen/dp_314"
app:shadowRadius="@dimen/dp_20"
app:shadowColor="#26666666"
app:xOffset="0dp"
app:yOffset="0dp"
app:blurRadius="@dimen/dp_26">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="@dimen/dp_269">
<ImageView
android:id="@+id/ivNdeImage"
android:layout_width="@dimen/dp_96"
android:layout_height="@dimen/dp_96"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:src="@drawable/icon_nde"
android:contentDescription="@string/nde_icon"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginStart="@dimen/dp_20"
/>
<TextView
android:id="@+id/tvNdeTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@id/ivNdeImage"
android:layout_marginTop="@dimen/dp_18"
android:layout_marginStart="@dimen/dp_15"
android:textColor="#FF203555"
android:textSize="@dimen/dp_26"
/>
<TextView
android:id="@+id/tvNdeContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tvNdeTitle"
app:layout_constraintLeft_toLeftOf="@id/tvNdeTitle"
android:layout_marginTop="@dimen/dp_4"
android:textColor="#CC203555"
android:textSize="@dimen/sp_24"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvNdeList"
android:layout_width="wrap_content"
android:layout_height="@dimen/dp_140"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/ivNdeImage"
android:layout_marginTop="@dimen/dp_15"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.mogo.och.common.module.wigets.OCHBorderShadowLayout>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/clRoadLayout"
android:layout_width="@dimen/dp_90"
android:layout_height="@dimen/dp_120"
android:minWidth="@dimen/dp_90"
android:maxWidth="@dimen/dp_180"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<ImageView
android:id="@+id/ivRoadType"
android:layout_width="@dimen/dp_55"
android:layout_height="@dimen/dp_55"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/nde_road_icon"
/>
<TextView
android:id="@+id/tvRoadStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/ivRoadType"
android:textSize="@dimen/sp_22"
android:layout_marginTop="@dimen/dp_12"
/>
<View
android:id="@+id/viewDivider"
android:layout_width="@dimen/dp_4"
android:layout_height="@dimen/dp_0"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:background="@color/msg_nde_road_passenger_divider"
/>
</androidx.constraintlayout.widget.ConstraintLayout>