[V2X]优化V2X弹窗语音加载逻辑
This commit is contained in:
@@ -1,18 +1,26 @@
|
||||
package com.mogo.eagle.core.function.hmi.ui
|
||||
|
||||
import android.animation.Animator
|
||||
import android.content.*
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.*
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.transition.*
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.view.WindowManager.LayoutParams
|
||||
import android.view.animation.*
|
||||
import android.widget.*
|
||||
import androidx.core.view.*
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.mogo.commons.mvp.MvpFragment
|
||||
import com.mogo.commons.voice.AIAssist
|
||||
import com.mogo.commons.voice.*
|
||||
import com.mogo.eagle.core.data.bindingcar.AdUpgradeStateHelper
|
||||
import com.mogo.eagle.core.data.bindingcar.IPCUpgradeStateInfo
|
||||
import com.mogo.eagle.core.data.camera.CameraEntity
|
||||
@@ -27,6 +35,7 @@ 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.IMoGoHmiViewProxy.IViewNotificationProvider
|
||||
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
|
||||
@@ -55,14 +64,19 @@ import com.mogo.eagle.core.function.hmi.ui.setting.ReportListFloatWindow
|
||||
import com.mogo.eagle.core.function.hmi.ui.tools.AdUpgradeDialog
|
||||
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.kotlin.*
|
||||
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.*
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_HMI
|
||||
import com.mogo.eagle.core.utilcode.reminder.*
|
||||
import com.mogo.eagle.core.utilcode.reminder.api.*
|
||||
import com.mogo.eagle.core.utilcode.reminder.api.IReminder.IStateChangeListener
|
||||
import com.mogo.eagle.core.utilcode.reminder.api.impl.*
|
||||
import com.mogo.eagle.core.utilcode.util.SoundUtils
|
||||
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 com.mogo.module.common.enums.*
|
||||
import kotlinx.android.synthetic.main.fragment_hmi.*
|
||||
import kotlinx.coroutines.*
|
||||
import mogo_msg.MogoReportMsg
|
||||
@@ -82,15 +96,13 @@ import kotlin.collections.ArrayList
|
||||
IMoGoHmiViewProxy,
|
||||
MoGoHmiContract.View,
|
||||
IMoGoAutopilotRecordListener,
|
||||
IMoGoAutopilotStatusListener {
|
||||
IMoGoAutopilotStatusListener, IViewNotificationProvider {
|
||||
private val TAG = "MoGoHmiFragment"
|
||||
|
||||
// DebugSettingView
|
||||
private var mDebugSettingViewFloat: WarningFloat.Builder? = null
|
||||
private var mDebugSettingView: DebugSettingView? = null
|
||||
|
||||
// V2X、OBU、云端推送,预警弹窗
|
||||
private var mWarningFloat: WarningFloat.Builder? = null
|
||||
|
||||
private var mNoticeFloat: WarningFloat.Builder? = null
|
||||
|
||||
@@ -113,7 +125,7 @@ import kotlin.collections.ArrayList
|
||||
private var mViewLimitingVelocity: IViewLimitingVelocity? = null
|
||||
|
||||
// V2X预警弹窗 View 代理
|
||||
private var mViewNotification: IViewNotification? = null
|
||||
private var mViewNotificationProvider: IViewNotificationProvider? = null
|
||||
|
||||
//工控机节点上报列表
|
||||
private var reportList = arrayListOf<ReportEntity>()
|
||||
@@ -123,6 +135,8 @@ import kotlin.collections.ArrayList
|
||||
|
||||
private var adUpgradeDialog: AdUpgradeDialog?=null
|
||||
|
||||
private var speakJob: Job? = null
|
||||
|
||||
override fun vipIdentification(visible: Boolean) {
|
||||
ThreadUtils.runOnUiThread {
|
||||
if (visible) {
|
||||
@@ -174,7 +188,7 @@ import kotlin.collections.ArrayList
|
||||
// 首次初始化使用默认视图
|
||||
setProxyTrafficLightView(viewTrafficLightVr)
|
||||
setProxyLimitingSpeedView(viewLimitingVelocity)
|
||||
setProxyNotificationView(V2XNotificationView(view.context))
|
||||
setViewNotificationProvider(this)
|
||||
|
||||
context?.also {
|
||||
if (!AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)) {
|
||||
@@ -183,7 +197,8 @@ import kotlin.collections.ArrayList
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun getNotificationView(): IViewNotification? = context?.let { V2XNotificationView(it) }
|
||||
|
||||
override fun onAutopilotRecordResult(recordPanel: RecordPanelOuterClass.RecordPanel) {
|
||||
if (HmiBuildConfig.isShowBadCaseView && recordPanel.type == 1 && recordPanel.stat == 100) {
|
||||
CallerDevaToolsManager.onReceiveBadCaseRecord(recordPanel)
|
||||
@@ -256,11 +271,8 @@ import kotlin.collections.ArrayList
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 V2X 通知 代理View
|
||||
*/
|
||||
override fun setProxyNotificationView(view: IViewNotification) {
|
||||
mViewNotification = view
|
||||
override fun setViewNotificationProvider(provider: IViewNotificationProvider) {
|
||||
mViewNotificationProvider = provider
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,88 +537,97 @@ import kotlin.collections.ArrayList
|
||||
alertContent: CharSequence?,
|
||||
ttsContent: String?,
|
||||
tag: String?,
|
||||
listenerIMoGo: IMoGoWarningStatusListener?,
|
||||
listener: IMoGoWarningStatusListener?,
|
||||
playTts: Boolean,
|
||||
expireTime: Long
|
||||
) {
|
||||
val playTTS = playTts && !AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode)
|
||||
lifecycleScope.launchWhenResumed {
|
||||
activity?.let {
|
||||
val floatWindow = mWarningFloat
|
||||
val showTag = floatWindow?.config?.floatTag
|
||||
if (floatWindow == null || TextUtils.isEmpty(showTag) || !floatWindow.isShow() || floatWindow.config.floatTag != tag) {
|
||||
// 代理View初始化了才可以弹窗
|
||||
mViewNotification?.let { notificationView ->
|
||||
notificationView.setWarningIcon(EventTypeEnum.getWarningIcon(v2xType))
|
||||
val warningContent = alertContent
|
||||
?: EventTypeEnum.getWarningContent(v2xType)
|
||||
if (warningContent.isEmpty()) {
|
||||
CallerLogger.e("$M_HMI$TAG", "Show warningContent is null or empty!")
|
||||
return@launchWhenResumed
|
||||
} else {
|
||||
notificationView.setWarningContent(warningContent)
|
||||
}
|
||||
if (floatWindow != null && floatWindow.isShow()) {
|
||||
showWarning(WarningDirectionEnum.ALERT_WARNING_NON)
|
||||
WarningFloat.dismiss(floatWindow.config.floatTag, true)
|
||||
}
|
||||
mWarningFloat = WarningFloat.with(it)
|
||||
.setTag(tag)
|
||||
.setLayout(notificationView)
|
||||
.setSidePattern(notificationView.sidePattern)
|
||||
.setCountDownTime(expireTime)
|
||||
.setGravity(notificationView.layoutGravity, offsetX = notificationView.offsetX, offsetY = notificationView.offsetY)
|
||||
.setImmersionStatusBar(true)
|
||||
.isEnqueue(true)
|
||||
.addWarningStatusListener(listenerIMoGo)
|
||||
.addWarningStatusListener(object : IMoGoWarningStatusListener {
|
||||
override fun onShow() {
|
||||
// 创建弹窗成功才进行TTS播报
|
||||
CallerLogger.d(
|
||||
"$M_HMI$TAG",
|
||||
"mWarningFloat = $mWarningFloat---ttsContent = $ttsContent"
|
||||
)
|
||||
if (mWarningFloat != null && !TextUtils.isEmpty(ttsContent) && playTTS) {
|
||||
CallerLogger.d("$M_HMI$TAG", "---> ttsContent = $ttsContent")
|
||||
AIAssist.getInstance(activity)
|
||||
.speakTTSVoice(ttsContent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismiss() {
|
||||
showWarning(WarningDirectionEnum.ALERT_WARNING_NON)
|
||||
}
|
||||
})
|
||||
.setAnimator(object : DefaultAnimator() {
|
||||
override fun enterAnim(
|
||||
view: View,
|
||||
params: LayoutParams,
|
||||
windowManager: WindowManager,
|
||||
sidePattern: SidePattern
|
||||
): Animator? =
|
||||
super.enterAnim(view, params, windowManager, sidePattern)?.apply {
|
||||
interpolator = OvershootInterpolator()
|
||||
}
|
||||
|
||||
override fun exitAnim(
|
||||
view: View,
|
||||
params: LayoutParams,
|
||||
windowManager: WindowManager,
|
||||
sidePattern: SidePattern
|
||||
): Animator? =
|
||||
super.exitAnim(view, params, windowManager, sidePattern)
|
||||
?.setDuration(200)
|
||||
})
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
val notification = floatWindow.config.layoutView as? V2XNotificationView
|
||||
if (alertContent?.isNotEmpty() == true) {
|
||||
notification?.setWarningContent(alertContent)
|
||||
floatWindow.resetExpireTime(expireTime)
|
||||
activity?.let {
|
||||
val warningContent = alertContent
|
||||
?: EventTypeEnum.getWarningContent(v2xType)
|
||||
if (warningContent.isEmpty()) {
|
||||
CallerLogger.e("$M_HMI$TAG", "Show warningContent is null or empty!")
|
||||
return
|
||||
}
|
||||
speakJob?.safeCancel()
|
||||
val content = mViewNotificationProvider?.getNotificationView() ?: return
|
||||
content.setWarningIcon(EventTypeEnum.getWarningIcon(v2xType))
|
||||
content.setWarningContent(warningContent)
|
||||
var reminder: IReminder? = null
|
||||
Reminder.enqueue(this@MoGoHmiFragment, object : PopupWindowReminder(PopupWindow(content, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).also { itx ->
|
||||
itx.isTouchable = false
|
||||
itx.isFocusable = false
|
||||
itx.isClippingEnabled = false
|
||||
itx.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
val transition = Slide(Gravity.TOP).also { t ->
|
||||
t.interpolator = AccelerateDecelerateInterpolator()
|
||||
t.duration = 200
|
||||
}
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||
itx.enterTransition = transition
|
||||
itx.exitTransition = transition
|
||||
}
|
||||
}) {
|
||||
override fun show() {
|
||||
val parent = it.window.decorView
|
||||
parent.doOnAttach {
|
||||
popupWindow.showAtLocation(parent, Gravity.TOP, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isOverride(): Boolean {
|
||||
return true
|
||||
}
|
||||
}.also { itx -> reminder = itx }, object : IStateChangeListener {
|
||||
|
||||
override fun onShow(reminder: IReminder) {
|
||||
listener?.onShow()
|
||||
if (ttsContent != null && !TextUtils.isEmpty(ttsContent) && playTTS) {
|
||||
CallerLogger.d("$M_HMI$TAG", "---> ttsContent = $ttsContent")
|
||||
lifecycleScope.launch {
|
||||
speak(it, ttsContent)
|
||||
}.also {
|
||||
speakJob = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHide(reminder: IReminder) {
|
||||
listener?.onDismiss()
|
||||
showWarning(WarningDirectionEnum.ALERT_WARNING_NON)
|
||||
}
|
||||
})
|
||||
|
||||
if (reminder == null) {
|
||||
return
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
delay(expireTime)
|
||||
reminder?.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun speak(ctx: Context, text: String) = suspendCancellableCoroutine<Unit> {
|
||||
try {
|
||||
val voiceCallback = object : IMogoVoiceCmdCallBack {
|
||||
override fun onSpeakEnd(speakText: String?) {
|
||||
super.onSpeakEnd(speakText)
|
||||
it.resumeWith(Result.success(Unit))
|
||||
}
|
||||
|
||||
override fun onSpeakError(speakText: String?, errorMsg: String?) {
|
||||
super.onSpeakError(speakText, errorMsg)
|
||||
it.resumeWith(Result.success(Unit))
|
||||
}
|
||||
}
|
||||
it.invokeOnCancellation {
|
||||
AIAssist.getInstance(ctx).stopSpeakTts(text)
|
||||
}
|
||||
AIAssist.getInstance(ctx).speakTTSVoice(text, voiceCallback)
|
||||
} catch (t: Throwable) {
|
||||
it.resumeWith(Result.success(Unit))
|
||||
Logger.e(TAG, t.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ class V2XNotificationView @JvmOverloads constructor(
|
||||
sidePattern = SidePattern.RESULT_TOP
|
||||
layoutGravity = Gravity.CENTER_HORIZONTAL
|
||||
// 设置View的停留位置
|
||||
offsetX = 0
|
||||
offsetY = 110
|
||||
setPadding(0, 110, 0, 0)
|
||||
}
|
||||
|
||||
override fun setWarningIcon(@DrawableRes warningIcon: Int) {
|
||||
|
||||
@@ -63,6 +63,16 @@ public class TestPanelBroadcastReceiver extends BroadcastReceiver {
|
||||
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
|
||||
// 存储本地,出行动态作展示
|
||||
saveLocalStory(V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING,
|
||||
v2XMessageEntity.getContent().getNoveltyInfo());
|
||||
} if (sceneType == 2) {// 触发AI道路施工事件
|
||||
V2XMessageEntity<V2XRoadEventEntity> v2XMessageEntity =
|
||||
TestOnLineCarUtils.getV2XScenarioAIRoadEventData();
|
||||
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
|
||||
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
|
||||
// 存储本地,出行动态作展示
|
||||
saveLocalStory(V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING,
|
||||
v2XMessageEntity.getContent().getNoveltyInfo());
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.mogo.eagle.core.function.v2x.events.utils;
|
||||
|
||||
import static com.mogo.module.common.entity.V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING;
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.function.v2x.R;
|
||||
import com.mogo.eagle.core.function.v2x.events.entity.net.V2XOptimalRouteDataRes;
|
||||
@@ -7,10 +9,12 @@ import com.mogo.eagle.core.function.v2x.events.entity.net.V2XSpecialCarRes;
|
||||
import com.mogo.eagle.core.network.utils.GsonUtil;
|
||||
import com.mogo.eagle.core.utilcode.util.Utils;
|
||||
import com.mogo.module.common.entity.MarkerExploreWay;
|
||||
import com.mogo.module.common.entity.MarkerLocation;
|
||||
import com.mogo.module.common.entity.MarkerResponse;
|
||||
import com.mogo.module.common.entity.V2XMessageEntity;
|
||||
import com.mogo.module.common.entity.V2XRoadEventEntity;
|
||||
import com.mogo.module.common.entity.V2XWarningEntity;
|
||||
import com.mogo.v2x.event.V2XEvent;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
@@ -80,7 +84,7 @@ public class TestOnLineCarUtils {
|
||||
|
||||
V2XMessageEntity<V2XRoadEventEntity> v2xMessageEntity = new V2XMessageEntity<>();
|
||||
// 控制类型
|
||||
v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING);
|
||||
v2xMessageEntity.setType(ALERT_ROAD_WARNING);
|
||||
// 设置数据
|
||||
v2xMessageEntity.setContent(v2xRoadEventEntity);
|
||||
// 控制展示状态
|
||||
@@ -92,7 +96,22 @@ public class TestOnLineCarUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 模拟道路事件测试数据
|
||||
*/
|
||||
public static V2XMessageEntity<V2XRoadEventEntity> getV2XScenarioAIRoadEventData() {
|
||||
V2XRoadEventEntity entity = new V2XRoadEventEntity();
|
||||
entity.setLocation(new MarkerLocation());
|
||||
entity.setShowEventButton(false);
|
||||
entity.setPoiType("100061");
|
||||
entity.setExpireTime(20000);
|
||||
V2XMessageEntity<V2XRoadEventEntity> body = new V2XMessageEntity<>();
|
||||
body.setOnlyShow(false);
|
||||
body.setShowState(true);
|
||||
body.setContent(entity);
|
||||
body.setType(ALERT_ROAD_WARNING);
|
||||
return body;
|
||||
}
|
||||
/**
|
||||
* 模拟道路事件UGC测试数据
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user