From 1a262230caec9ad91261d03d52f553206021290a Mon Sep 17 00:00:00 2001 From: renwj Date: Thu, 17 Mar 2022 19:47:54 +0800 Subject: [PATCH] =?UTF-8?q?[VisualAngle]=E5=9C=B0=E5=9B=BE=E8=A7=86?= =?UTF-8?q?=E8=A7=92=E5=88=87=E6=8D=A2=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmi/ui/turnlight/TurnLightViewStatus.kt | 15 ++ .../function/v2x/events/V2XEventManager.kt | 17 +- .../scene/road/V2XRoadEventScenario.java | 3 + .../call/map/CallerVisualAngleManager.kt | 220 ++++++++++++++++++ .../eagle/core/utilcode/kotlin/Extensions.kt | 1 + gradle.properties | 2 +- 6 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/map/CallerVisualAngleManager.kt diff --git a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/turnlight/TurnLightViewStatus.kt b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/turnlight/TurnLightViewStatus.kt index f71a762d9d..222aad6344 100644 --- a/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/turnlight/TurnLightViewStatus.kt +++ b/core/function-impl/mogo-core-function-hmi/src/main/java/com/mogo/eagle/core/function/hmi/ui/turnlight/TurnLightViewStatus.kt @@ -9,6 +9,9 @@ import android.view.animation.Animation import android.view.animation.LinearInterpolator import android.widget.ImageView import androidx.constraintlayout.widget.ConstraintLayout +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.Default +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.Turning import com.mogo.eagle.core.function.hmi.R import kotlinx.android.synthetic.main.view_turn_light_status.view.* import kotlinx.coroutines.Dispatchers @@ -35,6 +38,9 @@ class TurnLightViewStatus @JvmOverloads constructor( private var isRightLight :Boolean = false private var isDisappare :Boolean = false + @Volatile + private var isVisualAngleChanged = false + /** * 转向灯动画 */ @@ -46,6 +52,13 @@ class TurnLightViewStatus @JvmOverloads constructor( isShowNormalBg = true } + if (directionLight == 1 || directionLight == 2) { + if (!isVisualAngleChanged) { + isVisualAngleChanged = true + CallerVisualAngleManager.changeVisualAngle(Turning) + } + } + //根据左右进行显示和隐藏,实际要判断每个来的时间和频度 if (directionLight == 1) { //左转向 if (!isLeftLight) { @@ -73,6 +86,8 @@ class TurnLightViewStatus @JvmOverloads constructor( } } else { //消失 + CallerVisualAngleManager.changeVisualAngle(Default()) + isVisualAngleChanged = false if (!isDisappare) { GlobalScope.launch(Dispatchers.Main) { animationDisappear() diff --git a/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/V2XEventManager.kt b/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/V2XEventManager.kt index ee1b7f442c..f226543685 100644 --- a/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/V2XEventManager.kt +++ b/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/V2XEventManager.kt @@ -6,6 +6,7 @@ import android.content.IntentFilter import android.os.Handler import android.os.Looper import android.provider.Settings.System +import android.util.Log import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.mogo.cloud.passport.IMoGoTokenCallback import com.mogo.cloud.passport.MoGoAiCloudClient @@ -22,6 +23,9 @@ import com.mogo.eagle.core.function.call.hmi.CallerHmiManager import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger import com.mogo.eagle.core.function.call.map.CallerMapLocationListenerManager import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.Default +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.TooClose import com.mogo.eagle.core.function.v2x.events.alarm.V2XAlarmServer import com.mogo.eagle.core.function.v2x.events.bridge.BridgeApi import com.mogo.eagle.core.function.v2x.events.bridge.BridgeApi.context @@ -487,6 +491,7 @@ object V2XEventManager : IMoGoMapLocationListener, IMoGoTokenCallback, IV2XCallb scope.launch { val message = event.data val trafficData = buildTrafficData(message) + var changeVisualAngle = false when (message.status) { 1 -> { var tts = "" @@ -507,12 +512,14 @@ object V2XEventManager : IMoGoMapLocationListener, IMoGoTokenCallback, IV2XCallb } 1003 -> { // 交叉路口碰撞预警 + changeVisualAngle = true appId = EventTypeEnum.TYPE_USECASE_ID_ICW.poiType.toInt() tts = EventTypeEnum.TYPE_USECASE_ID_ICW.tts content = EventTypeEnum.TYPE_USECASE_ID_ICW.content } 1004 -> { // 交叉路口碰撞预警 + changeVisualAngle = true appId = EventTypeEnum.TYPE_USECASE_ID_BSW.poiType.toInt() tts = String.format(EventTypeEnum.TYPE_USECASE_ID_BSW.tts, getWarningDirection()) content = EventTypeEnum.TYPE_USECASE_ID_BSW.content @@ -544,8 +551,16 @@ object V2XEventManager : IMoGoMapLocationListener, IMoGoTokenCallback, IV2XCallb } // 显示弹框,语音提示 CallerHmiManager.showWarningV2X(appId, content, tts, "$appId", object : IMoGoWarningStatusListener { - override fun onShow() {} + val change = changeVisualAngle + override fun onShow() { + if (change) { + CallerVisualAngleManager.changeVisualAngle(TooClose) + } + } override fun onDismiss() { + if (change) { + CallerVisualAngleManager.changeVisualAngle(Default()) + } } }, true, 5000L) TrafficMarkerDrawer.updateITrafficInfo(trafficData) diff --git a/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/scenario/scene/road/V2XRoadEventScenario.java b/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/scenario/scene/road/V2XRoadEventScenario.java index 6ee3249755..ed566537b0 100644 --- a/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/scenario/scene/road/V2XRoadEventScenario.java +++ b/core/function-impl/mogo-core-function-v2x/src/main/java/com/mogo/eagle/core/function/v2x/events/scenario/scene/road/V2XRoadEventScenario.java @@ -5,6 +5,7 @@ import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X import com.mogo.eagle.core.data.enums.WarningDirectionEnum; import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener; import com.mogo.eagle.core.function.call.hmi.CallerHmiManager; +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager; import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; import com.mogo.eagle.core.function.v2x.events.bridge.BridgeApi; import com.mogo.eagle.core.function.v2x.events.consts.V2XConst; @@ -117,6 +118,7 @@ public class V2XRoadEventScenario extends AbsV2XScenario imp @Override public void onShow() { + CallerVisualAngleManager.INSTANCE.changeVisualAngle(CallerVisualAngleManager.Scene.RoadEvent.INSTANCE); CallerHmiManager.INSTANCE.showWarning(WarningDirectionEnum.ALERT_WARNING_TOP, TimeUnit.HOURS.toMillis(1)); V2XMessageEntity entity = getV2XMessageEntity(); if (entity != null && entity.isNeedAddLine()) { @@ -127,6 +129,7 @@ public class V2XRoadEventScenario extends AbsV2XScenario imp @Override public void onDismiss() { CallerHmiManager.INSTANCE.dismissWarning(WarningDirectionEnum.ALERT_WARNING_TOP); + CallerVisualAngleManager.INSTANCE.changeVisualAngle(new CallerVisualAngleManager.Scene.Default(3, TimeUnit.SECONDS)); clearPOI(); release(); } diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/map/CallerVisualAngleManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/map/CallerVisualAngleManager.kt new file mode 100644 index 0000000000..e179dd7966 --- /dev/null +++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/map/CallerVisualAngleManager.kt @@ -0,0 +1,220 @@ +package com.mogo.eagle.core.function.call.map + +import android.os.Handler +import android.os.Looper +import android.os.SystemClock +import android.util.Log +import com.mogo.eagle.core.data.map.MogoLatLng +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.Default +import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager.Scene.LowSpeed +import com.mogo.eagle.core.utilcode.kotlin.safeCancel +import com.mogo.map.uicontroller.VisualAngleMode +import kotlinx.coroutines.* +import kotlinx.coroutines.android.asCoroutineDispatcher +import kotlinx.coroutines.internal.synchronized +import java.util.* +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeUnit.SECONDS + +/** + * 高精地图视角管理类 + */ +object CallerVisualAngleManager { + + private const val TAG = "VisualAngle" + + private const val MaxDisplayThreshold = 20_000 //最大展示阈值 + + private var scope: CoroutineScope = acquireScope() + @Synchronized + get() { + if (field.isActive) { + return field + } + val scope = acquireScope() + field = scope + return field + } + + private var defaultDelayJob: Job? = null + + private fun acquireScope(): CoroutineScope { + return CoroutineScope(Handler(Looper.getMainLooper()).asCoroutineDispatcher("change-visual-angle") + SupervisorJob()) + } + + private interface IAttach { + val angle: VisualAngleMode + val priority: Int + } + + sealed class Scene private constructor(): IAttach { + + /** + * 默认视图 + * @param delay: 表示多少稍后,默认值为2 + * @param unit: 时间单位,默认为秒 + */ + class Default(val delay: Long = 2, val unit: TimeUnit = SECONDS): Scene() { + + override val angle: VisualAngleMode = VisualAngleMode.MODE_MEDIUM_SIGHT + + override val priority: Int = 0 + + override fun toString(): String { + return "Default(delay=$delay, unit=$unit, angle=$angle, priority=$priority)" + } + } + + /** + * 变道-接收到转向灯信息号 + */ + object Turning: Scene() { + + override val angle: VisualAngleMode = VisualAngleMode.MAP_STYLE_VR_ANGLE_TOP + + override val priority: Int = 0 + } + + /** + * 后方车辆离自车过近 + */ + object TooClose: Scene() { + + override val angle: VisualAngleMode = VisualAngleMode.MAP_STYLE_VR_ANGLE_300 + + override val priority: Int = 0 + } + + /** + * 道路事件 + */ + object RoadEvent: Scene() { + + override val angle: VisualAngleMode = VisualAngleMode.MODE_LONG_SIGHT + + override val priority: Int = 0 + } + + /** + * 车量低速行驶 + */ + class LowSpeed(val lat: Double, val lon: Double): Scene() { + + override val angle: VisualAngleMode = VisualAngleMode.MODE_CLOSE_SIGHT + + override val priority: Int = 0 + + override fun toString(): String { + return "LowSpeed(lat=$lat, lon=$lon, angle=$angle, priority=$priority)" + } + } + + /** + * 十字路口 + */ + object CrossRoad: Scene() { + override val angle: VisualAngleMode = VisualAngleMode.MAP_STYLE_VR_ANGLE_CROSS + override val priority: Int = 0 + } + } + + + /** + * 业务实体,不对外暴露 + * @param target: 目标场景 + * @param isDisplay: 是否正在展示 + * @param triggerTime: 触发时间 + */ + private data class Record(val target: Scene, var isDisplay: Boolean = false, val triggerTime: Long): Comparable { + override fun compareTo(other: Record): Int { + //大根堆 + if (triggerTime != other.triggerTime) { + //时间越晚,越靠近堆顶 + return if (triggerTime > other.triggerTime) -1 else 1 + } + //如果时间一样,优先级越高,越靠近堆顶 + return other.target.priority - target.priority + } + } + + private val heap by lazy { + /** + * 堆, 大根堆还是小根堆由[Record.compareTo]方法决定 + */ + PriorityQueue() + } + + @OptIn(InternalCoroutinesApi::class) + fun changeVisualAngle(scene: Scene) { + val triggerTime = SystemClock.elapsedRealtime() + scope.launch { + val displayed = getDisplayed() + if (displayed == null) { + val top = getTop() //堆顶 + if (top != null && top.target.priority > scene.priority) { + doChangeAngle(top) + synchronized(heap) { + heap += Record(scene, triggerTime = triggerTime) + } + } else { + doChangeAngle(Record(scene, triggerTime = triggerTime)) + } + Log.d(TAG, "没有正在展示的视角,当前要展示的视角: $scene") + } else { + if (scene.javaClass == displayed.javaClass) { + Log.d(TAG, "同一种场景不需要重复展示") + return@launch + } + if (scene is Default) { + Log.d(TAG, "恢复到默认视图,之前展示的视图:$displayed") + synchronized(heap) { + heap -= displayed + } + launch { + val delay = scene.unit.toMillis(scene.delay) + Log.d(TAG, "默认视图开启延时倒计时, 倒计时时间:${delay} ms.") + delay(delay) + Log.d(TAG, "默认视图结束倒计时,开始展示...") + doChangeAngle(Record(scene, triggerTime = triggerTime)) + }.also { defaultDelayJob = it } + } else { + val delta = triggerTime - displayed.triggerTime + if (delta >= MaxDisplayThreshold) { + Log.d(TAG, "场景: $scene 触发展示,满足条件开始展示...") + doChangeAngle(Record(scene, triggerTime = triggerTime)) + } else { + Log.d(TAG, "场景: $scene 触发展示,但是在20s内,丢弃...") + } + } + } + } + } + + @OptIn(InternalCoroutinesApi::class) + private fun doChangeAngle(record: Record) { + CallerMapUIServiceManager.getMapUIController()?.also { + record.isDisplay = true + synchronized(heap) { + heap += record + } + val target = record.target + if (target !is Default) { + defaultDelayJob?.safeCancel() + } + if (target is LowSpeed) { + it.changeMapVisualAngle(record.target.angle, MogoLatLng(target.lat, target.lon)) + } else { + it.changeMapVisualAngle(record.target.angle, null) + } + } + } + + /** + * 是否有正在展示的 + */ + @Synchronized + private fun getDisplayed() = heap.find { it.isDisplay } + + @Synchronized + private fun getTop() = heap.firstOrNull() +} \ No newline at end of file diff --git a/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/kotlin/Extensions.kt b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/kotlin/Extensions.kt index 69d5b1209c..9e17dc7e6a 100644 --- a/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/kotlin/Extensions.kt +++ b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/kotlin/Extensions.kt @@ -305,3 +305,4 @@ fun Context.toast(text: CharSequence, duration: Long = 2, unit: TimeUnit = SECON Reminder.enqueue(activity.lifeCycleOwner, reminder) } } + diff --git a/gradle.properties b/gradle.properties index 0425450858..4541faa64b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -82,7 +82,7 @@ MOGO_LOCATION_VERSION=1.3.31 MOGO_TELEMATIC_VERSION=1.3.31 ######## MogoAiCloudSDK Version ######## # 自研地图 -MAP_SDK_VERSION=2.0.5.7 +MAP_SDK_VERSION=2.0.9.1 MAP_SDK_OPERATION_VERSION=1.0.12 # websocket WEBSOCKET_VERSION=1.1.7