diff --git a/OCH/shuttle/passenger_weaknet/src/main/res/m2/layout/shuttle_p_m2_fragment.xml b/OCH/shuttle/passenger_weaknet/src/main/res/m2/layout/shuttle_p_m2_fragment.xml index 81567e8f78..0e9431c390 100644 --- a/OCH/shuttle/passenger_weaknet/src/main/res/m2/layout/shuttle_p_m2_fragment.xml +++ b/OCH/shuttle/passenger_weaknet/src/main/res/m2/layout/shuttle_p_m2_fragment.xml @@ -146,16 +146,16 @@ app:layout_constraintBottom_toTopOf="@+id/video_fragment" app:layout_constraintEnd_toEndOf="parent" /> - - + + + + + + + + + + imp ); CallerHmiManager.INSTANCE.warningV2X(poiType, alarmText, ttsText, this,WarningDirectionEnum.ALERT_WARNING_TOP, - TimeUnit.SECONDS.toMillis(5), AIAssist.LEVEL2, false); + TimeUnit.SECONDS.toMillis(5), AIAssist.NEW_LEVEL_2, false); //消息埋点 V2XEventAnalyticsManager.INSTANCE.triggerV2XEvent(poiType,alarmText,ttsText, DataSourceType.AICLOUD, CommunicationType.V2N); } diff --git a/core/function-impl/mogo-core-function-biz/src/main/java/com/mogo/eagle/function/biz/v2x/v2n/scenario/scene/warning/V2XFrontWarningScenario.java b/core/function-impl/mogo-core-function-biz/src/main/java/com/mogo/eagle/function/biz/v2x/v2n/scenario/scene/warning/V2XFrontWarningScenario.java index f64e97698b..44c9598e1e 100644 --- a/core/function-impl/mogo-core-function-biz/src/main/java/com/mogo/eagle/function/biz/v2x/v2n/scenario/scene/warning/V2XFrontWarningScenario.java +++ b/core/function-impl/mogo-core-function-biz/src/main/java/com/mogo/eagle/function/biz/v2x/v2n/scenario/scene/warning/V2XFrontWarningScenario.java @@ -88,7 +88,7 @@ public class V2XFrontWarningScenario extends AbsV2XScenario implements IMoGoChas CallerHmiManager.INSTANCE.warningV2X(v2xType + "", getAlertContentForFrontWarning(mMarkerEntity), mMarkerEntity.getTts(), this,getDirection(), - TimeUnit.SECONDS.toMillis(5), AIAssist.LEVEL2, false); + TimeUnit.SECONDS.toMillis(5), AIAssist.NEW_LEVEL_2, false); //消息埋点 V2XEventAnalyticsManager.INSTANCE.triggerV2XEvent(v2xType,getAlertContentForFrontWarning(mMarkerEntity).toString(), mMarkerEntity.getTts(), DataSourceType.AICLOUD, CommunicationType.V2N); diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/DataCenterProvider.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/DataCenterProvider.kt index 70c4c444e4..f3da028c43 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/DataCenterProvider.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/DataCenterProvider.kt @@ -29,18 +29,13 @@ class DataCenterProvider : IDataCenterProvider { CallerMsgBoxManager.queryAllMessages(it) TrafficLightDispatcher.INSTANCE.initServer(it) SpeedLimitDispatcher.INSTANCE.initLimit(it) - if (AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) { - IotManager.init() - } - + IotManager.init(AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) } } override fun onDestroy() { TrafficLightDispatcher.INSTANCE.destroy() SpeedLimitDispatcher.INSTANCE.destroy() - if (AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) { - IotManager.destroy() - } + IotManager.destroy() } } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt index 57aa07c5dd..54c899a533 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/MoGoAutopilotControlProvider.kt @@ -31,7 +31,6 @@ import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotCarConfigListene import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotControlProvider import com.mogo.eagle.core.function.api.hmi.view.IViewControlListener.Companion.FUNC_MODE_RAIN import com.mogo.eagle.core.function.api.map.collect.IMoGoMapDataCollectProvider -import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotCarConfigListenerManager import com.mogo.eagle.core.function.call.autopilot.CallerIpcConnectStateToastManager import com.mogo.eagle.core.function.call.cloud.CallerCloudCertManager @@ -55,6 +54,7 @@ import com.mogo.eagle.core.utilcode.util.ParseVersionUtils import com.mogo.eagle.core.utilcode.util.ThreadUtils import com.mogo.eagle.core.utilcode.util.ToastUtils import com.mogo.eagle.core.utilcode.util.UiThreadHandler +import com.mogo.support.device.led.LedSourceManager import com.mogo.telematic.MogoProtocolMsg import com.mogo.telematic.MogoProtocolMsg.NORMAL_DATA import com.mogo.telematic.MogoProtocolMsg.SYNC_FUSION_COLOR_STATUS @@ -1038,6 +1038,13 @@ class MoGoAutopilotControlProvider : */ override fun sendTripInfo(type: Int, lineName: String, departureStopName: String,arrivalStopName: String, isLastStop: Boolean) { AdasManager.getInstance().sendTripInfoReq(type, lineName, departureStopName,arrivalStopName, isLastStop) + LedSourceManager.updateTripInfoData( + type, + lineName, + departureStopName, + arrivalStopName, + isLastStop + ) } /** diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt index 35f34a1d8f..8780f7e7c6 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/autopilot/adapter/MoGoAdasListenerImpl.kt @@ -93,16 +93,17 @@ import com.mogo.eagle.core.function.call.obu.CallerObuWarningSpatListenerManager import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_D_C import com.mogo.eagle.core.utilcode.util.DeviceUtils +import com.mogo.support.device.led.LedSourceManager 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.chain.AdasChain -import com.zhjt.mogo.adas.data.bean.AdasParam import com.zhidao.support.adas.high.common.ProtocolStatus import com.zhjt.mogo.adas.common.MessageType import com.zhjt.mogo.adas.data.AdasConstants import com.zhjt.mogo.adas.data.AdasConstants.NodeExistState import com.zhjt.mogo.adas.data.AiCloudTask +import com.zhjt.mogo.adas.data.bean.AdasParam import com.zhjt.mogo.adas.data.bean.AutopilotStatistics import com.zhjt.mogo.adas.data.bean.LaunchConditionData import com.zhjt.mogo.adas.data.bean.NodeStateInfo @@ -135,6 +136,7 @@ import prediction.Prediction import record_cache.RecordPanelOuterClass import system_master.SsmInfo import system_master.SystemStatusInfo +import kotlin.math.roundToInt /** * 适配ADAS 回调监听分发,这里不做业务,只做数据包装及分发处理 @@ -178,6 +180,7 @@ class MoGoAdasListenerImpl : OnAdasListener { ) override fun onGnssInfo(header: MessagePad.Header, gnssInfo: MessagePad.GnssInfo) { CallerChassisGnssListenerManager.invokeChassisGnssListener(gnssInfo) + LedSourceManager.updateAccelerationData(gnssInfo.acceleration) if (gnssInfo != null) { // 同步更新经纬度和系统时间至 AutoPilotStatusListener CallerAutoPilotStatusListenerManager.updateAutoPilotLocAndTime( @@ -280,6 +283,15 @@ class MoGoAdasListenerImpl : OnAdasListener { override fun onLightSwitch(light: Chassis.LightSwitch) { //转向灯数据 CallerChassisStatesListenerManager.invokeAutopilotLightSwitchData(light) + var type = 0 + if (Chassis.LightSwitch.LIGHT_LEFT == light) { + type = 1 + } else if (Chassis.LightSwitch.LIGHT_RIGHT == light) { + type = 2 + } else if (Chassis.LightSwitch.LIGHT_FLASH == light) { + type = 3 + } + LedSourceManager.updateTurnSignalData(type) } //自动驾驶状态 @@ -322,6 +334,8 @@ class MoGoAdasListenerImpl : OnAdasListener { header: MessagePad.Header?, trafficLights: FusionTrafficLightOuterClass.FusionTrafficLights? ) { + //此分发新开线程,在invokeAutopilotPerceptionTrafficLight 前分发避免 invokeAutopilotPerceptionTrafficLight中存在耗时操作影响LED数据更新 + transitionTurnToLedData(trafficLights) if (trafficLights != null) { CallerAutopilotIdentifyListenerManager.invokeAutopilotPerceptionTrafficLight( trafficLights @@ -329,6 +343,92 @@ class MoGoAdasListenerImpl : OnAdasListener { } } + /** + * LED屏幕数据转换 + * 只能放在这 LedSourceManager LIB中并未依赖ADAS数据源 + */ + private fun transitionTurnToLedData(trafficLights: FusionTrafficLightOuterClass.FusionTrafficLights?) { + var stateTurnRound = -1 + var durationTurnRound = -1 + var stateTurnLeft = -1 + var durationTurnLeft = -1 + var stateStraight = -1 + var durationStraight = -1 + var stateTurnRight = -1 + var durationTurnRight = -1 + if (trafficLights != null) { + if (trafficLights.uTurn != null) { + val uTurn = trafficLights.uTurn + stateTurnRound = transitionTurnType(uTurn.state) + if (uTurn.duration > 0) { + durationTurnRound = uTurn.duration.roundToInt() + } + } + if (trafficLights.left != null) { + val left = trafficLights.left + stateTurnLeft = transitionTurnType(left.state) + if (left.duration > 0) { + durationTurnLeft = left.duration.roundToInt() + } + } + if (trafficLights.straight != null) { + val straight = trafficLights.straight + stateStraight = transitionTurnType(straight.state) + if (straight.duration > 0) { + durationStraight = straight.duration.roundToInt() + } + } + if (trafficLights.right != null) { + val right = trafficLights.right + stateTurnRight = transitionTurnType(right.state) + if (right.duration > 0) { + durationTurnRight = right.duration.roundToInt() + } + } + //来源是自车没有倒计时 不管域控发的倒计时是什么值 + if (trafficLights.source == 0) { + durationTurnRound = -1 + durationTurnLeft = -1 + durationStraight = -1 + durationTurnRight = -1 + } + } + LedSourceManager.updateTrafficLightData( + stateTurnRound, + durationTurnRound, + stateTurnLeft, + durationTurnLeft, + stateStraight, + durationStraight, + stateTurnRight, + durationTurnRight + ) + } + + private fun transitionTurnType(state: FusionTrafficLightOuterClass.FusionLightState?): Int { + var type = -1 + state?.let { + type = when (it) { + FusionTrafficLightOuterClass.FusionLightState.STATE_RED_FUSION -> { + 2 + } + + FusionTrafficLightOuterClass.FusionLightState.STATE_YELLOW_FUSION -> { + 3 + } + + FusionTrafficLightOuterClass.FusionLightState.STATE_GREEN_FUSION -> { + 4 + } + + else -> { + -1 + } + } + } + return type + } + //他车轨迹预测 override fun onPredictionObstacleTrajectory( header: MessagePad.Header?, diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/iot/IotManager.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/iot/IotManager.kt index a0bf9e9949..458c1eb0e8 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/iot/IotManager.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/iot/IotManager.kt @@ -10,6 +10,7 @@ import com.mogo.eagle.core.function.call.cloud.CallerCloudListenerManager import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.i import com.mogo.support.device.DevicesManager import com.mogo.support.device.IWriteChainLogListener +import com.mogo.support.device.led.LedSourceManager import com.zhjt.service.chain.ChainLog import java.text.SimpleDateFormat import java.util.Date @@ -19,11 +20,18 @@ object IotManager : IMoGoCloudListener, IWriteChainLogListener { private val sdf: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ", Locale.CHINA) private val TAG = IotManager::class.java.simpleName private const val EVENT_KEY_HARDWARE_DEVICES = "event_key_hardware_devices" + private var isPassenger: Boolean = false - fun init() { - CallerCloudListenerManager.addListener(TAG, this) - hardwareDeviceBind(SharedPrefsMgr.getInstance().sn) - DevicesManager.registerWriteChainLogListener(this) + fun init(isPassenger: Boolean) { + this.isPassenger = isPassenger + if (isPassenger) { + CallerCloudListenerManager.addListener(TAG, this) + DevicesManager.registerWriteChainLogListener(this) + hardwareDeviceBind(SharedPrefsMgr.getInstance().sn) + } else { + LedSourceManager.registerWriteChainLogListener(this) + LedSourceManager.init(true) + } } override fun tokenGot(token: String, sn: String) { @@ -42,21 +50,27 @@ object IotManager : IMoGoCloudListener, IWriteChainLogListener { } fun destroy() { - DevicesManager.destroy() - DevicesManager.unregisterWriteChainLogListener() + if (isPassenger) { + DevicesManager.unregisterWriteChainLogListener() + DevicesManager.destroy() + } else { + LedSourceManager.unregisterWriteChainLogListener() + LedSourceManager.destroy() + } } @ChainLog( linkChainLog = ChainConstant.CHAIN_TYPE_STATUS, linkCode = ChainConstant.CHAIN_SOURCE_INIT, nodeAliasCode = ChainConstant.CHAIN_CODE_HARDWARE_DEVICES, - paramIndexes = [0, 1] + paramIndexes = [0, 1, 2] ) - override fun onWriteChainLog(title: String, info: String) { + override fun onWriteChainLog(tag: String, title: String, info: String) { try { - i("${TAG}_${EVENT_KEY_HARDWARE_DEVICES}", "${title}_${info}") + i("${tag}_${EVENT_KEY_HARDWARE_DEVICES}", "${title}_${info}") val params = HashMap() params["time"] = sdf.format(Date()) + params["tag"] = tag params["title"] = title params["info"] = info MogoAnalyticUtils.track(EVENT_KEY_HARDWARE_DEVICES, params) diff --git a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/v2x/TrafficLightDispatcher.kt b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/v2x/TrafficLightDispatcher.kt index 5607717009..59d9ff213b 100644 --- a/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/v2x/TrafficLightDispatcher.kt +++ b/core/function-impl/mogo-core-function-datacenter/src/main/java/com/mogo/eagle/core/function/datacenter/v2x/TrafficLightDispatcher.kt @@ -5,6 +5,7 @@ import android.os.CountDownTimer import android.os.Handler import android.util.Log import com.mogo.commons.voice.AIAssist +import com.mogo.commons.voice.AIAssist.NEW_LEVEL_2 import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightStatus import com.mogo.eagle.core.data.biz.trafficlight.currentRoadTrafficLight @@ -232,7 +233,7 @@ class TrafficLightDispatcher : IMoGoAutopilotIdentifyListener, IMoGoTrafficLight if((light.state == FusionTrafficLightOuterClass.FusionLightState.STATE_YELLOW_FUSION || light.state ==FusionTrafficLightOuterClass.FusionLightState.STATE_RED_FUSION) && light.duration < 5 && light.nextState == FusionTrafficLightOuterClass.FusionLightState.STATE_GREEN_FUSION){ //语音播放:红灯即将变绿 - AIAssist.getInstance(mContext).speakTTSVoice("红灯即将变绿") + AIAssist.getInstance(mContext).speakTTSVoiceWithLevel("红灯即将变绿", NEW_LEVEL_2) isTurnGreen = true } } diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/OperatePanelLayout.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/OperatePanelLayout.kt index 9824d618a4..5028ea6cd0 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/OperatePanelLayout.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/OperatePanelLayout.kt @@ -5,7 +5,6 @@ import android.os.Bundle import android.os.SystemClock import android.util.AttributeSet import android.util.Log -import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -57,7 +56,6 @@ import com.mogo.eagle.core.function.hmi.ui.operate.preferences.PreferenceWithWel import com.mogo.eagle.core.function.hmi.ui.tools.SweeperModeChangedConfirmDialog import com.mogo.eagle.core.function.hmi.ui.utils.HmiActionLog.Companion.hmiAction import com.mogo.eagle.core.function.hmi.ui.utils.SOPAnalyticsManager.clickEventAnalytics -import com.mogo.eagle.core.utilcode.floating.MoGoPopWindow import com.mogo.eagle.core.utilcode.kotlin.onClick import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger @@ -66,7 +64,10 @@ import com.mogo.eagle.core.utilcode.mogo.vehicle.SweeperVehicleConfigUtils import com.mogo.eagle.core.utilcode.rv.divider.CommonDividerItemDecoration import com.mogo.eagle.core.utilcode.util.AppStateManager import com.mogo.eagle.core.utilcode.util.GsonUtils.* +import com.mogo.eagle.core.utilcode.util.ThreadUtils import com.mogo.eagle.core.utilcode.util.ToastUtils +import com.mogo.support.device.led.ILedForeverChangeWelcomeContentListener +import com.mogo.support.device.led.LedSourceManager import com.zhjt.mogo.adas.data.AdasConstants import com.zhjt.mogo.adas.data.bean.AdasParam import kotlinx.android.synthetic.main.layout_operate_panel.view.iv_operate_panel_close @@ -1521,6 +1522,22 @@ class OperatePanelLayout : LinearLayout { FunctionBuildConfig.welcomeWords = preference.extras.getString(PreferenceWithWelcomeWords.KEY_BUNDLE_CURRENT_EDIT_TEXT_VALUE) hmiAction("外屏欢迎语", FunctionBuildConfig.welcomeWords ?: "") clickEventAnalytics("外屏欢迎语", true) + LedSourceManager.foreverChangeWelcomeHint( + context?.applicationContext, + FunctionBuildConfig.welcomeWords, + object : ILedForeverChangeWelcomeContentListener { + override fun onChangeState(isSucceed: Boolean, errMsg: String) { + val customPreference: PreferenceWithWelcomeWords? = + findPreference(KEY_WELCOME_WORDS) + customPreference?.let { + ThreadUtils.runOnUiThread { + it.setOkBtnEnable() + } + } + ToastUtils.showLong(errMsg) + } + } + ) } return super.onPreferenceClick(preference) } diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/preferences/PreferenceWithWelcomeWords.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/preferences/PreferenceWithWelcomeWords.kt index cb6cd99e79..c456dfca2b 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/preferences/PreferenceWithWelcomeWords.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/operate/preferences/PreferenceWithWelcomeWords.kt @@ -3,6 +3,7 @@ package com.mogo.eagle.core.function.hmi.ui.operate.preferences import android.content.Context import android.text.TextUtils import android.util.AttributeSet +import android.view.View import android.widget.EditText import androidx.core.widget.doOnTextChanged import androidx.preference.Preference @@ -23,6 +24,7 @@ class PreferenceWithWelcomeWords: Preference { private var mCurrentWelcomeWords: String? = null + private var btnOk: View? = null override fun setDefaultValue(defaultValue: Any?) { super.setDefaultValue(defaultValue) @@ -36,21 +38,25 @@ class PreferenceWithWelcomeWords: Preference { super.onBindViewHolder(holder) val currentWelcomeWords = mCurrentWelcomeWords val et = holder.findViewById(R.id.et_welcome_words) as? EditText - val btn_ok = holder.findViewById(R.id.bt_ok) - btn_ok.isEnabled = false + btnOk = holder.findViewById(R.id.bt_ok) + btnOk?.isEnabled = false et?.doOnTextChanged { text, _, _, _ -> if (!TextUtils.isEmpty(text)) { - btn_ok?.isEnabled = true + btnOk?.isEnabled = true } else { - btn_ok?.isEnabled = false + btnOk?.isEnabled = false } } if (!TextUtils.isEmpty(currentWelcomeWords)) { et?.setText(currentWelcomeWords) } - btn_ok.onClick { + btnOk?.onClick { + btnOk?.isEnabled = false extras.putString(KEY_BUNDLE_CURRENT_EDIT_TEXT_VALUE, et?.text.toString()) onPreferenceClickListener?.onPreferenceClick(this) } } + fun setOkBtnEnable(){ + btnOk?.isEnabled = true + } } \ 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/v2n/RoadV2NEventWindowView.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/v2n/RoadV2NEventWindowView.kt index 207f5bb072..7451c5eb3c 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/v2n/RoadV2NEventWindowView.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/v2n/RoadV2NEventWindowView.kt @@ -484,7 +484,7 @@ class RoadV2NEventWindowView @JvmOverloads constructor( "更新时间:${DateTimeUtils.getTimeText(dataBean.timestamp, DateTimeUtils.HH_mm_ss)}" if (dataBean.isNeedTTS && !TextUtils.isEmpty(dataBean.ttsStr)) { AIAssist.getInstance(context) - .speakTTSVoiceWithLevel(dataBean.ttsStr, AIAssist.LEVEL0) + .speakTTSVoiceWithLevel(dataBean.ttsStr, AIAssist.NEW_LEVEL_2) } when (dataBean.eventType) { RoadV2NEventType.TEXT -> { diff --git a/core/function-impl/mogo-core-function-hmi/src/main/res/xml/operate_panel_preference_headers.xml b/core/function-impl/mogo-core-function-hmi/src/main/res/xml/operate_panel_preference_headers.xml index 9d3a450447..dc020a7d7a 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/res/xml/operate_panel_preference_headers.xml +++ b/core/function-impl/mogo-core-function-hmi/src/main/res/xml/operate_panel_preference_headers.xml @@ -31,10 +31,10 @@ android:key="mofang" android:layout="@layout/layout_operate_panel_preference_header" android:title="蘑方" /> - - - - - + \ No newline at end of file diff --git a/libraries/mogo-hardware-devices/build.gradle b/libraries/mogo-hardware-devices/build.gradle index c8f23195be..f3e63471cb 100644 --- a/libraries/mogo-hardware-devices/build.gradle +++ b/libraries/mogo-hardware-devices/build.gradle @@ -1,6 +1,7 @@ plugins { id 'com.android.library' id 'kotlin-android' + id 'org.jetbrains.kotlin.android' } android { @@ -30,10 +31,14 @@ android { lintOptions { abortOnError false } - + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { implementation rootProject.ext.dependencies.androidxappcompat api rootProject.ext.dependencies.serialport + implementation "com.mogo.support.device.manager:led_screen_cpower5a:1.0.10" + implementation rootProject.ext.dependencies.view_model_scope } diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/DevicesManager.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/DevicesManager.kt index 8cae092f86..5715da078b 100644 --- a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/DevicesManager.kt +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/DevicesManager.kt @@ -23,8 +23,7 @@ data class OpenState( ) object DevicesManager { - private const val TAG = "DevicesManager" - + private val TAG = DevicesManager::class.java.simpleName private val serialPortManager: SerialPortManager by lazy { SerialPortManager() // 初始化 SerialPortManager } @@ -218,7 +217,7 @@ object DevicesManager { it.value.onServiceState(serviceState) } } - writeChainLogListener?.onWriteChainLog("硬件服务", "绑定状态=${msg}") + writeChainLogListener?.onWriteChainLog(TAG, "硬件服务", "绑定状态=${msg}") } } @@ -240,6 +239,7 @@ object DevicesManager { } } writeChainLogListener?.onWriteChainLog( + TAG, "核销设备", "状态=地址:${path} 设备类型:${deviceType} 是否打开:${isOpen} 消息:${message}" ) @@ -251,7 +251,7 @@ object DevicesManager { it.value.onReceive(data) } } - writeChainLogListener?.onWriteChainLog("核销设备", "核销数据接收=$data") + writeChainLogListener?.onWriteChainLog(TAG, "核销设备", "核销数据接收=$data") } } @@ -272,6 +272,7 @@ object DevicesManager { } } writeChainLogListener?.onWriteChainLog( + TAG, "车外语音设备", "状态=地址:${path} 是否打开:${isOpen} 消息:${throwableMessage}" ) @@ -303,7 +304,7 @@ object DevicesManager { else -> "" } - writeChainLogListener?.onWriteChainLog("车外语音设备", "播报状态=${msg}") + writeChainLogListener?.onWriteChainLog(TAG, "车外语音设备", "播报状态=${msg}") } override fun onSwitchingValue(path: String, state: Int, data: SwitchingValueData?) { @@ -331,6 +332,7 @@ object DevicesManager { } if (!msg.isNullOrEmpty() && data != null) { writeChainLogListener?.onWriteChainLog( + TAG, "车外语音设备", "物理按钮状态=$msg $data" ) @@ -358,6 +360,7 @@ object DevicesManager { } if (!msg.isNullOrEmpty()) { writeChainLogListener?.onWriteChainLog( + TAG, "车外语音设备", "设备地址读取状态=$msg 设备地址$address" ) @@ -404,6 +407,7 @@ object DevicesManager { content ) writeChainLogListener?.onWriteChainLog( + TAG, "车外语音设备", "播报内容=${content ?: " 调用结果=${code}"}" ) diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/IWriteChainLogListener.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/IWriteChainLogListener.kt index 227dc01b60..a6ef9b2073 100644 --- a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/IWriteChainLogListener.kt +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/IWriteChainLogListener.kt @@ -5,5 +5,5 @@ package com.mogo.support.device */ interface IWriteChainLogListener { - fun onWriteChainLog(title: String, info: String) + fun onWriteChainLog(tag: String, title: String, info: String) } \ No newline at end of file diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/BackLedUIViewModel.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/BackLedUIViewModel.kt new file mode 100644 index 0000000000..4975410229 --- /dev/null +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/BackLedUIViewModel.kt @@ -0,0 +1,201 @@ +package com.mogo.support.device.led + +import android.util.Log +import com.mogo.support.device.IWriteChainLogListener +import com.mogo.support.device.manager.cpower5a.LedScreenCpower5aManager +import com.mogo.support.device.manager.cpower5a.common.LedScreen +import com.mogo.support.device.manager.cpower5a.common.Program + +/** + * 后屏 + */ +open class BackLedUIViewModel(writeChainLogListener: IWriteChainLogListener) : BaseLedUIViewModel( + writeChainLogListener +) { + companion object { + const val TAG = "BackLedUIViewModel" + + val supportUIList = mutableSetOf().also { + it += WelcomeUI::class.simpleName + it += FinishUI::class.simpleName + it += RouteInfoUI::class.simpleName + it += StationReportUI::class.simpleName + it += ArriveStationUI::class.simpleName + it += LeaveStationUI::class.simpleName + it += EmergencyBrakeUI::class.simpleName + it += TrafficLightUI::class.simpleName + it += TurnSignalUI::class.simpleName + it += RoadWorkAheadWarningUI::class.simpleName + } + } + + override suspend fun receive(msg: LedUI) { + if (supportUIList.contains(msg.javaClass.simpleName)) { + Log.i( + FrontLedUIViewModel.TAG, + "receive --> ${msg.javaClass.simpleName}[priority=${msg.priority}] " + ) + super.receive(msg) + } else { + Log.i( + FrontLedUIViewModel.TAG, + "receive --> 不支持的类型,放弃 ${msg.javaClass.simpleName}[priority=${msg.priority}] " + ) + } + } + + override fun handleLedUIShow(ledUI: LedUI) { + super.handleLedUIShow(ledUI) + when (ledUI) { + is WelcomeUI -> { + LedScreenCpower5aManager.getInstance().playProgramWelcome( + null, + LedScreen.OUTWARD_BACK, + ledUI.hintMsg, + ledUI.isForever + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.WELCOME.des}:${ledUI.hintMsg} 是否永久展示:${ledUI.isForever}" + ) + } + + is FinishUI -> { + LedScreenCpower5aManager.getInstance().playProgramFinish( + LedScreen.OUTWARD_BACK, + ledUI.hintMsg, + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.FINISH.des}:${ledUI.hintMsg}" + ) + } + + is RouteInfoUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineInformation(LedScreen.OUTWARD_BACK, ledUI.lineName) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.LINE_INFORMATION.des}:${ledUI.lineName}" + ) + } + + is StationReportUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineStationReport( + LedScreen.OUTWARD_BACK, + ledUI.stationName, + ledUI.state + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.LINE_STATION_REPORT.des} 站点:${ledUI.stationName} 状态:${ledUI.state}" + ) + } + + is ArriveStationUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineStationReportHint( + LedScreen.OUTWARD_BACK, + "车辆进站" + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.LINE_STATION_REPORT_HINT.des} 提示语:车辆进站" + ) + } + + is LeaveStationUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineStationReportHint( + LedScreen.OUTWARD_BACK, + "车辆起步" + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.LINE_STATION_REPORT_HINT.des} 提示语:车辆起步" + ) + } + + is EmergencyBrakeUI -> { + LedScreenCpower5aManager.getInstance() + .playProgram(LedScreen.OUTWARD_BACK, Program.REMIND_FRONT_CAR_EMERGENCY_BRAKE) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.REMIND_FRONT_CAR_EMERGENCY_BRAKE.des}" + ) + } + + is RoadWorkAheadWarningUI -> { + LedScreenCpower5aManager.getInstance() + .playProgram(LedScreen.OUTWARD_BACK, Program.REMIND_ROAD_WORK_AHEAD) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${Program.REMIND_ROAD_WORK_AHEAD.des}" + ) + } + + is TurnSignalUI -> { + var program: Program? = null + program = when (ledUI.type) { + 1 -> { + Program.REMIND_TURN_LEFT + } + + 2 -> { + Program.REMIND_TURN_RIGHT + } + + 3 -> { + Program.REMIND_VEHICLE_ANOMALY + } + + else -> { + null + } + } + program?.let { + LedScreenCpower5aManager.getInstance() + .playProgram( + LedScreen.OUTWARD_BACK, + it + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 ${program.des}" + ) + } + } + + is TrafficLightUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramTrafficLights( + LedScreen.OUTWARD_BACK, + ledUI.stateTurnRound, ledUI.durationTurnRound, + ledUI.stateTurnLeft, ledUI.durationTurnLeft, + ledUI.stateStraight, ledUI.durationStraight, + ledUI.stateTurnRight, ledUI.durationTurnRight + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "后屏 播放 信号灯 掉头:${ledUI.stateTurnRound} 掉头倒计时:${ledUI.durationTurnRound}\n" + + "左转:${ledUI.stateTurnLeft} 左转倒计时:${ledUI.durationTurnLeft}\n" + + "直行:${ledUI.stateStraight} 直行倒计时:${ledUI.durationStraight}\n" + + "右转:${ledUI.stateTurnRight} 右转倒计时:${ledUI.durationTurnRight}" + ) + } + } + + } + +} \ No newline at end of file diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/BaseLedUIViewModel.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/BaseLedUIViewModel.kt new file mode 100644 index 0000000000..6d109a01dd --- /dev/null +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/BaseLedUIViewModel.kt @@ -0,0 +1,259 @@ +package com.mogo.support.device.led + +import android.util.Log +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.mogo.support.device.IWriteChainLogListener +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.util.PriorityQueue +import kotlin.math.ceil + +open class BaseLedUIViewModel(protected val writeChainLogListener: IWriteChainLogListener) : + ViewModel() { + companion object { + const val TAG = "LedUIViewModel" + val DEFAULT_UI = WelcomeUI() + } + + private var baseUICountDownJob: Job? = null + private var currentLedUI: LedUI + private var currentCountDownJob: Job? = null + private val restoreLedUIQueue = PriorityQueue() + + private val currentLedUILiveData = MutableLiveData() + + private var currentRouteInfoUI: RouteInfoUI? = null//当前线路信息UI + private var currentStationReportUI: StationReportUI? = null//当前报站信息 + + + init { + currentLedUI = DEFAULT_UI + start() + } + + fun start() { + viewModelScope.launch { + restoreLastUI() + } + } + + /** + * 更新线路信息 + */ + fun updateCurrentRouteInfo(lineName: String) { + Log.i(TAG, "线路信息更新 线路名称:$lineName") + currentRouteInfoUI = RouteInfoUI(lineName) + } + + /** + * 更新报站信息 + */ + fun updateCurrentStationReport(stationName: String, state: String) { + Log.i(TAG, "报站信息更新 ${state}:$stationName 站点状态") + currentStationReportUI = StationReportUI(stationName, state) + } + + open suspend fun receive(msg: LedUI) { + Log.e( + TAG, + "receive --> ${msg.javaClass.simpleName}[priority=${msg.priority}] current:${currentLedUI.javaClass.simpleName}[priority=${currentLedUI.priority}]" + ) + if (msg.priority > currentLedUI.priority) { + //优先级低但是需要打断恢复,放入队列,否则直接舍弃 + if (msg.interruptRestore) { + Log.i( + TAG, + "receive --> 优先级低,放入等待队列 ${msg.javaClass.simpleName}[priority=${msg.priority}]" + ) + if (msg is LedUICountDown) { + val countdown = if (msg.countDownSeconds < 0) 0 else msg.countDownSeconds + + // 如果是打断恢复的,不重新设置值 + if (msg.absCountDownTimestamp == 0L) { + msg.absCountDownTimestamp = + System.currentTimeMillis() + countdown * 1000L + } + } + restoreLedUIQueue.offer(msg) + } else { + Log.i( + TAG, + "receive --> 优先级低,舍弃 ${msg.javaClass.simpleName}[priority=${msg.priority}]" + ) + } + } else { + // 打断当前 UI + Log.i( + TAG, + "receive --> 优先级高或相等,打断当前 ${msg.javaClass.simpleName}[priority=${msg.priority}]" + ) + if (msg is LedUIDataChange) { + if (msg.isShow) { + showUI(msg) + } else { + // 删除恢复队列中数据 + removeRestoreLedUI(msg) + // 当前正在展示,取消展示 + if (currentLedUI.javaClass.simpleName == msg.javaClass.simpleName) { + dismissUI(msg) + } + } + } else { + showUI(msg) + } + } + + } + + fun reset() { + Log.i(TAG, "reset()") + viewModelScope.launch { + currentLedUI = DEFAULT_UI + restoreLedUIQueue.clear() + currentCountDownJob?.cancel() + baseUICountDownJob?.cancel() + cancelBasicUISwitch() + currentRouteInfoUI = null + currentStationReportUI = null + } + } + + private suspend fun showUI(msg: LedUI) { + Log.i(TAG, "showUI ledUI=${msg.javaClass.simpleName}[priority=${msg.priority}]") + // 如果当前类型是 需要打断恢复的,放入等待队列 + if (currentLedUI.interruptRestore) { + restoreLedUIQueue.offer(msg) + } + + currentCountDownJob?.also { + it.cancel() + } + cancelBasicUISwitch() + + handleLedUIShow(msg) + currentLedUI = msg + + // 倒计时类型的 处理倒计时逻辑 + if (msg is LedUICountDown) { + val countdown = if (msg.countDownSeconds < 0) 0 else msg.countDownSeconds + Log.d(TAG, "LedUICountDown delay=${msg.countDownSeconds}秒") + + // 如果是打断恢复的,不重新设置值 + if (msg.absCountDownTimestamp == 0L) { + msg.absCountDownTimestamp = + System.currentTimeMillis() + countdown * 1000L + } + + viewModelScope.launch { + val delaySeconds = + if (msg.absCountDownTimestamp > 0) { + ceil((msg.absCountDownTimestamp - System.currentTimeMillis()) / 1000.0).toInt() + } else + countdown + Log.d(TAG, "设置currentCountDownJob delay=${delaySeconds}秒") + delay(delaySeconds * 1000L) + restoreLastUI() + }.also { currentCountDownJob = it } + } + } + + private suspend fun dismissUI(msg: LedUI) { + Log.i(TAG, "dismissUI ledUI=${msg.javaClass.simpleName}[priority=${msg.priority}]") + currentCountDownJob?.also { + it.cancel() + } + removeRestoreLedUI(msg) + restoreLastUI() + } + + private suspend fun restoreLastUI() { + //恢复打断 + val restoreUI = pollRestoreLedUI() + if (restoreUI != null) { + showUI(restoreUI) + } else { + // 启动 车辆基础状态 切换 + startBasicUISwitchLoop() + } + } + + private suspend fun startBasicUISwitchLoop() { + if (currentRouteInfoUI != null) { + showUI(currentRouteInfoUI!!) + } else if (currentStationReportUI != null) { + showUI(currentStationReportUI!!) + } else { + showUI(WelcomeUI()) + } + basicUISwitchInternal() + } + + private fun cancelBasicUISwitch() { + Log.i(TAG, "cancelBaseUISwitch()") + kotlin.runCatching { baseUICountDownJob?.cancel() } + } + + private suspend fun basicUISwitchInternal() { + Log.i(TAG, "baseUISwitchInternal()") + cancelBasicUISwitch() + viewModelScope.launch { + delay(10 * 1000L) + if (currentLedUI.javaClass.simpleName == WelcomeUI::class.simpleName) { + if (currentRouteInfoUI != null) { + showUI(currentRouteInfoUI!!) + } else { + showUI(WelcomeUI()) + } + } else if (currentLedUI.javaClass.simpleName == RouteInfoUI::class.simpleName) { + if (currentStationReportUI != null) { + showUI(currentStationReportUI!!) + } else { + showUI(WelcomeUI()) + } + } else if (currentLedUI.javaClass.simpleName == StationReportUI::class.simpleName) { + showUI(WelcomeUI()) + } + basicUISwitchInternal() + }.also { baseUICountDownJob = it } + } + + /** + * 控制屏幕 UI 展示 + */ + protected open fun handleLedUIShow(ledUI: LedUI) { + currentLedUILiveData.postValue(ledUI) + } + + /** + * 过滤队列中时间戳小于指定时间的消息,取出优先级最高的消息 + */ + private fun pollRestoreLedUI(): LedUI? { + while (restoreLedUIQueue.isNotEmpty()) { + val message = restoreLedUIQueue.poll() + if (message is LedUICountDown) { + if (message.countDownSeconds > 0 && message.absCountDownTimestamp > System.currentTimeMillis()) { + return message + } + } else { + return message + } + } + return null + } + + /** + * 从等待队列中删除目标类型数据 + */ + private fun removeRestoreLedUI(msg: LedUI) { + val toRemove = restoreLedUIQueue.filter { + it.javaClass == msg.javaClass || + (it is LedUICountDown && it.countDownSeconds > 0 + && it.absCountDownTimestamp <= System.currentTimeMillis()) + } + restoreLedUIQueue.removeAll(toRemove.toSet()) + } + +} \ No newline at end of file diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/FrontLedUIViewModel.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/FrontLedUIViewModel.kt new file mode 100644 index 0000000000..ac51b24654 --- /dev/null +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/FrontLedUIViewModel.kt @@ -0,0 +1,121 @@ +package com.mogo.support.device.led + +import android.util.Log +import com.mogo.support.device.IWriteChainLogListener +import com.mogo.support.device.manager.cpower5a.LedScreenCpower5aManager +import com.mogo.support.device.manager.cpower5a.common.LedScreen +import com.mogo.support.device.manager.cpower5a.common.Program + +/** + * 前屏幕 + */ +class FrontLedUIViewModel(writeChainLogListener: IWriteChainLogListener) : BaseLedUIViewModel( + writeChainLogListener +) { + companion object { + const val TAG = "FrontLedUIViewModel" + + val supportUIList = mutableSetOf().also { + it += WelcomeUI::class.simpleName + it += FinishUI::class.simpleName + it += RouteInfoUI::class.simpleName + it += StationReportUI::class.simpleName + it += ArriveStationUI::class.simpleName + it += LeaveStationUI::class.simpleName + } + } + + override suspend fun receive(msg: LedUI) { + if (supportUIList.contains(msg.javaClass.simpleName)) { + Log.i(TAG, "receive --> ${msg.javaClass.simpleName}[priority=${msg.priority}] ") + super.receive(msg) + } else { + Log.i( + TAG, + "receive --> 不支持的类型,放弃 ${msg.javaClass.simpleName}[priority=${msg.priority}] " + ) + } + } + + override fun handleLedUIShow(ledUI: LedUI) { + super.handleLedUIShow(ledUI) + when (ledUI) { + is WelcomeUI -> { + LedScreenCpower5aManager.getInstance().playProgramWelcome( + null, + LedScreen.OUTWARD_FRONT, + ledUI.hintMsg, + ledUI.isForever + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "前屏 播放 ${Program.WELCOME.des}:${ledUI.hintMsg} 是否永久展示:${ledUI.isForever}" + ) + } + + is FinishUI -> { + LedScreenCpower5aManager.getInstance().playProgramFinish( + LedScreen.OUTWARD_FRONT, + ledUI.hintMsg, + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "前屏 播放 ${Program.FINISH.des}:${ledUI.hintMsg}" + ) + } + + is RouteInfoUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineInformation(LedScreen.OUTWARD_FRONT, ledUI.lineName) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "前屏 播放 ${Program.LINE_INFORMATION.des}:${ledUI.lineName}" + ) + } + + is StationReportUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineStationReport( + LedScreen.OUTWARD_FRONT, + ledUI.stationName, + ledUI.state + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "前屏 播放 ${Program.LINE_STATION_REPORT.des} 站点:${ledUI.stationName} 状态:${ledUI.state}" + ) + } + + is ArriveStationUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineStationReportHint( + LedScreen.OUTWARD_FRONT, + "车辆进站" + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "前屏 播放 ${Program.LINE_STATION_REPORT_HINT.des} 提示语:车辆进站" + ) + } + + is LeaveStationUI -> { + LedScreenCpower5aManager.getInstance() + .playProgramLineStationReportHint( + LedScreen.OUTWARD_FRONT, + "车辆起步" + ) + writeChainLogListener.onWriteChainLog( + TAG, + "LED外屏调用", + "前屏 播放 ${Program.LINE_STATION_REPORT_HINT.des} 提示语:车辆起步" + ) + } + } + } + +} \ No newline at end of file diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/ILedForeverChangeWelcomeContentListener.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/ILedForeverChangeWelcomeContentListener.kt new file mode 100644 index 0000000000..7d1511000b --- /dev/null +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/ILedForeverChangeWelcomeContentListener.kt @@ -0,0 +1,11 @@ +package com.mogo.support.device.led + +/** + * 永久更换欢迎语结果 + * 仅更换,指的是仅回调文件上传状态 + * 更换时播放状态不作处理不管失败还是成功 + */ +interface ILedForeverChangeWelcomeContentListener { + + fun onChangeState(isSucceed: Boolean, errMsg: String) +} \ No newline at end of file diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/LedSourceManager.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/LedSourceManager.kt new file mode 100644 index 0000000000..f8d3ab9786 --- /dev/null +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/LedSourceManager.kt @@ -0,0 +1,493 @@ +package com.mogo.support.device.led + + +import android.content.Context +import android.os.CountDownTimer +import android.text.TextUtils +import com.mogo.support.device.IWriteChainLogListener +import com.mogo.support.device.manager.cpower5a.LedScreenCpower5aManager +import com.mogo.support.device.manager.cpower5a.OnLedScreenCpower5aListener +import com.mogo.support.device.manager.cpower5a.common.Cpower5aState.Execute +import com.mogo.support.device.manager.cpower5a.common.LedScreen +import com.mogo.support.device.manager.cpower5a.common.Program +import com.mogo.support.device.manager.cpower5a.common.TrafficLightState +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import java.util.concurrent.atomic.AtomicInteger + + +data class ForeverChangeWelcomeState( + val ip: String, + val state: Execute, + val errMsg: String? +) + +/** + * LED外屏控制 司机屏调用 + */ +object LedSourceManager : IWriteChainLogListener { + private val TAG = LedSourceManager::class.java.simpleName + private val frontViewModel: FrontLedUIViewModel by lazy { + FrontLedUIViewModel(this) // 初始化 + } + private val backViewModel: BackLedUIViewModel by lazy { + BackLedUIViewModel(this) // 初始化 + } + private var typeTurnSignal = 0;//转向灯状态 0:无灯;1:左转;2:右转;3:双闪 + private var lastUpdateEmergencyBrakeTime = 0L//上次触发急刹展示的时间 + private var isDriver = false + private var writeChainLogListener: IWriteChainLogListener? = null + + //红绿灯定时器,超时未更新隐藏红绿灯 + @Volatile + private var lightCountDownTimer: CountDownTimer? = null + private var lastLightTime: Long = System.currentTimeMillis() + private var foreverChangeWelcomeContentListener: ILedForeverChangeWelcomeContentListener? = + null//修改欢迎语状态回调 + private val foreverChangeWelcomeNum = AtomicInteger(0)//修改欢迎语设备回调个数 + + @Volatile + private var foreverChangeWelcomeState: ForeverChangeWelcomeState? = + null//修改欢迎语结果 一共两块屏幕 不管那那先回调就先赋值 + + fun registerWriteChainLogListener(writeChainLogListener: IWriteChainLogListener) { + this.writeChainLogListener = writeChainLogListener + } + + fun unregisterWriteChainLogListener() { + this.writeChainLogListener = null + } + + + fun init(isDriver: Boolean) { + this.isDriver = isDriver + LedScreenCpower5aManager.getInstance().addListener(cpower5aListener) + } + + fun destroy() { + frontViewModel.reset() + backViewModel.reset() + LedScreenCpower5aManager.getInstance().removeListener(cpower5aListener) + typeTurnSignal = 0 + lastUpdateEmergencyBrakeTime = 0L + lightCountDownTimer?.cancel() + lightCountDownTimer = null + lastLightTime = System.currentTimeMillis() + } + + private fun receiveUI(ledUI: LedUI) { + GlobalScope.launch(Dispatchers.IO) { + frontViewModel.receive(ledUI) + backViewModel.receive(ledUI) + } + } + + //更新线路信息 + private fun updateLineNameUI(lineName: String) { + GlobalScope.launch(Dispatchers.IO) { + frontViewModel.updateCurrentRouteInfo(lineName) + backViewModel.updateCurrentRouteInfo(lineName) + } + } + + //更新报站信息 + private fun updateStationReportUI(stationName: String, state: String) { + GlobalScope.launch(Dispatchers.IO) { + frontViewModel.updateCurrentStationReport(stationName, state) + backViewModel.updateCurrentStationReport(stationName, state) + } + + } + + + /** + * 更新转向灯 + * type: 0:无灯;1:左转;2:右转;3:双闪 + */ + fun updateTurnSignalData(type: Int) { + if (isDriver) { + if (typeTurnSignal != type) { + writeChainLogListener?.onWriteChainLog(TAG, "LED外屏数据源", "车灯状态=${type}") + typeTurnSignal = type + receiveUI(TurnSignalUI(type != 0, type)) + } + } + + } + + /** + * 车辆急刹 + */ + fun updateAccelerationData(acceleration: Double) { + if (isDriver) { + if (acceleration <= -2) { + writeChainLogListener?.onWriteChainLog( + TAG, + "LED外屏数据源", + "车辆加速度值=${acceleration}" + ) + val now = System.currentTimeMillis() + if (now - lastUpdateEmergencyBrakeTime > 60 * 1000L) {//1m内不进行多次提示 + lastUpdateEmergencyBrakeTime = now + receiveUI(EmergencyBrakeUI()) + } + } + } + } + + private fun updateLightCountDownTimer() { + lastLightTime = System.currentTimeMillis() + if (lightCountDownTimer == null) { + lightCountDownTimer = object : CountDownTimer(300000, 500) { + override fun onTick(millisUntilFinished: Long) { + if ((System.currentTimeMillis() - lastLightTime) > 1000) { + //隐藏红绿灯显示 + receiveUI( + TrafficLightUI( + false, + null, -1, + null, -1, + null, -1, + null, -1 + ) + ) + lightCountDownTimer?.cancel() + lightCountDownTimer = null + } + } + + override fun onFinish() { + //隐藏红绿灯显示 + receiveUI( + TrafficLightUI( + false, + null, -1, + null, -1, + null, -1, + null, -1 + ) + ) + lightCountDownTimer?.cancel() + lightCountDownTimer = null + } + + } + lightCountDownTimer?.start() + } + } + + /** + * 更新红绿灯数据 + * state -1:表示 null; 0:表示 CLEAR; 1:表示 NONE; 2:表示 RED; 3:表示 YELLOW; 4:表示 GREEN; + */ + fun updateTrafficLightData( + stateTurnRound: Int, durationTurnRound: Int, + stateTurnLeft: Int, durationTurnLeft: Int, + stateStraight: Int, durationStraight: Int, + stateTurnRight: Int, durationTurnRight: Int + ) { + if (isDriver) { + var stateTurnRoundTemp: TrafficLightState? = null + var stateTurnLeftTemp: TrafficLightState? = null + var stateStraightTemp: TrafficLightState? = null + var stateTurnRightTemp: TrafficLightState? = null + + var durationTurnRoundTemp = durationTurnRound + var durationTurnLeftTemp = durationTurnLeft + var durationStraightTemp = durationStraight + var durationTurnRightTemp = durationTurnRight + + updateLightCountDownTimer() + var isShow = true + if (stateTurnRound == -1 && stateTurnLeft == -1 && stateStraight == -1 && stateTurnRight == -1) { + isShow = false + durationTurnRoundTemp = -1 + durationTurnLeftTemp = -1 + durationStraightTemp = -1 + durationTurnRightTemp = -1 + } else { + stateTurnRoundTemp = transitionTurnType(stateTurnRound) + stateTurnLeftTemp = transitionTurnType(stateTurnLeft) + stateStraightTemp = transitionTurnType(stateStraight) + stateTurnRightTemp = transitionTurnType(stateTurnRight) + } + if (isShow){ + writeChainLogListener?.onWriteChainLog( + TAG, + "LED外屏数据源", + "信号灯 " + + "stateTurnRound=${stateTurnRound} durationTurnRound=${durationTurnRound} " + + "stateTurnLeft=${stateTurnLeft} durationTurnLeft=${durationTurnLeft} " + + "stateStraight=${stateStraight} durationStraight=${durationStraight} " + + "stateTurnRight=${stateTurnRight} durationTurnRight=${durationTurnRight}" + ) + } + receiveUI( + TrafficLightUI( + isShow, + stateTurnRoundTemp, durationTurnRoundTemp, + stateTurnLeftTemp, durationTurnLeftTemp, + stateStraightTemp, durationStraightTemp, + stateTurnRightTemp, durationTurnRightTemp + ) + ) + } + } + + private fun transitionTurnType(type: Int): TrafficLightState { + return when (type) { + 2 -> { + TrafficLightState.RED + } + + 3 -> { + TrafficLightState.YELLOW + } + + 4 -> { + TrafficLightState.GREEN + } + + else -> { + TrafficLightState.NONE + } + } + } + + /** + * 发生行程相关 + * type=1或2的时 需要参数 lineName + * type=3或4的时 需要参数 lineName departureStopName arrivalStopName isLastStop + * type=5时 不需要任何参数 + * + * @param type 事件类型, 1:行程开始, 2:行程结束, 3:出站, 4:进站, 5:城市占道施工预警 + * @param lineName 路线名 + * @param departureStopName 出站站点名 + * @param arrivalStopName 下一站到达站点名 + * @param isLastStop 是否最终站 + */ + fun updateTripInfoData( + type: Int, + lineName: String, + departureStopName: String, + arrivalStopName: String, + isLastStop: Boolean + ) { + if (isDriver) { + writeChainLogListener?.onWriteChainLog( + TAG, + "LED外屏数据源", + "行程 type=${type} lineName=${lineName} departureStopName=${departureStopName} arrivalStopName=${arrivalStopName} isLastStop=${isLastStop}" + ) + if (lineName.isNotEmpty()) { + updateLineNameUI(lineName) + } + if (type == 1) { + //开始 + updateLineNameUI(lineName); + } else if (type == 2) { + //结束 + frontViewModel.reset() + backViewModel.reset() + receiveUI(FinishUI()) + } else if (type == 3) { + //出站 + if (arrivalStopName.isNotEmpty()) { + updateStationReportUI(arrivalStopName, "下一站") + } + } else if (type == 4) { + //进站 + if (arrivalStopName.isNotEmpty()) { + updateStationReportUI( + arrivalStopName, if (isLastStop) { + "终点站" + } else { + "已到达" + } + ) + } + } else if (type == 5) { + //道路施工 + receiveUI(RoadWorkAheadWarningUI()) + } + } + } + + /** + * 永久更改欢迎节目显示内容 + * context如果是null会设置失败 + */ + fun foreverChangeWelcomeHint( + context: Context?, + hintMsg: String?, + listener: ILedForeverChangeWelcomeContentListener + ) { + this.foreverChangeWelcomeContentListener = listener + foreverChangeWelcomeNum.set(0) + foreverChangeWelcomeState = null + LedScreenCpower5aManager.getInstance() + .playProgramWelcome(context, LedScreen.OUTWARD_FRONT, hintMsg, true) + LedScreenCpower5aManager.getInstance() + .playProgramWelcome(context, LedScreen.OUTWARD_BACK, hintMsg, true) + } + + //调用LED屏接口数据埋点 + override fun onWriteChainLog(tag: String, title: String, info: String) { + writeChainLogListener?.onWriteChainLog(tag, title, info) + } + + + private val cpower5aListener: OnLedScreenCpower5aListener = + object : OnLedScreenCpower5aListener() { + override fun onPlayProgramState( + ip: String, + state: Execute, + program: Program, + errMsg: String? + ) { + super.onPlayProgramState(ip, state, program, errMsg) + writeChainLogListener?.let { + var msg = state.msg + if (!TextUtils.isEmpty(errMsg)) { + msg += " $errMsg" + } + val ledScreen = LedScreen.getLedScreen(ip) + var tag = BaseLedUIViewModel.TAG + if (ledScreen == LedScreen.OUTWARD_BACK) { + tag = "BackLedUIViewModel" + } else if (ledScreen == LedScreen.OUTWARD_FRONT) { + tag = "FrontLedUIViewModel" + } + it.onWriteChainLog( + tag, + "LED外屏调用结果", + "设备“$ip”播放【$program】节目结果:$msg" + ) + } + + } + + override fun onFileUploadState( + ip: String, + state: Execute, + program: Program?, + fileName: String, + progress: Int, + errMsg: String? + ) { + super.onFileUploadState(ip, state, program, fileName, progress, errMsg) + //上传进度不做展示和日志埋点粗吹牛 + if (state == Execute.EXECUTE_SUCCEED || + state == Execute.UNKNOWN || + state == Execute.DATA_EXCEPTION || + state == Execute.EXECUTE_EXCEPTION || + state == Execute.CONNECT_FAILED + ) { + if (program == Program.WELCOME) { + var msg: String + if (Execute.EXECUTE_SUCCEED == state) { + msg = "节目上传成功" + } else { + msg = state.msg + if (!TextUtils.isEmpty(errMsg)) { + msg += " $errMsg" + } + } + val ledScreen = LedScreen.getLedScreen(ip) + var tag = BaseLedUIViewModel.TAG + if (ledScreen == LedScreen.OUTWARD_BACK) { + tag = "BackLedUIViewModel" + } else if (ledScreen == LedScreen.OUTWARD_FRONT) { + tag = "FrontLedUIViewModel" + } + //回调永久更改欢迎语状态 + foreverChangeWelcomeContentListener?.let { + + val num = foreverChangeWelcomeNum.incrementAndGet() + if (num == 1) { + foreverChangeWelcomeState = ForeverChangeWelcomeState( + ip, + state, + errMsg + ) + } else if (num == 2) { + var temp = "" + if (foreverChangeWelcomeState != null) { + temp = getForeverChangeWelcomeMsg( + foreverChangeWelcomeState!!.ip, + foreverChangeWelcomeState!!.state, + foreverChangeWelcomeState!!.errMsg + ) + } + var temp1 = getForeverChangeWelcomeMsg( + ip, + state, + errMsg + ) + if (temp.isNotEmpty()) { + temp1 = temp + "\n" + temp1 + } + it.onChangeState(state == Execute.EXECUTE_SUCCEED, temp1) + foreverChangeWelcomeContentListener = null + foreverChangeWelcomeNum.set(0) + foreverChangeWelcomeState = null + } + + } + writeChainLogListener?.onWriteChainLog( + tag, + "LED外屏调用结果", + "设备“$ip”永久更换欢迎节目状态:$msg" + ) + } + } + } + } + + private fun getForeverChangeWelcomeMsg( + ip: String, + state: Execute, + errMsg: String? + ): String { + var temp = when (state) { + Execute.EXECUTE_SUCCEED -> { + "欢迎语更改成功" + } + + Execute.CONNECT_FAILED -> { + "欢迎语更改失败,无法连接到设备" + } + + Execute.DATA_EXCEPTION -> { + "欢迎语更改失败,数据异常" + } + + Execute.EXECUTE_EXCEPTION -> { + "欢迎语更改失败,解析或发送异常" + } + + else -> { + "欢迎语更改失败" + } + } + if (!TextUtils.isEmpty(errMsg)) { + temp += ":$errMsg" + } + val device = when (LedScreen.getLedScreen(ip)) { + LedScreen.OUTWARD_FRONT -> { + "前屏" + } + + LedScreen.OUTWARD_BACK -> { + "后屏" + } + + else -> { + "未知屏幕" + } + } + return device + temp + } + +} \ No newline at end of file diff --git a/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/LedUI.kt b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/LedUI.kt new file mode 100644 index 0000000000..7eb0260137 --- /dev/null +++ b/libraries/mogo-hardware-devices/src/main/java/com/mogo/support/device/led/LedUI.kt @@ -0,0 +1,96 @@ +package com.mogo.support.device.led + +import com.mogo.support.device.manager.cpower5a.common.TrafficLightState + +open class LedUI( + var priority: Int = 0, + var interruptRestore: Boolean = false, +) : Comparable { + override fun compareTo(other: LedUI): Int = other.priority - this.priority + override fun toString(): String { + return "LedUI(priority=$priority, interruptRestore=$interruptRestore)" + } +} + +open class LedUIBaseSwitch( + priority: Int = 0, + interruptRestore: Boolean = false, +) : LedUI(priority, interruptRestore) { + override fun toString(): String { + return "LedUIBaseSwitch() ${super.toString()}" + } +} + +open class LedUIDataChange( + var isShow: Boolean = false, + priority: Int = 0, + interruptRestore: Boolean = false, +) : LedUI(priority, interruptRestore) { + override fun toString(): String { + return "LedUIDataChange(isShow=$isShow) ${super.toString()}" + } +} + +open class LedUICountDown( + open var countDownSeconds: Int = 0, + open var absCountDownTimestamp: Long = 0L, + priority: Int = 0, + interruptRestore: Boolean = false, +) : LedUI(priority, interruptRestore) { + override fun toString(): String { + return "LedUICountDown(countDownSeconds=$countDownSeconds, absCountDownTimestamp=$absCountDownTimestamp) ${super.toString()}" + } +} + + +//欢迎提示 +class WelcomeUI(val hintMsg: String? = null, val isForever: Boolean = false) : + LedUIBaseSwitch(priority = 5) { +} + +//结束提示 +class FinishUI(val hintMsg: String = "感谢一路相伴") : + LedUICountDown(priority = 5, countDownSeconds = 10) + +//线路信息提示 +class RouteInfoUI(val lineName: String) : LedUIBaseSwitch(priority = 5) + +//报站提示 +class StationReportUI(val stationName: String, val state: String) : LedUIBaseSwitch(priority = 5) + +//进站提示 暂时没用 +class ArriveStationUI() : + LedUICountDown(priority = 0, countDownSeconds = 10) + +//出站提示 暂时没用 +class LeaveStationUI() : + LedUICountDown(priority = 0, countDownSeconds = 10) + + +/** + * 转向灯提示 + * type: 0:无灯;1:左转;2:右转;3:双闪 + */ +class TurnSignalUI(isShow: Boolean, val type: Int) : + LedUIDataChange(isShow = isShow, priority = 3, interruptRestore = true) + + +//急刹提示 +class EmergencyBrakeUI() : + LedUICountDown(priority = 1, countDownSeconds = 5) + +//信号灯提示 +class TrafficLightUI( + isShow: Boolean, + val stateTurnRound: TrafficLightState?, val durationTurnRound: Int, + val stateTurnLeft: TrafficLightState?, val durationTurnLeft: Int, + val stateStraight: TrafficLightState?, val durationStraight: Int, + val stateTurnRight: TrafficLightState?, val durationTurnRight: Int +) : + LedUIDataChange(isShow = isShow, priority = 4, interruptRestore = true) + + +//前方施工提示 +class RoadWorkAheadWarningUI() : LedUICountDown(priority = 2, countDownSeconds = 10) + + diff --git a/tts/tts-pad/src/main/java/com/mogo/tts/pad/PadTTS.java b/tts/tts-pad/src/main/java/com/mogo/tts/pad/PadTTS.java index 57bf744cfd..6b182d290b 100644 --- a/tts/tts-pad/src/main/java/com/mogo/tts/pad/PadTTS.java +++ b/tts/tts-pad/src/main/java/com/mogo/tts/pad/PadTTS.java @@ -401,7 +401,13 @@ public class PadTTS implements IMogoTTS, VoiceClient.VoiceCmdCallBack { List ttsEntityList = new ArrayList<>(); ttsEntityList.add(new LangTtsEntity(tts, LanguageType.CHINESE)); MultiLangTtsEntity ttsEntity = new MultiLangTtsEntity(ttsEntityList); - speakMultiLangTTSWithLevel(ttsEntity, level); + if (Thread.currentThread() != Looper.getMainLooper().getThread()) { + UiThreadHandler.post(() -> { + speakMultiLangTTSWithLevel(ttsEntity, level); + }, QUEUE); + } else { + speakMultiLangTTSWithLevel(ttsEntity, level); + } } private void speakMultiLangTTSWithLevel(MultiLangTtsEntity ttsEntity,int ttsLevel) {