diff --git a/OCH/common/biz/src/main/res/layout/biz_login_view.xml b/OCH/common/biz/src/main/res/layout/biz_login_view.xml index e9a131814d..b77d3de518 100644 --- a/OCH/common/biz/src/main/res/layout/biz_login_view.xml +++ b/OCH/common/biz/src/main/res/layout/biz_login_view.xml @@ -180,4 +180,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content"/> + + \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/ColdStartView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/ColdStartView.kt index 21d71e9d08..e131dc9053 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/ColdStartView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/widget/ColdStartView.kt @@ -1,15 +1,37 @@ package com.mogo.eagle.core.function.hmi.ui.widget +import android.animation.ObjectAnimator +import android.animation.ValueAnimator import android.content.Context +import android.os.CountDownTimer import android.util.AttributeSet import android.view.LayoutInflater +import android.view.View +import android.view.animation.LinearInterpolator import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener +import com.mogo.eagle.core.function.api.autopilot.IMoGoColdStartStateListener import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager +import com.mogo.eagle.core.function.call.autopilot.CallerColdStartStateListenerManager import com.mogo.eagle.core.function.hmi.R +import com.mogo.eagle.core.utilcode.util.ResourceUtils +import com.mogo.eagle.core.utilcode.util.ThreadUtils +import com.mogo.eagle.core.utilcode.util.UiThreadHandler import com.zhjt.mogo.adas.data.AdasConstants +import kotlinx.android.synthetic.main.view_cold_start.view.ivColdStartStatus +import kotlinx.android.synthetic.main.view_cold_start.view.ivIpcConnectStatus +import kotlinx.android.synthetic.main.view_cold_start.view.ivSsmConnectStatus +import kotlinx.android.synthetic.main.view_cold_start.view.tvColdStartContent +import kotlinx.android.synthetic.main.view_cold_start.view.tvColdStartNodeState +import kotlinx.android.synthetic.main.view_cold_start.view.tvIpcConnectContent +import kotlinx.android.synthetic.main.view_cold_start.view.tvSsmConnectContent +import kotlinx.android.synthetic.main.view_cold_start.view.tvSystemStartupTitle +import kotlinx.android.synthetic.main.view_cold_start.view.viewColdStartDivider +import kotlinx.android.synthetic.main.view_cold_start.view.viewSsmConnectDivider import system_master.SsmInfo import system_master.SystemStatusInfo +import java.lang.StringBuilder /** * 冷启动呈现二期 @@ -19,41 +41,185 @@ class ColdStartView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr), IMoGoAutopilotStatusListener { +) : ConstraintLayout(context, attrs, defStyleAttr), IMoGoAutopilotStatusListener, + IMoGoColdStartStateListener { companion object { const val TAG = "ColdStartView" + const val LOAD_SSM_WAITING_TIME = 60000L //SSM加载超时等待时间 + const val COLD_START_WAITING_TIME = 300000L //冷启动超时等待时间 } + private var ipcConnectStatus = false //连接域控状态,默认是未连接 + private var ssmConnectStatus = false //SSM连接状态,默认是未连接 + private var coldStartStatus = false //冷启动状态,默认是未冷启动成功 + + private var ssmRotationAnim: ObjectAnimator?= null //SSM连接状态动画 + private var connectSSMTimer: CountDownTimer?= null //连接SSM等待倒计时 + + private var coldStartRotationAnim: ObjectAnimator?= null //冷启动连接状态动画 + private var connectColdStartTimer: CountDownTimer?= null //连接冷启动等待倒计时 + + private val nodeStatusSb = StringBuilder() //冷启动关键节点启动详情 + + private var coldStartResultListener: ColdStartResultListener ?= null + init { LayoutInflater.from(context).inflate(R.layout.view_cold_start, this, true) initView() } private fun initView(){ + var num = 1 + tvSystemStartupTitle.setOnClickListener { + if(num == 1){ + val state = SsmInfo.ModeState.MODE_RUN_READY + val info = SsmInfo.SsmStatusInf + .newBuilder() + .setModeState(state) + .setAutoPilotReady(false) + .setRemotePilotReady(false) + .build() + + CallerAutoPilotStatusListenerManager.invokeSystemStatus(info) + num = 2 + } + else if(num == 2){ + val nodeOne = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("毫米波融合") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_FINISH) + .setEventCode("") + .build() + + val nodeTwo = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("后融合") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_STARTING) + .setEventCode("") + .build() + + val nodeThree = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("控制节点") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_STARTING) + .setEventCode("") + .build() + + val nodeFour = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("地图引擎") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_STARTING) + .setEventCode("") + .build() + + val list = ArrayList() + list.add(nodeOne) + list.add(nodeTwo) + list.add(nodeThree) + list.add(nodeFour) + + val coldStartState = SsmInfo.ColdStartState + .newBuilder() + .setEventStatus(SsmInfo.CSState.COLD_START_STARTING) + .setProcessStatus(SsmInfo.CSState.COLD_START_STARTING) + .addAllNode(list) + .build() + + CallerColdStartStateListenerManager.invokeColdStartState( + 123, + System.currentTimeMillis(), + false, + coldStartState + ) + num = 3 + }else if(num == 3){ + val nodeOne = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("毫米波融合") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_FINISH) + .setEventCode("") + .build() + + val nodeTwo = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("后融合") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_FINISH) + .setEventCode("") + .build() + + val nodeThree = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("控制节点") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_FINISH) + .setEventCode("") + .build() + + val nodeFour = SsmInfo.ColdStartNode + .newBuilder() + .setNodeName("地图引擎") + .setDesc("") + .setStatus(SsmInfo.NodeStatus.NODE_FINISH) + .setEventCode("") + .build() + + val list = ArrayList() + list.add(nodeOne) + list.add(nodeTwo) + list.add(nodeThree) + list.add(nodeFour) + + val coldStartState = SsmInfo.ColdStartState + .newBuilder() + .setEventStatus(SsmInfo.CSState.COLD_START_READY) + .setProcessStatus(SsmInfo.CSState.COLD_START_READY) + .addAllNode(list) + .build() + + CallerColdStartStateListenerManager.invokeColdStartState( + 123, + System.currentTimeMillis(), + false, + coldStartState + ) + } + } } override fun onAttachedToWindow() { super.onAttachedToWindow() CallerAutoPilotStatusListenerManager.addListener(TAG, this) + CallerColdStartStateListenerManager.addListener(TAG,this) } override fun onDetachedFromWindow() { super.onDetachedFromWindow() CallerAutoPilotStatusListenerManager.removeListener(TAG) + CallerColdStartStateListenerManager.removeListener(TAG) } override fun onAutopilotIpcConnectStatusChanged( status: AdasConstants.IpcConnectionStatus, reason: String? ){ - if(status == AdasConstants.IpcConnectionStatus.CONNECTED){ - //域控连接成功 - - }else{ - //域控连接失败 - + ThreadUtils.runOnUiThread { + ipcConnectStatus = if(status == AdasConstants.IpcConnectionStatus.CONNECTED){ + //域控连接成功 + showIPCConnectSuccessView() + true + }else{ + //域控连接失败 + showIPCConnectFailView(reason) + false + } } } @@ -63,7 +229,10 @@ class ColdStartView @JvmOverloads constructor( * HQ、M1 MAP350开始弃用,其他车型MAP360开始弃用 */ override fun onAutopilotStatusRespByQuery(status: SystemStatusInfo.StatusInfo) { - + ThreadUtils.runOnUiThread { + //SSM连接成功 + connectSSMSuccess() + } } @@ -74,7 +243,289 @@ class ColdStartView @JvmOverloads constructor( * @param statusInf 数据 */ override fun onSystemStatus(statusInf: SsmInfo.SsmStatusInf) { + ThreadUtils.runOnUiThread { + //SSM连接成功 + connectSSMSuccess() + } + } + + /** + * 冷启动状态变更上报以及查询状态 + * + * @param token 唯一消息ID + * @param timestamp 消息发送时间 单位:毫秒 + * @param isQuery 是否是查询 ture:查询相应的结果 false:表示状态变动域控主动推送 + * @param coldStartState 数据 null表示 PadSsmMsg中的消息体为null + */ + override fun onColdStartState( + token: Long, + timestamp: Long, + isQuery: Boolean, + coldStartState: SsmInfo.ColdStartState? + ) { + coldStartState?.let { + ThreadUtils.runOnUiThread { + if(it.eventStatus == SsmInfo.CSState.COLD_START_READY){ + //冷启动就绪 + showColdStartSuccessView() + } + tvColdStartContent.text = getColdStartEventStatus(it.eventStatus) + nodeStatusSb.clear() + it.nodeList.forEach {node-> + nodeStatusSb.append("【") + nodeStatusSb.append(node.nodeName) + nodeStatusSb.append(" ") + nodeStatusSb.append(getColdStartNodeStatus(node.status)) + nodeStatusSb.append("】\n") + } + tvColdStartNodeState.text = nodeStatusSb.toString() + } + } + } + + /** + * 冷启动状态 + */ + private fun getColdStartEventStatus(state: SsmInfo.CSState): String{ + return when(state){ + // 未开始 + SsmInfo.CSState.COLD_START_DEFAULT->{ + "启动中…" + } + // 启动中 + SsmInfo.CSState.COLD_START_STARTING->{ + "启动中…" + } + // 就绪 + SsmInfo.CSState.COLD_START_READY->{ + "系统启动成功,即将进入主页" + } + // 有异常未就绪 + SsmInfo.CSState.COLD_START_UNREADY->{ + "系统启动异常,建议重启车辆并上报问题" + } + // 超时 + SsmInfo.CSState.COLD_START_TIMEOUT->{ + "系统启动异常,建议重启车辆并上报问题" + } + } + } + + /** + * 获取节点启动状态 + */ + private fun getColdStartNodeStatus(nodeStatus: SsmInfo.NodeStatus): String{ + return when(nodeStatus){ + // 启动中 + SsmInfo.NodeStatus.NODE_STARTING->{ + "启动中" + } + // 启动成功 + SsmInfo.NodeStatus.NODE_FINISH->{ + "启动成功" + } + // 启动失败 + SsmInfo.NodeStatus.NODE_FAILED->{ + "启动失败" + } + // 启动超时 + SsmInfo.NodeStatus.NODE_TIMEOUT->{ + "启动超时" + } + + } + } + + + /** + * 展示域控连接成功视图 + */ + private fun showIPCConnectSuccessView(){ + ivIpcConnectStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_success)) + tvIpcConnectContent.text = resources.getString(R.string.ipc_connect_success) + //开启连接SSM倒计时 + connectSSMProcess() + //域控连接成功后开始展示SSM连接状态 + viewSsmConnectDivider.visibility = View.VISIBLE + ivSsmConnectStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_process)) + //旋转动画 + ssmRotationAnim = ObjectAnimator.ofFloat(ivSsmConnectStatus, "rotation", 0f, 360f) + ssmRotationAnim?.repeatCount = ValueAnimator.INFINITE + ssmRotationAnim?.repeatMode = ValueAnimator.RESTART + ssmRotationAnim?.duration = 1500 + ssmRotationAnim?.interpolator = LinearInterpolator() + ssmRotationAnim?.start() + //设置SSM连接文案为连接中 + tvSsmConnectContent.text = resources.getString(R.string.ssm_connect_loading) + tvSsmConnectContent.setTextColor(ContextCompat.getColor(context, android.R.color.white)) + //隐藏冷启动相关视图 + viewColdStartDivider.visibility = View.GONE + ivColdStartStatus.visibility = View.GONE + tvColdStartContent.visibility = View.GONE + } + + /** + * 展示域控连接失败视图 + */ + private fun showIPCConnectFailView(reason: String?){ + ivIpcConnectStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_fail)) + reason?.let { + tvIpcConnectContent.text = it + } + //隐藏SSM相关视图 + viewSsmConnectDivider.visibility = View.GONE + ivSsmConnectStatus.visibility = View.GONE + tvSsmConnectContent.visibility = View.GONE + //隐藏冷启动相关视图 + viewColdStartDivider.visibility = View.GONE + ivColdStartStatus.visibility = View.GONE + tvColdStartContent.visibility = View.GONE } + /** + * SSM连接成功 + */ + private fun connectSSMSuccess(){ + if(!ssmConnectStatus){ + showSSMConnectSuccessView() + //取消连接SSM超时等待倒计时 + connectSSMTimer?.cancel() + //开始启动冷启动等待倒计时 + coldStartProcess() + } + ssmConnectStatus = true + coldStartStatus = false + } + + /** + * 展示SSM连接成功视图 + */ + private fun showSSMConnectSuccessView(){ + //取消旋转动画 + ssmRotationAnim?.cancel() + //取消连接SSM超时等待倒计时 + connectSSMTimer?.cancel() + //展示SSM连接成功视图 + ivSsmConnectStatus.rotation = 0f + ivSsmConnectStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_success)) + tvSsmConnectContent.text = resources.getString(R.string.ssm_connect_success) + tvSsmConnectContent.setTextColor(ContextCompat.getColor(context, R.color.white)) + //展示冷启动连接过程视图 + viewColdStartDivider.visibility = View.VISIBLE + ivColdStartStatus.visibility = View.VISIBLE + tvColdStartContent.visibility = View.VISIBLE + tvColdStartContent.text = "启动中…" + ivColdStartStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_process)) + //开启冷启动连接状态动画 + coldStartRotationAnim = ObjectAnimator.ofFloat(ivColdStartStatus, "rotation", 0f, 360f) + coldStartRotationAnim?.repeatCount = ValueAnimator.INFINITE + coldStartRotationAnim?.repeatMode = ValueAnimator.RESTART + coldStartRotationAnim?.duration = 1500 + coldStartRotationAnim?.interpolator = LinearInterpolator() + coldStartRotationAnim?.start() + } + + /** + * 展示SSM连接失败视图 + */ + private fun showSSMConnectFailView(){ + //取消旋转动画 + ssmRotationAnim?.cancel() + ivSsmConnectStatus.rotation = 0f + ivSsmConnectStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_fail)) + tvSsmConnectContent.text = resources.getString(R.string.ssm_connect_fail) + tvSsmConnectContent.setTextColor(ContextCompat.getColor(context, R.color.cold_start_fail)) + } + + /** + * 连接SSM过程 + */ + private fun connectSSMProcess(){ + ThreadUtils.runOnUiThread { + connectSSMTimer = object: CountDownTimer(LOAD_SSM_WAITING_TIME,LOAD_SSM_WAITING_TIME){ + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + //将SSM连接状态置为false + ssmConnectStatus = false + coldStartStatus = false + //取消连接SSM超时等待倒计时 + connectSSMTimer?.cancel() + //展示连接SSM失败视图 + showSSMConnectFailView() + } + } + connectSSMTimer?.start() + } + } + + /** + * 冷启动过程 + */ + private fun coldStartProcess(){ + ThreadUtils.runOnUiThread { + connectColdStartTimer = object: CountDownTimer(COLD_START_WAITING_TIME,COLD_START_WAITING_TIME){ + override fun onTick(millisUntilFinished: Long) { + } + + override fun onFinish() { + //将冷启动状态置为false + coldStartStatus = false + //展示冷启动失败视图 + showColdStartFailView() + } + } + connectColdStartTimer?.start() + } + } + + /** + * 冷启动失败视图 + */ + private fun showColdStartFailView(){ + coldStartRotationAnim?.cancel() + ivColdStartStatus.rotation = 0f + ivColdStartStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_fail)) + tvColdStartContent.text = resources.getString(R.string.cold_start_fail_content) + coldStartResultListener?.coldStartFail() + } + + /** + * 冷启动成功视图 + */ + private fun showColdStartSuccessView(){ + tvSystemStartupTitle.text = resources.getString(R.string.cold_start_success_title) + coldStartRotationAnim?.cancel() + ivColdStartStatus.rotation = 0f + ivColdStartStatus.setImageDrawable(ResourceUtils.getDrawable(R.drawable.icon_cold_start_success)) + tvColdStartContent.text = resources.getString(R.string.cold_start_success_content) + connectColdStartTimer?.cancel() + hideColdStartView() + } + + /** + * 隐藏冷启动视图 + */ + private fun hideColdStartView(){ + UiThreadHandler.postDelayed({ + this@ColdStartView.visibility = View.GONE + coldStartResultListener?.coldStartSuccess() + }, 2000) + } + + /** + * 冷启动接管监听接口 + */ + interface ColdStartResultListener{ + fun coldStartSuccess() + fun coldStartFail() + } + + fun setColdStartResultListener(listener: ColdStartResultListener){ + coldStartResultListener = listener + } + } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_cold_start.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_cold_start.xml index 1da924a954..8c3e142080 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_cold_start.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_cold_start.xml @@ -2,7 +2,9 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:background="#7F000000" + > + + + + + + - \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/values/color.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/values/color.xml index f286b4bedd..99dcf87443 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/values/color.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/values/color.xml @@ -92,4 +92,6 @@ #131415 + #FFCD3D + \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml index a219598048..ff00a195de 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/values/strings.xml @@ -215,5 +215,14 @@ 域控连接状态图标 SSM连接状态图标 + 冷启动状态图标 + 已连接域控 + 系统启动中… + 系统启动成功 + 正在连接SSM… + 已连接SSM + SSM连接异常,建议重启车辆并上报问题 + 系统启动成功,即将进入主页 + 系统启动异常,建议重启车辆并上报问题