diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt index 62fe6d6e0d..335fd64ee9 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/MoGoHmiFragment.kt @@ -22,13 +22,16 @@ import com.mogo.eagle.core.data.enums.SidePattern import com.mogo.eagle.core.data.enums.WarningDirectionEnum import com.mogo.eagle.core.data.notice.NoticeNormalData import com.mogo.eagle.core.data.notice.NoticeTrafficStylePushData +import com.mogo.eagle.core.data.report.ReportEntity import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotRecordListener +import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener import com.mogo.eagle.core.function.api.hmi.IMoGoHmiViewProxy import com.mogo.eagle.core.function.api.hmi.view.IViewLimitingVelocity import com.mogo.eagle.core.function.api.hmi.view.IViewNotification import com.mogo.eagle.core.function.api.hmi.view.IViewTrafficLight import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWaringProvider 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.CallerAutopilotRecordListenerManager import com.mogo.eagle.core.function.call.check.CallerCheckManager import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager @@ -44,16 +47,19 @@ import com.mogo.eagle.core.function.hmi.ui.camera.CameraListView import com.mogo.eagle.core.function.hmi.ui.notice.NoticeBannerView import com.mogo.eagle.core.function.hmi.ui.notice.NoticeNormalBannerView import com.mogo.eagle.core.function.hmi.ui.setting.DebugSettingView +import com.mogo.eagle.core.function.hmi.ui.setting.ReportListFloatWindow import com.mogo.eagle.core.function.hmi.ui.tools.AutoPilotAndCheckView import com.mogo.eagle.core.function.hmi.ui.widget.V2XNotificationView 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.Companion.M_HMI import com.mogo.eagle.core.utilcode.util.ThreadUtils +import com.mogo.eagle.core.utilcode.util.TimeUtils import com.mogo.eagle.core.utilcode.util.ToastUtils import com.mogo.module.common.enums.EventTypeEnum import kotlinx.android.synthetic.main.fragment_hmi.* import kotlinx.coroutines.* +import mogo_msg.MogoReportMsg import record_cache.RecordPanelOuterClass import java.util.* @@ -68,7 +74,8 @@ class MoGoHmiFragment : MvpFragment(), IMoGoWaringProvider, IMoGoHmiViewProxy, MoGoHmiContract.View, - IMoGoAutopilotRecordListener { + IMoGoAutopilotRecordListener, + IMoGoAutopilotStatusListener { private val TAG = "MoGoHmiFragment" // DebugSettingView @@ -101,6 +108,10 @@ class MoGoHmiFragment : MvpFragment(), // V2X预警弹窗 View 代理 private var mViewNotification: IViewNotification? = null + //工控机节点上报列表 + private var reportList = arrayListOf() + //工控机上报列表悬浮窗 + private var reportListFloatWindow: ReportListFloatWindow?=null override fun vipIdentification(visible: Boolean) { ThreadUtils.runOnUiThread { @@ -143,6 +154,7 @@ class MoGoHmiFragment : MvpFragment(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) CallerAutopilotRecordListenerManager.addListener(TAG, this) + CallerAutoPilotStatusListenerManager.addListener(TAG, this) /*// TODO 这里后面需要改成独立进程通讯后台获取YUV view.postDelayed({ @@ -174,6 +186,7 @@ class MoGoHmiFragment : MvpFragment(), override fun onDestroyView() { super.onDestroyView() CallerAutopilotRecordListenerManager.removeListener(TAG) + CallerAutoPilotStatusListenerManager.removeListener(TAG) } @@ -386,7 +399,7 @@ class MoGoHmiFragment : MvpFragment(), */ override fun toggleDebugView() { CallerLogger.d("$M_HMI$TAG", "长按显示状态工具栏") - context?.let { + activity?.let { if (mDebugSettingViewFloat != null) { WarningFloat.dismiss(mDebugSettingViewFloat!!.config.floatTag, false) mDebugSettingViewFloat = null @@ -394,6 +407,18 @@ class MoGoHmiFragment : MvpFragment(), } else { if (mDebugSettingView == null) { mDebugSettingView = DebugSettingView(it) + mDebugSettingView?.setClickListener(object: DebugSettingView.ClickListener{ + override fun showReportListWindow(show: Boolean) { + if(show){ + //打开工控机上报列表 + reportListFloatWindow = ReportListFloatWindow(it) + reportListFloatWindow?.showFloatWindow() + }else{ + //关闭工控机上报列表 + reportListFloatWindow?.hideFloatWindow() + } + } + }) } var side = SidePattern.RIGHT var gravity = Gravity.RIGHT @@ -979,6 +1004,23 @@ class MoGoHmiFragment : MvpFragment(), } + /** + * 工控机监控节点上报 + */ + override fun onAutopilotGuardian(guardianInfo: MogoReportMsg.MogoReportMessage?) { + ThreadUtils.runOnUiThread{ + guardianInfo?.let { + if(reportList.size>20){ + reportList.removeLast() + } + reportList.add(0, + ReportEntity(TimeUtils.millis2String(System.currentTimeMillis()), + it.src,it.level,it.msg,it.code,it.resultList,it.actionsList)) + reportListFloatWindow?.refreshData(reportList) + } + } + } + override fun onDestroy() { super.onDestroy() CallerLogger.d("$M_HMI$TAG", "onDestroy") diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt index 9207392d7d..db6786db65 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/DebugSettingView.kt @@ -141,6 +141,8 @@ class DebugSettingView @JvmOverloads constructor( private var lastVisualAngleMode: VisualAngleMode? = null + private var clickListener: ClickListener? = null + init { LayoutInflater.from(context).inflate(R.layout.view_debug_setting, this, true) initView() @@ -604,6 +606,11 @@ class DebugSettingView @JvmOverloads constructor( //初始化ADAS日志开关状态 tbADASLog.isChecked = CallerAutoPilotManager.isEnableLog() + //查看上报历史列表 + tbReportMore.setOnCheckedChangeListener { _, isChecked -> + clickListener?.showReportListWindow(isChecked) + } + } /** @@ -1746,4 +1753,12 @@ class DebugSettingView @JvmOverloads constructor( } } + fun setClickListener(clickListener: ClickListener) { + this.clickListener = clickListener + } + + interface ClickListener{ + fun showReportListWindow(show: Boolean) + } + } \ 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/setting/ReportListAdapter.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/ReportListAdapter.kt new file mode 100644 index 0000000000..c10403b348 --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/ReportListAdapter.kt @@ -0,0 +1,90 @@ +package com.mogo.eagle.core.function.hmi.ui.setting + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.mogo.eagle.core.data.report.ReportEntity +import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotManager +import com.mogo.eagle.core.function.hmi.R + +/** + * @author XuXinChao + * @description 工控机上报列表适配器 + * @since: 2022/4/13 + */ +class ReportListAdapter(context: Context) : + RecyclerView.Adapter() { + + private var context: Context? = context + private var data:List? = null + + public fun setDada( data: List?){ + this.data = data + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReportListHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_report_detail, parent, false) + return ReportListHolder(view) + } + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder: ReportListHolder, position: Int) { + data?.let { it -> + val reportEntity = it[position] + reportEntity.let { + holder.tvReportTime.text = it.time + holder.tvReportSrc.text = "src:${it.src}" + holder.tvReportLevel.text = "level:${it.level}" + holder.tvReportMsg.text = "msg:${it.msg}" + holder.tvReportCode.text = "code:${it.code}" + var resultStr = "result:" + for (result in it.resultList) { + resultStr = "$resultStr$result${CallerAutoPilotManager.getReportResultDesc(result)} " + } + holder.tvReportResult.text = resultStr + var actionStr = "action:" + for (action in it.actionsList) { + actionStr = "$actionStr$action${CallerAutoPilotManager.getReportActionDesc(action)} " + } + holder.tvReportActions.text = actionStr + + if ("error" == it.level) { + //字体为红色,吐司提示 + holder.tvReportSrc.setTextColor(Color.RED) + holder.tvReportLevel.setTextColor(Color.RED) + holder.tvReportMsg.setTextColor(Color.RED) + holder.tvReportCode.setTextColor(Color.RED) + holder.tvReportResult.setTextColor(Color.RED) + holder.tvReportActions.setTextColor(Color.RED) + } else { + holder.tvReportSrc.setTextColor(Color.WHITE) + holder.tvReportLevel.setTextColor(Color.WHITE) + holder.tvReportMsg.setTextColor(Color.WHITE) + holder.tvReportCode.setTextColor(Color.WHITE) + holder.tvReportResult.setTextColor(Color.WHITE) + holder.tvReportActions.setTextColor(Color.WHITE) + } + } + } + + } + + override fun getItemCount() = data?.size ?: 0 + + class ReportListHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ + var tvReportTime: TextView = itemView.findViewById(R.id.tvReportTime) + var tvReportSrc: TextView = itemView.findViewById(R.id.tvReportSrc) + var tvReportLevel: TextView = itemView.findViewById(R.id.tvReportLevel) + var tvReportMsg: TextView = itemView.findViewById(R.id.tvReportMsg) + var tvReportCode: TextView = itemView.findViewById(R.id.tvReportCode) + var tvReportResult: TextView = itemView.findViewById(R.id.tvReportResult) + var tvReportActions: TextView = itemView.findViewById(R.id.tvReportActions) + } + +} \ 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/setting/ReportListFloatWindow.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/ReportListFloatWindow.kt new file mode 100644 index 0000000000..f14472f33c --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/setting/ReportListFloatWindow.kt @@ -0,0 +1,125 @@ +package com.mogo.eagle.core.function.hmi.ui.setting + +import android.app.Activity +import android.graphics.PixelFormat +import android.util.DisplayMetrics +import android.view.* +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.mogo.eagle.core.data.report.ReportEntity +import com.mogo.eagle.core.function.hmi.R +import java.lang.reflect.Field + +/** + * @author XuXinChao + * @description 工控机上报列表面板 + * @since: 2022/4/13 + */ +class ReportListFloatWindow constructor(activity: Activity) : View.OnTouchListener{ + + private var mActivity: Activity = activity + private var mWindowParams: WindowManager.LayoutParams? = null + private var mWindowManager: WindowManager? = null + private lateinit var rvReportList: RecyclerView + private var reportListAdapter: ReportListAdapter?=null + + private lateinit var mFloatLayout: View + private var mInViewX = 0f + private var mInViewY = 0f + private var mDownInScreenX = 0f + private var mDownInScreenY = 0f + private var mInScreenX = 0f + private var mInScreenY = 0f + + init { + initFloatWindow(); + } + + private fun initFloatWindow() { + mFloatLayout = LayoutInflater.from(mActivity).inflate(R.layout.view_report_list, null) as View + mFloatLayout.setOnTouchListener(this) + rvReportList= mFloatLayout.findViewById(R.id.rv_report_list) + mWindowParams = WindowManager.LayoutParams() + mWindowManager = mActivity.windowManager + mWindowParams?.let { + it.format = PixelFormat.RGBA_8888 + it.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + it.gravity = Gravity.START or Gravity.TOP + it.width = 800 + it.height = 1000 + it.alpha = 0.9f + } + reportListAdapter= ReportListAdapter(mActivity) + rvReportList.layoutManager = LinearLayoutManager(mActivity, + LinearLayoutManager.VERTICAL,false) + rvReportList.adapter = reportListAdapter + } + + fun refreshData(data:List){ + reportListAdapter?.setDada(data) + reportListAdapter?.notifyDataSetChanged() + } + + override fun onTouch(v: View?, motionEvent: MotionEvent?): Boolean { + when (motionEvent?.action) { + MotionEvent.ACTION_DOWN -> { + // 获取相对View的坐标,即以此View左上角为原点 + mInViewX = motionEvent.x + mInViewY = motionEvent.y + // 获取相对屏幕的坐标,即以屏幕左上角为原点 + mDownInScreenX = motionEvent.rawX + mDownInScreenY = motionEvent.rawY - getSysBarHeight(mActivity) + mInScreenX = motionEvent.rawX + mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity) + } + MotionEvent.ACTION_MOVE -> { + // 更新浮动窗口位置参数 + mInScreenX = motionEvent.rawX + mInScreenY = motionEvent.rawY - getSysBarHeight(mActivity) + mWindowParams!!.x = (mInScreenX - mInViewX).toInt() + mWindowParams!!.y = (mInScreenY - mInViewY).toInt() + // 手指移动的时候更新小悬浮窗的位置 + mWindowManager!!.updateViewLayout(mFloatLayout, mWindowParams) + } +// MotionEvent.ACTION_UP -> // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。 +// if (mDownInScreenX === mInScreenX && mDownInScreenY === mInScreenY) { +// } + } + return true + } + + fun showFloatWindow() { + if (mFloatLayout.parent == null) { + val metrics = DisplayMetrics() + // 默认固定位置,靠屏幕右边缘的中间 + mWindowManager!!.defaultDisplay.getMetrics(metrics) + mWindowParams!!.x = metrics.widthPixels + mWindowParams!!.y = metrics.heightPixels / 2 - getSysBarHeight(mActivity) + mWindowManager!!.addView(mFloatLayout, mWindowParams) + } + } + + fun hideFloatWindow() { + if (mFloatLayout.parent != null) mWindowManager!!.removeView(mFloatLayout) + } + + // 获取系统状态栏高度 + private fun getSysBarHeight(activity: Activity): Int { + val c: Class<*> + val obj: Any + val field: Field + val x: Int + var sbar = 0 + try { + c = Class.forName("com.android.internal.R\$dimen") + obj = c.newInstance() + field = c.getField("status_bar_height") + x = field.get(obj).toString().toInt() + sbar = activity.resources.getDimensionPixelSize(x) + } catch (e1: Exception) { + e1.printStackTrace() + } + return sbar + } + +} \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xxhdpi/icon_drag.png b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xxhdpi/icon_drag.png new file mode 100644 index 0000000000..305f239505 Binary files /dev/null and b/core/function-impl/mogo-core-function-hmi/src/main/res/drawable-xxhdpi/icon_drag.png differ diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/item_report_detail.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/item_report_detail.xml new file mode 100644 index 0000000000..767163596a --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/item_report_detail.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_debug_setting.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_debug_setting.xml index afaac05e7f..37747bf293 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_debug_setting.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_debug_setting.xml @@ -14,107 +14,158 @@ android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent"> - + android:layout_height="match_parent"> + android:background="#F0F0F0" + app:layout_constraintTop_toTopOf="parent" + /> + + + android:layout_width="0dp" + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@id/vReportLine" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toLeftOf="@id/tbReportMore" + app:layout_constraintTop_toTopOf="@id/tbReportMore" + app:layout_constraintBottom_toBottomOf="@id/tbReportMore" + /> + android:background="#F0F0F0" + app:layout_constraintTop_toBottomOf="@id/tbReportMore" + /> + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/vReportSrcLine" + /> + android:background="#F0F0F0" + app:layout_constraintTop_toBottomOf="@id/tvReportLevel" + /> + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/vReportLevelLine"/> + android:background="#F0F0F0" + app:layout_constraintTop_toBottomOf="@id/tvReportMsg" + /> + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/vReportMsgLine" + /> + android:background="#F0F0F0" + app:layout_constraintTop_toBottomOf="@id/tvReportCode" + /> + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/vReportCodeLine" + /> + android:background="#F0F0F0" + app:layout_constraintTop_toBottomOf="@id/tvReportResult" + /> + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/vReportResultLine" + /> + android:background="#F0F0F0" + app:layout_constraintTop_toBottomOf="@id/tvReportActions" + /> + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/vReportActionsLine" + /> + android:background="#F0F0F0" + app:layout_constraintTop_toBottomOf="@id/tvReportSec" + /> - - - - - + android:layout_height="wrap_content" + app:layout_constraintTop_toBottomOf="@id/vReportSecLine" + /> + diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_report_list.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_report_list.xml new file mode 100644 index 0000000000..ef4783691c --- /dev/null +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/layout/view_report_list.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/report/ReportEntity.kt b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/report/ReportEntity.kt new file mode 100644 index 0000000000..5487c5117f --- /dev/null +++ b/core/mogo-core-data/src/main/java/com/mogo/eagle/core/data/report/ReportEntity.kt @@ -0,0 +1,20 @@ +package com.mogo.eagle.core.data.report + +/** + * @author XuXinChao + * @description 工控机上报实例 + * @since: 2022/4/13 + */ +data class ReportEntity( + var time: String,//上报时间 + var src: String,//消息来源 + var level: String,//消息等级 error info + var msg: String,//研发自己看的信息;对标准日志来说就是日志内容 + var code: String, //error日志中的错误原因,这是一个类似宏的受约束字段,用字符串的目的是便于排查问题时查看 + var resultList: List,//带来的后果;例如pad无法启动驾驶,远程驾驶无法启动等;可供监控后台做错误分类;pad无法理解code时也可参考此字段 + var actionsList: List,//试验性字段。消息发出者希望触发的动作,例如:触发短信报警,自动创建工单,要求pad弹框等 +// var sec: Int,//秒 +// var nsec: Int//纳秒 sec和nsec拼接起来是消息发送事件 +) { + +} \ No newline at end of file