Merge branch 'dev_robotaxi-d_250620_8.1.0_new_ota' into dev_robotaxi-d_250804_8.2.0

# Conflicts:
#	core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt
This commit is contained in:
xuxinchao
2025-08-06 15:39:20 +08:00
19 changed files with 738 additions and 83 deletions

View File

@@ -1556,6 +1556,14 @@ class MoGoAutopilotControlProvider :
return AdasManager.getInstance().sendSsmFuncOtaStatusQuery(token)>-1
}
/**
* OTA2.0查询
* @param queryStr {"cmd":"PAD_QUERY_UPGRADE_STATUS","token":"123"} JSON
*/
override fun sendOtaPadMsgQuery(queryStr: String): Boolean {
return AdasManager.getInstance().sendOtaPadMsgQuery(queryStr) > -1
}
/**
* 人工接管时获取前方和后方摄像头数据
* 一次请求域控回调次两次摄像头数据 根据{@link MessagePad.CaptureImgOnTakeOver#getUuid()}进行区分是否是哪次请求

View File

@@ -622,6 +622,9 @@ class MoGoAdasListenerImpl : OnAdasListener {
timestamp: Long,
status: SsmInfo.PureStr?
) {
if(status != null){
CallerOTAManager.invokeOtaPureStr(token,timestamp,status)
}
}
/**

View File

@@ -28,4 +28,26 @@ object OTAUpgradeConfig {
//已经提示过升级成功的列表
@JvmField
var upgradeFinish: ArrayList<String> = ArrayList()
//OTA2.0 Token
@JvmField
var token: String = ""
//已经提示过升级的列表
var promptedUpgradeTwo: ArrayList<String> = ArrayList()
}

View File

@@ -46,6 +46,8 @@ object OTAUpgradeManager: IMoGoAutopilotStatusListener, IDataCenterBizListener,
private var responseTimeoutNum: Int = 0 //响应超时次数
private var shouldShowColdStartWindow: Boolean = false //是否需要展示冷启动页面
private var versionTwoTimeoutNum: Int = 0 //OTA2.0版本响应超时次数
private val handler =object : Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
@@ -68,6 +70,24 @@ object OTAUpgradeManager: IMoGoAutopilotStatusListener, IDataCenterBizListener,
//司机屏弹窗提示用车人执行车辆下电操作
CallerHmiManager.showOTAPowerOffFinishDialog()
shouldShowColdStartWindow = true
}else if(msg.what == 3){
//OTA2.0超时查询
if(versionTwoTimeoutNum<40){
versionTwoTimeoutNum++
//30秒没有收到OTA升级推送主动进行查询
Log.i(TAG,"30秒没有收到OTA升级推送主动进行查询")
//查询OTA升级
val query = JSONObject()
query.put("cmd","PAD_QUERY_UPGRADE_STATUS")
query.put("token",OTAUpgradeConfig.token)
Log.i("xuxinchao",query.toString())
CallerAutoPilotControlManager.sendOtaPadMsgQuery(query.toString())
this.sendEmptyMessageDelayed(3,30000)
}else{
Log.i(TAG,"20分钟没有收到OTA升级推送置为失败")
CallerHmiManager.showOTADownloadStatusDialog(false, emptyList())
CallerHmiManager.showOTAResultDialog(isShow = true, result = false)
}
}
}
}
@@ -394,6 +414,133 @@ object OTAUpgradeManager: IMoGoAutopilotStatusListener, IDataCenterBizListener,
}
/**
* OTA 2.0 新接口
* @param token PadSsmMsg唯一消息ID
* @param timestamp 消息发送时间 单位:毫秒
* @param status OTA 2.0 数据
*/
override fun onOtaPureStr(token: Long, timestamp: Long, status: SsmInfo.PureStr) {
super.onOtaPureStr(token, timestamp, status)
Log.i(TAG, "onOtaPureStr token=$token")
Log.i(TAG, "onOtaPureStr timestamp=$timestamp")
Log.i(TAG, "onOtaPureStr status=$status")
Log.i(TAG, "onOtaPureStr status.data=${status.data}")
val jsonObject = JSONObject(status.data)
val cmd = jsonObject.optString("cmd")
//无升级任务
if("ASK_PAD_NO_UPGRADE" == cmd){
ToastUtils.showShort("暂无OTA升级任务")
return
}
val otaToken = jsonObject.optString("token")
val otaStatus = jsonObject.optString("status")
val upgradeReason = jsonObject.optString("upgrade_reason")
val isDelay = jsonObject.optBoolean("is_delay")
val isCancel = jsonObject.optBoolean("is_cancel")
Log.i(TAG, "cmd=$cmd")
Log.i(TAG, "otaToken=$otaToken")
Log.i(TAG, "otaStatus=$otaStatus")
Log.i(TAG, "upgradeReason=$upgradeReason")
Log.i(TAG, "isDelay=$isDelay")
Log.i(TAG, "isCancel=$isCancel")
OTAUpgradeConfig.token = otaToken
val products = jsonObject.optString("products")
val productsArray = JSONArray(products)
val otaUpgradeList = ArrayList<OtaUpgradeInfo>()
if(productsArray.length() > 0){
for(index in 0 until productsArray.length()){
val productInfo = productsArray[index] as JSONObject
val productStatus = productInfo.optString("status")
val failReason = productInfo.optString("fail_reason")
val speed = productInfo.optDouble("speed")
val leftTime = productInfo.optInt("left_time")
val name = productInfo.optString("name")
val curSize = productInfo.optDouble("cur_size")
val totalSize = productInfo.optDouble("total_size")
Log.i(TAG, "productStatus=$productStatus")
Log.i(TAG, "failReason=$failReason")
Log.i(TAG, "speed=$speed")
Log.i(TAG, "leftTime=$leftTime")
Log.i(TAG, "name=$name")
Log.i(TAG, "curSize=$curSize")
Log.i(TAG, "totalSize=$totalSize")
val otaUpgradeInfo = OtaUpgradeInfo(otaToken, getProjectStatus(productStatus),failReason,upgradeReason,
0,0,1,name,true,isDelay,curSize,totalSize,leftTime)
otaUpgradeList.add(otaUpgradeInfo)
}
}
//请求升级
if(cmd == "ASK_PAD_UPGRADE" && otaStatus == "init"){
//冷启动已完成(包括成功/失败),且驾驶状态为非自驾状态,且当前无订单进行强提示,否则为弱提示
if(OTAUpgradeConfig.coldStartCompleted && !OTAUpgradeConfig.autopilotStatus
&& !OTAUpgradeConfig.inOrder){
//触发强提示升级
CallerHmiManager.showOTAUpgradeDialog(true,upgradeReason)
}else{
//触发弱提示升级
//冷启动未完成(进行中),或驾驶状态为自驾状态,或当前有订单,直接默认选择稍后升级,
// 并toast提示“收到车辆部署任务请在车辆空闲时发起升级”
val reason = if(OTAUpgradeConfig.autopilotStatus){
"处于自驾中"
}else if(OTAUpgradeConfig.inOrder){
"处于订单中"
}else{
"冷启动未完成"
}
val query = JSONObject()
query.put("cmd","ASK_PAD_UPGRADE_RES")
query.put("token",OTAUpgradeConfig.token)
query.put("allow_upgrade",false)
query.put("reason",reason)
Log.i("xuxinchao",query.toString())
CallerAutoPilotControlManager.sendOtaPadMsgQuery(query.toString())
ToastUtils.showLong("收到车辆部署任务,请在车辆空闲时发起升级")
}
return
}
//升级中
if(cmd == "PAD_UPGRADE_REPORT"){
CallerHmiManager.showOTADownloadStatusDialog(true,otaUpgradeList)
versionTwoTimeoutNum = 0
handler.removeMessages(3)
handler.sendEmptyMessageDelayed(3,30000)
}
//升级完成
if(otaStatus == "fail"){
CallerHmiManager.showOTADownloadStatusDialog(false,emptyList())
CallerHmiManager.showOTAResultDialog(isShow = true, result = false)
versionTwoTimeoutNum = 0
handler.removeMessages(3)
CallerOTAManager.invokeOtaDownloadStatus(false)
}
if(otaStatus == "success"){
//升级成功,自动执行优雅停服
CallerAutoPilotControlManager.sendIpcPowerOff()
//当优雅停服完成、需要车辆下电的时候比如当前是停服触发60s后车端告知鹰眼司机屏弹窗提示用车人执行车辆下电操作
handler.sendEmptyMessageDelayed(2,60000)
CallerOTAManager.invokeOtaDownloadStatus(false)
CallerHmiManager.showOTADownloadStatusDialog(false,emptyList())
CallerHmiManager.showOTAResultDialog(isShow = true, result = true)
versionTwoTimeoutNum = 0
handler.removeMessages(3)
}
}
private val pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+")
/**
@@ -438,5 +585,32 @@ object OTAUpgradeManager: IMoGoAutopilotStatusListener, IDataCenterBizListener,
return version
}
private fun getProjectStatus(status: String): Int{
return when(status){
"init"->{
0
}
"downloading"->{
1
}
"sync_slave"->{
2
}
"upgrading"->{
2
}
"success"->{
3
}
"fail"->{
4
}
else->{
0
}
}
}
}

View File

@@ -154,14 +154,24 @@ class CarInfoTabView @JvmOverloads constructor(
"${SceneConstant.M_HMI}${TAG}",
"ad version view clicked"
)
if(OTAUpgradeConfig.supportOTA){
//查询OTA状态
OTAUpgradeConfig.isQuery = true
OTAUpgradeConfig.promptedUpgrade.remove(OTAUpgradeConfig.otaToken)
CallerAutoPilotControlManager.sendSsmFuncOtaStatusQuery(OTAUpgradeConfig.otaToken)
}else{
ToastUtils.showLong("当前SSM节点未成功启动或当前版本不支持OTA升级")
}
// if(OTAUpgradeConfig.supportOTA){
// //查询OTA状态
// OTAUpgradeConfig.isQuery = true
// OTAUpgradeConfig.promptedUpgrade.remove(OTAUpgradeConfig.otaToken)
// CallerAutoPilotControlManager.sendSsmFuncOtaStatusQuery(OTAUpgradeConfig.otaToken)
// }else{
// ToastUtils.showLong("当前SSM节点未成功启动或当前版本不支持OTA升级")
// }
//查询OTA升级
val query = JSONObject()
query.put("cmd","PAD_QUERY_UPGRADE_STATUS")
query.put("token",OTAUpgradeConfig.token)
Log.i("xuxinchao",query.toString())
CallerAutoPilotControlManager.sendOtaPadMsgQuery(query.toString())
}
tvHDMapVersion.text = tvHDMapVersion.text.toString() + DebugConfig.getMapVersion()
//高精地图 检查更新

View File

@@ -8,25 +8,31 @@ import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.LinearLayoutManager
import com.mogo.commons.env.ProjectUtils
import com.mogo.commons.voice.AIAssist
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.deva.report.ReportEntity
import com.mogo.eagle.core.data.enums.DataSourceType
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
import com.mogo.eagle.core.data.msgbox.FMInfoMsg
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
import com.mogo.eagle.core.data.msgbox.MsgBoxCountDownBean
import com.mogo.eagle.core.data.msgbox.MsgBoxType
import com.mogo.eagle.core.data.msgbox.MsgCategory
import com.mogo.eagle.core.data.msgbox.MsgFmData
import com.mogo.eagle.core.data.takeover.TAKE_OVER_REQUEST
import com.mogo.eagle.core.function.api.autopilot.IMoGoNodeStateListener
import com.mogo.eagle.core.function.api.datacenter.IDataCenterBizListener
import com.mogo.eagle.core.function.api.datacenter.msgbox.IMsgBoxListener
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.call.autopilot.CallerNodeStateListenerManager
import com.mogo.eagle.core.function.call.datacenter.CallerDataCenterBizListener
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxEventListenerManager
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxListenerManager
import com.mogo.eagle.core.function.call.setting.CallerTakeOverManager
import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.function.hmi.ui.msgbox.adapter.DriverMsgBoxBubbleAdapter
import com.mogo.eagle.core.function.msgbox.MsgBoxConfig
@@ -149,41 +155,98 @@ class DriverMsgBoxBubbleView @JvmOverloads constructor(
} else if (category == MsgCategory.FM_INFO) {
CallerMsgBoxEventListenerManager.invokeUpdateTipListener(true)
if (FunctionBuildConfig.isTakeoverRemind) {
//属于停车警示(包括择机靠边停车、立即舒适停车、就地紧急停车)时,需要弹出消息气泡并伴有提示音
// //属于停车警示(包括择机靠边停车、立即舒适停车、就地紧急停车)时,需要弹出消息气泡并伴有提示音
// var curFaultLevel = 5 //默认级别遍历数组找出级别最高的level数越小级别越高
// fmInfoMsg.fmInfoList?.forEach { faultInfo ->
// if (faultInfo.faultActionCount > 0) {
// faultInfo.faultActionList.forEach { actionCode ->
// //获取建议操作级别,得到建议操作级别最高的操作
// if (MsgFmData.FaultAction.getFaultLevel(actionCode) < curFaultLevel) {
// curFaultLevel =
// MsgFmData.FaultAction.getFaultLevel(actionCode)
// }
// }
// }
// }
// //P0级消息弹出时需要判断驾驶状态非自动驾驶、非平行驾驶状态不弹出其余状态弹出
// if (curFaultLevel == 0) {
// //自动驾驶状态 0是不可用 1是ready 2是自动驾驶中 7:平行驾驶中
// if (CallerAutoPilotStatusListenerManager.getState() == 2
// || CallerAutoPilotStatusListenerManager.getState() == 7
// ) {
// // 6.6.0 ,因为 FSM 模块也会弹修改为只有没有 FSM 模块才弹
// // 6.6.0 20240823 考虑到 FSM 初期消息不一定全,先不加限制,产品先观察功能后再考虑是否过滤
// // if (hasNoneFSMNode()) {
// //语音提示
// try {
// SoundPoolUtils.getSoundPool()
// .playSoundWithRedId(context, R.raw.weak_net_tips)
// } catch (e: Exception) {
// e.printStackTrace()
// }
// //展示消息
// showData(msgBoxBean)
// //}
// }
// }
/**
* 8.2.0需求:定义三种不同提示强度的异常提示交互
* 不判断驾驶状态,发生相应故障时立即有相应的提醒
* 若同一时间触发多个多种级别异常,则按照最高级别的异常交互元素做提醒,低级别的异常不做特殊提醒
* 若同一时间触发多个同一级别异常,则同一时刻只提醒一次,不互相打断
* 除此以外不做其他提示频率限制
*
* 一级:安全停车
* FM_DP_EMERGENCY_STOP就地紧急停车、FM_DP_COMFORTABLE_STOP立刻舒适停车、FM_DP_PNC_CHOOSE_STOP择机靠边停车
* 交互图像、TTS、消息盒子
*
* 二级:降速行驶
* FM_DP_SPEED_LIMIT3三级降速、FM_DP_SPEED_LIMIT2二级降速、FM_DP_SPEED_LIMIT1一级降速
* 交互TTS、消息盒子
*
* 三级:无操作
* FM_DP_ONLY_WARNING警示、FM_DP_NO_ACTION报告
* ps以上异常提醒受司机屏工具箱-运营面板-美化模式-接管提醒开关控制,默认开启有全量提示,关闭后无语音/图像提示,只有消息盒子红点展示
*/
val fmInfoMsg = msgBoxBean.bean as FMInfoMsg
var curFaultLevel = 5 //默认级别遍历数组找出级别最高的level数越小级别越高
fmInfoMsg.fmInfoList?.forEach { faultInfo ->
if (faultInfo.faultActionCount > 0) {
faultInfo.faultActionList.forEach { actionCode ->
//获取建议操作级别,得到建议操作级别最高的操作
if (MsgFmData.FaultAction.getFaultLevel(actionCode) < curFaultLevel) {
curFaultLevel =
MsgFmData.FaultAction.getFaultLevel(actionCode)
}
}
}
}
//P0级消息弹出时需要判断驾驶状态非自动驾驶、非平行驾驶状态不弹出其余状态弹出
if (curFaultLevel == 0) {
//自动驾驶状态 0是不可用 1是ready 2是自动驾驶中 7:平行驾驶中
if (CallerAutoPilotStatusListenerManager.getState() == 2
|| CallerAutoPilotStatusListenerManager.getState() == 7
) {
// 6.6.0 ,因为 FSM 模块也会弹修改为只有没有 FSM 模块才弹
// 6.6.0 20240823 考虑到 FSM 初期消息不一定全,先不加限制,产品先观察功能后再考虑是否过滤
// if (hasNoneFSMNode()) {
//语音提示
try {
SoundPoolUtils.getSoundPool()
.playSoundWithRedId(context, R.raw.weak_net_tips)
} catch (e: Exception) {
e.printStackTrace()
}
//展示消息
when(MsgFmData.getFmPolicyLevel(fmInfoMsg.policyCode)){
//一级
MsgFmData.LEVEL_ONE->{
//接管图像提示、语音提示
CallerDevaToolsManager.takeOver(TAKE_OVER_REQUEST)
CallerHmiManager.warningV2X(
EventTypeEnumNew.TAKE_OVER_EVENT.poiType,
EventTypeEnumNew.TAKE_OVER_EVENT.content,
"识别车辆故障,建议立即接管安全停车,查看操作建议",
object : IMoGoWarningStatusListener {
override fun onShow() {
CallerTakeOverManager.invokeTakeOverEvent(true)
}
override fun onDismiss() {
CallerTakeOverManager.invokeTakeOverEvent(false)
}
},expireTime =3000L, isFromObu = false
)
//展示消息盒子消息
showData(msgBoxBean)
//}
}
//二级
MsgFmData.LEVEL_TWO->{
//语音提示
AIAssist.getInstance(context).speakTTSVoice("识别车辆异常,建议尽快安全停车,查看操作建议")
//展示消息盒子消息
showData(msgBoxBean)
}
//三级
MsgFmData.LEVEL_THREE->{
//在消息盒子图标上,可查看到红点标记,无其他元素特殊提醒;点进消息盒子可查看到详细信息
}
}
}
} else {
if (msgBoxBean.sourceType == DataSourceType.SUMMARY) {

View File

@@ -8,23 +8,29 @@ import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.LinearLayoutManager
import com.mogo.commons.env.ProjectUtils
import com.mogo.commons.voice.AIAssist
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.deva.report.ReportEntity
import com.mogo.eagle.core.data.enums.DataSourceType
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
import com.mogo.eagle.core.data.msgbox.FMInfoMsg
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
import com.mogo.eagle.core.data.msgbox.MsgBoxCountDownBean
import com.mogo.eagle.core.data.msgbox.MsgBoxType
import com.mogo.eagle.core.data.msgbox.MsgCategory
import com.mogo.eagle.core.data.msgbox.MsgFmData
import com.mogo.eagle.core.data.takeover.TAKE_OVER_REQUEST
import com.mogo.eagle.core.function.api.datacenter.IDataCenterBizListener
import com.mogo.eagle.core.function.api.datacenter.msgbox.IMsgBoxListener
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
import com.mogo.eagle.core.function.call.autopilot.CallerIpcConnectStateToastManager
import com.mogo.eagle.core.function.call.datacenter.CallerDataCenterBizListener
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxEventListenerManager
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxListenerManager
import com.mogo.eagle.core.function.call.setting.CallerTakeOverManager
import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.function.hmi.ui.msgbox.adapter.MsgBoxToastAdapter
import com.mogo.eagle.core.function.msgbox.MsgBoxConfig
@@ -141,41 +147,96 @@ class MsgBoxToastView @JvmOverloads constructor(
} else if (category == MsgCategory.FM_INFO) {
CallerMsgBoxEventListenerManager.invokeUpdateTipListener(true)
if (FunctionBuildConfig.isTakeoverRemind) {
//属于停车警示(包括择机靠边停车、立即舒适停车、就地紧急停车)时,需要弹出消息气泡并伴有提示音
// //属于停车警示(包括择机靠边停车、立即舒适停车、就地紧急停车)时,需要弹出消息气泡并伴有提示音
// var curFaultLevel = 5 //默认级别遍历数组找出级别最高的level数越小级别越高
// fmInfoMsg.fmInfoList?.forEach { faultInfo ->
// if (faultInfo.faultActionCount > 0) {
// faultInfo.faultActionList.forEach { actionCode ->
// //获取建议操作级别,得到建议操作级别最高的操作
// if (MsgFmData.FaultAction.getFaultLevel(actionCode) < curFaultLevel) {
// curFaultLevel =
// MsgFmData.FaultAction.getFaultLevel(actionCode)
// }
// }
// }
// }
// //P0级消息弹出时需要判断驾驶状态非自动驾驶、非平行驾驶状态不弹出其余状态弹出
// if (curFaultLevel == 0) {
// //自动驾驶状态 0是不可用 1是ready 2是自动驾驶中 7:平行驾驶中
// if (CallerAutoPilotStatusListenerManager.getState() == 2
// || CallerAutoPilotStatusListenerManager.getState() == 7
// ) {
// // 6.6.0 ,因为 FSM 模块也会弹修改为只有没有 FSM 模块才弹
// // 6.6.0 20240823 考虑到 FSM 初期消息不一定全,先不加限制,产品先观察功能后再考虑是否过滤
// // if (hasNoneFSMNode()) {
// //语音提示
// try {
// SoundPoolUtils.getSoundPool()
// .playSoundWithRedId(context, R.raw.weak_net_tips)
// } catch (e: Exception) {
// e.printStackTrace()
// }
// //展示消息
// showData(msgBoxBean)
// //}
// }
// }
/**
* 8.2.0需求:定义三种不同提示强度的异常提示交互
* 不判断驾驶状态,发生相应故障时立即有相应的提醒
* 若同一时间触发多个多种级别异常,则按照最高级别的异常交互元素做提醒,低级别的异常不做特殊提醒
* 若同一时间触发多个同一级别异常,则同一时刻只提醒一次,不互相打断
* 除此以外不做其他提示频率限制
*
* 一级:安全停车
* FM_DP_EMERGENCY_STOP就地紧急停车、FM_DP_COMFORTABLE_STOP立刻舒适停车、FM_DP_PNC_CHOOSE_STOP择机靠边停车
* 交互图像、TTS、消息盒子
*
* 二级:降速行驶
* FM_DP_SPEED_LIMIT3三级降速、FM_DP_SPEED_LIMIT2二级降速、FM_DP_SPEED_LIMIT1一级降速
* 交互TTS、消息盒子
*
* 三级:无操作
* FM_DP_ONLY_WARNING警示、FM_DP_NO_ACTION报告
* ps以上异常提醒受司机屏工具箱-运营面板-美化模式-接管提醒开关控制,默认开启有全量提示,关闭后无语音/图像提示,只有消息盒子红点展示
*/
val fmInfoMsg = msgBoxBean.bean as FMInfoMsg
var curFaultLevel = 5 //默认级别遍历数组找出级别最高的level数越小级别越高
fmInfoMsg.fmInfoList?.forEach { faultInfo ->
if (faultInfo.faultActionCount > 0) {
faultInfo.faultActionList.forEach { actionCode ->
//获取建议操作级别,得到建议操作级别最高的操作
if (MsgFmData.FaultAction.getFaultLevel(actionCode) < curFaultLevel) {
curFaultLevel =
MsgFmData.FaultAction.getFaultLevel(actionCode)
}
}
}
}
//P0级消息弹出时需要判断驾驶状态非自动驾驶、非平行驾驶状态不弹出其余状态弹出
if (curFaultLevel == 0) {
//自动驾驶状态 0是不可用 1是ready 2是自动驾驶中 7:平行驾驶中
if (CallerAutoPilotStatusListenerManager.getState() == 2
|| CallerAutoPilotStatusListenerManager.getState() == 7
) {
// 6.6.0 ,因为 FSM 模块也会弹修改为只有没有 FSM 模块才弹
// 6.6.0 20240823 考虑到 FSM 初期消息不一定全,先不加限制,产品先观察功能后再考虑是否过滤
// if (hasNoneFSMNode()) {
//语音提示
try {
SoundPoolUtils.getSoundPool()
.playSoundWithRedId(context, R.raw.weak_net_tips)
} catch (e: Exception) {
e.printStackTrace()
}
//展示消息
when(MsgFmData.getFmPolicyLevel(fmInfoMsg.policyCode)){
//一级
MsgFmData.LEVEL_ONE->{
//接管图像提示、语音提示
CallerDevaToolsManager.takeOver(TAKE_OVER_REQUEST)
CallerHmiManager.warningV2X(
EventTypeEnumNew.TAKE_OVER_EVENT.poiType,
EventTypeEnumNew.TAKE_OVER_EVENT.content,
"识别车辆故障,建议立即接管安全停车,查看操作建议",
object : IMoGoWarningStatusListener {
override fun onShow() {
CallerTakeOverManager.invokeTakeOverEvent(true)
}
override fun onDismiss() {
CallerTakeOverManager.invokeTakeOverEvent(false)
}
},expireTime =3000L, isFromObu = false
)
//展示消息盒子消息
showData(msgBoxBean)
//}
}
//二级
MsgFmData.LEVEL_TWO->{
//语音提示
AIAssist.getInstance(context).speakTTSVoice("识别车辆异常,建议尽快安全停车,查看操作建议")
//展示消息盒子消息
showData(msgBoxBean)
}
//三级
MsgFmData.LEVEL_THREE->{
//在消息盒子图标上,可查看到红点标记,无其他元素特殊提醒;点进消息盒子可查看到详细信息
}
}
}
} else {
if (msgBoxBean.sourceType == DataSourceType.SUMMARY) {

View File

@@ -0,0 +1,183 @@
package com.mogo.eagle.core.function.hmi.ui.setting;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
public class ScreenUtilsTest {
/**
* 获取当前屏幕截图,包含状态栏
*
* @param activity activity
* @return Bitmap
*/
public static Bitmap captureWithStatusBar(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap ret = Bitmap.createBitmap(bmp, 0, 0, width, height);
view.destroyDrawingCache();
return ret;
}
/**
* 获取当前屏幕截图,不包含状态栏
*
* @param activity activity
* @return Bitmap
*/
public static Bitmap captureWithoutStatusBar(Activity activity) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int statusBarHeight = getStatusBarHeight(activity);
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap ret = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);
view.destroyDrawingCache();
return ret;
}
/**
* 得到屏幕的高
*
* @param context
* @return
*/
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int height = wm.getDefaultDisplay().getHeight();
return height;
}
/**
* 得到屏幕的宽
*
* @param context
* @return
*/
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int width = wm.getDefaultDisplay().getWidth();
return width;
}
/**
* 获取状态栏高度
*
* @param context 上下文
* @return 状态栏高度
*/
public static int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources()
.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public static Bitmap mergeBitmaps(Bitmap background, Bitmap foreground) {
// 创建一个新的Bitmap大小为两个Bitmap的最大宽度和最大高度
int width = Math.max(background.getWidth(), foreground.getWidth());
int height = Math.max(background.getHeight(), foreground.getHeight());
Bitmap mergedBitmap = Bitmap.createBitmap(width, height, background.getConfig());
Canvas canvas = new Canvas(mergedBitmap);
// 绘制背景图
canvas.drawBitmap(background, 0, 0, null);
// 绘制前景图,可以调整位置
canvas.drawBitmap(foreground, 0, 0, null); // 根据需要调整位置
return mergedBitmap;
}
public static Bitmap overlayBitmaps(Bitmap bitmap1, Bitmap bitmap2, int xOffset, int yOffset) {
// 创建一个新的Bitmap其大小足以容纳两个重叠的bitmap
int width = Math.max(bitmap1.getWidth(), bitmap2.getWidth());
int height = bitmap1.getHeight() + bitmap2.getHeight(); // 假定重叠在垂直方向
Bitmap result = Bitmap.createBitmap(width, height, bitmap1.getConfig());
// 使用Canvas绘制bitmap1和bitmap2
Canvas canvas = new Canvas(result);
canvas.drawBitmap(bitmap1, 0, 0, null); // 首先绘制bitmap1
canvas.drawBitmap(bitmap2, xOffset, bitmap1.getHeight() + yOffset, null); // 然后绘制bitmap2根据需要调整xOffset和yOffset
return result;
}
/**
* 将2张图片合成
* @param downBitmap 底部图片
* @param upBitmap 置顶的图片
* @return
*/
public static Bitmap compoundBitmap(Bitmap downBitmap,Bitmap upBitmap)
{
Bitmap mBitmap = downBitmap.copy(Bitmap.Config.ARGB_8888, true);
//如果遇到黑色则显示downBitmap里面的颜色值如果不是则显示upBitmap里面的颜色值
//循环获得bitmap所有像素点
int mBitmapWidth = mBitmap.getWidth();
int mBitmapHeight = mBitmap.getHeight();
//首先保证downBitmap和 upBitmap是一致的高宽大小
Log.i("xuxinchao","mBitmapWidth="+mBitmapWidth);
Log.i("xuxinchao","mBitmapHeight="+mBitmapHeight);
Log.i("xuxinchao","upBitmap.getWidth()="+upBitmap.getWidth());
Log.i("xuxinchao","upBitmap.getHeight()="+upBitmap.getHeight());
// if(mBitmapWidth==upBitmap.getWidth() && mBitmapHeight==upBitmap.getHeight())
// {
// for (int i = 0; i < mBitmapHeight; i++) {
// for (int j = 0; j < mBitmapWidth; j++) {
// //获得Bitmap 图片中每一个点的color颜色值
// //将需要填充的颜色值如果不是
// //在这说明一下 如果color 是全透明 或者全黑 返回值为 0
// //getPixel()不带透明通道 getPixel32()才带透明部分 所以全透明是0x00000000
// //而不透明黑色是0xFF000000 如果不计算透明部分就都是0了
// int color = upBitmap.getPixel(j, i);
// Log.i("xuxinchao","color="+color);
// //将颜色值存在一个数组中 方便后面修改
// if (color != Color.BLACK) {
// mBitmap.setPixel(j, i, upBitmap.getPixel(j, i)); //将白色替换成透明色
// }
// }
// }
// }
for (int i = 0; i < mBitmapHeight; i++) {
for (int j = 0; j < mBitmapWidth; j++) {
//获得Bitmap 图片中每一个点的color颜色值
//将需要填充的颜色值如果不是
//在这说明一下 如果color 是全透明 或者全黑 返回值为 0
//getPixel()不带透明通道 getPixel32()才带透明部分 所以全透明是0x00000000
//而不透明黑色是0xFF000000 如果不计算透明部分就都是0了
int color = upBitmap.getPixel(j, i);
Log.i("xuxinchao","color="+color);
//将颜色值存在一个数组中 方便后面修改
if (color != Color.BLACK) {
mBitmap.setPixel(j, i, upBitmap.getPixel(j, i)); //将白色替换成透明色
}
}
}
// downBitmap.recycle();
// upBitmap.recycle();
return mBitmap;
}
}

View File

@@ -15,6 +15,7 @@ import com.zhjt.mogo_core_function_devatools.ota.OTAUpgradeConfig
import kotlinx.android.synthetic.main.dialog_ota_upgrade.tvUpgradeContent
import kotlinx.android.synthetic.main.dialog_ota_upgrade.tv_upgrade_later
import kotlinx.android.synthetic.main.dialog_ota_upgrade.tv_upgrade_now
import org.json.JSONObject
import system_master.SsmInfo
/**
@@ -40,22 +41,42 @@ class OTAUpgradeDialog(context: Context) :
private fun initView(){
//立即升级
tv_upgrade_now.setOnClickListener {
val result = CallerAutoPilotControlManager.sendSsmFuncOtaDownloadResponse(OTAUpgradeConfig.otaToken,SsmInfo.IfUpgrade.IMMEDIATELY)
if(result){
ToastUtils.showShort("立即升级命令发送成功")
}else{
ToastUtils.showShort("立即升级命令发送失败")
}
// val result = CallerAutoPilotControlManager.sendSsmFuncOtaDownloadResponse(OTAUpgradeConfig.otaToken,SsmInfo.IfUpgrade.IMMEDIATELY)
// if(result){
// ToastUtils.showShort("立即升级命令发送成功")
// }else{
// ToastUtils.showShort("立即升级命令发送失败")
// }
val query = JSONObject()
query.put("cmd","ASK_PAD_UPGRADE_RES")
query.put("token",OTAUpgradeConfig.token)
query.put("allow_upgrade",true)
query.put("reason","")
Log.i("xuxinchao",query.toString())
CallerAutoPilotControlManager.sendOtaPadMsgQuery(query.toString())
dismiss()
}
//稍后升级
tv_upgrade_later.setOnClickListener {
val delayResult = CallerAutoPilotControlManager.sendSsmFuncOtaDownloadResponse(OTAUpgradeConfig.otaToken,SsmInfo.IfUpgrade.DELAY)
if(delayResult){
ToastUtils.showShort("稍后升级命令发送成功")
}else{
ToastUtils.showShort("稍后升级命令发送失败")
}
// val delayResult = CallerAutoPilotControlManager.sendSsmFuncOtaDownloadResponse(OTAUpgradeConfig.otaToken,SsmInfo.IfUpgrade.DELAY)
// if(delayResult){
// ToastUtils.showShort("稍后升级命令发送成功")
// }else{
// ToastUtils.showShort("稍后升级命令发送失败")
// }
//不允许OTA升级
val query = JSONObject()
query.put("cmd","ASK_PAD_UPGRADE_RES")
query.put("token",OTAUpgradeConfig.token)
query.put("allow_upgrade",false)
query.put("reason","user click")
Log.i("xuxinchao",query.toString())
CallerAutoPilotControlManager.sendOtaPadMsgQuery(query.toString())
dismiss()
}
upgradeWaitingTimer = object: CountDownTimer(UPGRADE_WAITING_TIME,UPGRADE_WAITING_TIME){

View File

@@ -762,6 +762,22 @@
android:layout_height="1dp"
android:background="#F0F0F0" />
<ImageView
android:id="@+id/ivScreenTest"
android:layout_width="match_parent"
android:layout_height="600dp"
/>
<ImageView
android:id="@+id/ivScreenTestTwo"
android:layout_width="match_parent"
android:layout_height="600dp"/>
<ImageView
android:id="@+id/ivScreenTestThree"
android:layout_width="match_parent"
android:layout_height="600dp"/>
</LinearLayout>

View File

@@ -85,7 +85,7 @@ rootProject.gradle.taskGraph.whenReady { TaskExecutionGraph graph ->
def packageTask = (PackageApplication) t2
def outDir = packageTask.outputDirectory
def apkNames = packageTask.apkNames
if (apkNames != null && apkNames.size() > 0) {
if (false) {
apkNames.forEach { apkName ->
def apk = new File(outDir, apkName)
def lp = new File(rootProject.rootDir, "local.properties")

View File

@@ -163,6 +163,10 @@ class MsgFmData{
companion object{
const val LEVEL_ONE = 1 //降级策略:安全停车 交互:一级
const val LEVEL_TWO = 2 //降级策略:降速行驶 交互:二级
const val LEVEL_THREE = 3 //降级策略:无操作 交互:三级
@JvmStatic
fun getFmPolicyName(policyCode: String?): String{
return when(policyCode){
@@ -177,6 +181,30 @@ class MsgFmData{
else -> "暂无"
}
}
/**
* 获取异常分级
* 鹰眼8.2.0版本需求:定义三种不同提示强度的异常提示交互
* 一级交互TTS、图像、消息盒子
* 二级交互TTS、消息盒子
* 三级交互:消息盒子
*/
@JvmStatic
fun getFmPolicyLevel(policyCode: String?): Int{
return when(policyCode){
"FM_DP_NO_ACTION" -> LEVEL_THREE
"FM_DP_ONLY_WARNING" -> LEVEL_THREE
"FM_DP_SPEED_LIMIT1" -> LEVEL_TWO
"FM_DP_SPEED_LIMIT2" -> LEVEL_TWO
"FM_DP_SPEED_LIMIT3" -> LEVEL_TWO
"FM_DP_PNC_CHOOSE_STOP" -> LEVEL_ONE
"FM_DP_COMFORTABLE_STOP" -> LEVEL_ONE
"FM_DP_EMERGENCY_STOP" -> LEVEL_ONE
else -> LEVEL_THREE
}
}
}
}

View File

@@ -730,6 +730,12 @@ interface IMoGoAutopilotControlProvider : IMoGoFunctionServerProvider {
*/
fun sendSsmFuncOtaStatusQuery(token: String): Boolean
/**
* OTA2.0查询
* @param queryStr {"cmd":"PAD_QUERY_UPGRADE_STATUS","token":"123"} JSON
*/
fun sendOtaPadMsgQuery(queryStr: String): Boolean
/**
* 人工接管时获取前方和后方摄像头数据
* 一次请求域控回调次两次摄像头数据 根据{@link MessagePad.CaptureImgOnTakeOver#getUuid()}进行区分是否是哪次请求

View File

@@ -34,4 +34,12 @@ interface IOTAListener {
*/
fun onOtaDownloadStatus(status: Boolean){}
/**
* OTA 2.0 新接口
* @param token PadSsmMsg唯一消息ID
* @param timestamp 消息发送时间 单位:毫秒
* @param status OTA 2.0 数据
*/
fun onOtaPureStr(token: Long,timestamp: Long,status: SsmInfo.PureStr){}
}

View File

@@ -1095,6 +1095,14 @@ object CallerAutoPilotControlManager {
return providerApi?.sendSsmFuncOtaStatusQuery(token)?:false
}
/**
* OTA2.0查询
* @param queryStr {"cmd":"PAD_QUERY_UPGRADE_STATUS","token":"123"} JSON
*/
fun sendOtaPadMsgQuery(queryStr: String): Boolean{
return providerApi?.sendOtaPadMsgQuery(queryStr)?:false
}
/**
* 人工接管时获取前方和后方摄像头数据
* 一次请求域控回调次两次摄像头数据 根据{@link MessagePad.CaptureImgOnTakeOver#getUuid()}进行区分是否是哪次请求

View File

@@ -56,4 +56,17 @@ object CallerOTAManager: CallerBase<IOTAListener>() {
}
}
/**
* OTA 2.0 新接口
* @param token PadSsmMsg唯一消息ID
* @param timestamp 消息发送时间 单位:毫秒
* @param status OTA 2.0 数据
*/
fun invokeOtaPureStr(token: Long,timestamp: Long,status: SsmInfo.PureStr){
M_LISTENERS.forEach {
val listener = it.value
listener.onOtaPureStr(token, timestamp, status)
}
}
}

View File

@@ -3096,6 +3096,21 @@ public class AdasChannel implements IAdasNetCommApi, FpgaSocket.IWebSocketConnec
return sendSsmFuncMsg(true, system_master.SsmInfo.MessageType.OTA_STATUS_QUERY, builder.build().toByteString());
}
/**
* 查询OTA2.0状态
* @param queryStr 域控发送OTA升级请求中的 {"cmd":"PAD_QUERY_UPGRADE_STATUS","token":"123"}
* @return 消息是否添加到WS消息发送队列返回值为非0的正整数时表示下发消息的消息ID
* * >=0表示添加到WS发送消息队列
* * =0表示乘客屏模式添加到WS发送消息队列
* * -1L添加到WS发送消息队列失败
*/
@Override
public long sendOtaPadMsgQuery(@Nullable String queryStr) {
SsmInfo.PureStr.Builder builder = SsmInfo.PureStr.newBuilder();
builder.setData(TextUtils.isEmpty(queryStr) ? "" : queryStr);
return sendSsmFuncMsg(false,system_master.SsmInfo.MessageType.OTA_PAD_MSG,builder.build().toByteString());
}
/**
* 查询冷启动状态
*

View File

@@ -1848,6 +1848,16 @@ public class AdasManager implements IAdasNetCommApi {
return mChannel == null ? -1L : mChannel.sendSsmFuncOtaStatusQuery(token);
}
/**
* OTA2.0 请求命令下发
* @param queryStr {"cmd":"PAD_QUERY_UPGRADE_STATUS","token":"123"} JSON
* @return
*/
@Override
public long sendOtaPadMsgQuery(@Nullable String queryStr) {
return mChannel == null ? -1L : mChannel.sendOtaPadMsgQuery(queryStr);
}
/**
* 查询冷启动状态
*

View File

@@ -1348,6 +1348,12 @@ public interface IAdasNetCommApi {
*/
long sendSsmFuncOtaStatusQuery(@Nullable String token);
/**
* OTA2.0查询
* @param queryStr {"cmd":"PAD_QUERY_UPGRADE_STATUS","token":"123"} JSON
*/
long sendOtaPadMsgQuery(@Nullable String queryStr);
/**
* 查询冷启动状态
*