[merge2master]
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.eagle.core.function.biz">
|
||||
<application>
|
||||
<receiver android:name="com.mogo.eagle.function.biz.v2x.v2n.test.TestV2XReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.v2x.test_panel_control" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.mogo.eagle.function.biz
|
||||
|
||||
import android.content.Context
|
||||
import com.alibaba.android.arouter.facade.annotation.Route
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.eagle.core.data.biz.camera.CameraEntity
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.data.constants.MogoServicePaths
|
||||
import com.mogo.eagle.core.function.api.biz.IMoGoFuncBizProvider
|
||||
import com.mogo.eagle.core.function.api.biz.IMoGoNoticeNetCallBack
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.function.biz.dispatch.DispatchAutoPilotManager.Companion.dispatchAutoPilotManager
|
||||
import com.mogo.eagle.function.biz.monitoring.CronTaskManager.Companion.cronTaskManager
|
||||
import com.mogo.eagle.function.biz.notice.NoticeSocketManager.Companion.noticeSocketManager
|
||||
import com.mogo.eagle.function.biz.notice.network.NoticeNetWorkManager
|
||||
import com.mogo.eagle.function.biz.v2x.obu.V2xObuEventManager
|
||||
import com.mogo.eagle.function.biz.v2x.overview.OverViewDataManager
|
||||
import com.mogo.eagle.function.biz.v2x.overview.db.OverviewDb
|
||||
import com.mogo.eagle.function.biz.v2x.road.LineUploadManager
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.core.MogoTrafficLightManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.V2XEventManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.V2XPoiLoader.Companion.v2xPoiLoader
|
||||
import com.mogo.eagle.function.biz.v2x.vip.VipCarManager
|
||||
|
||||
@Route(path = MogoServicePaths.PATH_FUNC_BIZ)
|
||||
class FuncBizProvider : IMoGoFuncBizProvider {
|
||||
|
||||
override val functionName: String
|
||||
get() = "FuncBiz"
|
||||
|
||||
private var mContext:Context? = null
|
||||
|
||||
override fun init(context: Context) {
|
||||
mContext = context
|
||||
noticeSocketManager.init(context)
|
||||
dispatchAutoPilotManager.init(context)
|
||||
cronTaskManager.startCronTask()
|
||||
OverviewDb.getDb(context)
|
||||
MogoTrafficLightManager.INSTANCE.initServer(context)
|
||||
VipCarManager.INSTANCE.initServer(context)
|
||||
if(!(AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode)
|
||||
&& AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode))){
|
||||
V2XEventManager.init(context)
|
||||
}
|
||||
|
||||
if(AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)){
|
||||
LineUploadManager.getInstance(context)?.init()
|
||||
}
|
||||
V2xObuEventManager.init(context)
|
||||
// RedLightWarningManager.INSTANCE.listenTrafficLight()
|
||||
}
|
||||
|
||||
override fun feedBackNoticeTraffic(infoId: String, sn: String, accept: Int) {
|
||||
NoticeNetWorkManager.getInstance().sendAccidentAcceptStatus(infoId, sn, accept)
|
||||
}
|
||||
|
||||
override fun requestAccidentInfo(infoId: String, sn: String, callBack: IMoGoNoticeNetCallBack) {
|
||||
NoticeNetWorkManager.getInstance().requestAccidentInfo(infoId, sn, callBack)
|
||||
}
|
||||
|
||||
override fun dispatchAffirm() {
|
||||
dispatchAutoPilotManager.affirm()
|
||||
}
|
||||
|
||||
override fun dispatchCancel(manualTrigger: Boolean) {
|
||||
dispatchAutoPilotManager.cancel(manualTrigger)
|
||||
}
|
||||
|
||||
override fun testDispatch(sceneType: Int) {
|
||||
dispatchAutoPilotManager.testDispatch(sceneType)
|
||||
}
|
||||
|
||||
override val getCameraList: List<CameraEntity>
|
||||
get() = cronTaskManager.getCameraList()
|
||||
|
||||
override fun openCameraStream(cameraIp: String) {
|
||||
cronTaskManager.reqOpenCameraStream(cameraIp)
|
||||
}
|
||||
|
||||
override fun openCameraStream(cameraIp: String, success: (String) -> Unit, error: (Throwable) -> Unit) {
|
||||
cronTaskManager.reqOpenCameraStream(cameraIp, success, error)
|
||||
}
|
||||
|
||||
override fun closeCameraLive() {
|
||||
cronTaskManager.clear()
|
||||
}
|
||||
|
||||
override fun fetchInfStructures() {
|
||||
OverViewDataManager.fetchInfStructures()
|
||||
}
|
||||
|
||||
override fun getAllV2XEvents() {
|
||||
OverViewDataManager.getAllV2XEventsByLineId(MoGoAiCloudClientConfig.getInstance().sn)
|
||||
}
|
||||
|
||||
override fun queryV2XEvents() {
|
||||
v2xPoiLoader.queryWholeRoadEvents()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
noticeSocketManager.release()
|
||||
dispatchAutoPilotManager.release()
|
||||
cronTaskManager.release()
|
||||
|
||||
VipCarManager.INSTANCE.destroy()
|
||||
|
||||
if(!(AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode)
|
||||
&& AppIdentityModeUtils.isPassenger(FunctionBuildConfig.appIdentityMode))){
|
||||
V2XEventManager.onDestroy()
|
||||
}
|
||||
if(AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)){
|
||||
mContext?.let {
|
||||
LineUploadManager.getInstance(it)?.onDestroy()
|
||||
}
|
||||
}
|
||||
V2xObuEventManager.release()
|
||||
// RedLightWarningManager.INSTANCE.onDestroy()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package com.mogo.eagle.function.biz.dispatch
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import com.mogo.aicloud.services.socket.IMogoOnMessageListener
|
||||
import com.mogo.aicloud.services.socket.MogoAiCloudSocketManager
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotRouteInfo
|
||||
import com.mogo.eagle.core.data.biz.dispatch.DispatchAdasAutoPilotLocReceiverBean
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener
|
||||
import com.mogo.eagle.core.function.api.hmi.autopilot.IMoGoCheckAutoPilotBtnListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfo
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningRottingListenerManager
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiListenerManager
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.eagle.function.biz.dispatch.network.DispatchServiceModel.Companion.DISPATCH_RESULT_AFFIRM
|
||||
import com.mogo.eagle.function.biz.dispatch.network.DispatchServiceModel.Companion.DISPATCH_RESULT_MANUAL_CANCEL
|
||||
import com.mogo.eagle.function.biz.dispatch.network.DispatchServiceModel.Companion.DISPATCH_RESULT_TIMER_CANCEL
|
||||
import com.mogo.eagle.function.biz.dispatch.network.DispatchServiceModel.Companion.dispatchServiceModel
|
||||
import mogo.telematics.pad.MessagePad
|
||||
|
||||
|
||||
//负责监听自动驾驶状态并进行状态上报,自动驾驶路线上报,接收调度指令展示指令弹窗
|
||||
class DispatchAutoPilotManager private constructor() :
|
||||
IMogoOnMessageListener<DispatchAdasAutoPilotLocReceiverBean>,
|
||||
IMoGoCheckAutoPilotBtnListener,
|
||||
IMoGoPlanningRottingListener,
|
||||
IMoGoAutopilotStatusListener {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DispatchAutoPilotManager"
|
||||
|
||||
private const val MSG_SOCKET_TYPE = 501000
|
||||
private const val MSG_TYPE_SHOW_DIALOG = 0
|
||||
private const val MSG_TYPE_UPLOAD_AUTOPILOT_STATUS = 1
|
||||
private const val MSG_TYPE_UPLOAD_AUTOPILOT_ROTTING = 2
|
||||
|
||||
val dispatchAutoPilotManager by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
DispatchAutoPilotManager()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var mContext: Context? = null
|
||||
private var receiverBean: DispatchAdasAutoPilotLocReceiverBean? = null
|
||||
private var isDispatch = false
|
||||
private var isArriveEnd = false
|
||||
|
||||
private val handler: Handler = object : Handler() {
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
if (msg.what == MSG_TYPE_SHOW_DIALOG) {
|
||||
isDispatch = true
|
||||
isArriveEnd = false
|
||||
val msgData: DispatchAdasAutoPilotLocReceiverBean =
|
||||
msg.obj as DispatchAdasAutoPilotLocReceiverBean
|
||||
CallerHmiManager.showDispatchDialog(msgData)
|
||||
} else if (msg.what == MSG_TYPE_UPLOAD_AUTOPILOT_STATUS) {
|
||||
dispatchServiceModel.uploadAutopilotStatus(
|
||||
getAutoPilotStatusInfo().state,
|
||||
getAutoPilotStatusInfo().reason
|
||||
)
|
||||
sendEmptyMessageDelayed(MSG_TYPE_UPLOAD_AUTOPILOT_STATUS, 1000L)
|
||||
} else if(msg.what == MSG_TYPE_UPLOAD_AUTOPILOT_ROTTING){
|
||||
val data = msg.obj as MessagePad.GlobalPathResp
|
||||
val list: MutableList<AutopilotRouteInfo.RouteModels> = ArrayList()
|
||||
for (location in data.wayPointsList) {
|
||||
val routeModels = AutopilotRouteInfo.RouteModels()
|
||||
routeModels.lat = location.latitude
|
||||
routeModels.lon = location.longitude
|
||||
list.add(routeModels)
|
||||
}
|
||||
dispatchServiceModel.uploadAutopilotRoute(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
mContext = context
|
||||
MogoAiCloudSocketManager.getInstance(context)
|
||||
.registerOnMessageListener(MSG_SOCKET_TYPE, this)
|
||||
// 添加自动驾驶按钮选中监听
|
||||
CallerHmiListenerManager.addListener(TAG, this)
|
||||
// 添加 规划路径相关回调 监听
|
||||
CallerPlanningRottingListenerManager.addListener(TAG, this)
|
||||
// 添加 ADAS状态 监听
|
||||
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
|
||||
handler.sendEmptyMessageDelayed(MSG_TYPE_UPLOAD_AUTOPILOT_STATUS, 1000L)
|
||||
}
|
||||
|
||||
fun release() {
|
||||
// 添加自动驾驶按钮选中监听
|
||||
CallerHmiListenerManager.removeListener(TAG)
|
||||
// 添加 规划路径相关回调 监听
|
||||
CallerPlanningRottingListenerManager.removeListener(TAG)
|
||||
// 添加 ADAS状态 监听
|
||||
CallerAutoPilotStatusListenerManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
override fun target(): Class<DispatchAdasAutoPilotLocReceiverBean> {
|
||||
return DispatchAdasAutoPilotLocReceiverBean::class.java
|
||||
}
|
||||
|
||||
override fun onMsgReceived(adasAutoPilotLocReceiverBean: DispatchAdasAutoPilotLocReceiverBean?) {
|
||||
if (adasAutoPilotLocReceiverBean != null && adasAutoPilotLocReceiverBean.startLat != 0.0 && adasAutoPilotLocReceiverBean.startLon != 0.0) {
|
||||
receiverBean = adasAutoPilotLocReceiverBean
|
||||
val message = Message()
|
||||
message.what = MSG_TYPE_SHOW_DIALOG
|
||||
message.obj = adasAutoPilotLocReceiverBean
|
||||
handler.sendMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startAutoPilot() {
|
||||
val currentAutopilot = AutopilotControlParameters()
|
||||
currentAutopilot.isSpeakVoice = false
|
||||
val wayLatLon: MutableList<AutopilotControlParameters.AutoPilotLonLat> = ArrayList()
|
||||
receiverBean?.let {
|
||||
if (it.stopsList != null) {
|
||||
for (mogoLatLng in receiverBean!!.stopsList) {
|
||||
wayLatLon.add(
|
||||
AutopilotControlParameters.AutoPilotLonLat(
|
||||
mogoLatLng.lat,
|
||||
mogoLatLng.lon
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
currentAutopilot.wayLatLons = wayLatLon
|
||||
currentAutopilot.startLatLon =
|
||||
AutopilotControlParameters.AutoPilotLonLat(it.startLat, it.startLon)
|
||||
currentAutopilot.endLatLon =
|
||||
AutopilotControlParameters.AutoPilotLonLat(it.endLat, it.endLon)
|
||||
currentAutopilot.vehicleType = 10
|
||||
CallerLogger.d(SceneConstant.Companion.M_DISPATCH + TAG, "开启自动驾驶====$currentAutopilot")
|
||||
CallerAutoPilotControlManager.startAutoPilot(currentAutopilot)
|
||||
}
|
||||
}
|
||||
|
||||
fun affirm() {
|
||||
CallerHmiManager.dismissDispatchDialog()
|
||||
dispatchServiceModel.dispatchResultUpload(DISPATCH_RESULT_AFFIRM)
|
||||
}
|
||||
|
||||
fun cancel(manualTrigger: Boolean) {
|
||||
CallerHmiManager.dismissDispatchDialog()
|
||||
dispatchServiceModel.dispatchResultUpload(
|
||||
if (manualTrigger) DISPATCH_RESULT_MANUAL_CANCEL else DISPATCH_RESULT_TIMER_CANCEL
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCheck(isChecked: Boolean) {
|
||||
if (isChecked) {
|
||||
// 确保到达终点后,再次点击,不会有回馈,并且在下次调开始时,才会重置
|
||||
if (isArriveEnd) {
|
||||
return
|
||||
}
|
||||
//todo 确认是否要根据停靠时自动驾驶状态,再次开启自动驾驶
|
||||
// 确保处于调度中并且返回的自动驾驶状态为1才开启自动驾驶
|
||||
// 上述等待鄂州项目复盘后,产品输出完成方案后再进操作!!!
|
||||
if (isDispatch) {
|
||||
startAutoPilot()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotRotting(globalPathResp: MessagePad.GlobalPathResp?) {
|
||||
if (globalPathResp == null || globalPathResp.wayPointsList.isEmpty()) {
|
||||
return
|
||||
}
|
||||
val message = Message()
|
||||
message.what = MSG_TYPE_UPLOAD_AUTOPILOT_ROTTING
|
||||
message.obj = globalPathResp
|
||||
handler.sendMessage(message)
|
||||
}
|
||||
|
||||
override fun onAutopilotArriveAtStation(arrivalNotification: MessagePad.ArrivalNotification?) {
|
||||
if (!isDispatch) {
|
||||
return
|
||||
}
|
||||
if (arrivalNotification == null) {
|
||||
return
|
||||
}
|
||||
if (receiverBean == null) {
|
||||
return
|
||||
}
|
||||
|
||||
CallerLogger.d(
|
||||
SceneConstant.Companion.M_DISPATCH + TAG,
|
||||
"onArriveAt data : $arrivalNotification"
|
||||
)
|
||||
|
||||
if (arrivalNotification.endLocation == null) {
|
||||
return
|
||||
}
|
||||
val endLat: Double = arrivalNotification.endLocation.latitude
|
||||
val endLon: Double = arrivalNotification.endLocation.longitude
|
||||
// 计算是不是到了终点
|
||||
val distanceFromSelf: Float = CoordinateUtils.calculateLineDistance(
|
||||
receiverBean!!.endLon, receiverBean!!.endLat, endLon, endLat
|
||||
)
|
||||
CallerLogger.d(
|
||||
SceneConstant.Companion.M_DISPATCH + TAG,
|
||||
"onArriveAt cal distance : $distanceFromSelf"
|
||||
)
|
||||
if (distanceFromSelf < 10) {
|
||||
CallerLogger.d(SceneConstant.Companion.M_DISPATCH + TAG, "onArriveAt end location")
|
||||
isDispatch = false
|
||||
isArriveEnd = true
|
||||
}
|
||||
}
|
||||
|
||||
fun testDispatch(sceneType: Int) {
|
||||
when (sceneType) {
|
||||
0 -> testEZhouStart()
|
||||
1 -> testEZhouStop()
|
||||
2 -> testHengYangStart()
|
||||
3 -> testDispatchResultUpload()//验证自动驾驶调度上报接口
|
||||
}
|
||||
}
|
||||
|
||||
private fun testEZhouStart() {
|
||||
val adasAutoPilotLocReceiverBean =
|
||||
DispatchAdasAutoPilotLocReceiverBean(
|
||||
DispatchAdasAutoPilotLocReceiverBean.DISPATCH_SOURCE_EZHOU,
|
||||
DispatchAdasAutoPilotLocReceiverBean.DISPATCH_TYPE_START,
|
||||
"1",
|
||||
26.825571122,
|
||||
112.5762410415,
|
||||
"起点---5号跑道",
|
||||
26.825571122,
|
||||
112.5762410415,
|
||||
"终点---鄂州机场",
|
||||
"5分钟",
|
||||
"AR453航班",
|
||||
"你车需执行编号ca1098次航班的引导任务,从A区A1到B区B1",
|
||||
System.currentTimeMillis(),
|
||||
ArrayList<MogoLatLng>()
|
||||
)
|
||||
receiverBean = adasAutoPilotLocReceiverBean
|
||||
CallerHmiManager.showDispatchDialog(adasAutoPilotLocReceiverBean)
|
||||
}
|
||||
|
||||
private fun testEZhouStop() {
|
||||
val adasAutoPilotLocReceiverBean =
|
||||
DispatchAdasAutoPilotLocReceiverBean(
|
||||
DispatchAdasAutoPilotLocReceiverBean.DISPATCH_SOURCE_EZHOU,
|
||||
DispatchAdasAutoPilotLocReceiverBean.DISPATCH_TYPE_STOP,
|
||||
"1",
|
||||
0.0,
|
||||
0.0,
|
||||
"",
|
||||
0.0,
|
||||
0.0,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
System.currentTimeMillis(),
|
||||
ArrayList<MogoLatLng>()
|
||||
)
|
||||
receiverBean = adasAutoPilotLocReceiverBean
|
||||
CallerHmiManager.showDispatchDialog(adasAutoPilotLocReceiverBean)
|
||||
}
|
||||
|
||||
private fun testHengYangStart() {
|
||||
val adasAutoPilotLocReceiverBean =
|
||||
DispatchAdasAutoPilotLocReceiverBean(
|
||||
DispatchAdasAutoPilotLocReceiverBean.DISPATCH_SOURCE_HENGYANG,
|
||||
DispatchAdasAutoPilotLocReceiverBean.DISPATCH_TYPE_START,
|
||||
"2",
|
||||
26.825571122,
|
||||
112.5762410415,
|
||||
"衡阳科学城",
|
||||
26.825571122,
|
||||
112.5762410415,
|
||||
"衡阳首钢集团",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
System.currentTimeMillis(),
|
||||
ArrayList<MogoLatLng>()
|
||||
)
|
||||
receiverBean = adasAutoPilotLocReceiverBean
|
||||
CallerHmiManager.showDispatchDialog(adasAutoPilotLocReceiverBean)
|
||||
}
|
||||
|
||||
private fun testDispatchResultUpload() {
|
||||
dispatchServiceModel.dispatchResultUpload(DISPATCH_RESULT_AFFIRM)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.mogo.eagle.function.biz.dispatch.network
|
||||
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.commons.constants.HostConst
|
||||
import com.mogo.commons.context.ContextHolderUtil
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotRouteInfo.RouteModels
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotStatus
|
||||
import com.mogo.eagle.core.data.biz.dispatch.ReportDispatchResult
|
||||
import com.mogo.eagle.core.data.biz.dispatch.ReportedRoute
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.eagle.core.network.RequestOptions
|
||||
import com.mogo.eagle.core.network.SubscribeImpl
|
||||
import com.mogo.eagle.core.network.utils.GsonUtil
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.util.*
|
||||
|
||||
class DispatchServiceModel private constructor() {
|
||||
|
||||
companion object {
|
||||
|
||||
const val DISPATCH_RESULT_AFFIRM = 0
|
||||
const val DISPATCH_RESULT_MANUAL_CANCEL = 1
|
||||
const val DISPATCH_RESULT_TIMER_CANCEL = 2
|
||||
|
||||
val dispatchServiceModel by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
DispatchServiceModel()
|
||||
}
|
||||
}
|
||||
|
||||
private var mAdasApiService: IDispatchAdasApiService =
|
||||
MoGoRetrofitFactory.getInstance(HostConst.getEagleHost()).create(
|
||||
IDispatchAdasApiService::class.java
|
||||
)
|
||||
|
||||
/**
|
||||
* 上报自动驾驶状态
|
||||
*/
|
||||
fun uploadAutopilotStatus(state: Int, reason: String?) {
|
||||
val autopilotStatus = AutopilotStatus()
|
||||
autopilotStatus.action = "autopilotstate"
|
||||
val valuesBean = AutopilotStatus.ValuesBean()
|
||||
valuesBean.state = state
|
||||
valuesBean.reason = reason
|
||||
autopilotStatus.values = valuesBean
|
||||
val sn = MoGoAiCloudClientConfig.getInstance().sn
|
||||
val reportedRoute = ReportedRoute(
|
||||
sn,
|
||||
autopilotStatus.values
|
||||
)
|
||||
val map: MutableMap<String, Any> = HashMap()
|
||||
map["sn"] = sn
|
||||
map["data"] = GsonUtil.jsonFromObject(reportedRoute)
|
||||
mAdasApiService.uploadAutopilotState(map)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object :
|
||||
SubscribeImpl<BaseData>(RequestOptions.create(ContextHolderUtil.getContext())) {
|
||||
override fun onNext(o: BaseData) {
|
||||
super.onNext(o)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
}
|
||||
|
||||
override fun onSuccess(o: BaseData) {
|
||||
super.onSuccess(o)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报自动驾驶路线
|
||||
*
|
||||
* @param list 路线集合
|
||||
*/
|
||||
fun uploadAutopilotRoute(list: List<RouteModels?>?) {
|
||||
val sn = MoGoAiCloudClientConfig.getInstance().sn
|
||||
val reportedRoute = ReportedRoute(
|
||||
sn,
|
||||
GsonUtil.jsonFromObject(list)
|
||||
)
|
||||
val map: MutableMap<String, String> = HashMap()
|
||||
map["sn"] = sn
|
||||
map["data"] = GsonUtil.jsonFromObject(reportedRoute)
|
||||
mAdasApiService.uploadAutopilotRoute(map)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object :
|
||||
SubscribeImpl<BaseData>(RequestOptions.create(ContextHolderUtil.getContext())) {
|
||||
override fun onNext(o: BaseData) {
|
||||
super.onNext(o)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
}
|
||||
|
||||
override fun onSuccess(o: BaseData) {
|
||||
super.onSuccess(o)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报调度处理结果
|
||||
*
|
||||
* @param dispatchResultType int
|
||||
*/
|
||||
fun dispatchResultUpload(
|
||||
dispatchResultType: Int,
|
||||
onSuccess: ((BaseData) -> Unit)? = null,
|
||||
onError: ((String) -> Unit)? = null
|
||||
) {
|
||||
val sn = MoGoAiCloudClientConfig.getInstance().sn
|
||||
val reportDispatchResult =
|
||||
ReportDispatchResult(
|
||||
sn,
|
||||
dispatchResultType
|
||||
)
|
||||
val map: MutableMap<String, Any> = HashMap()
|
||||
map["sn"] = sn
|
||||
map["data"] = GsonUtil.jsonFromObject(reportDispatchResult)
|
||||
mAdasApiService.uploadDispatchResult(map)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object :
|
||||
SubscribeImpl<BaseData>(RequestOptions.create(ContextHolderUtil.getContext())) {
|
||||
override fun onNext(o: BaseData) {
|
||||
super.onNext(o)
|
||||
onSuccess?.invoke(o)
|
||||
}
|
||||
|
||||
override fun onError(e: Throwable) {
|
||||
super.onError(e)
|
||||
if (!e.message.isNullOrBlank()) {
|
||||
onError?.invoke(e.message!!)
|
||||
} else {
|
||||
onError?.invoke("上报失败")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSuccess(o: BaseData) {
|
||||
super.onSuccess(o)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.mogo.eagle.function.biz.dispatch.network
|
||||
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import io.reactivex.Observable
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface IDispatchAdasApiService {
|
||||
/**
|
||||
* 上报自动驾驶路径 服务于业务调度
|
||||
*
|
||||
* @param parameters map
|
||||
* @return [BaseData]
|
||||
*/
|
||||
@FormUrlEncoded
|
||||
@POST("eagle-eye-dns/dataService/autoDriver/receiveCarPreSetPath")
|
||||
fun uploadAutopilotRoute(@FieldMap parameters: Map<String, String>): Observable<BaseData>
|
||||
|
||||
/**
|
||||
* 上报自动驾驶调度处理结果 服务于业务调度
|
||||
*
|
||||
* @param parameters map
|
||||
* @return [BaseData]
|
||||
*/
|
||||
@FormUrlEncoded
|
||||
@POST("eagle-eye-dns/dataService/autoDriver/receiverDestSiteResult")
|
||||
fun uploadDispatchResult(@FieldMap parameters: MutableMap<String, Any>): Observable<BaseData>
|
||||
|
||||
/**
|
||||
* 上报自动驾驶状态 服务于业务调度
|
||||
*
|
||||
* @param parameters map
|
||||
* @return [BaseData]
|
||||
*/
|
||||
@FormUrlEncoded
|
||||
@POST("eagle-eye-dns/dataService/autoDriver/receiveAutopilotState")
|
||||
fun uploadAutopilotState(@FieldMap parameters: MutableMap<String, Any>): Observable<BaseData>
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
package com.mogo.eagle.function.biz.monitoring
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import com.mogo.commons.constants.HostConst
|
||||
import com.mogo.commons.utils.RetryWithDelay
|
||||
import com.mogo.eagle.core.data.biz.camera.CameraEntity
|
||||
import com.mogo.eagle.core.data.biz.camera.ReqLiveCarBean
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_MONITOR
|
||||
import com.mogo.eagle.function.biz.monitoring.net.ICameraListServices
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
class CronTaskManager {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "CronTaskManager"
|
||||
private const val CRON_TASK_TYPE = 1011
|
||||
|
||||
val cronTaskManager by lazy(LazyThreadSafetyMode.SYNCHRONIZED){
|
||||
CronTaskManager()
|
||||
}
|
||||
}
|
||||
|
||||
// 请求路侧摄像头
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
// 请求车侧摄像头
|
||||
private var carDisposable: Disposable? = null
|
||||
|
||||
// 开启路侧摄像头推流
|
||||
private var streamDisposable: Disposable? = null
|
||||
private var streamDisposable2: Disposable? = null
|
||||
private var cameraList: List<CameraEntity>? = null
|
||||
private var carCameraList: List<CameraEntity>? = null
|
||||
|
||||
private val cronHandler: Handler = object : Handler(Looper.getMainLooper()) {
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
CRON_TASK_TYPE -> {
|
||||
removeMessages(CRON_TASK_TYPE)
|
||||
// 路测和车侧摄像头列表分开调用
|
||||
// requestCameraList()
|
||||
requestDeviceList()
|
||||
requestCarCameraList()
|
||||
sendEmptyMessageDelayed(CRON_TASK_TYPE, 10000)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("已废弃", ReplaceWith("requestDeviceList()"), DeprecationLevel.WARNING)
|
||||
private fun requestCameraList() {
|
||||
// 衡阳可直播的摄像头有限,先写死roadId便于调试
|
||||
disposable = MoGoRetrofitFactory.getInstance(HostConst.CAMERA_STREAM_HOST)
|
||||
.create(ICameraListServices::class.java)
|
||||
.getCameraList("10849")
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { cameraListInfo ->
|
||||
cameraListInfo.result?.crossings?.flatMap { crossing ->
|
||||
crossing.cameras.filter { camera ->
|
||||
!camera.flvUrl.isNullOrEmpty()
|
||||
}.map {
|
||||
CameraEntity(
|
||||
it.flvUrl, "", it.roadName,
|
||||
it.crossingName, it.getHeadingStr(), it.ip
|
||||
)
|
||||
}
|
||||
} ?: ArrayList()
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
cameraList = it
|
||||
CallerLogger.d("$M_MONITOR$TAG", "requestCameraList返回结果为:$it")
|
||||
}, {
|
||||
it.printStackTrace()
|
||||
CallerLogger.e("$M_MONITOR$TAG", "message is:${it.message}, cause is:${it.cause}")
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求路口一定范围内的设备信息(包含:摄像头、灯)
|
||||
*/
|
||||
private fun requestDeviceList() {
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()?.let { location ->
|
||||
disposable = MoGoRetrofitFactory.getInstance(HostConst.getEagleHost())
|
||||
.create(ICameraListServices::class.java)
|
||||
.getDeviceList(location.longitude, location.latitude, 500)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { cameraListInfo ->
|
||||
cameraListInfo.result?.crossings?.flatMap { crossing ->
|
||||
crossing.cameras.filter { camera ->
|
||||
!camera.ip.isNullOrEmpty()
|
||||
}.map {
|
||||
CameraEntity(
|
||||
it.flvUrl, "", it.roadName,
|
||||
it.crossingName, it.getHeadingStr(), it.ip
|
||||
)
|
||||
}
|
||||
} ?: ArrayList()
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
cameraList = it
|
||||
// CallerLogger.d("$M_MONITOR$TAG", "requestDeviceList返回结果为:$it")
|
||||
}, {
|
||||
it.printStackTrace()
|
||||
CallerLogger.e(
|
||||
"$M_MONITOR$TAG",
|
||||
"requestDeviceList:message is:${it.message}, cause is:${it.cause}"
|
||||
)
|
||||
})
|
||||
}?: run {
|
||||
CallerLogger.e("$M_MONITOR$TAG", "CurrentLocation is null!")
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestCarCameraList() {
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()?.let { location ->
|
||||
carDisposable = MoGoRetrofitFactory.getInstance(HostConst.getEagleHost())
|
||||
.create(ICameraListServices::class.java)
|
||||
.getCarCameraList(ReqLiveCarBean(location.longitude, location.latitude))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { liveCarCameraInfo ->
|
||||
liveCarCameraInfo.result?.liveCamera?.filter { liveCarCamera ->
|
||||
!liveCarCamera.videoSn.isNullOrEmpty()
|
||||
}?.map { cameraInfo ->
|
||||
CameraEntity(
|
||||
sn = cameraInfo.videoSn,
|
||||
street = cameraInfo.street,
|
||||
township = cameraInfo.township
|
||||
)
|
||||
} ?: ArrayList()
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
carCameraList = it
|
||||
// CallerLogger.d("$M_MONITOR$TAG", "requestCarCameraList返回结果为:$it")
|
||||
}, {
|
||||
CallerLogger.e(
|
||||
"$M_MONITOR$TAG",
|
||||
"message is:${it.message}, cause is:${it.cause}"
|
||||
)
|
||||
it.printStackTrace()
|
||||
})
|
||||
} ?: run {
|
||||
CallerLogger.e("$M_MONITOR$TAG", "CurrentLocation is null!")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启从摄像头拉流
|
||||
*/
|
||||
@Deprecated("已废弃", ReplaceWith("requestDeviceList()"), DeprecationLevel.WARNING)
|
||||
fun requestOpenCamera(cameraIp: String) {
|
||||
streamDisposable?.let {
|
||||
if (!it.isDisposed) it.dispose()
|
||||
}
|
||||
streamDisposable = MoGoRetrofitFactory.getInstance(HostConst.OPEN_CAMERA_STREAM_HOST)
|
||||
.create(ICameraListServices::class.java)
|
||||
.openCameraStream(cameraIp)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
CallerLogger.d("$M_MONITOR$TAG", "openCameraStream返回结果为:$it")
|
||||
it.result?.let { streamResult ->
|
||||
if (!streamResult.flvUrl.isNullOrEmpty()) CallerHmiManager.startRoadCameraLive(
|
||||
streamResult.flvUrl!!
|
||||
)
|
||||
}
|
||||
}, {
|
||||
CallerLogger.e(
|
||||
"$M_MONITOR$TAG",
|
||||
"openCameraStream&message is:${it.message}, cause is:${it.cause}"
|
||||
)
|
||||
CallerHmiManager.showNoSignalView()
|
||||
it.printStackTrace()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开单个视频推流
|
||||
*/
|
||||
fun reqOpenCameraStream(cameraIp: String) {
|
||||
streamDisposable?.let {
|
||||
if (!it.isDisposed) it.dispose()
|
||||
}
|
||||
streamDisposable = MoGoRetrofitFactory.getInstance(HostConst.getEagleHost())
|
||||
.create(ICameraListServices::class.java)
|
||||
.reqOpenCameraStream(cameraIp)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
CallerLogger.d("$M_MONITOR$TAG", "reqOpenCameraStream返回结果为:$it")
|
||||
if (!it.flvUrl.isNullOrEmpty()) {
|
||||
CallerHmiManager.startRoadCameraLive(it.flvUrl!!)
|
||||
} else {
|
||||
CallerHmiManager.showNoSignalView()
|
||||
}
|
||||
}, {
|
||||
CallerLogger.e(
|
||||
"$M_MONITOR$TAG",
|
||||
"reqOpenCameraStream&message is:${it.message}, cause is:${it.cause}"
|
||||
)
|
||||
CallerHmiManager.showNoSignalView()
|
||||
it.printStackTrace()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 供全览模式摄像头业务使用
|
||||
*/
|
||||
fun reqOpenCameraStream(cameraIp: String, success: (String) -> Unit, error: (Throwable) -> Unit) {
|
||||
streamDisposable2?.let {
|
||||
if (!it.isDisposed) it.dispose()
|
||||
}
|
||||
streamDisposable2 = MoGoRetrofitFactory.getInstance(HostConst.getEagleHost())
|
||||
.create(ICameraListServices::class.java)
|
||||
.reqOpenCameraStreamWithRetry(cameraIp)
|
||||
.flatMap {
|
||||
if (it.code != 200 && it.code != 0) {
|
||||
Observable.error(Throwable(it.msg))
|
||||
} else {
|
||||
Observable.just(it)
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.retryWhen(RetryWithDelay())
|
||||
.subscribe({
|
||||
CallerLogger.d("$M_MONITOR$TAG", "reqOpenCameraStream返回结果为:$it")
|
||||
if (it.code == 200 || it.code == 0) {
|
||||
val flvString = it.flvUrl
|
||||
if (!flvString.isNullOrEmpty()) {
|
||||
success(flvString)
|
||||
} else {
|
||||
error(Throwable("flvUrl为空"))
|
||||
}
|
||||
} else {
|
||||
error(Throwable(it.msg))
|
||||
}
|
||||
}, {
|
||||
CallerLogger.e(
|
||||
"$M_MONITOR$TAG",
|
||||
"reqOpenCameraStream&message is:${it.message}, cause is:${it.cause}"
|
||||
)
|
||||
error(it)
|
||||
it.printStackTrace()
|
||||
})
|
||||
}
|
||||
|
||||
fun startCronTask() {
|
||||
cronHandler.sendEmptyMessageDelayed(CRON_TASK_TYPE, 0)
|
||||
}
|
||||
|
||||
fun getCameraList() = ArrayList<CameraEntity>().apply {
|
||||
cameraList?.let { addAll(it) }
|
||||
carCameraList?.let { addAll(it) }
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
streamDisposable?.let {
|
||||
if (!it.isDisposed) it.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
fun release() {
|
||||
disposable?.dispose()
|
||||
carDisposable?.dispose()
|
||||
streamDisposable?.let {
|
||||
if (!it.isDisposed) it.dispose()
|
||||
}
|
||||
streamDisposable2?.let {
|
||||
if (!it.isDisposed) it.dispose()
|
||||
}
|
||||
cronHandler.removeMessages(CRON_TASK_TYPE)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.mogo.eagle.function.biz.monitoring.net
|
||||
|
||||
import com.mogo.eagle.core.data.biz.camera.*
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import retrofit2.http.*
|
||||
|
||||
interface ICameraListServices {
|
||||
@GET("/yycp-smartTransportationAiCloud-service/eagle/device/list")
|
||||
fun getCameraList(@Query("roadId") roadId: String?): Single<CameraListInfo?>
|
||||
|
||||
@POST("eagle-eye-dns/yycp-launcherSnapshot/car/queryLiveCarByLocal")
|
||||
fun getCarCameraList(@Body reqBody: ReqLiveCarBean): Single<LiveCarCameraInfo?>
|
||||
|
||||
@GET("/openStream/{cameraIp}")
|
||||
fun openCameraStream(@Path("cameraIp") cameraIp: String): Single<CameraStreamEntity>
|
||||
|
||||
@GET("eagle-eye-dns/camera-stream/stream/camera/openStream")
|
||||
fun reqOpenCameraStream(@Query("ip") cameraIp: String): Single<OpenCameraStreamEntity>
|
||||
|
||||
@GET("eagle-eye-dns/mec-etl-server/crossing/geo/device")
|
||||
fun getDeviceList(
|
||||
@Query("lon") lon: Double, @Query("lat") lat: Double,
|
||||
@Query("radiusMeter") radiusMeter: Int
|
||||
): Single<CameraListInfo?>
|
||||
|
||||
@GET("eagle-eye-dns/camera-stream/stream/camera/openStream")
|
||||
fun reqOpenCameraStreamWithRetry(@Query("ip") cameraIp: String): Observable<OpenCameraStreamEntity>
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.mogo.eagle.function.biz.notice
|
||||
|
||||
import android.content.Context
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager.saveMsgBox
|
||||
import com.mogo.aicloud.services.socket.MogoAiCloudSocketManager
|
||||
import com.mogo.aicloud.services.socket.IMogoOnMessageListener
|
||||
import com.mogo.eagle.core.data.biz.notice.NoticeNormalData
|
||||
import java.lang.Class
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.data.msgbox.NoticeFrCloudMsg
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.biz.notice.NoticeTrafficStylePushData
|
||||
import com.mogo.eagle.core.network.utils.GsonUtil
|
||||
|
||||
/**
|
||||
* @author Jing
|
||||
* @description 云公告注册、反注册
|
||||
* @since: 10/27/21
|
||||
*/
|
||||
internal class NoticeSocketManager {
|
||||
|
||||
private var mContext: Context? = null
|
||||
|
||||
companion object {
|
||||
private const val TAG = "NoticeSocketManager"
|
||||
|
||||
val noticeSocketManager:NoticeSocketManager by lazy(LazyThreadSafetyMode.SYNCHRONIZED){
|
||||
NoticeSocketManager()
|
||||
}
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
mContext = context
|
||||
MogoAiCloudSocketManager.getInstance(context)
|
||||
.registerOnMessageListener(301001, mTrafficNoticeListener)
|
||||
MogoAiCloudSocketManager.getInstance(context)
|
||||
.registerOnMessageListener(100, mNormalNoticeListener)
|
||||
}
|
||||
|
||||
fun release() {
|
||||
MogoAiCloudSocketManager.getInstance(mContext)
|
||||
.unregisterOnMessageListener(301001, mTrafficNoticeListener)
|
||||
MogoAiCloudSocketManager.getInstance(mContext)
|
||||
.unregisterOnMessageListener(100, mNormalNoticeListener)
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通云公告
|
||||
*/
|
||||
private val mNormalNoticeListener: IMogoOnMessageListener<NoticeNormalData> =
|
||||
object : IMogoOnMessageListener<NoticeNormalData> {
|
||||
override fun target(): Class<NoticeNormalData> {
|
||||
return NoticeNormalData::class.java
|
||||
}
|
||||
|
||||
override fun onMsgReceived(obj: NoticeNormalData?) {
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
d(SceneConstant.M_NOTICE + TAG, "100-- 普通公告数据:" + GsonUtil.jsonFromObject(obj))
|
||||
val noticeFromCloudMsg = NoticeFrCloudMsg(obj, null, 0)
|
||||
saveMsgBox(MsgBoxBean(MsgBoxType.NOTICE, noticeFromCloudMsg))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 交警类型公告弹窗
|
||||
*/
|
||||
private val mTrafficNoticeListener: IMogoOnMessageListener<NoticeTrafficStylePushData> =
|
||||
object : IMogoOnMessageListener<NoticeTrafficStylePushData> {
|
||||
override fun target(): Class<NoticeTrafficStylePushData> {
|
||||
return NoticeTrafficStylePushData::class.java
|
||||
}
|
||||
|
||||
override fun onMsgReceived(obj: NoticeTrafficStylePushData?) {
|
||||
if (obj == null) {
|
||||
return
|
||||
}
|
||||
d(SceneConstant.M_NOTICE + TAG, "301001-- 交警类型公告数据:" + GsonUtil.jsonFromObject(obj))
|
||||
val noticeFromCloudMsg = NoticeFrCloudMsg(null, obj, 1)
|
||||
saveMsgBox(MsgBoxBean(MsgBoxType.NOTICE, noticeFromCloudMsg))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.mogo.eagle.function.biz.notice.network;
|
||||
|
||||
import com.mogo.eagle.core.data.BaseData;
|
||||
import com.mogo.eagle.core.data.biz.notice.NoticeNormalDetail;
|
||||
import com.mogo.eagle.core.data.biz.notice.NoticeTrafficStyleInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import okhttp3.RequestBody;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.QueryMap;
|
||||
|
||||
/**
|
||||
* @author Jing
|
||||
* @description 云公告相关的短链请求接口定义
|
||||
* @since: 10/28/21
|
||||
*/
|
||||
public interface INoticeApiService {
|
||||
/**
|
||||
* 获取道路事故详情
|
||||
*
|
||||
* @param requestBody 请求体(infoId 交警任务id)
|
||||
* @return {@link NoticeTrafficStyleInfo}
|
||||
*/
|
||||
@Headers("Content-Type:application/json;charset=UTF-8")
|
||||
@POST("eagle-eye-dns/deva/accidentInfoManage/queryMyAccidentHandleInfo/server/v1")
|
||||
Observable<NoticeTrafficStyleInfo> getAccidentInfo(@Body RequestBody requestBody);
|
||||
|
||||
/**
|
||||
* 反馈对交警事故的操作
|
||||
*
|
||||
* @param accidentParameters 请求数据(infoID事故ID;sn;status接受状态 0否 1是)
|
||||
* @return {@link BaseData}
|
||||
*/
|
||||
@GET("eagle-eye-dns/deva/accidentInfoManage/policeUpdateTroubleStatus")
|
||||
Observable<BaseData> sendAcceptStatus(@QueryMap Map<String, String> accidentParameters);
|
||||
|
||||
/**
|
||||
* 获取普通公告详情
|
||||
*
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
@GET("/deva/pc/pathAndPoi/getAnnouncementByDbId")
|
||||
Observable<NoticeNormalDetail> getNoticeDetail(@QueryMap Map<String, String> param);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.mogo.eagle.function.biz.notice.network;
|
||||
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.mogo.cloud.network.RetrofitFactory;
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClient;
|
||||
import com.mogo.commons.constants.HostConst;
|
||||
import com.mogo.eagle.core.data.BaseData;
|
||||
import com.mogo.eagle.core.data.biz.notice.NoticeNormalDetail;
|
||||
import com.mogo.eagle.core.data.biz.notice.NoticeRequest;
|
||||
import com.mogo.eagle.core.data.biz.notice.NoticeTrafficStyleInfo;
|
||||
|
||||
import com.mogo.eagle.core.function.api.biz.IMoGoNoticeNetCallBack;
|
||||
import com.mogo.eagle.core.network.utils.GsonUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.annotations.NonNull;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
/**
|
||||
* @author Jing
|
||||
* @description 云公告网络请求类
|
||||
* @since: 10/28/21
|
||||
*/
|
||||
public class NoticeNetWorkManager {
|
||||
private static volatile NoticeNetWorkManager requestNoticeManager;
|
||||
private final INoticeApiService mNoticeApiService;
|
||||
|
||||
private NoticeNetWorkManager() {
|
||||
mNoticeApiService = RetrofitFactory.INSTANCE.getInstance(HostConst.getEagleHost())
|
||||
.create(INoticeApiService.class);
|
||||
}
|
||||
|
||||
public static NoticeNetWorkManager getInstance() {
|
||||
if (requestNoticeManager == null) {
|
||||
synchronized (NoticeNetWorkManager.class) {
|
||||
if (requestNoticeManager == null) {
|
||||
requestNoticeManager = new NoticeNetWorkManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return requestNoticeManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取事故详细信息
|
||||
*
|
||||
* @param infoId 事故id
|
||||
* @param callBack 回调
|
||||
*/
|
||||
public void requestAccidentInfo(String infoId, String sn, IMoGoNoticeNetCallBack callBack) {
|
||||
NoticeRequest request = new NoticeRequest(infoId);
|
||||
RequestBody requestBody = RequestBody.create(MediaType.get("application/json;charset=UTF-8"),
|
||||
GsonUtil.jsonFromObject(request));
|
||||
mNoticeApiService.getAccidentInfo(requestBody)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<NoticeTrafficStyleInfo>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull NoticeTrafficStyleInfo noticeTrafficStyleInfo) {
|
||||
if (noticeTrafficStyleInfo.getResult().getAccidentInfo() != null) {
|
||||
callBack.callBackWithResult(noticeTrafficStyleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 反馈交警是否接受事故任务
|
||||
*
|
||||
* @param infoId 事故id
|
||||
* @param sn
|
||||
* @param status 是否接受 0否 1是
|
||||
*/
|
||||
public void sendAccidentAcceptStatus(String infoId, String sn, int status) {
|
||||
Map<String, String> map = new ArrayMap<>();
|
||||
map.put("sn", sn);
|
||||
map.put("infoId", infoId);
|
||||
map.put("status", String.valueOf(status));
|
||||
mNoticeApiService.sendAcceptStatus(map)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<BaseData>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseData baseData) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取普通公告的详情
|
||||
*
|
||||
* @param dbId
|
||||
*/
|
||||
public void getNoticeDetail(String dbId) {
|
||||
String sn = MoGoAiCloudClient.getInstance().getAiCloudClientConfig().getSn();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("sn", sn);
|
||||
map.put("infoId", dbId);
|
||||
mNoticeApiService.getNoticeDetail(map)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<NoticeNormalDetail>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull NoticeNormalDetail noticeNormalDetail) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.mogo.eagle.function.biz.v2x.obu
|
||||
|
||||
import android.content.Context
|
||||
import com.mogo.eagle.core.data.enums.DataSourceType
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.msgbox.V2XMsg
|
||||
import com.mogo.eagle.core.data.obu.MogoObuConst
|
||||
import com.mogo.eagle.core.function.api.datacenter.obu.IMoGoObuSaveMessageListener
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager
|
||||
import com.mogo.eagle.core.function.call.obu.CallerObuSaveMessageListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
|
||||
/**
|
||||
* 处理obu分发出来,在消息盒子展示的消息
|
||||
*/
|
||||
object V2xObuEventManager : IMoGoObuSaveMessageListener {
|
||||
private const val TAG = "V2xObuEventManager"
|
||||
|
||||
fun init(context: Context) {
|
||||
registerListener()
|
||||
}
|
||||
|
||||
private fun registerListener() {
|
||||
CallerObuSaveMessageListenerManager.addListener(TAG,this)
|
||||
}
|
||||
|
||||
private fun unRegisterListener() {
|
||||
CallerObuSaveMessageListenerManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
private val obuDataMap = mutableMapOf<String, Long>()
|
||||
|
||||
/**
|
||||
* @param type 事件id,类似与uuid
|
||||
* @param content 事件内容
|
||||
* @param tts 事件语音播报 //30秒内同一个事件只出现一次 TODO 临时添加,后面宏宇统一在数据中心处理
|
||||
*/
|
||||
override fun onMoGoObuSaveMessage(type: String, content: String, tts: String, source: DataSourceType) {
|
||||
if (content.isNotEmpty()) {
|
||||
if (obuDataMap.containsKey(type)) {
|
||||
var oldTime = obuDataMap[type]
|
||||
var timeDiff = (System.currentTimeMillis() - oldTime!!) / 1000
|
||||
if (timeDiff < 30) {
|
||||
return
|
||||
}
|
||||
obuDataMap.remove(type)
|
||||
obuDataMap[type] = System.currentTimeMillis()
|
||||
} else {
|
||||
obuDataMap[type] = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
CallerLogger.d("${SceneConstant.M_OBU}${TAG}", "onMoGoObuSaveMessage type = $type ---content = $content ---tts = $tts ")
|
||||
CallerMsgBoxManager.saveMsgBox(
|
||||
MsgBoxBean(
|
||||
MsgBoxType.V2X,
|
||||
V2XMsg(
|
||||
type,
|
||||
content,
|
||||
tts
|
||||
)
|
||||
).apply {
|
||||
sourceType = source
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun release() {
|
||||
unRegisterListener()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.mogo.eagle.function.biz.v2x.overview
|
||||
|
||||
import androidx.lifecycle.*
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.commons.constants.HostConst
|
||||
import com.mogo.eagle.core.data.map.Infrastructure
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.biz.CallerFuncBizListenerManager
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.function.biz.v2x.overview.db.OverviewDb
|
||||
import com.mogo.eagle.function.biz.v2x.overview.remote.OverViewServiceApi
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object OverViewDataManager {
|
||||
|
||||
private const val TAG = "OverViewDataManager"
|
||||
|
||||
private val overviewDao by lazy {
|
||||
OverviewDb.getDb(AbsMogoApplication.getApp()).overviewDao()
|
||||
}
|
||||
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
fun fetchInfStructures() {
|
||||
ProcessLifecycleOwner.get().lifecycleScope.launch {
|
||||
val data = try {
|
||||
// 只查找摄像头
|
||||
overviewDao.listInfStructures(0)
|
||||
// overviewDao.listAllInfStructures()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
data?.let { infStructures ->
|
||||
withContext(Dispatchers.Default) {
|
||||
val map = HashMap<String, ArrayList<Infrastructure>>()
|
||||
infStructures.forEach {
|
||||
val geoHash = it.geoHash
|
||||
if (geoHash == null) {
|
||||
return@forEach
|
||||
} else {
|
||||
if (!map.containsKey(geoHash)) {
|
||||
val list = ArrayList<Infrastructure>()
|
||||
list.add(it)
|
||||
map[geoHash] = list
|
||||
} else {
|
||||
map[geoHash]?.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
CallerFuncBizListenerManager.invokeInfStructures(map)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateGeoHash(id: Int, geoHash: String) {
|
||||
ProcessLifecycleOwner.get().lifecycleScope.launch {
|
||||
try {
|
||||
overviewDao.updateGeoHash(id, geoHash)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllV2XEventsByLineId(sn: String) {
|
||||
if (disposable != null && !disposable!!.isDisposed) {
|
||||
disposable!!.dispose()
|
||||
}
|
||||
|
||||
// 1分钟查询一次
|
||||
disposable = Observable.interval(2000, 60000, TimeUnit.MILLISECONDS)
|
||||
.flatMap {
|
||||
val lineId = getLineId()
|
||||
if (lineId > 0) {
|
||||
MoGoRetrofitFactory.getInstance(HostConst.getHost())
|
||||
.create(OverViewServiceApi::class.java)
|
||||
.queryAllV2XEventsByLineId(lineId.toString(), sn)
|
||||
.map {
|
||||
if (it.code == 200 || it.code == 0) {
|
||||
CallerLogger.d(SceneConstant.M_MAP + TAG, "请求成功,size为:${it.result?.v2XEventList?.size}")
|
||||
return@map it.result?.v2XEventList
|
||||
} else {
|
||||
CallerLogger.d(SceneConstant.M_MAP + TAG, "请求失败,code为:${it.code}")
|
||||
return@map ArrayList()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Observable.just(ArrayList())
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
it?.apply {
|
||||
CallerFuncBizListenerManager.invokeV2XEvents(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stopQueryV2XEvents() {
|
||||
disposable?.dispose()
|
||||
}
|
||||
|
||||
private fun getLineId(): Long {
|
||||
var lineId: Long = -1
|
||||
val parameter = CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfo()
|
||||
.autopilotControlParameters
|
||||
if (parameter != null) {
|
||||
if (parameter.autoPilotLine != null) {
|
||||
lineId = parameter.autoPilotLine!!.lineId
|
||||
CallerLogger.d(SceneConstant.M_MAP + TAG, "lineId为:$lineId")
|
||||
} else {
|
||||
CallerLogger.d(SceneConstant.M_MAP + TAG, "parameter.autoPilotLine为null")
|
||||
}
|
||||
} else {
|
||||
CallerLogger.d(SceneConstant.M_MAP + TAG, "parameter为null")
|
||||
}
|
||||
return lineId
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mogo.eagle.function.biz.v2x.overview.db
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import com.mogo.eagle.core.data.map.Infrastructure
|
||||
|
||||
@Dao
|
||||
interface OverviewDao {
|
||||
// 0表示摄像头,8表示红绿灯
|
||||
@Query("SELECT * FROM t_device WHERE category = :category")
|
||||
suspend fun listInfStructures(category: Int): List<Infrastructure>
|
||||
|
||||
@Query("SELECT * FROM t_device")
|
||||
suspend fun listAllInfStructures(): List<Infrastructure>
|
||||
|
||||
@Query("UPDATE t_device SET geohash = :geoHash WHERE id = :id")
|
||||
suspend fun updateGeoHash(id: Int, geoHash: String)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.mogo.eagle.function.biz.v2x.overview.db
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.mogo.eagle.core.data.map.Infrastructure
|
||||
|
||||
@Database(entities = [Infrastructure::class], version = 2, exportSchema = false)
|
||||
abstract class OverviewDb: RoomDatabase() {
|
||||
abstract fun overviewDao(): OverviewDao
|
||||
|
||||
companion object {
|
||||
private const val DB_PATH = "database/t_device.db"
|
||||
private const val INTERNAL_DB_NAME = "t_device.db"
|
||||
|
||||
private val MIGRATION_1_2 = object : Migration(1, 2) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
}
|
||||
}
|
||||
|
||||
private var db: OverviewDb? = null
|
||||
|
||||
fun getDb(context: Context): OverviewDb {
|
||||
if (db == null) {
|
||||
db = Room.databaseBuilder(context.applicationContext, OverviewDb::class.java, INTERNAL_DB_NAME)
|
||||
.createFromAsset(DB_PATH)
|
||||
.addMigrations(MIGRATION_1_2)
|
||||
.fallbackToDestructiveMigration()
|
||||
.build()
|
||||
}
|
||||
return db!!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.eagle.function.biz.v2x.overview.remote
|
||||
|
||||
import com.mogo.eagle.core.data.v2x.V2XEventResult
|
||||
import io.reactivex.Observable
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
interface OverViewServiceApi {
|
||||
|
||||
@GET("/eagleEye-mis/config/queryV2NInformation")
|
||||
fun queryAllV2XEventsByLineId(@Query("lineId") lineId: String, @Query("sn") sn: String): Observable<V2XEventResult>
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
package com.mogo.eagle.function.biz.v2x.redlightwarning
|
||||
|
||||
import android.util.Log
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.*
|
||||
import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig.Companion.BIZ_IVP
|
||||
import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig.Companion.BIZ_IVP_GREEN
|
||||
import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig.Companion.V2I
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.msgbox.V2XMsg
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightStatusHelper.getCurrentRoadTrafficLight
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
|
||||
import com.mogo.eagle.core.function.api.datacenter.union.IMoGoTrafficLightListener
|
||||
import com.mogo.eagle.core.function.api.v2x.IMoGoVipSetListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager
|
||||
import com.mogo.eagle.core.function.call.v2x.CallerTrafficLightListenerManager
|
||||
import com.mogo.eagle.core.function.call.v2x.CallVipSetListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_V2X
|
||||
import com.mogo.eagle.core.utilcode.util.LocationUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.core.MogoTrafficLightManager
|
||||
import com.zhjt.service_biz.BizConfig
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
class RedLightWarningManager : IMoGoTrafficLightListener, IMoGoVipSetListener,
|
||||
IMoGoChassisLocationGCJ02Listener {
|
||||
|
||||
private var vip: Boolean = false
|
||||
|
||||
// 是否第一次进入道路100m处
|
||||
private var isFirst = true
|
||||
|
||||
// 是否已进入到路口(停止线处)
|
||||
private var isEnter = false
|
||||
|
||||
private var mLocation: MogoLocation? = null
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "RedLightWarningManager"
|
||||
|
||||
val INSTANCE: RedLightWarningManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
RedLightWarningManager()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTrafficLightStatus(trafficLightResult: TrafficLightResult) {
|
||||
// 到路口100m时回调
|
||||
CallerLogger.d("$M_V2X$TAG", "处理路口交通数据:是否是第一次处理:${isFirst}是否进入路口:${isEnter}")
|
||||
if (trafficLightResult.currentRoadIsRight()) {
|
||||
CallerLogger.d("$M_V2X$TAG", "当前道路右转,不处理")
|
||||
return
|
||||
}
|
||||
if (isFirst && !isEnter) {
|
||||
getCurrentRoadTrafficLight(trafficLightResult)?.let {
|
||||
handleRedLightWarning(it, trafficLightResult)
|
||||
}
|
||||
isFirst = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onEnterCrossRoad(enter: Boolean) {
|
||||
CallerLogger.d("$M_V2X$TAG", "回调是否进入路口:$enter")
|
||||
isEnter = enter
|
||||
if (enter) {
|
||||
isFirst = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onVipSet(status: Boolean) {
|
||||
vip = status
|
||||
}
|
||||
|
||||
fun listenTrafficLight() {
|
||||
CallerTrafficLightListenerManager.addListener(TAG, this)
|
||||
CallerChassisLocationGCJ02ListenerManager.addListener(TAG, this)
|
||||
CallVipSetListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
private fun handleRedLightWarning(
|
||||
trafficLightStatus: TrafficLightStatus,
|
||||
trafficLightResult: TrafficLightResult
|
||||
) {
|
||||
// 如果是Vip则不处理
|
||||
if (vip) {
|
||||
CallerLogger.w("$M_V2X$TAG", "Vip用户不处理闯红灯、绿灯通行预警逻辑!")
|
||||
return
|
||||
}
|
||||
// 路口100m闯红灯预警
|
||||
mLocation?.let {
|
||||
// 单位m/s
|
||||
val speed = it.gnssSpeed
|
||||
// 车停止或者速度非常慢,可能返回负数或者很小的值,需要过滤
|
||||
CallerLogger.d("$M_V2X$TAG", "speed is:$speed")
|
||||
if (speed <= 2.5f) return// 小于等于9km/h不处理
|
||||
// 由于到路口100m时回调不准,手动计算直线距离
|
||||
val roadResult = MogoTrafficLightManager.INSTANCE.getRoadResult()
|
||||
val distance = if (roadResult != null && roadResult.rectLatLngs.size >= 2) {
|
||||
getMinDistance(roadResult.rectLatLngs, it.latitude, it.longitude)
|
||||
} else {
|
||||
CallerMapUIServiceManager.getMapUIController()?.calculateLineDistance(
|
||||
MogoLatLng(it.latitude, it.longitude),
|
||||
MogoLatLng(trafficLightResult.lat, trafficLightResult.lon)
|
||||
) ?: 0f
|
||||
}
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"路口经度为:${trafficLightResult.lon},纬度为:${trafficLightResult.lat};车的经度为:${it.longitude},纬度为:${it.latitude};两点距离为:${distance}"
|
||||
)
|
||||
val remainTime = trafficLightStatus.remain
|
||||
val arriveTime = distance / speed
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"speed is:$speed,remainTime is:$remainTime,arriveTime is:$arriveTime,yellowTime is:${trafficLightResult.flashYellow}"
|
||||
)
|
||||
|
||||
when {
|
||||
trafficLightStatus.isRed() -> {
|
||||
CallerLogger.d("$M_V2X$TAG", "=====当前为红灯=====")
|
||||
// 到达路口时红灯还没走完(由于多个数据有偏差,红灯预警延长1s,绿灯提示条件延长1.5s,多报出错不如少报且准)
|
||||
if (arriveTime <= remainTime + 1) {
|
||||
redLightWarning()
|
||||
} else if (arriveTime > remainTime + trafficLightResult.flashYellow + 1.5) {// 到达时红、黄灯都走完
|
||||
// 单位Km/h,当前为红灯,推荐速度越慢越容易绿灯通过,且要满足[10,50]
|
||||
val originRemainSpeed =
|
||||
floor(distance / (remainTime + trafficLightResult.flashYellow + 1.5) * 3.6).toInt()
|
||||
when {
|
||||
originRemainSpeed > 50 -> greenLightWarning("10到50")
|
||||
originRemainSpeed in 10..50 -> greenLightWarning("10到$originRemainSpeed")
|
||||
}
|
||||
}
|
||||
}
|
||||
trafficLightStatus.isYellow() -> {
|
||||
CallerLogger.d("$M_V2X$TAG", "=====当前为黄灯=====")
|
||||
// 到达路口时黄灯还没走完(由于多个数据有偏差,红灯预警延长1s,绿灯提示延长1.5s,多报出错不如少报且准)
|
||||
if (arriveTime <= remainTime + 1) {
|
||||
redLightWarning()
|
||||
} else if (arriveTime > remainTime + 1.5) {
|
||||
// 单位Km/h,当前为黄灯,推荐速度越慢越容易绿灯通过,且要满足[10,50]
|
||||
val originRemainSpeed = floor(distance / (remainTime + 1.5) * 3.6).toInt()
|
||||
when {
|
||||
originRemainSpeed > 50 -> greenLightWarning("10到50")
|
||||
originRemainSpeed in 10..50 -> greenLightWarning("10到$originRemainSpeed")
|
||||
}
|
||||
}
|
||||
}
|
||||
trafficLightStatus.isGreen() -> {
|
||||
CallerLogger.d("$M_V2X$TAG", "=====当前为绿灯=====")
|
||||
// 到达路口时绿灯已经走完(由于多个数据有偏差,多报出错不如少报且准,绿灯时间减少一点)
|
||||
if (arriveTime >= remainTime - 1) {
|
||||
redLightWarning()
|
||||
} else if (arriveTime < remainTime - 1.5) {
|
||||
// 单位Km/h,当前为绿灯,推荐速度越快越容易绿灯通过,且要满足[10,50]
|
||||
val originRemainSpeed = ceil(distance / (remainTime - 1.5) * 3.6).toInt()
|
||||
when {
|
||||
originRemainSpeed < 10 -> greenLightWarning("10到50")
|
||||
originRemainSpeed in 10..50 -> greenLightWarning("${originRemainSpeed}到50")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} ?: run {
|
||||
CallerLogger.e("$M_V2X$TAG", "CurrentLocation is null!")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMinDistance(points: List<MogoLatLng>, lat: Double, lon: Double): Float {
|
||||
// 到路口100m时才计算,赋值一个较大值
|
||||
var minValue = 9999.9
|
||||
val size = points.size
|
||||
for (i in 0..size step 2) {
|
||||
if (i < size) {
|
||||
// 自车到0-1、2-3、4-5、6-7组成的线段的最小距离
|
||||
minValue = min(
|
||||
minValue,
|
||||
LocationUtils.pointToLine(
|
||||
points[i].lon,
|
||||
points[i].lat,
|
||||
points[i + 1].lon,
|
||||
points[i + 1].lat,
|
||||
lon,
|
||||
lat
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return if (minValue > 9999) 0f else minValue.toFloat()
|
||||
}
|
||||
|
||||
/**
|
||||
* 闯红灯预警
|
||||
*/
|
||||
@BizConfig(V2I, "", BIZ_IVP)
|
||||
private fun redLightWarning() {
|
||||
CallerLogger.d("$M_V2X$TAG", "=====闯红灯预警=====")
|
||||
ThreadUtils.runOnUiThread {
|
||||
CallerMsgBoxManager.saveMsgBox(
|
||||
MsgBoxBean(
|
||||
MsgBoxType.V2X,
|
||||
V2XMsg(
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.poiType,
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.content,
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.tts
|
||||
)
|
||||
)
|
||||
)
|
||||
CallerHmiManager.warningV2X(
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.poiType,
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.content,
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.tts
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绿灯通行提示
|
||||
*/
|
||||
@BizConfig(V2I, "", BIZ_IVP_GREEN)
|
||||
private fun greenLightWarning(speed: String = "50") {
|
||||
CallerLogger.d("$M_V2X$TAG", "=====绿灯通行预警=====")
|
||||
ThreadUtils.runOnUiThread {
|
||||
val content = String.format(
|
||||
EventTypeEnumNew.getWarningContent(EventTypeEnumNew.TYPE_USECASE_ID_IVP_GREEN.poiType),
|
||||
speed
|
||||
)
|
||||
val tts = String.format(
|
||||
EventTypeEnumNew.getWarningTts(EventTypeEnumNew.TYPE_USECASE_ID_IVP_GREEN.poiType),
|
||||
speed
|
||||
)
|
||||
if (content.isNullOrEmpty() || tts.isNullOrEmpty()) {
|
||||
Log.d("MsgBox-RedLightWarManaG", "alertContent或ttsContent为空!")
|
||||
}
|
||||
CallerMsgBoxManager.saveMsgBox(
|
||||
MsgBoxBean(
|
||||
MsgBoxType.V2X,
|
||||
V2XMsg(
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_GREEN.poiType,
|
||||
content,
|
||||
tts
|
||||
)
|
||||
)
|
||||
)
|
||||
CallerHmiManager.warningV2X(
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_IVP_GREEN.poiType,
|
||||
content,
|
||||
tts
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fEqual(a: Float, b: Float): Boolean {
|
||||
return abs(a - b) < 0.000001
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
CallVipSetListenerManager.removeListener(TAG)
|
||||
CallerTrafficLightListenerManager.removeListener(TAG)
|
||||
CallerChassisLocationGCJ02ListenerManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
override fun onChassisLocationGCJ02(gnssInfo: MogoLocation?) {
|
||||
gnssInfo?.let {
|
||||
mLocation = it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.mogo.eagle.function.biz.v2x.road
|
||||
|
||||
import com.mogo.eagle.core.data.BaseData
|
||||
import com.mogo.eagle.core.data.v2x.LineUploadData
|
||||
import io.reactivex.Observable
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface ILineUploadApi {
|
||||
|
||||
@Headers("Content-type:application/json;charset=UTF-8" )
|
||||
@POST( "eagle-eye-dns/yycp-data-center-service/carTrack/receiveCarTrack/" )
|
||||
fun uploadLineId(@Body lineId: LineUploadData): Observable<BaseData>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.mogo.eagle.function.biz.v2x.road
|
||||
|
||||
import android.content.Context
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.commons.constants.HostConst.DATA_CENTER_HOST
|
||||
import com.mogo.commons.constants.HostConst.getEagleHost
|
||||
import com.mogo.eagle.core.data.v2x.LineUploadData
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
class LineUploadManager private constructor(context: Context) : IMoGoAutopilotStatusListener {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "LineUploadManager"
|
||||
|
||||
@Volatile
|
||||
private var lineUploadManager: LineUploadManager? = null
|
||||
|
||||
@Synchronized
|
||||
fun getInstance(context: Context): LineUploadManager? {
|
||||
if (lineUploadManager == null) {
|
||||
synchronized(LineUploadManager::class.java) {
|
||||
if (lineUploadManager == null) {
|
||||
lineUploadManager = LineUploadManager(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineUploadManager
|
||||
}
|
||||
}
|
||||
|
||||
private var mContext: Context? = null
|
||||
private var disposable: Disposable? = null
|
||||
|
||||
init {
|
||||
mContext = context
|
||||
}
|
||||
|
||||
fun init() {
|
||||
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
override fun onAutopilotRouteLineId(lineId: Long) {
|
||||
super.onAutopilotRouteLineId(lineId)
|
||||
if (lineId > 0) {
|
||||
uploadLine(lineId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun uploadLine(lineId: Long) {
|
||||
val lineUploadData = LineUploadData(lineId, MoGoAiCloudClientConfig.getInstance().sn)
|
||||
disposable = MoGoRetrofitFactory.getInstance(getEagleHost())
|
||||
.create(ILineUploadApi::class.java)
|
||||
.uploadLineId(lineUploadData)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ data ->
|
||||
CallerLogger.d(TAG, " uploadLine : $data")
|
||||
}, {
|
||||
CallerLogger.d(TAG, "e : ${it.message}")
|
||||
})
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
mContext = null
|
||||
disposable?.dispose()
|
||||
CallerAutoPilotStatusListenerManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.eagle.function.biz.v2x.trafficlight
|
||||
|
||||
class TrafficLightConst {
|
||||
|
||||
companion object {
|
||||
const val MODULE_NAME = "MODULE_V2X_TRAFFIC_LIGHT"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.mogo.eagle.function.biz.v2x.trafficlight.core
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.RoadIDResult
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightControl
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.isInRange
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager
|
||||
import com.mogo.eagle.core.function.call.v2x.CallerTrafficLightListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_V2X
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.core.TrafficLightThreadHandler.Companion.MSG_WHAT_LOOP_SEARCH_CROSS_ROAD
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.core.TrafficLightThreadHandler.Companion.MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.core.TrafficLightThreadHandler.Companion.MSG_WHAT_STOP_SEARCH_CROSS_ROAD
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.core.TrafficLightThreadHandler.Companion.MSG_WHAT_STOP_SEARCH_TRAFFIC_LIGHT
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.network.TrafficLightNetWorkModel
|
||||
|
||||
class MogoTrafficLightManager : IMoGoChassisLocationGCJ02Listener {
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "MogoTrafficLightManager"
|
||||
|
||||
val INSTANCE: MogoTrafficLightManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
MogoTrafficLightManager()
|
||||
}
|
||||
}
|
||||
|
||||
private var mContext: Context? = null
|
||||
private val trafficLightNetWorkModel = TrafficLightNetWorkModel()
|
||||
private var mLocation: MogoLocation? = null
|
||||
private var roadIDResult: RoadIDResult? = null
|
||||
private var trafficLightResult: TrafficLightResult? = null
|
||||
|
||||
private var inRange: Boolean = false
|
||||
private var firstLoopCrossRoad: Boolean = true //开启循环请求路口
|
||||
|
||||
private var mThreadHandler: Handler? = null
|
||||
|
||||
fun initServer(context: Context) {
|
||||
mContext = context
|
||||
CallerChassisLocationGCJ02ListenerManager.addListener(TAG, this)
|
||||
mThreadHandler =
|
||||
TrafficLightThreadHandler(Looper.getMainLooper(), {
|
||||
//第一次查询路口时,如果红绿灯显示,则隐藏掉
|
||||
if (firstLoopCrossRoad) {
|
||||
CallerTrafficLightListenerManager.resetTrafficLightStatus()
|
||||
}
|
||||
firstLoopCrossRoad = false
|
||||
mLocation?.let { it ->
|
||||
val tileId = CallerMapUIServiceManager.getMapUIController()
|
||||
?.getTileId(it.longitude, it.latitude) ?: 0
|
||||
trafficLightNetWorkModel.requestRoadID(
|
||||
tileId, it.latitude, it.longitude, it.heading,
|
||||
{
|
||||
mThreadHandler?.sendEmptyMessage(MSG_WHAT_STOP_SEARCH_CROSS_ROAD)
|
||||
roadIDResult = it
|
||||
},
|
||||
{
|
||||
//CallerLogger.w(M_V2X + TAG, "request road id error : $it")
|
||||
})
|
||||
}
|
||||
}, {
|
||||
//stop loop search road id
|
||||
trafficLightNetWorkModel.cancelRequestRoadID()
|
||||
//开始请求红绿灯
|
||||
mThreadHandler?.sendEmptyMessage(MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT)
|
||||
}, {
|
||||
//start loop traffic light
|
||||
mLocation?.let {
|
||||
val road =
|
||||
if (roadIDResult?.rsCrossId.isNullOrBlank()) "" else roadIDResult?.rsCrossId
|
||||
trafficLightNetWorkModel.requestTrafficLight(
|
||||
it.latitude, it.longitude, it.heading, road, { result ->
|
||||
trafficLightResult = result
|
||||
CallerTrafficLightListenerManager.invokeTrafficLightStatus(result)
|
||||
},
|
||||
{ errorMsg ->
|
||||
//如果没有获取到正确的红绿灯数据,则取消读灯,继续读路口,防止出现一直读灯的情况
|
||||
CallerLogger.e(M_V2X + TAG, "request Traffic Light error : $errorMsg")
|
||||
//stop loop traffic light
|
||||
trafficLightNetWorkModel.cancelRequestTrafficLight()
|
||||
//未查到红绿灯,加入2秒延时请求路口ID
|
||||
mThreadHandler?.let { handler ->
|
||||
if (handler.hasMessages(MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT)) {
|
||||
handler.removeMessages(MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT)
|
||||
}
|
||||
if (handler.hasMessages(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD)) {
|
||||
handler.removeMessages(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD)
|
||||
}
|
||||
handler.sendEmptyMessageDelayed(
|
||||
MSG_WHAT_LOOP_SEARCH_CROSS_ROAD,
|
||||
2_000L
|
||||
)
|
||||
}
|
||||
CallerTrafficLightListenerManager.resetTrafficLightStatus()
|
||||
CallerTrafficLightListenerManager.invokeTrafficRequestError()
|
||||
|
||||
})
|
||||
}
|
||||
}, {
|
||||
//stop loop traffic light
|
||||
trafficLightNetWorkModel.cancelRequestTrafficLight()
|
||||
//刚经过红绿灯,加入3秒延时请求路口ID
|
||||
mThreadHandler?.let {
|
||||
if (it.hasMessages(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD)) {
|
||||
it.removeMessages(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD)
|
||||
}
|
||||
it.sendEmptyMessageDelayed(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD, 2_000L)
|
||||
}
|
||||
})
|
||||
mThreadHandler?.sendEmptyMessageDelayed(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD, 5_000L)
|
||||
}
|
||||
|
||||
private fun checkOutOfRange() {
|
||||
mLocation?.let { loc ->
|
||||
roadIDResult?.let {
|
||||
// 检测是否开过路口,开过路口则停止读灯。并重置 trafficLightResult 值为 null
|
||||
if (trafficLightResult != null && it.isInRange(loc.latitude, loc.longitude)) {
|
||||
inRange = true
|
||||
// CallerLogger.d(M_V2X + TAG, "进入路口")
|
||||
CallerTrafficLightListenerManager.invokeEnterCrossRoad(true)
|
||||
return
|
||||
}
|
||||
if (inRange) {
|
||||
// CallerLogger.d(M_V2X + TAG, "离开路口")
|
||||
CallerTrafficLightListenerManager.invokeEnterCrossRoad(false)
|
||||
inRange = false
|
||||
trafficLightResult = null
|
||||
firstLoopCrossRoad = true
|
||||
mThreadHandler?.sendEmptyMessage(MSG_WHAT_STOP_SEARCH_TRAFFIC_LIGHT)
|
||||
CallerTrafficLightListenerManager.resetTrafficLightStatus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getRoadResult(): RoadIDResult? {
|
||||
return roadIDResult
|
||||
}
|
||||
|
||||
fun turnLightToGreen(
|
||||
lightId: Int,
|
||||
crossingNo: String,
|
||||
heading: Double,
|
||||
controlTime: Int,
|
||||
onSuccess: ((TrafficLightControl) -> Unit),
|
||||
onError: ((String) -> Unit)
|
||||
) {
|
||||
trafficLightNetWorkModel.turnLightToGreen(
|
||||
lightId,
|
||||
crossingNo,
|
||||
heading,
|
||||
controlTime,
|
||||
onSuccess,
|
||||
onError
|
||||
)
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
mThreadHandler = null
|
||||
mContext = null
|
||||
mLocation = null
|
||||
trafficLightResult = null
|
||||
}
|
||||
|
||||
override fun onChassisLocationGCJ02(gnssInfo: MogoLocation?) {
|
||||
gnssInfo?.let {
|
||||
mLocation = it
|
||||
checkOutOfRange()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.mogo.eagle.function.biz.v2x.trafficlight.core
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
|
||||
class TrafficLightThreadHandler : Handler {
|
||||
|
||||
private var loopSearchCrossRoad: (() -> Unit)? = null
|
||||
private var stopSearchCrossRoad: (() -> Unit)? = null
|
||||
private var loopSearchTrafficLight: (() -> Unit)? = null
|
||||
private var stopSearchTrafficLight: (() -> Unit)? = null
|
||||
|
||||
constructor(
|
||||
looper: Looper,
|
||||
loopSearchCrossRoad: (() -> Unit),
|
||||
stopSearchCrossRoad: (() -> Unit),
|
||||
loopSearchTrafficLight: (() -> Unit),
|
||||
stopSearchTrafficLight: (() -> Unit)
|
||||
) : super(looper) {
|
||||
this.loopSearchCrossRoad = loopSearchCrossRoad
|
||||
this.stopSearchCrossRoad = stopSearchCrossRoad
|
||||
this.loopSearchTrafficLight = loopSearchTrafficLight
|
||||
this.stopSearchTrafficLight = stopSearchTrafficLight
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MSG_WHAT_LOOP_SEARCH_CROSS_ROAD = 1
|
||||
const val MSG_WHAT_STOP_SEARCH_CROSS_ROAD = 2
|
||||
const val MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT = 3
|
||||
const val MSG_WHAT_STOP_SEARCH_TRAFFIC_LIGHT = 4
|
||||
}
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
super.handleMessage(msg)
|
||||
when (msg.what) {
|
||||
MSG_WHAT_LOOP_SEARCH_CROSS_ROAD -> {
|
||||
//handler轮询,后续从地图处获取到车道线(前提获取车道线没有异步调用),来优化轮询时长
|
||||
sendEmptyMessageDelayed(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD,300L)
|
||||
loopSearchCrossRoad?.invoke()
|
||||
}
|
||||
MSG_WHAT_STOP_SEARCH_CROSS_ROAD -> {
|
||||
if(hasMessages(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD)){
|
||||
removeMessages(MSG_WHAT_LOOP_SEARCH_CROSS_ROAD)
|
||||
}
|
||||
stopSearchCrossRoad?.invoke()
|
||||
}
|
||||
MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT -> {
|
||||
sendEmptyMessageDelayed(MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT,700L)
|
||||
loopSearchTrafficLight?.invoke()
|
||||
}
|
||||
MSG_WHAT_STOP_SEARCH_TRAFFIC_LIGHT -> {
|
||||
if(hasMessages(MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT)){
|
||||
removeMessages(MSG_WHAT_LOOP_SEARCH_TRAFFIC_LIGHT)
|
||||
}
|
||||
stopSearchTrafficLight?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.mogo.eagle.function.biz.v2x.trafficlight.network
|
||||
|
||||
import com.mogo.eagle.core.data.BaseResponse
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.RoadIDResult
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightControl
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult
|
||||
import retrofit2.http.FieldMap
|
||||
import retrofit2.http.FormUrlEncoded
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface TrafficLightApiService {
|
||||
|
||||
//获取前方路口RoadID
|
||||
@FormUrlEncoded
|
||||
@POST("eagle-eye-dns/ai-roadInfo-service/cross/near")
|
||||
suspend fun getFrontRoadID(@FieldMap roadID: Map<String, String>): BaseResponse<RoadIDResult>
|
||||
|
||||
//获取前方红绿灯状态
|
||||
@FormUrlEncoded
|
||||
@POST("eagle-eye-dns/mec-etl-server/light/bgd/channel/realTime")
|
||||
suspend fun getTrafficLight(@FieldMap status: Map<String, String>): BaseResponse<TrafficLightResult>
|
||||
|
||||
//变灯
|
||||
@FormUrlEncoded
|
||||
@POST("eagle-eye-dns/mec-etl-server/light/bdg/newTask")
|
||||
suspend fun changeLight(@FieldMap turnLight: Map<String, String>): BaseResponse<TrafficLightControl>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.mogo.eagle.function.biz.v2x.trafficlight.network
|
||||
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.commons.constants.HostConst
|
||||
import com.mogo.eagle.core.data.BaseResponse
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.*
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.eagle.core.network.apiCall
|
||||
import com.mogo.eagle.core.network.cancel
|
||||
import com.mogo.eagle.core.network.request
|
||||
import com.mogo.eagle.core.utilcode.util.GsonUtils
|
||||
|
||||
class TrafficLightNetWorkModel {
|
||||
|
||||
private fun getNetWorkApi(baseUrl: String = HostConst.getEagleHost()): TrafficLightApiService {
|
||||
return MoGoRetrofitFactory.getInstanceNoCallAdapter(baseUrl)
|
||||
.create(TrafficLightApiService::class.java)
|
||||
}
|
||||
|
||||
fun requestRoadID(
|
||||
tileID: Long,
|
||||
lat: Double,
|
||||
lon: Double,
|
||||
bearing: Double,
|
||||
onSuccess: ((RoadIDResult) -> Unit),
|
||||
onError: ((String) -> Unit),
|
||||
) {
|
||||
request<BaseResponse<RoadIDResult>>("requestRoadID") {
|
||||
val map = hashMapOf<String, String>()
|
||||
start {
|
||||
val roadIDRequestData = RoadIDRequestData(tileID, lat, lon, bearing)
|
||||
map["sn"] = MoGoAiCloudClientConfig.getInstance().sn
|
||||
map["data"] = GsonUtils.toJson(roadIDRequestData)
|
||||
}
|
||||
loader {
|
||||
apiCall {
|
||||
getNetWorkApi().getFrontRoadID(map)
|
||||
}
|
||||
}
|
||||
onSuccess {
|
||||
if (it?.result != null) {
|
||||
if (!it.result.rsCrossId.isNullOrEmpty() && !it.result.rectLatLngs.isNullOrEmpty()) {
|
||||
onSuccess.invoke(it.result)
|
||||
} else {
|
||||
onError.invoke("requestRoadID result rsCrossId is null")
|
||||
}
|
||||
} else {
|
||||
onError.invoke("requestRoadID result is null")
|
||||
}
|
||||
}
|
||||
onError {
|
||||
if (it.message != null) {
|
||||
onError.invoke(it.message!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelRequestRoadID() {
|
||||
cancel("requestRoadID")
|
||||
}
|
||||
|
||||
fun requestTrafficLight(
|
||||
lat: Double,
|
||||
lon: Double,
|
||||
bearing: Double,
|
||||
roadId: String?,
|
||||
onSuccess: ((TrafficLightResult) -> Unit),
|
||||
onError: ((String) -> Unit),
|
||||
) {
|
||||
request<BaseResponse<TrafficLightResult>>("requestTrafficLight") {
|
||||
val map = hashMapOf<String, String>()
|
||||
start {
|
||||
if (roadId == null) {
|
||||
return@start
|
||||
}
|
||||
val trafficLightRequestData = TrafficLightRequestData(lat, lon, bearing, roadId)
|
||||
map["sn"] = MoGoAiCloudClientConfig.getInstance().sn
|
||||
map["data"] = GsonUtils.toJson(trafficLightRequestData)
|
||||
}
|
||||
loader {
|
||||
apiCall {
|
||||
getNetWorkApi().getTrafficLight(map)
|
||||
}
|
||||
}
|
||||
onSuccess {
|
||||
if (it.result != null) {
|
||||
onSuccess.invoke(it.result)
|
||||
} else {
|
||||
onError.invoke(it.msg ?: "返回result数据为null")
|
||||
}
|
||||
}
|
||||
onError {
|
||||
if (it.message != null) {
|
||||
onError.invoke(it.message!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun cancelRequestTrafficLight() {
|
||||
cancel("requestTrafficLight")
|
||||
}
|
||||
|
||||
fun turnLightToGreen(
|
||||
lightId: Int,
|
||||
crossingNo: String,
|
||||
heading: Double,
|
||||
controlTime: Int,
|
||||
onSuccess: ((TrafficLightControl) -> Unit),
|
||||
onError: ((String) -> Unit)
|
||||
) {
|
||||
request<BaseResponse<TrafficLightControl>> {
|
||||
val map = hashMapOf<String, String>()
|
||||
start {
|
||||
val trafficLightRequestData =
|
||||
ChangeLightRequestData(lightId, crossingNo, heading, controlTime)
|
||||
map["sn"] = MoGoAiCloudClientConfig.getInstance().sn
|
||||
map["data"] = GsonUtils.toJson(trafficLightRequestData)
|
||||
}
|
||||
loader {
|
||||
apiCall {
|
||||
getNetWorkApi().changeLight(map)
|
||||
}
|
||||
}
|
||||
onSuccess {
|
||||
onSuccess.invoke(it.result)
|
||||
}
|
||||
onError {
|
||||
if (it.message != null) {
|
||||
onError.invoke(it.message!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_ALIAS_CODE_CLOUD_V2N
|
||||
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_LINK_CLOUD
|
||||
import com.mogo.eagle.core.data.deva.chain.ChainConstant.Companion.CHAIN_LINK_LOG_CLOUD_V2N
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
|
||||
import com.mogo.eagle.core.data.enums.EventTypeHelper
|
||||
import com.mogo.eagle.core.data.enums.TrafficTypeEnum
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.msgbox.V2XMsg
|
||||
import com.mogo.eagle.core.data.traffic.TrafficData
|
||||
import com.mogo.eagle.core.data.v2x.V2XAdvanceWarning
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
|
||||
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener
|
||||
import com.mogo.eagle.core.function.api.map.angle.*
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotIdentifyListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapIdentifyManager
|
||||
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.msgbox.CallerMsgBoxManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.alarm.V2XAlarmServer
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.bridge.BridgeApi
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.V2XConst.BROADCAST_SCENE_EXTRA_KEY
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.V2XConst.BROADCAST_SCENE_HANDLER_ACTION
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.receiver.SceneBroadcastReceiver
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.impl.V2XScenarioManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.utils.toRoadMarker
|
||||
import com.mogo.eagle.core.data.v2x.V2XEvent
|
||||
import com.mogo.eagle.core.data.v2x.V2XMarkerCardResult
|
||||
import com.mogo.eagle.core.data.v2x.V2XWarningTarget
|
||||
import com.mogo.eagle.core.function.api.cloud.IMoGoCloudListener
|
||||
import com.mogo.eagle.core.function.call.cloud.CallerCloudListenerManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.V2XPoiLoader.Companion.v2xPoiLoader
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_V2X
|
||||
import com.mogo.eagle.core.utilcode.util.Utils
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.network.callback.IV2XCallback
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.utils.toV2XRoadEventEntity
|
||||
import com.zhjt.service.chain.ChainLog
|
||||
import com.zhjt.service.chain.TracingConstants
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.android.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import mogo.telematics.pad.MessagePad
|
||||
|
||||
object V2XEventManager : IMoGoChassisLocationGCJ02Listener, IV2XCallback,
|
||||
IMoGoAutopilotIdentifyListener, IMoGoCloudListener {
|
||||
|
||||
private const val TAG = "V2XEventManager"
|
||||
|
||||
private val scope: CoroutineScope by lazy {
|
||||
CoroutineScope(Handler(Looper.getMainLooper()).asCoroutineDispatcher(TAG))
|
||||
}
|
||||
|
||||
private val hasInit by lazy { AtomicBoolean(false) }
|
||||
|
||||
fun init(context: Context) {
|
||||
BridgeApi.init(context)
|
||||
if (hasInit.compareAndSet(false, true)) {
|
||||
registerListener()
|
||||
v2xPoiLoader.startLoopPoi()
|
||||
// 注册广播接收场景弹窗使用的
|
||||
SceneBroadcastReceiver.register(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerListener() {
|
||||
CallerChassisLocationGCJ02ListenerManager.addListener(TAG, 1,this)
|
||||
v2xPoiLoader.addCallback(this)
|
||||
CallerCloudListenerManager.addListener(TAG,this)
|
||||
CallerAutopilotIdentifyListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
private fun unRegisterListener() {
|
||||
CallerChassisLocationGCJ02ListenerManager.removeListener(TAG)
|
||||
v2xPoiLoader.removeCallback(this)
|
||||
CallerCloudListenerManager.removeListener(TAG)
|
||||
CallerAutopilotIdentifyListenerManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
|
||||
BridgeApi.location.set(mogoLocation)
|
||||
mogoLocation?.let {
|
||||
v2xPoiLoader.updateCheck(mogoLocation.longitude,mogoLocation.latitude)
|
||||
refreshCarState(mogoLocation)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshCarState(location: MogoLocation) {
|
||||
// 巡航处理
|
||||
val v2XRoadEventEntity = V2XAlarmServer.getDriveFrontAlarmEvent(
|
||||
BridgeApi.v2xMarker()?.v2XRoadEventEntityList, location
|
||||
)
|
||||
if (v2XRoadEventEntity != null) {
|
||||
val distance = v2XRoadEventEntity.distance
|
||||
val min = if (EventTypeEnumNew.isCloudSocketEvent(v2XRoadEventEntity.poiType)) 0 else 5
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"--- trigger show before ---:data=>[${location.longitude}, ${location.latitude}, ${location.gnssSpeed}], distance: $distance, minDistance: $min, poiType: ${v2XRoadEventEntity.poiType}"
|
||||
)
|
||||
if (distance >= min) {
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"--- trigger show ---:poiType:" + v2XRoadEventEntity.poiType
|
||||
)
|
||||
val v2XMessageEntity = V2XMessageEntity<V2XRoadEventEntity>()
|
||||
v2XMessageEntity.type = V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING
|
||||
v2XMessageEntity.content = v2XRoadEventEntity
|
||||
V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* V2XEvent事件回调
|
||||
*/
|
||||
@ChainLog(
|
||||
linkChainLog = CHAIN_LINK_LOG_CLOUD_V2N,
|
||||
linkCode = CHAIN_LINK_CLOUD,
|
||||
endpoint = TracingConstants.Endpoint.PAD,
|
||||
nodeAliasCode = CHAIN_ALIAS_CODE_CLOUD_V2N,
|
||||
paramIndexes = [0],
|
||||
clientPkFileName = "sn"
|
||||
)
|
||||
override fun onAck(event: V2XEvent) {
|
||||
Log.d("$M_V2X$TAG", "OK->: $event")
|
||||
when (event) {
|
||||
is V2XEvent.ForwardsWarning -> {
|
||||
handleAdvanceWarningEvent(event)
|
||||
}
|
||||
is V2XEvent.Marker -> {
|
||||
event.data.result?.let {
|
||||
handleRoadMarkerEvent(it)
|
||||
}
|
||||
}
|
||||
is V2XEvent.Road -> {
|
||||
handleRoadMarkerEvent(event.data)
|
||||
}
|
||||
is V2XEvent.Warning -> {
|
||||
handleWarningTargetEvent(event.data)
|
||||
}
|
||||
is V2XEvent.RoadAI -> {
|
||||
handleRoadMarkerEvent(event.data.toRoadMarker())
|
||||
}
|
||||
is V2XEvent.RoadEventX -> {
|
||||
handleRoadMarkerEvent(event.data.toRoadMarker())
|
||||
}
|
||||
else -> {
|
||||
Logger.e(TAG, "onAck other event: $event")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ChainLog(
|
||||
linkChainLog = CHAIN_LINK_LOG_CLOUD_V2N,
|
||||
linkCode = CHAIN_LINK_CLOUD,
|
||||
endpoint = TracingConstants.Endpoint.PAD,
|
||||
nodeAliasCode = CHAIN_ALIAS_CODE_CLOUD_V2N,
|
||||
paramIndexes = [0],
|
||||
clientPkFileName = "sn"
|
||||
)
|
||||
override fun onAutopilotIdentifyPlanningObj(planningObjects: List<MessagePad.PlanningObject>?) {
|
||||
super.onAutopilotIdentifyPlanningObj(planningObjects)
|
||||
planningObjects?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
val first = it.stream()
|
||||
.filter { planningObj: MessagePad.PlanningObject -> planningObj.type >= 1000 }
|
||||
.findFirst()
|
||||
if (first.isPresent) {
|
||||
val poiType = when (first.get().type) {
|
||||
// 1004 -> { //V2N_RSM,静止事件,包括异常停车、异常静止障碍物
|
||||
// }
|
||||
1005 -> { //V2N_RSI,施工事件,包括锥桶或者挡板围城的施工场景,是个多边形包围区域
|
||||
EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.poiType
|
||||
}
|
||||
1007 -> { //三角牌
|
||||
EventTypeEnumNew.FOURS_ACCIDENT_04.poiType
|
||||
}
|
||||
else -> {
|
||||
return
|
||||
}
|
||||
}
|
||||
CallerLogger.d("$M_V2X$TAG", "poiType : $poiType , 触发道路事件")
|
||||
val trackedObj =
|
||||
CallerMapIdentifyManager.getIdentifyObj(first.get().uuid.toString())
|
||||
trackedObj?.let { t ->
|
||||
CallerLogger.d("$M_V2X$TAG", "polygon size : ${(t.polygonList.size)}")
|
||||
val v2XMessageEntity = V2XMessageEntity<V2XRoadEventEntity>()
|
||||
v2XMessageEntity.type = V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING
|
||||
v2XMessageEntity.content = t.toRoadMarker(poiType).toV2XRoadEventEntity()
|
||||
V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleWarningTargetEvent(data: V2XWarningTarget) {
|
||||
val v2xMessageEntity = V2XMessageEntity<V2XWarningTarget>()
|
||||
v2xMessageEntity.type = V2XMessageEntity.V2XTypeEnum.ALERT_THE_FRONT_WEAKNESS
|
||||
// 设置数据
|
||||
v2xMessageEntity.content = data
|
||||
val intent = Intent(BROADCAST_SCENE_HANDLER_ACTION)
|
||||
intent.putExtra(BROADCAST_SCENE_EXTRA_KEY, v2xMessageEntity)
|
||||
LocalBroadcastManager.getInstance(Utils.getApp()).sendBroadcast(intent)
|
||||
}
|
||||
|
||||
private fun handleRoadMarkerEvent(data: V2XMarkerCardResult) {
|
||||
try {
|
||||
scope.launch(Dispatchers.Default) {
|
||||
BridgeApi.v2xMarker()?.analysisV2XRoadEvent(data)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
//todo 可优化,与obu解析类似
|
||||
private fun handleAdvanceWarningEvent(event: V2XEvent.ForwardsWarning) {
|
||||
scope.launch {
|
||||
val message = event.data
|
||||
val trafficData = buildTrafficData(message)
|
||||
var changeVisualAngle = false
|
||||
when (message.status) {
|
||||
1 -> {
|
||||
var tempAppId = 0
|
||||
var tempTts = ""
|
||||
var tempContent = ""
|
||||
when (message.typeId) {
|
||||
1001 -> {
|
||||
// 弱势交通碰撞预警
|
||||
EventTypeHelper.getVRU { appId, tts, content ->
|
||||
tempAppId = appId
|
||||
tempTts = tts
|
||||
tempContent = content
|
||||
}
|
||||
}
|
||||
1002 -> {
|
||||
// 弱势交通逆行预警
|
||||
EventTypeHelper.getVRURI { appId, tts, content ->
|
||||
tempAppId = appId
|
||||
tempTts = tts
|
||||
tempContent = content
|
||||
}
|
||||
}
|
||||
1003 -> {
|
||||
// 交叉路口碰撞预警
|
||||
changeVisualAngle = true
|
||||
tempAppId = EventTypeEnumNew.TYPE_USECASE_ID_ICW.poiType.toInt()
|
||||
tempTts = EventTypeEnumNew.TYPE_USECASE_ID_ICW.tts
|
||||
tempContent = EventTypeEnumNew.TYPE_USECASE_ID_ICW.content
|
||||
}
|
||||
1004 -> {
|
||||
// 交叉路口碰撞预警
|
||||
changeVisualAngle = true
|
||||
tempAppId = EventTypeEnumNew.TYPE_USECASE_ID_BSW.poiType.toInt()
|
||||
tempTts = String.format(
|
||||
EventTypeEnumNew.TYPE_USECASE_ID_BSW.tts,
|
||||
getWarningDirection()
|
||||
)
|
||||
tempContent = EventTypeEnumNew.TYPE_USECASE_ID_BSW.content
|
||||
}
|
||||
1006 -> {
|
||||
// 逆向超车预警
|
||||
tempAppId = EventTypeEnumNew.TYPE_USECASE_ID_DNPW.poiType.toInt()
|
||||
tempTts = EventTypeEnumNew.TYPE_USECASE_ID_DNPW.tts
|
||||
tempContent = EventTypeEnumNew.TYPE_USECASE_ID_DNPW.content
|
||||
}
|
||||
1005 -> {
|
||||
// 闯红灯预警
|
||||
tempAppId = EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.poiType.toInt()
|
||||
tempTts = EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.tts
|
||||
tempContent = EventTypeEnumNew.TYPE_USECASE_ID_IVP_RED.content
|
||||
}
|
||||
2001 -> {
|
||||
// 最优车道100061
|
||||
EventTypeHelper.getOptLine { appId, tts, content ->
|
||||
tempAppId = appId
|
||||
tempTts = tts
|
||||
tempContent = content
|
||||
}
|
||||
}
|
||||
3001 -> {
|
||||
// 前方道路拥堵预警
|
||||
EventTypeHelper.getTJW { appId, tts, content ->
|
||||
tempAppId = appId
|
||||
tempTts = tts
|
||||
tempContent = content
|
||||
}
|
||||
}
|
||||
}
|
||||
// 不显示弹框,其它保留
|
||||
if (tempContent.isEmpty() || tempTts.isEmpty()) {
|
||||
Log.d("MsgBox-V2XEventManager", "alertContent或ttsContent为空!")
|
||||
}
|
||||
CallerMsgBoxManager.saveMsgBox(
|
||||
MsgBoxBean(
|
||||
MsgBoxType.V2X,
|
||||
V2XMsg(
|
||||
tempAppId.toString(),
|
||||
tempContent,
|
||||
tempTts
|
||||
)
|
||||
)
|
||||
)
|
||||
CallerHmiManager.warningV2X(
|
||||
tempAppId.toString(),
|
||||
tempContent,
|
||||
tempTts,
|
||||
object : IMoGoWarningStatusListener {
|
||||
val change = changeVisualAngle
|
||||
override fun onShow() {
|
||||
if (change) {
|
||||
CallerVisualAngleManager.changeAngle(TooClose)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismiss() {
|
||||
if (change) {
|
||||
CallerVisualAngleManager.changeAngle(Default())
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
CallerMapUIServiceManager.getMarkerService()?.updateITrafficInfo(trafficData)
|
||||
}
|
||||
2 -> {
|
||||
CallerMapUIServiceManager.getMarkerService()?.updateITrafficInfo(trafficData)
|
||||
}
|
||||
3 -> {
|
||||
trafficData.uuid?.let {
|
||||
CallerMapUIServiceManager.getMarkerService()?.removeCvxRvInfoIndInfo(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWarningDirection(): String {
|
||||
return "右" //TODO renwj 原来的逻辑,预警方向先写死, 后续做兼容
|
||||
}
|
||||
|
||||
private fun buildTrafficData(message: V2XAdvanceWarning): TrafficData {
|
||||
return TrafficData().apply {
|
||||
type = when (message.objectType) {
|
||||
1 -> TrafficTypeEnum.TYPE_TRAFFIC_ID_PEOPLE
|
||||
2 -> TrafficTypeEnum.TYPE_TRAFFIC_ID_BICYCLE
|
||||
3 -> TrafficTypeEnum.TYPE_TRAFFIC_ID_TA_CHE
|
||||
4 -> TrafficTypeEnum.TYPE_TRAFFIC_ID_MOTO
|
||||
6 -> TrafficTypeEnum.TYPE_TRAFFIC_ID_BUS
|
||||
8 -> TrafficTypeEnum.TYPE_TRAFFIC_ID_TRUCK
|
||||
9 -> TrafficTypeEnum.TYPE_TRAFFIC_ID_CAMERA
|
||||
else -> TrafficTypeEnum.TYPE_TRAFFIC_ID_WEI_ZHI
|
||||
}
|
||||
uuid = message.objectId
|
||||
lat = message.position?.lat ?: 0.0
|
||||
lon = message.position?.lon ?: 0.0
|
||||
heading = message.heading ?: 0.0
|
||||
threatLevel = message.threatLevel ?: -1
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFail(msg: String) {
|
||||
CallerLogger.e("$M_V2X$TAG", "Error: $msg")
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
if (hasInit.compareAndSet(true, false)) {
|
||||
try {
|
||||
scope.cancel()
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
unRegisterListener()
|
||||
}
|
||||
v2xPoiLoader.stopLoopPoi()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.eagle.core.data.enums.DataSourceType
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.msgbox.V2XMsg
|
||||
import com.mogo.eagle.core.data.v2x.V2XEvent
|
||||
import com.mogo.eagle.core.data.v2x.V2XMarkerResponse
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.network.V2XRefreshModel
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.network.callback.IV2XCallback
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.network.callback.IV2XRefreshCallback
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.utils.DistanceUtils
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class V2XPoiLoader private constructor() {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "V2XPoiLoader"
|
||||
|
||||
val v2xPoiLoader by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
V2XPoiLoader()
|
||||
}
|
||||
}
|
||||
|
||||
private val lastLongitude by lazy { AtomicReference(0.0) }
|
||||
|
||||
private val lastLatitude by lazy { AtomicReference(0.0) }
|
||||
|
||||
private val realLongitude by lazy { AtomicReference(0.0) }
|
||||
|
||||
private val realLatitude by lazy { AtomicReference(0.0) }
|
||||
|
||||
private val handler by lazy {
|
||||
Handler(Looper.getMainLooper())
|
||||
}
|
||||
|
||||
private val cbs by lazy {
|
||||
CopyOnWriteArrayList<IV2XCallback>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加相关信息接口回调
|
||||
* @param cb 要添加的回调接口
|
||||
*/
|
||||
fun addCallback(cb: IV2XCallback) {
|
||||
if (cbs.contains(cb)) {
|
||||
return
|
||||
}
|
||||
cbs += cb
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除相关信息接口回调
|
||||
* @param cb 要移除的回调接口
|
||||
*/
|
||||
fun removeCallback(cb: IV2XCallback) {
|
||||
if (!cbs.contains(cb)) {
|
||||
return
|
||||
}
|
||||
cbs.remove(cb)
|
||||
}
|
||||
|
||||
fun updateCheck(longitude: Double, latitude: Double) {
|
||||
realLongitude.set(longitude)
|
||||
realLatitude.set(latitude)
|
||||
val oldLon = lastLongitude.get()
|
||||
val oldLat = lastLatitude.get()
|
||||
var update = false
|
||||
try {
|
||||
if (oldLon == 0.0 || oldLat == 0.0) {
|
||||
handler.removeCallbacks(refreshTask)
|
||||
handler.post(refreshTask)
|
||||
update = true
|
||||
return
|
||||
}
|
||||
if (DistanceUtils.calculateLineDistance(oldLon, oldLat, longitude, latitude) >= 200f) {
|
||||
handler.removeCallbacks(refreshTask)
|
||||
handler.post(refreshTask)
|
||||
update = true
|
||||
}
|
||||
} finally {
|
||||
if (update) {
|
||||
lastLatitude.set(latitude)
|
||||
lastLongitude.set(longitude)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启loop Poi事件
|
||||
*/
|
||||
fun startLoopPoi() {
|
||||
handler.removeCallbacks(refreshTask)
|
||||
handler.post(refreshTask)
|
||||
}
|
||||
|
||||
private val refreshTask = object : Runnable {
|
||||
override fun run() {
|
||||
V2XRefreshModel.querySnapshot(
|
||||
longitude = realLongitude.get(), latitude = realLatitude.get(),
|
||||
refreshCallback
|
||||
)
|
||||
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(60))
|
||||
}
|
||||
}
|
||||
|
||||
fun stopLoopPoi() {
|
||||
handler.removeCallbacks(refreshTask)
|
||||
lastLatitude.set(0.0)
|
||||
lastLongitude.set(0.0)
|
||||
}
|
||||
|
||||
private val refreshCallback = object : IV2XRefreshCallback<V2XMarkerResponse> {
|
||||
|
||||
override fun onSuccess(result: V2XMarkerResponse) {
|
||||
cbs.forEach {
|
||||
it.onAck(V2XEvent.Marker(result))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFail(msg: String?) {
|
||||
cbs.forEach {
|
||||
it.onFail(msg ?: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询全览路径上的事件信息
|
||||
*/
|
||||
fun queryWholeRoadEvents() {
|
||||
V2XRefreshModel.roadEventDispose()
|
||||
val sn = MoGoAiCloudClientConfig.getInstance().sn
|
||||
val lineId = getLineId()
|
||||
if (lineId > 0) {
|
||||
realQueryV2xEvents(lineId.toString(), sn)
|
||||
} else {
|
||||
UiThreadHandler.postDelayed({
|
||||
realQueryV2xEvents(getLineId().toString(), sn)
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLineId(): Long {
|
||||
var lineId: Long = -1
|
||||
val parameter = CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfo()
|
||||
.autopilotControlParameters
|
||||
if (parameter != null) {
|
||||
if (parameter.autoPilotLine != null) {
|
||||
lineId = parameter.autoPilotLine!!.lineId
|
||||
CallerLogger.d(SceneConstant.M_V2X + TAG, "lineId为:$lineId")
|
||||
} else {
|
||||
CallerLogger.d(SceneConstant.M_V2X + TAG, "parameter.autoPilotLine为null")
|
||||
}
|
||||
} else {
|
||||
CallerLogger.d(SceneConstant.M_V2X + TAG, "parameter为null")
|
||||
}
|
||||
return lineId
|
||||
}
|
||||
|
||||
private fun realQueryV2xEvents(lineId: String, sn: String) {
|
||||
V2XRefreshModel.getRoadEvents(lineId, sn) {
|
||||
val size = it?.size ?: 0
|
||||
if (size > 0) {
|
||||
val msgBoxBean =
|
||||
MsgBoxBean(MsgBoxType.V2X, V2XMsg("", "查询到当前全程共${size}个事件", ""))
|
||||
msgBoxBean.sourceType = DataSourceType.SUMMARY
|
||||
CallerMsgBoxManager.saveMsgBox(msgBoxBean)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.alarm;
|
||||
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew;
|
||||
import com.mogo.eagle.core.data.map.MogoLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
|
||||
import com.mogo.eagle.core.utilcode.util.DrivingDirectionUtils;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import io.netty.util.internal.ConcurrentSet;
|
||||
|
||||
/**
|
||||
* @author donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/4/13 11:02 AM
|
||||
* desc :
|
||||
* 这里是车机端自己实现预警信息的触发操作,首先获取当前车位置周围2公里范围的道路事件,
|
||||
* 普通模式:根据当前「车辆位置」及「行驶方向」判断「车辆前方」「500米」是否有道路事件需要触发。
|
||||
* 导航模式:根据当前「路径规划」及「行驶方向」判断「路径前方」「500米」是否有道路事件需要触发。
|
||||
* 疲劳驾驶:根据服务端下发的触发条件进行触发
|
||||
* <p>
|
||||
* version: 1.0
|
||||
*/
|
||||
public class V2XAlarmServer {
|
||||
|
||||
private static final String TAG = "V2XAlarmServer";
|
||||
|
||||
// 记录道路播报的事件
|
||||
private static final ConcurrentSet<V2XRoadEventEntity> showedEvents = new ConcurrentSet<>();
|
||||
/**
|
||||
* 获取当前车辆前方距离最近的道路事件
|
||||
*/
|
||||
public static V2XRoadEventEntity getDriveFrontAlarmEvent(
|
||||
CopyOnWriteArrayList<V2XRoadEventEntity> v2XRoadEventEntityList,
|
||||
MogoLocation currentLocation) {
|
||||
try {
|
||||
//Logger.d(TAG, "getDriveFrontAlarmEvent --- 1 ---" + currentLocation );
|
||||
if (!showedEvents.isEmpty()) {
|
||||
Iterator<V2XRoadEventEntity> iterator = showedEvents.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
V2XRoadEventEntity next = iterator.next();
|
||||
if (next == null) {
|
||||
continue;
|
||||
}
|
||||
MarkerLocation poiLocation = next.getLocation();
|
||||
if (poiLocation == null) {
|
||||
continue;
|
||||
}
|
||||
if (isOutOfRange(poiLocation.getLon(), poiLocation.getLat(), currentLocation.getLongitude(), currentLocation.getLatitude(), currentLocation.getHeading())) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
//Logger.d(TAG, "getDriveFrontAlarmEvent --- 2 ---" + currentLocation);
|
||||
if (currentLocation != null && v2XRoadEventEntityList != null) {
|
||||
// 因为集合是按照距离排序后的所以这里检索出来第一个就发出警告
|
||||
for (V2XRoadEventEntity v2XRoadEventEntity : v2XRoadEventEntityList) {
|
||||
// 0、道路事件必须有朝向,角度>=0;
|
||||
//Logger.d(TAG, "entity:" + v2XRoadEventEntity.getLocation());
|
||||
if (v2XRoadEventEntity.getLocation().getAngle() >= 0) {
|
||||
// 计算车辆距离指定气泡的距离
|
||||
MarkerLocation eventLocation = v2XRoadEventEntity.getLocation();
|
||||
// 1、判断是否到达了触发距离,20 ~ 500,
|
||||
double distance = v2XRoadEventEntity.getDistance();
|
||||
//Logger.d(TAG, "distance:" + distance);
|
||||
if (distance <= 500) {
|
||||
if (EventTypeEnumNew.GHOST_PROBE.getPoiType().equals(v2XRoadEventEntity.getPoiType())) {
|
||||
if (distance > 25) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// 2、道路事件方向与当前行驶方向角度偏差《20度以内
|
||||
double carBearing = currentLocation.getHeading();
|
||||
double eventBearing = eventLocation.getAngle();
|
||||
double diffAngle = DrivingDirectionUtils.getAngleDiff(carBearing, eventBearing);
|
||||
//Logger.d(TAG, "car_bearing:" + carBearing + ",eventBearing:" + eventBearing + ",diffAngle:" + diffAngle);
|
||||
if (diffAngle <= 20) {
|
||||
// 3、计算当前车辆行驶方向与事件位置之间夹角《20度,保证道路事件在车辆前方
|
||||
double eventAngle = DrivingDirectionUtils.getDegreeOfCar2Poi(
|
||||
currentLocation.getLongitude(),
|
||||
currentLocation.getLatitude(),
|
||||
eventLocation.getLon(),
|
||||
eventLocation.getLat(),
|
||||
(int) currentLocation.getHeading()
|
||||
);
|
||||
|
||||
//Logger.d(TAG, "eventAngle:" + eventAngle);
|
||||
if (0 <= eventAngle && eventAngle <= 20) {
|
||||
if (showedEvents.contains(v2XRoadEventEntity)) {
|
||||
return null;
|
||||
}
|
||||
//Logger.d(TAG, "showed---");
|
||||
showedEvents.add(v2XRoadEventEntity);
|
||||
return v2XRoadEventEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Logger.w(TAG, "error: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isOutOfRange(double poi_lon, double poi_lat, double car_lon, double car_lat, double car_angle) {
|
||||
return !isFrontOfCar(poi_lon, poi_lat, car_lon, car_lat, car_angle);
|
||||
}
|
||||
|
||||
private static boolean isFrontOfCar(double poi_lon, double poi_lat, double car_lon, double car_lat, double car_angle) {
|
||||
double degree = DrivingDirectionUtils.getDegreeOfCar2Poi(car_lon, car_lat, poi_lon, poi_lat, (int)car_angle);
|
||||
return degree <= 90;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.bridge
|
||||
|
||||
import android.content.Context
|
||||
import com.alibaba.android.arouter.launcher.ARouter
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.MoGoV2XServicePaths
|
||||
import com.mogo.eagle.core.utilcode.util.Utils
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoPersonWarnPolylineManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoStopPolylineManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoV2XMarkerManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoWarnPolylineManager
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
internal object BridgeApi {
|
||||
|
||||
private val context by lazy {
|
||||
AtomicReference<WeakReference<Context>>(null)
|
||||
}
|
||||
|
||||
val location by lazy {
|
||||
AtomicReference<MogoLocation>()
|
||||
}
|
||||
|
||||
private val v2xMarker by lazy {
|
||||
ARouter.getInstance().build(MoGoV2XServicePaths.PATH_V2X_MARKER_MANAGER).navigation(context()) as? IMoGoV2XMarkerManager
|
||||
}
|
||||
|
||||
private val v2xWarnPolyline by lazy {
|
||||
ARouter.getInstance().build(MoGoV2XServicePaths.PATH_V2X_WARN_POLYLINE_MANAGER).navigation(
|
||||
context()
|
||||
) as? IMoGoWarnPolylineManager
|
||||
}
|
||||
|
||||
private val v2xPersonWarnPolyline by lazy {
|
||||
ARouter.getInstance().build(MoGoV2XServicePaths.PATH_V2X_PERSON_WARN_POLYLINE_MANAGER).navigation(
|
||||
context()
|
||||
) as? IMoGoPersonWarnPolylineManager
|
||||
}
|
||||
|
||||
private val v2xStopPolyline by lazy {
|
||||
ARouter.getInstance().build(MoGoV2XServicePaths.PATH_V2X_STOP_POLYLINE_MANAGER).navigation(
|
||||
context()
|
||||
) as? IMoGoStopPolylineManager
|
||||
}
|
||||
|
||||
fun init(context: Context) {
|
||||
BridgeApi.context.set(WeakReference(context))
|
||||
}
|
||||
|
||||
fun context(): Context = context.get()?.get() ?: Utils.getApp()
|
||||
|
||||
fun v2xMarker() = v2xMarker
|
||||
|
||||
fun v2xWarnPolyline() = v2xWarnPolyline
|
||||
|
||||
fun v2xPersonWarnPolyline() = v2xPersonWarnPolyline
|
||||
|
||||
fun v2xStopPolyline() = v2xStopPolyline
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.consts;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/4/17 7:35 PM
|
||||
* desc : 对外服务模块路径
|
||||
* version: 1.0
|
||||
* 使用方式:
|
||||
* Arouter.getInstance().path("").navigate()
|
||||
*/
|
||||
@Keep
|
||||
public class MoGoV2XServicePaths {
|
||||
|
||||
/**
|
||||
* V2X 道路事件POI点
|
||||
*/
|
||||
@Keep
|
||||
public static final String PATH_V2X_MARKER_MANAGER = "/v2xMarkerManager/api";
|
||||
|
||||
|
||||
/**
|
||||
* V2X 道路事件与车辆的连接线
|
||||
*/
|
||||
@Keep
|
||||
public static final String PATH_V2X_WARN_POLYLINE_MANAGER = "/v2xWarnPolylineManager/api";
|
||||
|
||||
/**
|
||||
* V2X 二轮车和行人连接线
|
||||
*/
|
||||
@Keep
|
||||
public static final String PATH_V2X_PERSON_WARN_POLYLINE_MANAGER = "/v2xPersonWarnPolylineManager/api";
|
||||
|
||||
/**
|
||||
* V2X 停止线连接线
|
||||
*/
|
||||
@Keep
|
||||
public static final String PATH_V2X_STOP_POLYLINE_MANAGER = "/v2xStopPolylineManager/api";
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.consts;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020-01-2114:10
|
||||
* desc : V2X使用到的常量
|
||||
* version: 1.0
|
||||
*/
|
||||
public class V2XConst {
|
||||
|
||||
|
||||
/**
|
||||
* V2X 场景广播 Action
|
||||
*/
|
||||
public static final String BROADCAST_SCENE_HANDLER_ACTION = "com.v2x.scene_handler_broadcast";
|
||||
public static final String BROADCAST_SCENE_EXTRA_KEY = "V2XMessageEntity";
|
||||
|
||||
|
||||
/**
|
||||
* V2X预警日志tag
|
||||
*/
|
||||
public static final String LOG_NAME_WARN = "PersonWarn";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.template.IProvider;
|
||||
import com.mogo.eagle.core.data.v2x.DrawLineInfo;
|
||||
import com.mogo.map.overlay.IMogoPolyline;
|
||||
|
||||
/**
|
||||
* 绘制可变宽度和渐变的线,
|
||||
*/
|
||||
public interface IMoGoPersonWarnPolylineManager extends IProvider {
|
||||
/**
|
||||
* 绘制连接线,人物和二轮车
|
||||
*
|
||||
* @param context
|
||||
* @param info
|
||||
*/
|
||||
void drawPersonWarnPolyline(Context context, DrawLineInfo info);
|
||||
|
||||
/**
|
||||
* 移除连接线
|
||||
*/
|
||||
void clearLine();
|
||||
|
||||
IMogoPolyline getMogoPersonWarnPolyline();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.template.IProvider;
|
||||
import com.mogo.eagle.core.data.v2x.DrawLineInfo;
|
||||
import com.mogo.map.overlay.IMogoPolyline;
|
||||
|
||||
/**
|
||||
* 绘制可变宽度和渐变的线
|
||||
*/
|
||||
public interface IMoGoStopPolylineManager extends IProvider {
|
||||
/**
|
||||
* 绘制连接线,目标车,与当前车辆间连线
|
||||
*
|
||||
* @param context
|
||||
* @param info
|
||||
*/
|
||||
void drawStopPolyline(Context context, DrawLineInfo info);
|
||||
|
||||
/**
|
||||
* 移除连接线
|
||||
*/
|
||||
void clearLine();
|
||||
|
||||
IMogoPolyline getMogoStopPolyline();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.template.IProvider;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.map.marker.IMogoMarker;
|
||||
import com.mogo.map.marker.IMogoMarkerClickListener;
|
||||
import com.mogo.eagle.core.data.v2x.V2XMarkerCardResult;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/4/17 8:15 PM
|
||||
* desc : V2X 涉及到的地图 POI 点的绘制
|
||||
* version: 1.0
|
||||
*/
|
||||
public interface IMoGoV2XMarkerManager extends IProvider {
|
||||
|
||||
/**
|
||||
* 获取所有的道路事件点,探路事件,返回结果是按照距离当前车辆从近到远排列好的
|
||||
*
|
||||
* @return 按从近到远排列好的道路事件
|
||||
*/
|
||||
CopyOnWriteArrayList<V2XRoadEventEntity> getV2XRoadEventEntityList();
|
||||
|
||||
/**
|
||||
* 从探路数据和新鲜事儿的路况信息中解析出道路事件信息
|
||||
*/
|
||||
void analysisV2XRoadEvent(V2XMarkerCardResult markerCardResult);
|
||||
|
||||
/**
|
||||
* 绘制正在预警的道路事件的POI点
|
||||
* @param context
|
||||
* @param roadEventEntity
|
||||
* @return
|
||||
*/
|
||||
IMogoMarker drawableAlarmPOI(Context context, V2XRoadEventEntity roadEventEntity, IMogoMarkerClickListener clickListener);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.template.IProvider;
|
||||
import com.mogo.eagle.core.data.v2x.DrawLineInfo;
|
||||
import com.mogo.map.overlay.IMogoPolyline;
|
||||
|
||||
/**
|
||||
* 绘制可变宽度和渐变的线
|
||||
*/
|
||||
public interface IMoGoWarnPolylineManager extends IProvider {
|
||||
/**
|
||||
* 绘制连接线,目标车,与当前车辆间连线
|
||||
*
|
||||
* @param context
|
||||
* @param info
|
||||
*/
|
||||
void drawWarnPolyline(Context context, DrawLineInfo info);
|
||||
|
||||
/**
|
||||
* 移除连接线
|
||||
*/
|
||||
void clearLine();
|
||||
|
||||
IMogoPolyline getMogoWarnPolyline();
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager.impl;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.MoGoV2XServicePaths;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.V2XConst;
|
||||
import com.mogo.eagle.core.data.v2x.DrawLineInfo;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoPersonWarnPolylineManager;
|
||||
import com.mogo.map.overlay.IMogoOverlayManager;
|
||||
import com.mogo.map.overlay.IMogoPolyline;
|
||||
import com.mogo.map.overlay.MogoPolylineOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 绘制行人和二轮车连线
|
||||
*/
|
||||
@Route(path = MoGoV2XServicePaths.PATH_V2X_PERSON_WARN_POLYLINE_MANAGER)
|
||||
public class MoGoPersonWarnPolylineManager implements IMoGoPersonWarnPolylineManager {
|
||||
private static IMogoPolyline mMogoPolyline;
|
||||
|
||||
|
||||
@Override
|
||||
public void drawPersonWarnPolyline(Context context, DrawLineInfo info) {
|
||||
if (info == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.remove();
|
||||
}
|
||||
|
||||
// 连接线参数
|
||||
MogoPolylineOptions options = new MogoPolylineOptions().setGps(true);
|
||||
|
||||
// 渐变色
|
||||
List<Integer> colors = new ArrayList<>();
|
||||
colors.add(0x0DE32F46);
|
||||
colors.add(0xD9E32F46);
|
||||
colors.add(0x0DE32F46);
|
||||
|
||||
// 线条粗细,渐变,渐变色值
|
||||
CallerLogger.INSTANCE.d(M_V2X + V2XConst.LOG_NAME_WARN, "MoGoPersonWarnPolylineManager width = " + info.getWidth());
|
||||
options.width(info.getWidth()).useGradient(true).colorValues(colors);
|
||||
List<MogoLatLng> locations = info.getLocations();
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
options.add(locations.get(i));
|
||||
}
|
||||
// 绘制线的对象
|
||||
IMogoOverlayManager overlay = CallerMapUIServiceManager.INSTANCE.getOverlayManager();
|
||||
if (overlay != null) {
|
||||
mMogoPolyline = overlay.addPolyline(options);
|
||||
mMogoPolyline.setTransparency(0.5f);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearLine() {
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.remove();
|
||||
mMogoPolyline = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 绘制连接线的对象
|
||||
*/
|
||||
@Override
|
||||
public IMogoPolyline getMogoPersonWarnPolyline() {
|
||||
return mMogoPolyline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager.impl;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.MoGoV2XServicePaths;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.V2XConst;
|
||||
import com.mogo.eagle.core.data.v2x.DrawLineInfo;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoStopPolylineManager;
|
||||
import com.mogo.map.overlay.IMogoOverlayManager;
|
||||
import com.mogo.map.overlay.IMogoPolyline;
|
||||
import com.mogo.map.overlay.MogoPolylineOptions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 当前车辆与道路事件的连接线
|
||||
*/
|
||||
@Route(path = MoGoV2XServicePaths.PATH_V2X_STOP_POLYLINE_MANAGER)
|
||||
public class MoGoStopPolylineManager implements IMoGoStopPolylineManager {
|
||||
private static IMogoPolyline mMogoPolyline;
|
||||
|
||||
@Override
|
||||
public void drawStopPolyline(Context context, DrawLineInfo info) {
|
||||
if (info == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.remove();
|
||||
}
|
||||
|
||||
// 连接线参数
|
||||
MogoPolylineOptions options = new MogoPolylineOptions()
|
||||
.setGps(true);
|
||||
List<Integer> colors = new ArrayList<>();
|
||||
colors.add(0x0DE32F46);
|
||||
colors.add(0xD9E32F46);
|
||||
colors.add(0x0DE32F46);
|
||||
|
||||
CallerLogger.INSTANCE.d(M_V2X + V2XConst.LOG_NAME_WARN, "MoGoStopPolylineManager roadWidth = " + info.getWidth());
|
||||
// 线条粗细,渐变,渐变色值
|
||||
// 当前车辆位置
|
||||
options.width(info.getWidth() == 0.0 ? 60 : info.getWidth()).useGradient(true).colorValues(colors);
|
||||
List<MogoLatLng> locations = info.getLocations();
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
options.add(locations.get(i));
|
||||
}
|
||||
// 绘制线的对象
|
||||
IMogoOverlayManager overlay = CallerMapUIServiceManager.INSTANCE.getOverlayManager();
|
||||
if (overlay != null) {
|
||||
mMogoPolyline = overlay.addPolyline(options);
|
||||
}
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.setTransparency(0.5f);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearLine() {
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.remove();
|
||||
mMogoPolyline = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IMogoPolyline getMogoStopPolyline() {
|
||||
return mMogoPolyline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager.impl;
|
||||
|
||||
import static com.mogo.commons.module.ServiceConst.CARD_TYPE_NOVELTY;
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew;
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.data.map.MogoLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerExploreWay;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerShowEntity;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.MoGoV2XServicePaths;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoV2XMarkerManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.marker.V2XMarkerAdapter;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.utils.MapUtils;
|
||||
import com.mogo.eagle.core.data.v2x.V2XMarkerCardResult;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils;
|
||||
import com.mogo.map.marker.IMogoMarker;
|
||||
import com.mogo.map.marker.IMogoMarkerClickListener;
|
||||
import com.mogo.map.marker.MogoMarkerOptions;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/4/17 9:57 PM
|
||||
* desc : V2X 涉及到的地图 POI 点的绘制
|
||||
* version: 1.0
|
||||
*/
|
||||
@Route(path = MoGoV2XServicePaths.PATH_V2X_MARKER_MANAGER)
|
||||
public class MoGoV2XMarkerManager implements IMoGoV2XMarkerManager {
|
||||
private static final String TAG = "MoGoV2XMarkerManager";
|
||||
|
||||
// 记录所有的:新鲜事儿的道路事件点、探路事件
|
||||
private final CopyOnWriteArraySet<V2XRoadEventEntity> mV2XRoadEventEntityArrayList = new CopyOnWriteArraySet<>();
|
||||
|
||||
@Override
|
||||
public void init(Context context) {}
|
||||
|
||||
@Override
|
||||
public CopyOnWriteArrayList<V2XRoadEventEntity> getV2XRoadEventEntityList() {
|
||||
CopyOnWriteArrayList<V2XRoadEventEntity> roadEventEntities = new CopyOnWriteArrayList<>();
|
||||
// 当前车辆数据
|
||||
MogoLocation currentLocation = CallerChassisLocationGCJ02ListenerManager.INSTANCE.getChassisLocationGCJ02();
|
||||
if (currentLocation != null) {
|
||||
// 重新计算距离
|
||||
for (V2XRoadEventEntity v2XRoadEventEntity : mV2XRoadEventEntityArrayList) {
|
||||
// 事件位置
|
||||
MarkerLocation location = v2XRoadEventEntity.getLocation();
|
||||
if (location != null) {
|
||||
float calculateDistance = CoordinateUtils.calculateLineDistance(location.getLat(), location.getLon(),
|
||||
currentLocation.getLatitude(), currentLocation.getLongitude());
|
||||
v2XRoadEventEntity.setDistance(calculateDistance);
|
||||
}
|
||||
roadEventEntities.add(v2XRoadEventEntity);
|
||||
}
|
||||
// 按照与当前车辆距离排序
|
||||
for (int i = 0; i < roadEventEntities.size(); i++) {
|
||||
for (int j = i; j > 0; j--) {
|
||||
if (roadEventEntities.get(j).getDistance() < roadEventEntities.get(j - 1).getDistance()) {
|
||||
V2XRoadEventEntity v2XRoadEventEntity = roadEventEntities.get(j - 1);
|
||||
roadEventEntities.set(j - 1, roadEventEntities.get(j));
|
||||
roadEventEntities.set(j, v2XRoadEventEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return roadEventEntities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void analysisV2XRoadEvent(V2XMarkerCardResult markerCardResult) {
|
||||
try {
|
||||
//当没有预警提示的时候重新绘制地图POI点
|
||||
if (markerCardResult != null) {
|
||||
// 清除上次的道路事件, 这里注意,道路事件的触发和这里是异步操作会触发异常
|
||||
mV2XRoadEventEntityArrayList.clear();
|
||||
// 获取探路以及新鲜事儿
|
||||
List<MarkerExploreWay> exploreWayList = markerCardResult.getExploreWay();
|
||||
if (exploreWayList != null) {
|
||||
for (MarkerExploreWay markerExploreWay : exploreWayList) {
|
||||
if (EventTypeEnumNew.isRoadEvent(markerExploreWay.getPoiType())) {
|
||||
MarkerLocation markerLocation = markerExploreWay.getLocation();
|
||||
// 记录道路事件
|
||||
V2XRoadEventEntity v2XRoadEventEntity = new V2XRoadEventEntity();
|
||||
v2XRoadEventEntity.setLocation(markerLocation);
|
||||
// 探路目前只有上报拥堵
|
||||
String poi = markerExploreWay.getPoiType();
|
||||
v2XRoadEventEntity.setPoiType(poi);
|
||||
v2XRoadEventEntity.setNoveltyInfo(markerExploreWay);
|
||||
v2XRoadEventEntity.setExpireTime(20000);
|
||||
mV2XRoadEventEntityArrayList.add(v2XRoadEventEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMogoMarker drawableAlarmPOI(Context context, V2XRoadEventEntity roadEventEntity, IMogoMarkerClickListener clickListener) {
|
||||
try {
|
||||
// 清除原来的大而全的新鲜事儿
|
||||
if (roadEventEntity.getLocation() != null) {
|
||||
// 道路事件,或者水波纹扩散效果
|
||||
MogoMarkerOptions optionsRipple = new MogoMarkerOptions()
|
||||
.data(roadEventEntity)
|
||||
.latitude(roadEventEntity.getLocation().getLat())
|
||||
.longitude(roadEventEntity.getLocation().getLon());
|
||||
optionsRipple.anchor(0.5f, 0.5f);
|
||||
MarkerShowEntity markerShowEntity = new MarkerShowEntity();
|
||||
MarkerExploreWay markerExploreWay = roadEventEntity.getNoveltyInfo();
|
||||
markerShowEntity.setBindObj(markerExploreWay);
|
||||
markerShowEntity.setChecked(false);
|
||||
markerShowEntity.setTextContent(markerExploreWay.getAddr());
|
||||
markerShowEntity.setMarkerLocation(markerExploreWay.getLocation());
|
||||
markerShowEntity.setMarkerType(CARD_TYPE_NOVELTY);
|
||||
optionsRipple.icons(V2XMarkerAdapter.getV2XRoadEventViewGif(context, roadEventEntity));
|
||||
optionsRipple.period(1);
|
||||
IMogoMarker ret = Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getMarkerService()).drawMarker(markerShowEntity);
|
||||
// 当前Marker设置为最上面
|
||||
if (ret != null) {
|
||||
ret.setToTop();
|
||||
}
|
||||
// 缩放地图
|
||||
MapUtils.zoomMap(
|
||||
new MogoLatLng(roadEventEntity.getLocation().getLat(),
|
||||
roadEventEntity.getLocation().getLon()
|
||||
), context);
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
CallerLogger.INSTANCE.e(M_V2X + TAG, "Location 必须进行初始化!!!!!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.manager.impl;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.alibaba.android.arouter.facade.annotation.Route;
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.MoGoV2XServicePaths;
|
||||
import com.mogo.eagle.core.data.v2x.DrawLineInfo;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoWarnPolylineManager;
|
||||
import com.mogo.map.overlay.IMogoOverlayManager;
|
||||
import com.mogo.map.overlay.IMogoPolyline;
|
||||
import com.mogo.map.overlay.MogoPolylineOptions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 当前车辆与道路事件的连接线
|
||||
*/
|
||||
@Route(path = MoGoV2XServicePaths.PATH_V2X_WARN_POLYLINE_MANAGER)
|
||||
public class MoGoWarnPolylineManager implements IMoGoWarnPolylineManager {
|
||||
private static IMogoPolyline mMogoPolyline;
|
||||
private static final String TAG = "V2XWarningMarker";
|
||||
|
||||
@Override
|
||||
public void drawWarnPolyline(Context context, DrawLineInfo info) {
|
||||
if (info == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.remove();
|
||||
}
|
||||
|
||||
// 连接线参数
|
||||
MogoPolylineOptions options = new MogoPolylineOptions()
|
||||
.setGps(true);
|
||||
List<Integer> colors = new ArrayList<>();
|
||||
|
||||
if (info.isHasStopLines()) {
|
||||
colors.add(0x0D3036FF);
|
||||
colors.add(0xD93036FF);
|
||||
colors.add(0x0D3036FF);
|
||||
} else {
|
||||
colors.add(0x0DE32F46);
|
||||
colors.add(0xD9E32F46);
|
||||
colors.add(0x0DE32F46);
|
||||
}
|
||||
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "MoGoWarnPolylineManager roadWidth = " + info.getWidth());
|
||||
// 线条粗细,渐变,渐变色值
|
||||
options.width(info.getWidth() == 0.0 ? 60 : info.getWidth()).useGradient(true).colorValues(colors);
|
||||
List<MogoLatLng> locations = info.getLocations();
|
||||
for (int i = 0; i < locations.size(); i++) {
|
||||
options.add(locations.get(i));
|
||||
}
|
||||
// 绘制线的对象
|
||||
|
||||
IMogoOverlayManager overlay = CallerMapUIServiceManager.INSTANCE.getOverlayManager();
|
||||
if (overlay != null) {
|
||||
mMogoPolyline = overlay.addPolyline(options);
|
||||
}
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.setTransparency(0.5f);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearLine() {
|
||||
if (mMogoPolyline != null) {
|
||||
mMogoPolyline.remove();
|
||||
mMogoPolyline = null;
|
||||
} else {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "mMogoPolyline==null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Context context) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 绘制连接线的对象
|
||||
*/
|
||||
@Override
|
||||
public IMogoPolyline getMogoWarnPolyline() {
|
||||
return mMogoPolyline;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.marker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.core.function.biz.R;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.view.V2XMarkerRoadEventView;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020-01-1015:55
|
||||
* desc : V2X 地图气泡
|
||||
* version: 1.0
|
||||
*/
|
||||
public class V2XMarkerAdapter {
|
||||
|
||||
/**
|
||||
* 返回道路事件
|
||||
*/
|
||||
public static Bitmap getV2XRoadEventMarkerView(Context context, V2XRoadEventEntity alarmInfo, int imageRes) {
|
||||
return new V2XMarkerRoadEventView(context, alarmInfo).setBackground(imageRes).getView();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回道路事件gif序列图集合
|
||||
*/
|
||||
public static ArrayList<Bitmap> getV2XRoadEventViewGif(Context context, V2XRoadEventEntity alarmInfo) {
|
||||
ArrayList<Bitmap> bitmapArrayList;
|
||||
if (EventTypeEnumNew.ALERT_TRAFFIC_LIGHT_SUGGEST.getPoiType().equals(alarmInfo.getPoiType())
|
||||
|| EventTypeEnumNew.ALERT_TRAFFIC_LIGHT_WARNING.getPoiType().equals(alarmInfo.getPoiType())
|
||||
|| EventTypeEnumNew.FOURS_BLOCK_UP.getPoiType().equals(alarmInfo.getPoiType())
|
||||
|| EventTypeEnumNew.ALERT_CAR_TROUBLE_WARNING.getPoiType().equals(alarmInfo.getPoiType())) {
|
||||
bitmapArrayList = getV2XRoadEventOrangeMarkerView(context, alarmInfo);
|
||||
} else {
|
||||
bitmapArrayList = getV2XRoadEventRedMarkerView(context, alarmInfo);
|
||||
}
|
||||
return bitmapArrayList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回红色扩散效果的序列
|
||||
*/
|
||||
public static ArrayList<Bitmap> getV2XRoadEventRedMarkerView(Context context, V2XRoadEventEntity alarmInfo) {
|
||||
ArrayList<Bitmap> icons = new ArrayList<>();
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00011));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00012));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00013));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00014));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00015));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00016));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00017));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00018));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00019));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00020));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00021));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00022));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00023));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00024));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00025));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00026));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00027));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00028));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00029));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00030));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00031));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00032));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00033));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00034));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00035));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00036));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00037));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00038));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00039));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00040));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00041));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00042));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00043));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00044));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00045));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00046));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00047));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_red_00048));
|
||||
return icons;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回橘色色扩散效果的序列
|
||||
*/
|
||||
public static ArrayList<Bitmap> getV2XRoadEventOrangeMarkerView(Context context, V2XRoadEventEntity alarmInfo) {
|
||||
ArrayList<Bitmap> icons = new ArrayList<>();
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00011));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00012));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00013));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00014));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00015));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00016));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00017));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00018));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00019));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00020));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00021));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00022));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00023));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00024));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00025));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00026));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00027));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00028));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00029));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00030));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00031));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00032));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00033));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00034));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00035));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00036));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00037));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00038));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00039));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00040));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00041));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00042));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00043));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00044));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00045));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00046));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00047));
|
||||
icons.add(V2XMarkerAdapter.getV2XRoadEventMarkerView(context, alarmInfo, R.drawable.v_to_x_warning_circle_orange_00048));
|
||||
return icons;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.network
|
||||
|
||||
import com.elegant.network.utils.GsonUtil
|
||||
import com.elegant.network.utils.SignUtil
|
||||
import com.elegant.utils.CommonUtils
|
||||
import com.mogo.cloud.network.RetrofitFactory
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.commons.constants.HostConst
|
||||
import com.mogo.commons.network.ParamsUtil
|
||||
import com.mogo.eagle.core.data.v2x.V2XEventData
|
||||
import com.mogo.eagle.core.data.v2x.V2XLocation
|
||||
import com.mogo.eagle.core.data.v2x.V2XMarkerResponse
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.network.api.V2XApiService
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.network.body.V2XRefreshEntity
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.network.callback.IV2XRefreshCallback
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.DeviceUtils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
internal class V2XRefreshModel {
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "V2XRefreshModel"
|
||||
|
||||
fun querySnapshot(
|
||||
longitude: Double,
|
||||
latitude: Double,
|
||||
callback: IV2XRefreshCallback<V2XMarkerResponse>?
|
||||
): Disposable? {
|
||||
val retrofit = RetrofitFactory.getInstance(HostConst.getEagleHost()) ?: return null
|
||||
return retrofit
|
||||
.create(V2XApiService::class.java)
|
||||
.querySnapshotSync(buildParams(longitude, latitude))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ data ->
|
||||
if (data == null) {
|
||||
callback?.onFail("returned data is null.")
|
||||
return@subscribe
|
||||
}
|
||||
if (data.code != 0 && data.code != 200) {
|
||||
callback?.onFail("code:${data.code}, msg: ${data.msg}")
|
||||
} else {
|
||||
callback?.onSuccess(data)
|
||||
}
|
||||
}, {
|
||||
callback?.onFail(it.message)
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildParams(
|
||||
longitude: Double,
|
||||
latitude: Double,
|
||||
): Map<String, Any> = mutableMapOf<String, Any>().apply {
|
||||
putAll(ParamsUtil.getStaticParams().let {
|
||||
val handled = mutableMapOf<String, Any>()
|
||||
it.asIterable().forEach { itx ->
|
||||
val value = itx.value
|
||||
if (value != null) {
|
||||
handled[itx.key] = value
|
||||
}
|
||||
}
|
||||
handled
|
||||
})
|
||||
this["netType"] = CommonUtils.getNetworkType(AbsMogoApplication.getApp())
|
||||
this["cellId"] = DeviceUtils.getCellId() ?: ""
|
||||
this["sn"] = MoGoAiCloudClientConfig.getInstance().sn
|
||||
this["ticket"] = MoGoAiCloudClientConfig.getInstance().token
|
||||
this["sig"] = SignUtil.createSign(this, "JGjZx6")
|
||||
this["data"] = GsonUtil.jsonFromObject(V2XRefreshEntity().apply {
|
||||
limit = 999
|
||||
location = V2XLocation().also {
|
||||
it.lat = latitude
|
||||
it.lon = longitude
|
||||
}
|
||||
radius = 1000
|
||||
dataType.add("CARD_TYPE_ROAD_CONDITION")
|
||||
viewPush = true
|
||||
})
|
||||
}
|
||||
|
||||
private var v2xEventDisposable: Disposable? = null
|
||||
|
||||
fun roadEventDispose(){
|
||||
if (v2xEventDisposable != null && !v2xEventDisposable!!.isDisposed) {
|
||||
v2xEventDisposable!!.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
fun getRoadEvents(lineId: String, sn: String, onSuccess:((List<V2XEventData>?) -> Unit)){
|
||||
v2xEventDisposable = MoGoRetrofitFactory.getInstance(HostConst.getHost())
|
||||
.create(V2XApiService::class.java)
|
||||
.queryAllV2XEventsByLineId(lineId, sn)
|
||||
.map {
|
||||
if (it.code == 200 || it.code == 0) {
|
||||
CallerLogger.d(SceneConstant.M_V2X + TAG, "请求成功,size为:${it.result?.v2XEventList?.size}")
|
||||
return@map it.result?.v2XEventList
|
||||
} else {
|
||||
CallerLogger.d(SceneConstant.M_V2X + TAG, "请求失败,code为:${it.code}")
|
||||
return@map ArrayList()
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
onSuccess.invoke(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.network.api
|
||||
|
||||
import com.mogo.eagle.core.data.v2x.V2XEventResult
|
||||
import com.mogo.eagle.core.data.v2x.V2XMarkerResponse
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import retrofit2.http.*
|
||||
|
||||
internal interface V2XApiService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST("eagle-eye-dns/yycp-launcherSnapshot/launcherSnapshot/querySnapshotSync")
|
||||
fun querySnapshotSync(@FieldMap parameters: Map<String, @JvmSuppressWildcards Any>): Maybe<V2XMarkerResponse?>
|
||||
|
||||
@GET("/eagleEye-mis/config/queryV2NInformation")
|
||||
fun queryAllV2XEventsByLineId(@Query("lineId") lineId: String, @Query("sn") sn: String): Observable<V2XEventResult>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.network.body
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.mogo.eagle.core.data.v2x.V2XLocation
|
||||
|
||||
/**
|
||||
* 刷新地图信息接口
|
||||
*/
|
||||
@Keep
|
||||
internal class V2XRefreshEntity {
|
||||
|
||||
@JvmField
|
||||
var dataType: MutableList<String> = mutableListOf() // 要查询的类型
|
||||
|
||||
@JvmField
|
||||
var limit = 50 // 请求数量
|
||||
|
||||
@JvmField
|
||||
var radius = 2000 // 地理围栏半径(米)
|
||||
|
||||
@JvmField
|
||||
var location // 坐标
|
||||
: V2XLocation? = null
|
||||
@JvmField
|
||||
var sn: String? = null
|
||||
|
||||
@JvmField
|
||||
var onlyFocus // 是否仅查询已关注的好友
|
||||
= false
|
||||
@JvmField
|
||||
var onlySameCity // 是否仅查询注册城市相同的同城用户
|
||||
= false
|
||||
@JvmField
|
||||
var viewPush // 是否走V2X通道 ,true-401011,false -401001
|
||||
= false
|
||||
@JvmField
|
||||
var onlyRealUser = false
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.network.callback
|
||||
|
||||
import com.mogo.eagle.core.data.v2x.V2XEvent
|
||||
|
||||
interface IV2XCallback {
|
||||
|
||||
|
||||
/**
|
||||
* 获取到V2X事件成功回调
|
||||
* @param event
|
||||
* - 参数说明:目前此参数支持以下类型
|
||||
* - [V2XEvent.ForwardsWarning]: 路口碰撞预警、盲区预警等预警事件, 数据实体取自[V2XEvent.ForwardsWarning.data]
|
||||
* - [V2XEvent.Road]: 道路事件, 数据实体取自[V2XEvent.Road.data]
|
||||
* - [V2XEvent.Warning]: 预警目标物事件, 数据实体取自[V2XEvent.Warning.data]
|
||||
* - [V2XEvent.Marker]: 道路标记事件, 数据实体取自[V2XEvent.Marker.data]
|
||||
*/
|
||||
fun onAck(event: V2XEvent)
|
||||
|
||||
/**
|
||||
* V2X事件获取过程中,出现的异常信息,用于问题排查
|
||||
* @param msg 异常信息
|
||||
*/
|
||||
fun onFail(msg: String)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.network.callback
|
||||
|
||||
/**
|
||||
* 刷新回调
|
||||
*/
|
||||
internal interface IV2XRefreshCallback<T> {
|
||||
|
||||
fun onSuccess(result: T)
|
||||
|
||||
fun onFail(msg: String?)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.V2XConst
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.impl.V2XScenarioManager
|
||||
|
||||
class SceneBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
companion object {
|
||||
fun register(context: Context) {
|
||||
val localReceiver = SceneBroadcastReceiver()
|
||||
val localBroadcastManager = LocalBroadcastManager.getInstance(context)
|
||||
val intentFilter = IntentFilter()
|
||||
intentFilter.addAction(V2XConst.BROADCAST_SCENE_HANDLER_ACTION)
|
||||
localBroadcastManager.registerReceiver(localReceiver, intentFilter)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
try {
|
||||
val v2XMessageEntity =
|
||||
intent?.getSerializableExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY) as? V2XMessageEntity<*>
|
||||
v2XMessageEntity?.let {
|
||||
V2XScenarioManager.getInstance().handlerMessage(it)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.remove
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.util.Log
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.eagle.core.utilcode.util.DrivingDirectionUtils
|
||||
import com.mogo.map.marker.IMogoMarker
|
||||
import com.mogo.map.overlay.IMogoPolyline
|
||||
import kotlinx.coroutines.Runnable
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
|
||||
data class MarkerWrapper(val id: String, val lon: Double, val lat: Double, val coordinateType: Int, var markers: ArrayList<IMogoMarker>? = null, var lines: ArrayList<IMogoPolyline>? = null) {
|
||||
|
||||
fun addLine(line: IMogoPolyline) {
|
||||
var ll = this.lines
|
||||
if (ll == null) {
|
||||
ll = ArrayList()
|
||||
this.lines = ll
|
||||
}
|
||||
ll.add(line)
|
||||
}
|
||||
|
||||
fun addMarker(marker: IMogoMarker) {
|
||||
var mm = this.markers
|
||||
if (mm == null) {
|
||||
mm = ArrayList()
|
||||
this.markers = mm
|
||||
}
|
||||
mm.add(marker)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as MarkerWrapper
|
||||
|
||||
if (id != other.id) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
object MarkerRemoveManager {
|
||||
|
||||
private const val TAG = "MarkerManager"
|
||||
|
||||
private val showedMarkers by lazy { LinkedList<MarkerWrapper>() }
|
||||
|
||||
private val toRemoveMakers by lazy { LinkedList<MarkerWrapper>() }
|
||||
|
||||
private val isFirstAdd by lazy { AtomicBoolean(false) }
|
||||
|
||||
private val elapsedDistances by lazy { ConcurrentHashMap<MarkerWrapper, Double>() }
|
||||
|
||||
private val lastCarLocation by lazy { AtomicReference<Pair<Double, Double>>() }
|
||||
|
||||
private val lastGpsLocation by lazy { AtomicReference<Pair<Double, Double>>() }
|
||||
|
||||
private val checkTask = object : Runnable {
|
||||
|
||||
override fun run() {
|
||||
|
||||
try {
|
||||
Log.d(TAG, "--- checkTask --- 1 ---")
|
||||
if (lastCarLocation.get() == null) {
|
||||
return
|
||||
}
|
||||
Log.d(TAG, "--- checkTask --- 2 ---")
|
||||
if (lastGpsLocation.get() == null) {
|
||||
return
|
||||
}
|
||||
Log.d(TAG, "--- checkTask --- 3 ---")
|
||||
val toRemove = toRemoveMakers.iterator()
|
||||
val carLoc = AtomicReference<MogoLocation>()
|
||||
while (toRemove.hasNext()) {
|
||||
val marker = toRemove.next()
|
||||
if (carLoc.get() == null) {
|
||||
carLoc.set(if (marker.coordinateType == 0) {
|
||||
//高德坐标
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
} else {
|
||||
//高精坐标
|
||||
CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84()
|
||||
})
|
||||
}
|
||||
val currentLocation = carLoc.get()
|
||||
val lastLocation = if (marker.coordinateType == 0) lastCarLocation.get() else lastGpsLocation.get()
|
||||
if (currentLocation != null && lastLocation != null) {
|
||||
val delta = CoordinateUtils.calculateLineDistance(currentLocation.longitude, currentLocation.latitude, lastLocation.first, lastLocation.second)
|
||||
Log.d(TAG, "--- checkTask --- 4 ---:delta:$delta, id:${marker.id}")
|
||||
var elapsed = elapsedDistances[marker]
|
||||
if (elapsed == null) {
|
||||
elapsed = delta.toDouble()
|
||||
} else {
|
||||
elapsed += delta
|
||||
}
|
||||
Log.d(TAG, "--- checkTask --- 5 ---:delta:$delta, elapsed:${elapsed}, id: ${marker.id}")
|
||||
if (elapsed >= 200) {
|
||||
var removeMarkerError = false
|
||||
marker.markers?.forEach {
|
||||
try {
|
||||
Log.e(TAG, "--- checkTask --- remove marker: $it, id: ${marker.id}")
|
||||
it.setVisible(false)
|
||||
it.destroy()
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
removeMarkerError = true
|
||||
Log.e(TAG, "--- checkTask --- remove marker error:${t.message}, id: ${marker.id}")
|
||||
}
|
||||
}
|
||||
var removeLineError = false
|
||||
marker.lines?.forEach {
|
||||
try {
|
||||
it.isVisible = false
|
||||
Log.e(TAG, "--- checkTask --- remove line : $it, id:${marker.id}")
|
||||
it.destroy()
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
removeLineError = true
|
||||
Log.e(TAG, "--- checkTask --- remove line error:${t.message}, id: ${marker.id}")
|
||||
}
|
||||
}
|
||||
if (!removeLineError && !removeMarkerError) {
|
||||
toRemove.remove()
|
||||
synchronized(elapsedDistances) {
|
||||
elapsedDistances.remove(marker)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
elapsedDistances[marker] = elapsed
|
||||
}
|
||||
}
|
||||
}
|
||||
val iterator = showedMarkers.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val marker = iterator.next()
|
||||
if (carLoc.get() == null) {
|
||||
carLoc.set(if (marker.coordinateType == 0) {
|
||||
//高德坐标
|
||||
CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
} else {
|
||||
//高精坐标
|
||||
CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84()
|
||||
})
|
||||
}
|
||||
val location = carLoc.get()
|
||||
if (location != null) {
|
||||
val angle = DrivingDirectionUtils.getDegreeOfCar2Poi2(location.longitude, location.latitude, marker.lon, marker.lat, location.heading)
|
||||
if (angle >= 90) {
|
||||
iterator.remove()
|
||||
synchronized(toRemoveMakers) {
|
||||
toRemoveMakers.offer(marker)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (t: Throwable) {
|
||||
t.printStackTrace()
|
||||
} finally {
|
||||
val gcInfo = CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
lastCarLocation.set((gcInfo?.longitude ?: 0.0) to (gcInfo?.latitude ?: 0.0))
|
||||
val wgsInfo = CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84()
|
||||
lastGpsLocation.set((wgsInfo?.longitude ?: 0.0) to (wgsInfo?.latitude ?: 0.0))
|
||||
handler.postDelayed(this, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val handler by lazy {
|
||||
val thread = HandlerThread("check_marker_expired")
|
||||
thread.start()
|
||||
Handler(thread.looper)
|
||||
}
|
||||
|
||||
|
||||
fun addMarker(marker: MarkerWrapper) {
|
||||
Log.d(TAG, "=== addMarker ====: $marker")
|
||||
synchronized(showedMarkers) {
|
||||
showedMarkers.offer(marker)
|
||||
}
|
||||
if (isFirstAdd.compareAndSet(false,true)) {
|
||||
handler.postDelayed(checkTask, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario;
|
||||
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/15 4:13 PM
|
||||
* desc : V2X安全驾驶场景接口
|
||||
* version: 1.0
|
||||
*/
|
||||
public interface IV2XScenario {
|
||||
|
||||
/**
|
||||
* 展示场景
|
||||
*/
|
||||
void show();
|
||||
|
||||
/**
|
||||
* 关闭场景
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* 绘制POI
|
||||
*/
|
||||
void drawPOI();
|
||||
|
||||
/**
|
||||
* 清除POI
|
||||
*/
|
||||
void clearPOI();
|
||||
|
||||
/**
|
||||
* 是否是相同的场景,如果是说明重复的场景,需要根据场景进行不同的处理
|
||||
*
|
||||
* @param v2XMessageEntity 要比较的场景
|
||||
* @return true-相同的场景,false-不同场景
|
||||
*/
|
||||
boolean isSameScenario(V2XMessageEntity v2XMessageEntity);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario;
|
||||
|
||||
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/15 3:47 PM
|
||||
* desc : V2X安全驾驶场景管理
|
||||
* version: 1.0
|
||||
*/
|
||||
public interface IV2XScenarioManager {
|
||||
void handlerMessage(V2XMessageEntity v2XMessageEntity);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.impl;
|
||||
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.IV2XScenario;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.view.IV2XMarker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/15 5:01 PM
|
||||
* desc :
|
||||
* version: 1.0
|
||||
*/
|
||||
public abstract class AbsV2XScenario<T> implements IV2XScenario {
|
||||
protected String TAG = "AbsV2XScenario";
|
||||
private IV2XMarker mV2XMarker;
|
||||
private final AtomicReference<V2XMessageEntity> mV2XMessageEntity = new AtomicReference<>();
|
||||
|
||||
protected AbsV2XScenario() {
|
||||
}
|
||||
|
||||
public abstract void init(@Nullable V2XMessageEntity<T> v2XMessageEntity);
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// clearPOI();
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放资源
|
||||
*/
|
||||
public void release() {
|
||||
mV2XMessageEntity.set(null);
|
||||
mV2XMarker = null;
|
||||
}
|
||||
|
||||
public IV2XMarker getV2XMarker() {
|
||||
return mV2XMarker;
|
||||
}
|
||||
|
||||
public void setV2XMarker(@Nullable IV2XMarker mV2XMarker) {
|
||||
this.mV2XMarker = mV2XMarker;
|
||||
}
|
||||
|
||||
public void setV2XMessageEntity(@Nullable V2XMessageEntity<T> mV2XMessageEntity) {
|
||||
this.mV2XMessageEntity.set(mV2XMessageEntity);
|
||||
}
|
||||
|
||||
public V2XMessageEntity<T> getV2XMessageEntity() {
|
||||
return mV2XMessageEntity.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameScenario(@Nullable V2XMessageEntity v2XMessageEntity) {
|
||||
V2XMessageEntity old = mV2XMessageEntity.get();
|
||||
if (old == null) {
|
||||
return false;
|
||||
}
|
||||
return old.equals(v2XMessageEntity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.impl;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import com.mogo.commons.module.status.MogoStatusManager;
|
||||
import com.mogo.eagle.core.data.config.HmiBuildConfig;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.IV2XScenarioManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.road.V2XRoadEventScenario;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.warning.V2XFrontWarningScenario;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils;
|
||||
import com.mogo.map.uicontroller.IMogoMapUIController;
|
||||
import com.mogo.map.uicontroller.VisualAngleMode;
|
||||
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/15 4:22 PM
|
||||
* desc : 场景管理的分发
|
||||
* version: 1.0
|
||||
*/
|
||||
public class V2XScenarioManager implements IV2XScenarioManager {
|
||||
private static V2XScenarioManager mV2XScenarioManager;
|
||||
private static final String TAG = "V2XScenarioManager";
|
||||
private AbsV2XScenario mV2XScenario = null;
|
||||
|
||||
private V2XScenarioManager() {
|
||||
}
|
||||
|
||||
public static V2XScenarioManager getInstance() {
|
||||
if (mV2XScenarioManager == null) {
|
||||
synchronized (V2XScenarioManager.class) {
|
||||
if (mV2XScenarioManager == null) {
|
||||
mV2XScenarioManager = new V2XScenarioManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return mV2XScenarioManager;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handlerMessage(V2XMessageEntity v2XMessageEntity) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "处理V2X场景:" + (v2XMessageEntity == null ? "null" : v2XMessageEntity.toString()));
|
||||
try {
|
||||
synchronized (V2XScenarioManager.class) {
|
||||
// 展示
|
||||
ThreadUtils.runOnUiThread(() -> {
|
||||
// 提取之前存储的场景
|
||||
if (v2XMessageEntity != null) {
|
||||
// 如果没有拿到之前的,根据类型分发
|
||||
switch (v2XMessageEntity.getType()) {
|
||||
case V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING:
|
||||
mV2XScenario = new V2XRoadEventScenario();
|
||||
break;
|
||||
case V2XMessageEntity.V2XTypeEnum.ALERT_THE_FRONT_WEAKNESS:
|
||||
if (HmiBuildConfig.isShowCloudWeaknessTrafficView) { //默认关闭云端弱势交通
|
||||
sceneChange();
|
||||
if (MogoStatusManager.getInstance().isVrMode()) {
|
||||
mV2XScenario = new V2XFrontWarningScenario();
|
||||
} else {
|
||||
mV2XScenario = null;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
mV2XScenario = null;
|
||||
CallerLogger.INSTANCE.e(M_V2X + TAG, "当前V2X消息类型未定义:" + v2XMessageEntity);
|
||||
return;
|
||||
}
|
||||
// 展示最新的消息
|
||||
if (mV2XScenario != null) {
|
||||
mV2XScenario.init(v2XMessageEntity);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* http://wiki.zhidaohulian.com/pages/viewpage.action?pageId=52833468
|
||||
* 道路事件触发后,切换到中景
|
||||
*/
|
||||
private void sceneChange() {
|
||||
IMogoMapUIController mapUiController = CallerMapUIServiceManager.INSTANCE.getMapUIController();
|
||||
if (mapUiController != null && mapUiController.getCurrentMapVisualAngle() != VisualAngleMode.MODE_MEDIUM_SIGHT) {
|
||||
mapUiController.changeMapVisualAngle(VisualAngleMode.MODE_MEDIUM_SIGHT, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.airoad
|
||||
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.graphics.Color
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import androidx.core.util.Pair
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity
|
||||
import com.mogo.eagle.core.function.call.autopilot.*
|
||||
import com.mogo.eagle.core.function.call.map.*
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.road.V2XAiRoadEventMarker
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
|
||||
import com.mogo.eagle.core.utilcode.util.DrivingDirectionUtils
|
||||
import com.mogo.map.MogoMap
|
||||
import com.mogo.map.overlay.IMogoPolyline
|
||||
import com.mogo.map.overlay.MogoPolylineOptions
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.remove.MarkerRemoveManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.remove.MarkerWrapper
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
|
||||
/**
|
||||
* Ai云道路施工事件,道路颜色标记类
|
||||
*/
|
||||
class AiRoadMarker {
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val aiMakers = ConcurrentHashMap<String, AiRoadMarker>()
|
||||
}
|
||||
|
||||
private val TAG = "AiRoadMarker"
|
||||
|
||||
private val marker by lazy { AtomicReference<Marker>() }
|
||||
|
||||
private val overlayManager by lazy {
|
||||
CallerMapUIServiceManager.getOverlayManager()
|
||||
}
|
||||
|
||||
private val START_COLOR = Color.parseColor("#002ABAD9")
|
||||
private val END_COLOR = Color.parseColor("#66FF7A30")
|
||||
|
||||
private val roadMarker by lazy { V2XAiRoadEventMarker() }
|
||||
|
||||
private val line = AtomicReference<IMogoPolyline>()
|
||||
|
||||
private val handler by lazy {
|
||||
Handler(Looper.getMainLooper())
|
||||
}
|
||||
|
||||
private val checkExpiredTask = Runnable {
|
||||
val poi = this.marker.get()
|
||||
val car = CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84()
|
||||
if (poi != null && car != null) {
|
||||
val distance = CoordinateUtils.calculateLineDistance(car.longitude, car.latitude, poi.poi_lon, poi.poi_lat)
|
||||
if (distance < 500) {
|
||||
unMarker(poi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val options by lazy {
|
||||
MogoPolylineOptions().apply {
|
||||
zIndex(40000f)
|
||||
setGps(true)
|
||||
width(50f)
|
||||
useGradient(true)
|
||||
}
|
||||
}
|
||||
|
||||
fun marker(marker: Marker, drawMarker: Boolean, drawRoadLine: Boolean = false) {
|
||||
val location = CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84() ?: return
|
||||
this.marker.set(marker)
|
||||
val wrapper = MarkerWrapper(marker.id, marker.poi_lon, marker.poi_lat, 1, null, null)
|
||||
if (drawMarker) {
|
||||
marker.entity?.apply { roadMarker.drawMarkers(this, wrapper) }
|
||||
}
|
||||
if (drawRoadLine) {
|
||||
//施工中心点前方的自车行驶方向上300米距离
|
||||
val l1 = MogoMap.getInstance().mogoMap.getCenterLineRangeInfo(marker.poi_lon, marker.poi_lat, location.heading.toFloat(), 300f)
|
||||
//施工中心点后方的自车行驶方向上300米距离
|
||||
Logger.d(TAG, "--- marker --- 3 --- l1: $l1")
|
||||
val l2 = MogoMap.getInstance().mogoMap.getCenterLineRangeInfo(marker.poi_lon, marker.poi_lat, location.heading.toFloat(), -300f)
|
||||
if (l1.points.isEmpty() || l2.points.isEmpty()) {
|
||||
Logger.d(TAG, "--- marker --- 3 --- return ----")
|
||||
return
|
||||
}
|
||||
Logger.d(TAG, "--- marker --- 4 --- l2: $l2")
|
||||
val points = LinkedList<MogoLatLng>()
|
||||
if (l2 != null && l2.points.isNotEmpty()) {
|
||||
points.addAll(l2.points.reversed().map {
|
||||
MogoLatLng(it.second, it.first)
|
||||
})
|
||||
}
|
||||
val centerX= marker.poi_lon
|
||||
val centerY = marker.poi_lat
|
||||
Logger.d(TAG, "--- marker --- 5 --- marker: $marker")
|
||||
val farthestPoint = marker.polygon?.let {
|
||||
var find: Pair<Double, Double> = Pair(centerX, centerY)
|
||||
var min = Long.MAX_VALUE
|
||||
for (p in it) {
|
||||
val angle = DrivingDirectionUtils.getDegreeOfCar2Poi2(centerX, centerY, p.first, p.second, location.heading)
|
||||
if (angle < min) {
|
||||
min = angle
|
||||
find = p
|
||||
}
|
||||
}
|
||||
MogoLatLng(find.second, find.first)
|
||||
} ?: MogoLatLng(centerY, centerX)
|
||||
marker.farthestPoint = Pair(farthestPoint.lon, farthestPoint.lat)
|
||||
Logger.d(TAG, "--- marker --- 6 --- marker: $marker")
|
||||
if (l1 != null && l1.points.isNotEmpty()) {
|
||||
for (l in l1.points) {
|
||||
if (DrivingDirectionUtils.getDegreeOfCar2Poi2(farthestPoint.lon, farthestPoint.lat, l.first, l.second, (location.heading + 180)) < 90L) {
|
||||
points.add(l.let { MogoLatLng(it.second, it.first) })
|
||||
}
|
||||
}
|
||||
}
|
||||
if (points.size <= 1) {
|
||||
return
|
||||
}
|
||||
val evaluator = ArgbEvaluator()
|
||||
val interceptor = DecelerateInterpolator(1.5f)
|
||||
val total = points.size
|
||||
val colors = ArrayList<Int>()
|
||||
(0..total).forEach { i ->
|
||||
colors += evaluator.evaluate(interceptor.getInterpolation(i * 1f / total), START_COLOR, END_COLOR) as Int
|
||||
}
|
||||
var line = line.get()
|
||||
options.points(points)
|
||||
options.colorValues(colors)
|
||||
Logger.d(TAG, "--- marker --- 7 --- points: ${points.size}")
|
||||
if (line == null || line.isDestroyed) {
|
||||
val l = overlayManager?.addPolyline(options)
|
||||
this.line.set(l)
|
||||
line = l
|
||||
} else {
|
||||
line.setOption(options)
|
||||
}
|
||||
if (!line.isVisible) {
|
||||
line.isVisible = true
|
||||
}
|
||||
if (line != null) {
|
||||
wrapper.addLine(line)
|
||||
}
|
||||
}
|
||||
MarkerRemoveManager.addMarker(wrapper)
|
||||
}
|
||||
|
||||
private fun removeLine() {
|
||||
val old = line.get()
|
||||
Logger.d(TAG, "--- removeRedLine --- 1 ---")
|
||||
if (old != null) {
|
||||
Logger.d(TAG, "--- removeRedLine --- 2 ---")
|
||||
line.set(null)
|
||||
old.isVisible = false
|
||||
old.remove()
|
||||
}
|
||||
}
|
||||
|
||||
private fun unMarker(marker: Marker) {
|
||||
Logger.d(TAG, "--- unMarker ---")
|
||||
this.marker.set(null)
|
||||
removeLine()
|
||||
roadMarker.removeMarkers()
|
||||
handler.removeCallbacks(checkExpiredTask)
|
||||
}
|
||||
|
||||
fun receive() {
|
||||
Logger.d(TAG, "receive --- 1 ---")
|
||||
val poi = this.marker.get()
|
||||
val car = CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84()
|
||||
if (poi != null && car != null) {
|
||||
val distance = CoordinateUtils.calculateLineDistance(car.longitude, car.latitude, poi.poi_lon, poi.poi_lat)
|
||||
Logger.d(TAG, "receive --- 2 ---:car:[${car.longitude}, ${car.latitude}] -> poi:[${poi.poi_lon}, ${poi.poi_lat}] --> distance:$distance")
|
||||
if (distance < 500) {
|
||||
checkExpired()
|
||||
} else {
|
||||
handler.removeCallbacks(checkExpiredTask)
|
||||
}
|
||||
} else {
|
||||
if (poi != null) {
|
||||
checkExpired()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkExpired() {
|
||||
handler.removeCallbacks(checkExpiredTask)
|
||||
handler.postDelayed(checkExpiredTask, 10000)
|
||||
}
|
||||
|
||||
data class Marker(
|
||||
val id: String,
|
||||
val poiType: String,
|
||||
val poi_lat: Double,
|
||||
val poi_lon: Double,
|
||||
val poi_angle: Double,
|
||||
val polygon: List<Pair<Double, Double>>? = null,
|
||||
var farthestPoint: Pair<Double, Double>? = null,
|
||||
var entity: V2XRoadEventEntity? = null
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as Marker
|
||||
if (id != other.id) return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return id.hashCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.road
|
||||
|
||||
import android.graphics.Color
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.bridge.BridgeApi.context
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.bridge.BridgeApi.v2xMarker
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.remove.MarkerWrapper
|
||||
import com.mogo.map.marker.IMogoMarker
|
||||
import com.mogo.map.overlay.IMogoPolyline
|
||||
import com.mogo.map.overlay.MogoPolylineOptions
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class V2XAiRoadEventMarker {
|
||||
|
||||
private val current = AtomicReference<Pair<IMogoPolyline?, List<IMogoMarker>?>>()
|
||||
|
||||
private val overlayManager by lazy { CallerMapUIServiceManager.getOverlayManager() }
|
||||
|
||||
fun drawMarkers(entity: V2XRoadEventEntity, wrapper: MarkerWrapper) {
|
||||
val polygon = entity.noveltyInfo.polygon
|
||||
v2xMarker()?.drawableAlarmPOI(context(), entity, null)?.also {
|
||||
wrapper.addMarker(it)
|
||||
}
|
||||
if (polygon != null && polygon.isNotEmpty() && entity.poiType != EventTypeEnumNew.TYPE_SOCKET_ROAD_JINGZHI.poiType) {
|
||||
val options = MogoPolylineOptions()
|
||||
val colors = ArrayList<Int>()
|
||||
colors.add(Color.argb(204, 237, 172, 21))
|
||||
colors.add(Color.argb(0, 255, 255, 255))
|
||||
options.colorValues(colors)
|
||||
val points = ArrayList<MogoLatLng>()
|
||||
|
||||
for (p in polygon) {
|
||||
points.add(MogoLatLng(p.first, p.second))
|
||||
}
|
||||
if (points.size > 2) {
|
||||
points.add(points[0])
|
||||
}
|
||||
options.points(points)
|
||||
options.useGradient(true)
|
||||
options.useFacade(true)
|
||||
options.setGps(true)
|
||||
options.width(5f)
|
||||
options.zIndex(75000f)
|
||||
options.maxIndex(800000f)
|
||||
val line = overlayManager?.addPolyline(options)
|
||||
line?.let {
|
||||
current.set(Pair(line, wrapper.markers))
|
||||
line.isVisible = true
|
||||
wrapper.addLine(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeMarkers() {
|
||||
val prev = current.get()
|
||||
if (prev != null) {
|
||||
realRemove(prev)
|
||||
}
|
||||
}
|
||||
|
||||
private fun realRemove(pair: Pair<IMogoPolyline?, List<IMogoMarker>?>) {
|
||||
val line = pair.first
|
||||
if (line != null && line.isVisible) {
|
||||
line.remove()
|
||||
}
|
||||
val markers = pair.second
|
||||
if (markers != null && markers.isNotEmpty()) {
|
||||
for (m in markers) {
|
||||
m.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.road;
|
||||
|
||||
import android.util.Log;
|
||||
import androidx.core.util.Pair;
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerExploreWay;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.bridge.BridgeApi;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoV2XMarkerManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.remove.MarkerWrapper;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.remove.MarkerRemoveManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.airoad.AiRoadMarker;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.view.IV2XMarker;
|
||||
import com.mogo.map.marker.IMogoMarker;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 道路V2X事件的Marker
|
||||
*/
|
||||
public class V2XRoadEventMarker implements IV2XMarker<V2XRoadEventEntity> {
|
||||
|
||||
|
||||
@Override
|
||||
public void drawPOI(V2XRoadEventEntity entity) {
|
||||
try {
|
||||
// 清除道路事件
|
||||
IMoGoV2XMarkerManager marker = BridgeApi.INSTANCE.v2xMarker();
|
||||
if (marker != null) {
|
||||
if (entity != null) {
|
||||
Log.d("RWJ", "V2XRoadEventMarker:" + entity.getPoiType());
|
||||
if (isAiRoadEvent(entity.getPoiType())) {
|
||||
MarkerExploreWay noveltyInfo = entity.getNoveltyInfo();
|
||||
Log.d("RWJ", "V2XRoadEventMarker -> noveltyInfo:" + noveltyInfo);
|
||||
if (noveltyInfo != null) {
|
||||
Pair<Double, Double> gpsLocation = noveltyInfo.getGpsLocation();
|
||||
List<Pair<Double, Double>> polygons = noveltyInfo.getPolygon();
|
||||
if (gpsLocation != null && polygons != null) {
|
||||
MarkerLocation location = noveltyInfo.getLocation();
|
||||
AiRoadMarker.Marker m = new AiRoadMarker.Marker(noveltyInfo.getInfoId(), noveltyInfo.getPoiType(), gpsLocation.second, gpsLocation.first, location.getAngle(), polygons, null, entity);
|
||||
AiRoadMarker aiMarker = new AiRoadMarker();
|
||||
aiMarker.marker(m, true, isDrawRoadLine(m.getPoiType()));
|
||||
AiRoadMarker.aiMakers.put(noveltyInfo.getInfoId(), aiMarker);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IMogoMarker iMarker = marker.drawableAlarmPOI(BridgeApi.INSTANCE.context(), entity, null);
|
||||
if (iMarker != null) {
|
||||
Log.d("RWJ", "V2XRoadEventMarker:" + entity.getPoiType() + "--- add Marker");
|
||||
ArrayList<IMogoMarker> markers = new ArrayList<>();
|
||||
markers.add(iMarker);
|
||||
String id = entity.getLocation().getLon() + "_" + entity.getLocation().getLat();
|
||||
MarkerRemoveManager.INSTANCE.addMarker(new MarkerWrapper(id, entity.getLocation().getLon(), entity.getLocation().getLat(), 0, markers, null));
|
||||
} else {
|
||||
Log.d("RWJ", "V2XRoadEventMarker:" + entity.getPoiType() + "--- return empty marker");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAiRoadEvent(String poiType) {
|
||||
return Objects.equals(poiType, EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.getPoiType())
|
||||
&& Objects.equals(poiType, EventTypeEnumNew.FOURS_ACCIDENT_04.getPoiType())
|
||||
&& Objects.equals(poiType, EventTypeEnumNew.TYPE_SOCKET_ROAD_JINGZHI.getPoiType())
|
||||
&& Objects.equals(poiType, EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGU.getPoiType());
|
||||
}
|
||||
|
||||
private boolean isDrawRoadLine(String poiType) {
|
||||
return EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.getPoiType().equals(poiType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.road;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew;
|
||||
import com.mogo.eagle.core.data.enums.WarningDirectionEnum;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerExploreWay;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean;
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType;
|
||||
import com.mogo.eagle.core.data.msgbox.V2XMsg;
|
||||
import com.mogo.eagle.core.function.api.hmi.warning.IMoGoWarningStatusListener;
|
||||
import com.mogo.eagle.core.function.api.map.angle.Default;
|
||||
import com.mogo.eagle.core.function.api.map.angle.RoadEvent;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager;
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager;
|
||||
import com.mogo.eagle.core.function.call.map.CallerVisualAngleManager;
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.impl.AbsV2XScenario;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.view.IV2XMarker;
|
||||
import com.mogo.eagle.core.network.utils.GsonUtil;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
|
||||
import com.mogo.eagle.core.utilcode.mogo.storage.SharedPrefsMgr;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/15 5:37 PM
|
||||
* desc : 道路预警场景
|
||||
* version: 1.0
|
||||
*/
|
||||
public class V2XRoadEventScenario extends AbsV2XScenario<V2XRoadEventEntity> implements IMoGoWarningStatusListener {
|
||||
private static final String TAG = "V2XRoadEventScenario";
|
||||
|
||||
public V2XRoadEventScenario() {
|
||||
setV2XMarker(new V2XRoadEventMarker());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(V2XMessageEntity<V2XRoadEventEntity> v2XMessageEntity) {
|
||||
try {
|
||||
Logger.d(TAG, "v2XMessageEntity:" + GsonUtil.jsonFromObject(v2XMessageEntity));
|
||||
V2XRoadEventEntity v2XRoadEventEntity = v2XMessageEntity.getContent();
|
||||
if (v2XRoadEventEntity != null) {
|
||||
if (!isSameScenario(v2XMessageEntity)) {
|
||||
// 更新要提醒的数据
|
||||
setV2XMessageEntity(v2XMessageEntity);
|
||||
show();
|
||||
} else {
|
||||
// 更新要提醒的数据
|
||||
setV2XMessageEntity(v2XMessageEntity);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
try {
|
||||
if (getV2XMessageEntity() != null && getV2XMessageEntity().getContent() != null) {
|
||||
//只展示不播报 不广播
|
||||
V2XMessageEntity<V2XRoadEventEntity> entity = getV2XMessageEntity();
|
||||
V2XRoadEventEntity content = entity.getContent();
|
||||
if (content != null && !Objects.equals(content.getPoiType(), EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.getPoiType())
|
||||
&& !Objects.equals(content.getPoiType(), EventTypeEnumNew.TYPE_SOCKET_ROAD_JINGZHI.getPoiType())
|
||||
&& !Objects.equals(content.getPoiType(), EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGU.getPoiType())
|
||||
&& !Objects.equals(content.getPoiType(), EventTypeEnumNew.TYPE_SOCKET_ROAD_CONGESTION.getPoiType())) {
|
||||
content.getTts(false);
|
||||
}
|
||||
showWindow();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void showWindow() {
|
||||
V2XMessageEntity<V2XRoadEventEntity> entity = getV2XMessageEntity();
|
||||
V2XRoadEventEntity content = entity != null ? entity.getContent() : null;
|
||||
if (content != null) {
|
||||
// //显示警告红边
|
||||
String alarmText = content.getAlarmContent();
|
||||
String ttsText = content.getTts();
|
||||
if (alarmText == null || alarmText.isEmpty()
|
||||
|| ttsText == null || ttsText.isEmpty()) {
|
||||
Logger.d("MsgBox-V2XRoadScenario", "alertContent或ttsContent为空!");
|
||||
}
|
||||
String poiType = content.getPoiType();
|
||||
if (EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGONG.getPoiType().equals(poiType) ||
|
||||
EventTypeEnumNew.TYPE_SOCKET_ROAD_JINGZHI.getPoiType().equals(poiType) ||
|
||||
EventTypeEnumNew.TYPE_SOCKET_ROAD_CONGESTION.getPoiType().equals(poiType) ||
|
||||
EventTypeEnumNew.TYPE_SOCKET_ROAD_SHIGU.getPoiType().equals(poiType)) {
|
||||
MarkerExploreWay noveltyInfo = content.getNoveltyInfo();
|
||||
if (noveltyInfo != null) {
|
||||
MarkerLocation eventLocation = noveltyInfo.getLocation();
|
||||
if (eventLocation != null) {
|
||||
double distance = content.getDistance();
|
||||
alarmText = String.format(alarmText, Math.round(distance) + "");
|
||||
ttsText = String.format(ttsText, Math.round(distance) + "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//占道施工预警
|
||||
if (poiType.equals("10006") || poiType.equals("100061")) {
|
||||
long currentTime = System.currentTimeMillis() / 1000;
|
||||
long oldTime = SharedPrefsMgr.getInstance(AbsMogoApplication.getApp()).getLong("roadwork", 0);
|
||||
if (currentTime - oldTime > 60) { //超过一分钟,才会继续播报重复提醒
|
||||
SharedPrefsMgr.getInstance(AbsMogoApplication.getApp()).putLong("roadwork", System.currentTimeMillis() / 1000);
|
||||
CallerAutoPilotControlManager.sendTripInfo(5, "", "", "", false);
|
||||
}
|
||||
}
|
||||
|
||||
CallerMsgBoxManager.INSTANCE.saveMsgBox(
|
||||
new MsgBoxBean(
|
||||
MsgBoxType.V2X,
|
||||
new V2XMsg(poiType,
|
||||
alarmText,
|
||||
ttsText)
|
||||
)
|
||||
);
|
||||
CallerHmiManager.INSTANCE.warningV2X(poiType, alarmText,
|
||||
ttsText, this,WarningDirectionEnum.ALERT_WARNING_TOP,
|
||||
TimeUnit.SECONDS.toMillis(5));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPOI() {
|
||||
IV2XMarker marker = getV2XMarker();
|
||||
if (marker != null) {
|
||||
// 重置告警信息
|
||||
marker.drawPOI(getV2XMessageEntity().getContent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPOI() {
|
||||
// IV2XMarker marker = getV2XMarker();
|
||||
// if (marker != null) {
|
||||
// marker.clearPOI();
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShow() {
|
||||
if (isNeedChangeAngle()) {
|
||||
CallerVisualAngleManager.INSTANCE.changeAngle(RoadEvent.INSTANCE);
|
||||
}
|
||||
V2XMessageEntity<V2XRoadEventEntity> entity = getV2XMessageEntity();
|
||||
if (entity != null) {
|
||||
V2XRoadEventEntity content = entity.getContent();
|
||||
if (content != null) {
|
||||
if (entity.isNeedAddLine() && !EventTypeEnumNew.TYPE_SOCKET_ROAD_CONGESTION.getPoiType().equals(content.getPoiType())) {
|
||||
drawPOI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNeedChangeAngle() {
|
||||
V2XMessageEntity<V2XRoadEventEntity> entity = getV2XMessageEntity();
|
||||
V2XRoadEventEntity content = entity != null ? entity.getContent() : null;
|
||||
if (content == null) {
|
||||
return true;
|
||||
}
|
||||
return !EventTypeEnumNew.GHOST_PROBE.getPoiType().equals(content.getPoiType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
CallerHmiManager.INSTANCE.dismissWarning(WarningDirectionEnum.ALERT_WARNING_TOP);
|
||||
if (isNeedChangeAngle()) {
|
||||
CallerVisualAngleManager.INSTANCE.changeAngle(new Default(3, TimeUnit.SECONDS));
|
||||
}
|
||||
release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.warning;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew;
|
||||
import com.mogo.eagle.core.data.enums.WarningDirectionEnum;
|
||||
import com.mogo.eagle.core.data.map.MogoLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean;
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType;
|
||||
import com.mogo.eagle.core.data.msgbox.V2XMsg;
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener;
|
||||
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.msgbox.CallerMsgBoxManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.impl.AbsV2XScenario;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.view.IV2XMarker;
|
||||
import com.mogo.eagle.core.data.v2x.V2XWarningTarget;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author liujing
|
||||
* @description 车路云—场景预警-V1.0 前车/行人/摩托车/盲区碰撞预警
|
||||
* @since: 2021/3/24
|
||||
*/
|
||||
public class V2XFrontWarningScenario extends AbsV2XScenario implements IMoGoChassisLocationGCJ02Listener, IMoGoWarningStatusListener {
|
||||
private static final String TAG = "V2XWarningMarker";
|
||||
private static final V2XWarningMarker sV2XWarningMarker = new V2XWarningMarker();
|
||||
private V2XWarningTarget mMarkerEntity;
|
||||
|
||||
private WarningDirectionEnum mDirection;
|
||||
|
||||
public V2XFrontWarningScenario() {
|
||||
//setV2XMarker(sV2XWarningMarker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(@Nullable V2XMessageEntity v2XMessageEntity) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "----- init -----:\n" + (v2XMessageEntity == null ? "null" : v2XMessageEntity.toString()));
|
||||
try {
|
||||
setV2XMessageEntity(v2XMessageEntity);
|
||||
if (v2XMessageEntity != null && v2XMessageEntity.getContent() instanceof V2XWarningTarget) {
|
||||
mMarkerEntity = (V2XWarningTarget) v2XMessageEntity.getContent();
|
||||
show();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "----- show --- 1 --:\n" + (mMarkerEntity == null ? "null" : mMarkerEntity.toString()));
|
||||
if (mMarkerEntity != null) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "----- show --- 2 --:\n" + mMarkerEntity);
|
||||
String v2xType = getV2XTypeForFrontWarning(mMarkerEntity);
|
||||
V2XMessageEntity entity = getV2XMessageEntity();
|
||||
if (!v2xType.equals("0")) {
|
||||
if (getAlertContentForFrontWarning(mMarkerEntity).toString() == null
|
||||
|| getAlertContentForFrontWarning(mMarkerEntity).toString().isEmpty()
|
||||
|| mMarkerEntity.getTts() == null || mMarkerEntity.getTts().isEmpty()) {
|
||||
Log.d("MsgBox-FrontWarScenario", "alertContent或ttsContent为空!");
|
||||
}
|
||||
CallerMsgBoxManager.INSTANCE.saveMsgBox(
|
||||
new MsgBoxBean(
|
||||
MsgBoxType.V2X,
|
||||
new V2XMsg(v2xType + "",
|
||||
getAlertContentForFrontWarning(mMarkerEntity).toString(),
|
||||
mMarkerEntity.getTts())
|
||||
)
|
||||
);
|
||||
CallerHmiManager.INSTANCE.warningV2X(v2xType + "",
|
||||
getAlertContentForFrontWarning(mMarkerEntity), mMarkerEntity.getTts(),
|
||||
this,getDirection(),
|
||||
TimeUnit.SECONDS.toMillis(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getV2XTypeForFrontWarning(V2XWarningTarget entity) {
|
||||
switch (entity.getType()) {
|
||||
case 1:
|
||||
case 11:
|
||||
entity.setTts("注意行人");
|
||||
return EventTypeEnumNew.TYPE_USECASE_ID_VRUCW_PERSON.getPoiType();
|
||||
case 2:
|
||||
entity.setTts("注意自行车");
|
||||
case 4:
|
||||
entity.setTts("注意摩托车");
|
||||
return EventTypeEnumNew.TYPE_USECASE_ID_VRUCW_MOTOR_VEHICLES.getPoiType();
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
|
||||
private CharSequence getAlertContentForFrontWarning(V2XWarningTarget entity) {
|
||||
double dis = entity.getDistance();
|
||||
//距离四舍五入保留整数
|
||||
BigDecimal bg = new BigDecimal(dis);
|
||||
double disBig = bg.setScale(0, BigDecimal.ROUND_HALF_UP).doubleValue();
|
||||
String distance = String.format(Locale.getDefault(), "%.0f", disBig) + "米";
|
||||
String content = entity.getWarningContent();
|
||||
SpannableStringBuilder ssb = new SpannableStringBuilder(content + distance);
|
||||
ssb.setSpan(new ForegroundColorSpan(Color.parseColor("#FF3036")), content.length(), ssb.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
return ssb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPOI() {
|
||||
IV2XMarker marker = getV2XMarker();
|
||||
if (marker != null && mMarkerEntity != null) {
|
||||
marker.drawPOI(mMarkerEntity);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "drawPOI");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPOI() {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "----- clearPOI -----");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChassisLocationGCJ02(@Nullable MogoLocation gnssInfo) {
|
||||
sV2XWarningMarker.onCarLocationChanged2(gnssInfo);
|
||||
}
|
||||
|
||||
private WarningDirectionEnum getDirection(){
|
||||
WarningDirectionEnum warningDirectionEnum = WarningDirectionEnum.ALERT_WARNING_ALL;
|
||||
switch (mMarkerEntity.getDirection()) {
|
||||
case 0:
|
||||
warningDirectionEnum = WarningDirectionEnum.ALERT_WARNING_NON;
|
||||
break;
|
||||
case 1:
|
||||
warningDirectionEnum = WarningDirectionEnum.ALERT_WARNING_TOP;
|
||||
break;
|
||||
case 2:
|
||||
warningDirectionEnum = WarningDirectionEnum.ALERT_WARNING_BOTTOM;
|
||||
break;
|
||||
case 3:
|
||||
warningDirectionEnum = WarningDirectionEnum.ALERT_WARNING_LEFT;
|
||||
break;
|
||||
case 4:
|
||||
warningDirectionEnum = WarningDirectionEnum.ALERT_WARNING_RIGHT;
|
||||
break;
|
||||
}
|
||||
mDirection = warningDirectionEnum;
|
||||
return warningDirectionEnum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShow() {
|
||||
//预警蒙层
|
||||
drawPOI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
if (mDirection != null) {
|
||||
CallerHmiManager.INSTANCE.dismissWarning(mDirection);
|
||||
}
|
||||
// clearPOI();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,446 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.warning;
|
||||
|
||||
import static com.mogo.eagle.core.data.constants.DataTypes.TYPE_MARKER_CLOUD_STOP_LINE_DATA;
|
||||
import static com.mogo.eagle.core.data.constants.DataTypes.TYPE_MARKER_CLOUD_WARN_DATA;
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_V2X;
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication;
|
||||
import com.mogo.commons.module.status.MogoStatusManager;
|
||||
import com.mogo.commons.utils.Trigonometric;
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.data.map.MogoLocation;
|
||||
import com.mogo.eagle.core.data.v2x.DrawLineInfo;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.bridge.BridgeApi;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoPersonWarnPolylineManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoStopPolylineManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.manager.IMoGoWarnPolylineManager;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.view.IV2XMarker;
|
||||
import com.mogo.eagle.core.data.v2x.V2XLocation;
|
||||
import com.mogo.eagle.core.data.v2x.V2XWarningTarget;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.utilcode.mogo.thread.WorkThreadHandler;
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils;
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
|
||||
import com.mogo.map.marker.IMogoMarkerManager;
|
||||
import com.mogo.map.overlay.IMogoPolyline;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author liujing
|
||||
* @description 前方预警marker打点 绘制安全线和预警线 衡阳交付-取消划线需求,只渲染识别物红色模型移动过程,代码保留
|
||||
* @since: 2021/3/30
|
||||
*/
|
||||
public class V2XWarningMarker implements IV2XMarker {
|
||||
private static final String TAG = "V2XWarningMarker";
|
||||
private static final String WARNING_ARROWS = "WARNING_ARROWS";
|
||||
private V2XWarningTarget mCloundWarningInfo;
|
||||
private boolean isSelfLineClear = true;//绘制线是否已被清除
|
||||
private final List fillPoints = new ArrayList();//停止线经纬度合集
|
||||
private boolean isFirstLocation = false;
|
||||
private MogoLatLng carLocation = new MogoLatLng(
|
||||
CallerChassisLocationWGS84ListenerManager.INSTANCE.getChassisLocationWGS84().getLatitude(),
|
||||
CallerChassisLocationWGS84ListenerManager.INSTANCE.getChassisLocationWGS84().getLongitude()
|
||||
);
|
||||
|
||||
/*
|
||||
* 自车前方的点,在停止线上--通过自车位置与距离停止线之间的距离计算
|
||||
* */
|
||||
private MogoLatLng middleLocationInStopLine = new MogoLatLng(0, 0);
|
||||
private static long showTime = 6000;
|
||||
private double bearing;
|
||||
private boolean hasStopLines = false;
|
||||
|
||||
@Override
|
||||
public void drawPOI(Object entity) {
|
||||
try {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "===drawPOI");
|
||||
mCloundWarningInfo = (V2XWarningTarget) entity;
|
||||
drawLineWithEntity();
|
||||
|
||||
} catch (Exception e) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void drawLineWithEntity() {
|
||||
showTime = mCloundWarningInfo.getShowTime() > 0 ? mCloundWarningInfo.getShowTime() * 1000 : 6000;
|
||||
fillPointOnStopLine();
|
||||
MogoLocation location = BridgeApi.INSTANCE.getLocation().get();
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
bearing = location.getHeading();
|
||||
|
||||
if (mCloundWarningInfo != null && mCloundWarningInfo.getStopLines() != null) {
|
||||
hasStopLines = mCloundWarningInfo.getStopLines().size() > 0;
|
||||
}
|
||||
isSelfLineClear = false;
|
||||
isFirstLocation = false;
|
||||
if (fillPoints != null && fillPoints.size() > 0) {
|
||||
//存在停止线的情况 自车与停止线之间绘制蓝色安全线 停止线向前50m绘制红色预警线
|
||||
middleLocationInStopLine = getMiddleLocationInStopLine();
|
||||
//停止线前方画线
|
||||
WorkThreadHandler.getInstance().postDelayed(() -> {
|
||||
if (carLocation.lat != 0 && carLocation.lon != 0) {
|
||||
//在自车与停止线直线绘制蓝色预警线
|
||||
//衡阳交付-取消划线需求,只渲染识别物红色模型移动过程
|
||||
//drawSelfCarLine(carLocation.lon, carLocation.lat, bearing);
|
||||
} else {
|
||||
}
|
||||
//二轮车和行人的渲染和移动
|
||||
IMogoMarkerManager marker = CallerMapUIServiceManager.INSTANCE.getMarkerManager(AbsMogoApplication.getApp());
|
||||
if (marker != null) {
|
||||
marker.removeMarkers(TYPE_MARKER_CLOUD_WARN_DATA);
|
||||
}
|
||||
|
||||
/* 衡阳交付-取消划线需求,只渲染识别物红色模型移动过程
|
||||
//获取停止线前方50m坐标点
|
||||
MogoLatLng warningLocation = Trigonometric.getNewLocation(middleLocationInStopLine,
|
||||
50, angleForCarMoveDirection());
|
||||
//停止线向前方50m绘制红色预警线
|
||||
drawRedWarningLineFrontOfStopLine(mCloundWarningInfo, middleLocationInStopLine,
|
||||
warningLocation);
|
||||
|
||||
*/
|
||||
Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getMarkerService()).renderWarningMoveMarker(mCloundWarningInfo.getLon(), mCloundWarningInfo.getLat(), mCloundWarningInfo.getType(), mCloundWarningInfo.getCollisionLat(), mCloundWarningInfo.getCollisionLon(), mCloundWarningInfo.getAngle(), mCloundWarningInfo.getShowTime());
|
||||
|
||||
//添加停止线marker
|
||||
//衡阳交付-取消划线需求,只渲染识别物红色模型移动过程
|
||||
//handleStopLine();
|
||||
}, 0);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "显示时间为++" + showTime + "识别物类型:" +
|
||||
String.valueOf(mCloundWarningInfo.getType()));
|
||||
|
||||
} else { //无停止线
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "无停止线");
|
||||
WorkThreadHandler.getInstance().postDelayed(() -> {
|
||||
/* 衡阳交付-取消划线需求,只渲染识别物红色模型移动过程
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "无停止线" + mCloundWarningInfo.toString());
|
||||
//绘制识别物与交汇点连线,并且更新连线数据
|
||||
drawOtherObjectLine(mCloundWarningInfo);
|
||||
//二轮车和行人的渲染和移动
|
||||
V2XServiceManager.getMarkerManager().removeMarkers(TYPE_MARKER_CLOUD_WARN_DATA);
|
||||
if (carLocation.lat != 0 && carLocation.lon != 0) {
|
||||
drawSelfCarLine(carLocation.lon, carLocation.lat, bearing);
|
||||
} else {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "数据为空carLocation == null");
|
||||
}
|
||||
*/
|
||||
Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getMarkerService()).renderWarningMoveMarker(mCloundWarningInfo.getLon()
|
||||
, mCloundWarningInfo.getLat()
|
||||
, mCloundWarningInfo.getType()
|
||||
, mCloundWarningInfo.getCollisionLat()
|
||||
, mCloundWarningInfo.getCollisionLon()
|
||||
, mCloundWarningInfo.getAngle()
|
||||
, mCloundWarningInfo.getShowTime());
|
||||
}, 0);
|
||||
|
||||
}
|
||||
clearAllLine();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* */
|
||||
public double angleForCarMoveDirection() {
|
||||
MogoLatLng startLatLng = new MogoLatLng(carLocation.lat, carLocation.lon);
|
||||
MogoLatLng endLatLng = new MogoLatLng(middleLocationInStopLine.lat, middleLocationInStopLine.lon);
|
||||
double angle = Trigonometric.getAngle(startLatLng.lon, startLatLng.lat, endLatLng.lon, endLatLng.lat);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "angle==" + String.valueOf(angle));
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
/*绘制停止线前方50m的红色预警线
|
||||
* startLatLng: 划线起点=停止线上的坐标点
|
||||
* mogoLatLng: 停止线前方50m坐标点
|
||||
* */
|
||||
private void drawRedWarningLineFrontOfStopLine(V2XWarningTarget info, MogoLatLng
|
||||
startLatLng, MogoLatLng mogoLatLng) {
|
||||
if (info != null) {
|
||||
double angle = Trigonometric.getAngle(startLatLng.lon, startLatLng.lat, mogoLatLng.lon, mogoLatLng.lat);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "angle==drawRedWarningLineFrontOfStopLine:" + String.valueOf(angle));
|
||||
IMoGoStopPolylineManager stopPolyLineMnager = BridgeApi.INSTANCE.v2xStopPolyline();
|
||||
if (stopPolyLineMnager != null) {
|
||||
IMogoPolyline polyLine = stopPolyLineMnager.getMogoStopPolyline();
|
||||
MogoLatLng endLatlng = new MogoLatLng(mogoLatLng.lat, mogoLatLng.lon);
|
||||
MogoLatLng addMiddleLoc = Trigonometric.getNewLocation(startLatLng.lon, startLatLng.lat, 25, angle);
|
||||
if (polyLine != null) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "drawStopLine polyLine != null");
|
||||
polyLine.setPoints(Arrays.asList(startLatLng, addMiddleLoc, endLatlng));
|
||||
polyLine.setTransparency(0.5f);
|
||||
} else {
|
||||
DrawLineInfo lineInfo = new DrawLineInfo();
|
||||
List locations = new ArrayList();
|
||||
locations.add(startLatLng);
|
||||
locations.add(addMiddleLoc);
|
||||
locations.add(endLatlng);
|
||||
lineInfo.setLocations(locations);
|
||||
lineInfo.setHeading(info.getHeading());
|
||||
CallerLogger.INSTANCE.d(TAG, "drawStopLine width = " + info.getRoadwidth());
|
||||
lineInfo.setWidth(info.getRoadwidth() * 14 + 5);
|
||||
stopPolyLineMnager.drawStopPolyline(BridgeApi.INSTANCE.context(), lineInfo);
|
||||
}
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "停止线前方50m区域的三个坐标点是:" + startLatLng.lon + "," + startLatLng.lat +
|
||||
"中间点坐标:" + addMiddleLoc.lon + "," + addMiddleLoc.lat
|
||||
+ "终点" + endLatlng.lon + "," + endLatlng.lat);
|
||||
}
|
||||
} else {
|
||||
clearAllLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAllLine() {
|
||||
UiThreadHandler.postDelayed(() -> {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "清除所有预警线的时间是:" + String.valueOf(showTime));
|
||||
//清除识别物到碰撞点预警线
|
||||
IMoGoPersonWarnPolylineManager personStopPolyLineManager = BridgeApi.INSTANCE.v2xPersonWarnPolyline();
|
||||
if (personStopPolyLineManager != null) {
|
||||
personStopPolyLineManager.clearLine();
|
||||
}
|
||||
//清除车前方第一条预警线
|
||||
IMoGoWarnPolylineManager warnPolyLineManager = BridgeApi.INSTANCE.v2xWarnPolyline();
|
||||
if (warnPolyLineManager != null) {
|
||||
warnPolyLineManager.clearLine();
|
||||
}
|
||||
//清除停止线
|
||||
IMoGoStopPolylineManager stopPolyLineManager = BridgeApi.INSTANCE.v2xStopPolyline();
|
||||
if (stopPolyLineManager != null) {
|
||||
stopPolyLineManager.clearLine();
|
||||
}
|
||||
|
||||
IMogoMarkerManager marker = CallerMapUIServiceManager.INSTANCE.getMarkerManager(AbsMogoApplication.getApp());
|
||||
if (marker != null) {
|
||||
//清除小箭头
|
||||
marker.removeMarkers(WARNING_ARROWS);
|
||||
//清除停止线
|
||||
marker.removeMarkers(TYPE_MARKER_CLOUD_STOP_LINE_DATA);
|
||||
}
|
||||
|
||||
isSelfLineClear = true;
|
||||
}, showTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 补点后的停止线经纬度合集
|
||||
*/
|
||||
public void fillPointOnStopLine() {
|
||||
try {
|
||||
fillPoints.clear();
|
||||
List stopLines = mCloundWarningInfo.getStopLines();
|
||||
if (stopLines != null && stopLines.size() > 1) {
|
||||
V2XLocation x = mCloundWarningInfo.getStopLines().get(0);
|
||||
V2XLocation y = mCloundWarningInfo.getStopLines().get(1);
|
||||
//两点间的距离
|
||||
float distance = CoordinateUtils.calculateLineDistance(x.getLon(), x.getLat(), y.getLon(), y.getLat());
|
||||
float average = distance / 3;
|
||||
//两点间的角度
|
||||
double angle = Trigonometric.getAngle(x.getLon(), x.getLat(), y.getLon(), y.getLat());
|
||||
//根据距离和角度获取下个点的经纬度
|
||||
fillPoints.add(x);
|
||||
for (int i = 1; i < 3; i++) {
|
||||
MogoLatLng newLocation = Trigonometric.getNewLocation(x.getLon(), x.getLat(), average * i, angle);
|
||||
fillPoints.add(newLocation);
|
||||
}
|
||||
fillPoints.add(y);
|
||||
} else {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "停止线数据不存在");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CallerLogger.INSTANCE.e(M_V2X + TAG, "exception : " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 停止线绘制
|
||||
* */
|
||||
private void handleStopLine() {
|
||||
try {
|
||||
if (mCloundWarningInfo != null) {
|
||||
IMogoMarkerManager marker = CallerMapUIServiceManager.INSTANCE.getMarkerManager(AbsMogoApplication.getApp());
|
||||
if (marker != null) {
|
||||
marker.removeMarkers(TYPE_MARKER_CLOUD_STOP_LINE_DATA);
|
||||
}
|
||||
for (int i = 0; i < fillPoints.size(); i++) {
|
||||
V2XWarningTarget entity = new V2XWarningTarget();
|
||||
MogoLatLng latLng = (MogoLatLng) fillPoints.get(i);
|
||||
entity.setLat(latLng.lat);
|
||||
entity.setLon(latLng.lon);
|
||||
entity.setHeading(mCloundWarningInfo.getHeading());
|
||||
Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getMarkerService()).renderStopLineMarker(entity.getLon(), entity.getLat());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private MogoLatLng getMogoLat(MogoLatLng latlng) {
|
||||
MogoLatLng newLocation = Trigonometric.getNewLocation(latlng.lon, latlng.lat, mCloundWarningInfo.getStopLineDistance(),
|
||||
mCloundWarningInfo.getAngle());
|
||||
return newLocation;
|
||||
}
|
||||
|
||||
/*
|
||||
* 自车前方的点,落点在停止线上--通过自车位置与距离停止线之间的距离计算
|
||||
* */
|
||||
private MogoLatLng getMiddleLocationInStopLine() {
|
||||
if (carLocation.lat == 0 || carLocation.lon == 0) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "获取不到车的位置");
|
||||
}
|
||||
MogoLatLng newLocation = new MogoLatLng(0, 0);
|
||||
if (mCloundWarningInfo != null && mCloundWarningInfo.getStopLines() != null && mCloundWarningInfo.getStopLines().size() > 1) {
|
||||
V2XLocation x = mCloundWarningInfo.getStopLines().get(0);
|
||||
V2XLocation y = mCloundWarningInfo.getStopLines().get(1);
|
||||
float distance = CoordinateUtils.calculateLineDistance(x.getLon(), x.getLat(), y.getLat(), y.getLat());
|
||||
double angle = Trigonometric.getAngle(x.getLat(), x.getLat(), y.getLon(), y.getLat());
|
||||
newLocation = Trigonometric.getNewLocation(x.getLon(), x.getLat(), distance * 0.5, angle);
|
||||
} else {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "停止线返回坐标点数量不正确" + mCloundWarningInfo.getStopLines().size());
|
||||
}
|
||||
return newLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 存在停止线时自车与停止线之间为蓝色预警
|
||||
* 不存在停止线,自车与预碰撞点之间为红色预警
|
||||
* lon 自车经度
|
||||
* lat 自车纬度
|
||||
*/
|
||||
public void drawSelfCarLine(double lon, double lat, float bearing) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "drawSelfCarLine");
|
||||
if (!isSelfLineClear) {
|
||||
if (mCloundWarningInfo != null) {
|
||||
IMoGoWarnPolylineManager warnPolyLineManager = BridgeApi.INSTANCE.v2xWarnPolyline();
|
||||
if (warnPolyLineManager == null) {
|
||||
return;
|
||||
}
|
||||
IMogoPolyline mogoPolyline = warnPolyLineManager.getMogoWarnPolyline();
|
||||
MogoLatLng startLatlng = new MogoLatLng(0, 0);
|
||||
MogoLatLng endLatlng = new MogoLatLng(0, 0);
|
||||
MogoLatLng addMiddleLoc = new MogoLatLng(0, 0);
|
||||
|
||||
if (!isFirstLocation) {
|
||||
carLocation = getMogoLat(new MogoLatLng(lat, lon));
|
||||
isFirstLocation = true;
|
||||
}
|
||||
//绘制线的终点(在停止线上或者预碰撞点上)
|
||||
endLatlng = new MogoLatLng(hasStopLines ?
|
||||
middleLocationInStopLine.lat : mCloundWarningInfo.getCollisionLat(), hasStopLines ?
|
||||
middleLocationInStopLine.lon : mCloundWarningInfo.getCollisionLon());
|
||||
|
||||
startLatlng = new MogoLatLng(lat, lon);
|
||||
float distance = CoordinateUtils.calculateLineDistance(startLatlng.lon, startLatlng.lat, endLatlng.lon, endLatlng.lat);
|
||||
//扩展点为了渐变色添加
|
||||
addMiddleLoc = Trigonometric.getNewLocation(startLatlng.getLon(), startLatlng.getLat(), distance / 2,
|
||||
Trigonometric.getAngle(startLatlng.lon, startLatlng.lat, endLatlng.lon, endLatlng.lat));
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "angle==扩展点为了渐变色添加:" +
|
||||
String.valueOf(Trigonometric.getAngle(startLatlng.lon, startLatlng.lat, endLatlng.lon, endLatlng.lat)));
|
||||
if (mogoPolyline != null) {
|
||||
mogoPolyline.setPoints(Arrays.asList(startLatlng, addMiddleLoc, endLatlng));
|
||||
mogoPolyline.setTransparency(0.5f);
|
||||
} else {
|
||||
DrawLineInfo info = new DrawLineInfo(); // 对象
|
||||
List locations = new ArrayList();
|
||||
locations.add(startLatlng);
|
||||
locations.add(addMiddleLoc);
|
||||
locations.add(endLatlng);
|
||||
info.setLocations(locations);
|
||||
info.setHeading(bearing);
|
||||
info.setWidth(mCloundWarningInfo.getRoadwidth() * 14 + 5);
|
||||
if (mCloundWarningInfo.getStopLines() != null) {
|
||||
info.setHasStopLines(mCloundWarningInfo.getStopLines().size() > 0);
|
||||
}
|
||||
warnPolyLineManager.drawWarnPolyline(BridgeApi.INSTANCE.context(), info);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "自车前方第一条线" + "起点:" + startLatlng + "中间点:" + addMiddleLoc + "终点:" + endLatlng);
|
||||
}
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "自车为起点绘制 自车;" + startLatlng.lon + "," + startLatlng.lat +
|
||||
"中间扩展点" + addMiddleLoc.lon + "," + addMiddleLoc.lat + "终点:" + endLatlng.lon + "," + endLatlng.lat);
|
||||
} else {
|
||||
clearAllLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 侧方目标物与预碰撞点连线,并且更新数据 TODO 需要实时给行人当前位置
|
||||
*/
|
||||
private void drawOtherObjectLine(V2XWarningTarget info) {
|
||||
if (info != null) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "info != null");
|
||||
IMoGoPersonWarnPolylineManager personWarnPolylineManager = BridgeApi.INSTANCE.v2xPersonWarnPolyline();
|
||||
if (personWarnPolylineManager == null) {
|
||||
return;
|
||||
}
|
||||
IMogoPolyline polyLine = personWarnPolylineManager.getMogoPersonWarnPolyline();
|
||||
MogoLatLng startLatlng = new MogoLatLng(info.getLat(), info.getLon());//识别物坐标
|
||||
MogoLatLng endLatlng = new MogoLatLng(info.getCollisionLat(), info.getCollisionLon());//预碰撞点坐标
|
||||
float distance = CoordinateUtils.calculateLineDistance(startLatlng.lon, startLatlng.lat, endLatlng.lon, endLatlng.lat);//识别物到碰撞点之间的距离
|
||||
MogoLatLng addMiddleLoc = Trigonometric.getNewLocation(startLatlng.getLon(), startLatlng.getLat(), distance / 2,
|
||||
Trigonometric.getAngle(startLatlng.lon, startLatlng.lat, endLatlng.lon, endLatlng.lat));//补点
|
||||
if (polyLine != null) {
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "目标物与碰撞点连线 != null");
|
||||
polyLine.setPoints(Arrays.asList(startLatlng, addMiddleLoc, endLatlng));
|
||||
polyLine.setTransparency(0.5f);
|
||||
} else {
|
||||
//识别物到预碰撞点之间的箭头
|
||||
addArrows(startLatlng, endLatlng);
|
||||
DrawLineInfo lineInfo = new DrawLineInfo();
|
||||
List locations = new ArrayList();
|
||||
locations.add(startLatlng);
|
||||
locations.add(addMiddleLoc);
|
||||
locations.add(endLatlng);
|
||||
lineInfo.setLocations(locations);
|
||||
lineInfo.setHeading(info.getHeading());
|
||||
lineInfo.setWidth(info.getRoadwidth() * 14 + 5);
|
||||
personWarnPolylineManager.drawPersonWarnPolyline(BridgeApi.INSTANCE.context(), lineInfo);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "目标物与预碰撞点画线点为" + "起点:" + startLatlng + "中间点:" + addMiddleLoc + "终点:" + endLatlng);
|
||||
}
|
||||
} else {
|
||||
CallerLogger.INSTANCE.e(M_V2X + TAG, "info == null");
|
||||
clearAllLine();
|
||||
}
|
||||
}
|
||||
|
||||
//侧面目标物与碰撞点之间添加多个小箭头
|
||||
private void addArrows(MogoLatLng startLatLng, MogoLatLng endLatLng) {
|
||||
float distance = CoordinateUtils.calculateLineDistance(
|
||||
startLatLng.lon, startLatLng.lat, endLatLng.lon, endLatLng.lat);
|
||||
double rotate = Trigonometric.getAngle(startLatLng.lon, startLatLng.lat, endLatLng.lon, endLatLng.lat);
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "添加小箭头--目标物与预碰撞点之间的距离是" + String.valueOf(distance));
|
||||
if (distance > 5) {
|
||||
int count = (int) (distance / 5);
|
||||
for (int i = 0; i < count; i++) {
|
||||
MogoLatLng newLo = Trigonometric.getNewLocation(
|
||||
startLatLng.getLon(), startLatLng.getLat(), 5 * (i + 1), Trigonometric.getAngle(startLatLng.lon, startLatLng.lat, endLatLng.lon, endLatLng.lat));
|
||||
Objects.requireNonNull(CallerMapUIServiceManager.INSTANCE.getMarkerService()).drawerArrowsMarkerWithLocation(newLo, WARNING_ARROWS, 10, new Double(rotate).intValue());
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "小箭头位置" + newLo);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//线随车动
|
||||
public void onCarLocationChanged2(MogoLocation latLng) {
|
||||
carLocation = new MogoLatLng(latLng.getLatitude(), latLng.getLongitude());
|
||||
if (MogoStatusManager.getInstance().isVrMode() && !isSelfLineClear) {
|
||||
if (mCloundWarningInfo != null) {
|
||||
V2XLocation v2XLocation = new V2XLocation();
|
||||
v2XLocation.setLat(latLng.getLatitude());
|
||||
v2XLocation.setLon(latLng.getLongitude());
|
||||
mCloundWarningInfo.setCarLocation(v2XLocation);
|
||||
}
|
||||
//衡阳交付-取消划线需求,只渲染识别物红色模型移动过程
|
||||
//drawSelfCarLine(latLng.getLongitude(), latLng.getLatitude(), latLng.getBearing());
|
||||
}
|
||||
CallerLogger.INSTANCE.d(M_V2X + TAG, "车辆行驶轨迹" + latLng.getLongitude() + "," + latLng.getLatitude());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.scenario.view;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020/5/15 4:13 PM
|
||||
* desc : V2X安全驾驶场景接口
|
||||
* version: 1.0
|
||||
*/
|
||||
public interface IV2XMarker<T> {
|
||||
|
||||
void drawPOI(T entity);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.test
|
||||
|
||||
class TestConsts {
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* V2X 测试控制面板广播Action
|
||||
*/
|
||||
@JvmField
|
||||
val BROADCAST_TEST_PANEL_CONTROL_TYPE_EXTRA_KEY = "sceneType"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.test;
|
||||
|
||||
import static com.mogo.eagle.core.data.map.entity.V2XMessageEntity.V2XTypeEnum.ALERT_ROAD_WARNING;
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerLocation;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XWarningEntity;
|
||||
import com.mogo.eagle.core.data.v2x.V2XOptimalRouteDataRes;
|
||||
import com.mogo.eagle.core.function.biz.R;
|
||||
import com.mogo.eagle.core.network.utils.GsonUtil;
|
||||
import com.mogo.eagle.core.utilcode.util.Utils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020-01-0918:20
|
||||
* desc : 生成测试数据
|
||||
* version: 1.0
|
||||
*/
|
||||
public class TestOnLineCarUtils {
|
||||
|
||||
/**
|
||||
* 模拟道路事件测试数据
|
||||
*/
|
||||
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.setContent(entity);
|
||||
body.setType(ALERT_ROAD_WARNING);
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟道路事件UGC测试数据
|
||||
*/
|
||||
public static V2XMessageEntity<V2XRoadEventEntity> getV2XScenarioRoadEventUGCData() {
|
||||
try {
|
||||
InputStream inputStream = Utils.getApp()
|
||||
.getResources()
|
||||
.openRawResource(R.raw.scenario_road_event_data);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int len = -1;
|
||||
byte[] buffer = new byte[1024];
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
inputStream.close();
|
||||
|
||||
// 加载数据源
|
||||
V2XRoadEventEntity v2xRoadEventEntity = GsonUtil.objectFromJson(baos.toString(), V2XRoadEventEntity.class);
|
||||
|
||||
V2XMessageEntity<V2XRoadEventEntity> v2xMessageEntity = new V2XMessageEntity<>();
|
||||
// 控制类型
|
||||
v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_EVENT_UGC_WARNING);
|
||||
// 设置数据
|
||||
v2xMessageEntity.setContent(v2xRoadEventEntity);
|
||||
return v2xMessageEntity;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试数据
|
||||
*/
|
||||
public static V2XMessageEntity getV2XScenarioPushFrontWarningEventData(String adasResult) {
|
||||
|
||||
try {
|
||||
int id = R.raw.scenario_warning_event_data_right;
|
||||
switch (adasResult) {
|
||||
case "left":
|
||||
id = R.raw.scenario_warning_event_data_left;
|
||||
break;
|
||||
case "pedestrians":
|
||||
id = R.raw.scenario_warning_event_data_pedestrians;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
InputStream inputStream = Utils.getApp()
|
||||
.getResources()
|
||||
.openRawResource(id);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int len = -1;
|
||||
byte[] buffer = new byte[1024];
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
inputStream.close();
|
||||
|
||||
// 加载数据源
|
||||
V2XWarningEntity warningEntity = GsonUtil.objectFromJson(baos.toString(), V2XWarningEntity.class);
|
||||
V2XMessageEntity messageEntity = new V2XMessageEntity();
|
||||
messageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_THE_FRONT_WEAKNESS);
|
||||
messageEntity.setContent(warningEntity);
|
||||
return messageEntity;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟最优路线推送
|
||||
*/
|
||||
public static V2XMessageEntity<V2XOptimalRouteDataRes> getV2XOptimalRoute() {
|
||||
try {
|
||||
InputStream inputStream = Utils.getApp()
|
||||
.getResources()
|
||||
.openRawResource(R.raw.test_data_v2x_zuiyouluxian);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int len = -1;
|
||||
byte[] buffer = new byte[1024];
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
inputStream.close();
|
||||
|
||||
// 加载数据源
|
||||
V2XOptimalRouteDataRes v2xRoadEventEntity = GsonUtil.objectFromJson(baos.toString(), V2XOptimalRouteDataRes.class);
|
||||
|
||||
V2XMessageEntity<V2XOptimalRouteDataRes> v2xMessageEntity = new V2XMessageEntity<>();
|
||||
// 控制类型
|
||||
v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_PUSH_VR_SHOW);
|
||||
// 设置数据
|
||||
v2xMessageEntity.setContent(v2xRoadEventEntity);
|
||||
return v2xMessageEntity;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自车求助测试数据
|
||||
*/
|
||||
public static V2XMessageEntity<Boolean> getV2XScenarioCarForHelpEventData() {
|
||||
try {
|
||||
|
||||
V2XMessageEntity<Boolean> v2xMessageEntity = new V2XMessageEntity<>();
|
||||
// 控制类型
|
||||
v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_CAR_FOR_HELP);
|
||||
// 设置数据
|
||||
v2xMessageEntity.setContent(true);
|
||||
return v2xMessageEntity;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回绘制线路测试数据
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static List<MogoLatLng> getTestCoordinates() {
|
||||
try {
|
||||
InputStream inputStream = Utils.getApp()
|
||||
.getResources()
|
||||
.openRawResource(R.raw.test_coordinates);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
int len = -1;
|
||||
byte[] buffer = new byte[1024];
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
inputStream.close();
|
||||
|
||||
// 加载数据源
|
||||
return GsonUtil.arrayFromJson(baos.toString(), MogoLatLng.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.test;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XMessageEntity;
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity;
|
||||
import com.mogo.eagle.core.data.v2x.V2XOptimalRouteDataRes;
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.consts.V2XConst;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* V2X 测试面板广播接收,目的是可以通过广播调用起来面板
|
||||
*
|
||||
* @author donghongyu
|
||||
*/
|
||||
public class TestV2XReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "TestV2XReceiver";
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
try {
|
||||
this.mContext = context;
|
||||
int sceneType = intent.getIntExtra(TestConsts.BROADCAST_TEST_PANEL_CONTROL_TYPE_EXTRA_KEY, 0);
|
||||
|
||||
// 分发场景
|
||||
dispatchSceneTest(sceneType);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 分发处理场景
|
||||
*
|
||||
* @param sceneType 场景类型
|
||||
*/
|
||||
private void dispatchSceneTest(int sceneType) {
|
||||
if (sceneType == 1) {// 触发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);
|
||||
} else if (sceneType == 10) {//触发事件UGC
|
||||
V2XMessageEntity<V2XRoadEventEntity> v2XMessageEntity =
|
||||
TestOnLineCarUtils.getV2XScenarioRoadEventUGCData();
|
||||
|
||||
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
|
||||
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
} else if (sceneType == 12) {//车路云场景预警-右侧
|
||||
V2XMessageEntity messageEntity = TestOnLineCarUtils.getV2XScenarioPushFrontWarningEventData("right");
|
||||
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
|
||||
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, messageEntity);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
} else if (sceneType == 13) {//车路云场景预警-左侧
|
||||
V2XMessageEntity messageEntity = TestOnLineCarUtils.getV2XScenarioPushFrontWarningEventData("left");
|
||||
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
|
||||
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, messageEntity);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
} else if (sceneType == 14) {//行人预警,行人路线预测 车路云预警-前方行人
|
||||
V2XMessageEntity messageEntity = TestOnLineCarUtils.getV2XScenarioPushFrontWarningEventData("pedestrians");
|
||||
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
|
||||
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, messageEntity);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
} else if (sceneType == 17) {//最优路线推荐
|
||||
V2XMessageEntity<V2XOptimalRouteDataRes> v2XMessageEntity =
|
||||
TestOnLineCarUtils.getV2XOptimalRoute();
|
||||
|
||||
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
|
||||
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2XMessageEntity);
|
||||
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
} else if (sceneType == 20) {// 小地图绘制线
|
||||
List<MogoLatLng> coordinates = TestOnLineCarUtils.getTestCoordinates();
|
||||
// CallerSmpManager.drawablePolyline(coordinates);
|
||||
} else if (sceneType == 21) {// 小地图清除绘制线
|
||||
// CallerSmpManager.clearPolyline();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.utils
|
||||
|
||||
import kotlin.math.asin
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
internal class DistanceUtils {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* @param lon1
|
||||
* @param lat1
|
||||
* @param lon2
|
||||
* @param lat2
|
||||
* @return 两坐标的距离 单位:米(M)
|
||||
*/
|
||||
fun calculateLineDistance(lon1: Double, lat1: Double, lon2: Double, lat2: Double): Float {
|
||||
return try {
|
||||
var var2 = lon1
|
||||
var var4 = lat1
|
||||
var var6 = lon2
|
||||
var var8 = lat2
|
||||
var2 *= 0.01745329251994329
|
||||
var4 *= 0.01745329251994329
|
||||
var6 *= 0.01745329251994329
|
||||
var8 *= 0.01745329251994329
|
||||
val var10 = sin(var2)
|
||||
val var12 = sin(var4)
|
||||
val var14 = cos(var2)
|
||||
val var16 = cos(var4)
|
||||
val var18 = sin(var6)
|
||||
val var20 = sin(var8)
|
||||
val var22 = cos(var6)
|
||||
val var24 = cos(var8)
|
||||
val var28 = DoubleArray(3)
|
||||
val var29 = DoubleArray(3)
|
||||
var28[0] = var16 * var14
|
||||
var28[1] = var16 * var10
|
||||
var28[2] = var12
|
||||
var29[0] = var24 * var22
|
||||
var29[1] = var24 * var18
|
||||
var29[2] = var20
|
||||
(asin(sqrt((var28[0] - var29[0]) * (var28[0] - var29[0]) + (var28[1] - var29[1]) * (var28[1] - var29[1]) + (var28[2] - var29[2]) * (var28[2] - var29[2])) / 2.0) * 1.27420015798544E7).toFloat()
|
||||
} catch (var26: Throwable) {
|
||||
var26.printStackTrace()
|
||||
0.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.utils
|
||||
|
||||
import androidx.core.util.Pair
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew.Companion.isRoadEvent
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerExploreWay
|
||||
import com.mogo.eagle.core.data.map.entity.MarkerLocation
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity
|
||||
import com.mogo.eagle.core.data.v2x.V2XMarkerCardResult
|
||||
import com.mogo.eagle.core.data.v2x.V2XRoadXData
|
||||
import com.mogo.eagle.function.biz.v2x.v2n.scenario.scene.airoad.AiRoadMarker
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateTransform
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import roadwork.Road
|
||||
|
||||
|
||||
fun Road.RW_PB.toRoadMarker(): V2XMarkerCardResult =
|
||||
V2XMarkerCardResult().also { l1 ->
|
||||
val centerX = this.roadwork?.center?.point?.lon ?: 0.0
|
||||
val centerY = this.roadwork?.center?.point?.lat ?: 0.0
|
||||
val id = "${centerX}_${centerY}"
|
||||
l1.exploreWay = ArrayList<MarkerExploreWay>().also { l2 ->
|
||||
l2.add(MarkerExploreWay().also { l3 ->
|
||||
l3.poiType = this.roadwork?.poiType?.toString()
|
||||
l3.setGenerateTime(this.roadwork?.detectTime ?: 0L)
|
||||
l3.location = MarkerLocation().also { l4 ->
|
||||
val p = CoordinateTransform.WGS84ToGCJ02(this.roadwork?.center?.point?.lon ?: 0.0, this.roadwork?.center?.point?.lat ?: 0.0)
|
||||
l4.lon = p[0]
|
||||
l4.lat = p[1]
|
||||
l4.angle = this.roadwork?.center?.road?.bearing?.toDouble() ?: 0.0
|
||||
}
|
||||
l3.infoId = id
|
||||
l3.gpsLocation = Pair(this.roadwork?.center?.point?.lon ?: 0.0, this.roadwork?.center?.point?.lat ?: 0.0)
|
||||
l3.polygon = this.roadwork?.polygonList?.takeIf { it.isNotEmpty() }?.map { Pair(it.lon, it.lat) }
|
||||
})
|
||||
}
|
||||
AiRoadMarker.aiMakers[id]?.receive()
|
||||
}
|
||||
|
||||
fun V2XRoadXData.toRoadMarker(): V2XMarkerCardResult =
|
||||
V2XMarkerCardResult().also { l1 ->
|
||||
l1.exploreWay = ArrayList<MarkerExploreWay>().also { l2 ->
|
||||
l2.add(MarkerExploreWay().also { l3 ->
|
||||
l3.poiType = this.poiType
|
||||
l3.setGenerateTime(this.detectTime ?: 0L)
|
||||
l3.location = MarkerLocation().also { l4 ->
|
||||
val p = CoordinateTransform.WGS84ToGCJ02(this.center?.lon ?: 0.0, this.center?.lat ?: 0.0)
|
||||
l4.lon = p[0]
|
||||
l4.lat = p[1]
|
||||
l4.angle = this.centerRoad?.bearing ?: 0.0
|
||||
}
|
||||
l3.infoId = this.index
|
||||
l3.gpsLocation = Pair(this.center?.lon ?: 0.0, this.center?.lat ?: 0.0)
|
||||
l3.polygon = this.polygon?.takeIf { it.isNotEmpty() }?.map { Pair(it.lon, it.lat) }
|
||||
})
|
||||
}
|
||||
AiRoadMarker.aiMakers[this.index]?.receive()
|
||||
}
|
||||
|
||||
fun MessagePad.TrackedObject.toRoadMarker(poiType: String): V2XMarkerCardResult =
|
||||
V2XMarkerCardResult().also { l1 ->
|
||||
val id = "${this.longitude}_${this.latitude}"
|
||||
l1.exploreWay = ArrayList<MarkerExploreWay>().also { l2 ->
|
||||
l2.add(MarkerExploreWay().also { l3 ->
|
||||
l3.poiType = poiType
|
||||
l3.setGenerateTime(0L)
|
||||
l3.location = MarkerLocation().also { l4 ->
|
||||
val p = CoordinateTransform.WGS84ToGCJ02(this.longitude, this.latitude)
|
||||
l4.lon = p[0]
|
||||
l4.lat = p[1]
|
||||
l4.angle = this.heading
|
||||
}
|
||||
l3.infoId = id
|
||||
|
||||
l3.gpsLocation = Pair(this.longitude, this.latitude)
|
||||
l3.polygon = this.polygonList?.takeIf { it.isNotEmpty() }?.map { Pair(it.longitude, it.latitude) }
|
||||
})
|
||||
}
|
||||
AiRoadMarker.aiMakers[id]?.receive()
|
||||
}
|
||||
|
||||
fun V2XMarkerCardResult.toV2XRoadEventEntity(): V2XRoadEventEntity =
|
||||
V2XRoadEventEntity().also { l1 ->
|
||||
val exploreWayList: List<MarkerExploreWay>? = this.exploreWay
|
||||
if (!exploreWayList.isNullOrEmpty() && exploreWayList.isNotEmpty()) {
|
||||
for (markerExploreWay in exploreWayList) {
|
||||
if (isRoadEvent(markerExploreWay.poiType)) {
|
||||
val markerLocation = markerExploreWay.location
|
||||
l1.location = markerLocation
|
||||
l1.poiType = markerExploreWay.poiType
|
||||
l1.noveltyInfo = markerExploreWay
|
||||
l1.expireTime = 20000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapUIServiceManager
|
||||
import com.mogo.eagle.core.utilcode.util.WindowUtils
|
||||
|
||||
class MapUtils {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun zoomMap(latLng: MogoLatLng?, context: Context) {
|
||||
try {
|
||||
if (latLng == null) {
|
||||
return
|
||||
}
|
||||
val mBoundRect = Rect()
|
||||
mBoundRect.bottom = WindowUtils.dip2px(context, 100f)
|
||||
mBoundRect.top = WindowUtils.dip2px(context, 370f)
|
||||
mBoundRect.left = WindowUtils.dip2px(context, 575f)
|
||||
mBoundRect.right = WindowUtils.dip2px(context, 100f)
|
||||
// 当前车辆位置
|
||||
val carLocation = MogoLatLng(
|
||||
CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().latitude,
|
||||
CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84().longitude
|
||||
)
|
||||
// 调整自适应的地图镜头
|
||||
CallerMapUIServiceManager.getMapUIController()
|
||||
?.showBounds("MapUtils", carLocation, listOf(latLng), mBoundRect, true)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.mogo.eagle.function.biz.v2x.v2n.view
|
||||
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
|
||||
import com.mogo.eagle.core.data.map.entity.V2XRoadEventEntity
|
||||
import com.mogo.eagle.core.function.biz.R
|
||||
import com.mogo.eagle.core.utilcode.util.ViewUtils
|
||||
import kotlinx.android.synthetic.main.view_marker_event_car.view.*
|
||||
|
||||
/**
|
||||
* author : donghongyu
|
||||
* e-mail : 1358506549@qq.com
|
||||
* date : 2020-01-0619:55
|
||||
* desc :
|
||||
* 3、道路事件
|
||||
* 2.18 演示 :驾驶模式中地图展示“拥堵“、“施工”;
|
||||
* (ADAS模式下还包含 原有的拥堵、交通检查、封路事件)
|
||||
* version: 1.0
|
||||
*/
|
||||
class V2XMarkerRoadEventView(context: Context, alarmInfo: V2XRoadEventEntity) :
|
||||
ConstraintLayout(context) {
|
||||
|
||||
companion object{
|
||||
const val TAG = "V2XMarkerRoadEventView"
|
||||
}
|
||||
|
||||
init {
|
||||
initView(context, alarmInfo)
|
||||
}
|
||||
|
||||
fun initView(context: Context, alarmInfo: V2XRoadEventEntity) {
|
||||
if (alarmInfo.poiType == EventTypeEnumNew.ALERT_FRONT_CAR.poiType ||
|
||||
alarmInfo.poiType == EventTypeEnumNew.ALERT_CAR_TROUBLE_WARNING.poiType
|
||||
) {
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.view_marker_event_car, this)
|
||||
} else {
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.view_marker_event_road, this)
|
||||
}
|
||||
updateIcon(alarmInfo)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventTypeEnumNew
|
||||
*/
|
||||
private fun updateIcon(alarmInfo: V2XRoadEventEntity) {
|
||||
// 道路施工、积水、路面结冰、浓雾、事故、拥堵
|
||||
val iconResId = EventTypeEnumNew.getUpdateIconRes(alarmInfo.poiType)
|
||||
if (iconResId != 0) {
|
||||
ivCar.setImageResource(iconResId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 背景
|
||||
*/
|
||||
fun setBackground(imageRes: Int): V2XMarkerRoadEventView {
|
||||
ivBg.setImageResource(imageRes)
|
||||
return this
|
||||
}
|
||||
|
||||
fun getView(): Bitmap {
|
||||
return ViewUtils.fromView(this)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
package com.mogo.eagle.function.biz.v2x.vip
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import com.mogo.aicloud.services.socket.IMogoOnMessageListener
|
||||
import com.mogo.aicloud.services.socket.MogoAiCloudSocketManager
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig.Companion.BIZ_VIP
|
||||
import com.mogo.eagle.core.data.deva.bizconfig.FuncBizConfig.Companion.V2N
|
||||
import com.mogo.eagle.core.data.enums.EventTypeEnumNew
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.data.msgbox.V2XMsg
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.TrafficLightResult
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.currentRoadTrafficLight
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.isGreen
|
||||
import com.mogo.eagle.core.data.biz.trafficlight.isRed
|
||||
import com.mogo.eagle.core.data.v2x.VipMessage
|
||||
import com.mogo.eagle.core.function.api.datacenter.union.IMoGoTrafficLightListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager
|
||||
import com.mogo.eagle.core.function.call.v2x.CallerTrafficLightListenerManager
|
||||
import com.mogo.eagle.core.function.call.v2x.CallVipSetListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_V2X
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
|
||||
import com.mogo.eagle.function.biz.v2x.trafficlight.core.MogoTrafficLightManager
|
||||
import com.mogo.eagle.function.biz.v2x.vip.network.VipNetWorkModel
|
||||
import com.zhjt.service_biz.BizConfig
|
||||
|
||||
class VipCarManager : IMogoOnMessageListener<VipMessage>, IMoGoTrafficLightListener,
|
||||
Handler.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "VipCarManager"
|
||||
private const val MSG_WHAT_VIP_SEARCH = 1
|
||||
private const val MSG_WHAT_VIP_CANCEL = 2
|
||||
|
||||
val INSTANCE: VipCarManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
VipCarManager()
|
||||
}
|
||||
}
|
||||
|
||||
private var mContext: Context? = null
|
||||
private var turnLight = false
|
||||
private var vip: Boolean = false
|
||||
|
||||
@Volatile
|
||||
private var exit: Boolean = false
|
||||
|
||||
private var result: TrafficLightResult? = null
|
||||
|
||||
private val vipNetWorkModel = VipNetWorkModel()
|
||||
private val handler = Handler(Looper.getMainLooper(), this)
|
||||
|
||||
fun initServer(context: Context) {
|
||||
mContext = context
|
||||
MogoAiCloudSocketManager.getInstance(context)
|
||||
.registerOnMessageListener(401025, this)
|
||||
|
||||
//首次进入应用查询是否为VIP车辆
|
||||
requestVip()
|
||||
}
|
||||
|
||||
override fun handleMessage(msg: Message): Boolean {
|
||||
when (msg.what) {
|
||||
MSG_WHAT_VIP_SEARCH -> {
|
||||
requestVip()
|
||||
}
|
||||
MSG_WHAT_VIP_CANCEL -> {
|
||||
cancelVip()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun target(): Class<VipMessage> {
|
||||
return VipMessage::class.java
|
||||
}
|
||||
|
||||
@BizConfig(V2N, "", BIZ_VIP)
|
||||
override fun onMsgReceived(vipMessage: VipMessage?) {
|
||||
CallerLogger.d("$M_V2X$TAG", "onMsgReceived vipMessage : ${vipMessage.toString()}")
|
||||
vipMessage?.let {
|
||||
when (it.vipType) {
|
||||
0 -> { //取消VIP
|
||||
cancelVip()
|
||||
}
|
||||
1 -> { //设置VIP
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"设置handler超时时间 " + ", time : ${System.currentTimeMillis() - vipMessage.timeOut}"
|
||||
)
|
||||
setVip(vipMessage.timeOut)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTrafficLightStatus(trafficLightResult: TrafficLightResult) {
|
||||
if (!vip) {
|
||||
return
|
||||
}
|
||||
|
||||
if (exit) {
|
||||
CallerLogger.d("$M_V2X$TAG", "驶离路口,返回 , then resetConditions")
|
||||
resetConditions()
|
||||
exit = false
|
||||
return
|
||||
}
|
||||
|
||||
if (trafficLightResult.currentRoadTrafficLight() == null) {
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"vip 获取到灯态,但没找到对应车道数据 trafficLightResult : $trafficLightResult , then resetConditions"
|
||||
)
|
||||
resetConditions()
|
||||
return
|
||||
}
|
||||
|
||||
val currentResult = trafficLightResult.currentRoadTrafficLight()
|
||||
val lastResult = result?.currentRoadTrafficLight()
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"检查是否变灯 last.remain : ${lastResult?.remain} , color : ${lastResult?.color} , current.remain : ${currentResult?.remain} , color : ${currentResult?.color}, turnLight : $turnLight"
|
||||
)
|
||||
|
||||
this.result = trafficLightResult
|
||||
|
||||
if (!turnLight) {
|
||||
// 首次判断,变灯
|
||||
turnLight = true
|
||||
val controlTime = if (currentResult!!.isGreen()) 45 - currentResult.remain else 45
|
||||
CallerLogger.d("$M_V2X$TAG", "触发变灯 , controlTime : $controlTime")
|
||||
turnLight(controlTime)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun resetConditions() {
|
||||
turnLight = false
|
||||
result = null
|
||||
}
|
||||
|
||||
@BizConfig(V2N, "", BIZ_VIP)
|
||||
private fun setVip(cancelDelayTime: Long) {
|
||||
vip = true
|
||||
handler.sendEmptyMessageDelayed(
|
||||
MSG_WHAT_VIP_CANCEL,
|
||||
cancelDelayTime - System.currentTimeMillis()
|
||||
)
|
||||
CallVipSetListenerManager.invokeVipSetStatus(true)
|
||||
CallerTrafficLightListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
private fun cancelVip() {
|
||||
vip = false
|
||||
if (handler.hasMessages(MSG_WHAT_VIP_CANCEL)) {
|
||||
handler.removeMessages(MSG_WHAT_VIP_CANCEL)
|
||||
}
|
||||
resetConditions()
|
||||
CallVipSetListenerManager.invokeVipSetStatus(false)
|
||||
CallerTrafficLightListenerManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
private fun requestVip() {
|
||||
vipNetWorkModel.requestVip({
|
||||
if (handler.hasMessages(MSG_WHAT_VIP_SEARCH)) {
|
||||
handler.removeMessages(MSG_WHAT_VIP_SEARCH)
|
||||
}
|
||||
if (it.vipStatus) {
|
||||
setVip(it.cancelDelayTime)
|
||||
} else {
|
||||
cancelVip()
|
||||
}
|
||||
}, {
|
||||
CallerLogger.e("$M_V2X$TAG", "获取VIP信息失败, 准备间隔5秒重新获取")
|
||||
handler.sendEmptyMessageDelayed(MSG_WHAT_VIP_SEARCH, 5_000L)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onEnterCrossRoad(enter: Boolean) {
|
||||
super.onEnterCrossRoad(enter)
|
||||
UiThreadHandler.post {
|
||||
this.exit = !enter
|
||||
}
|
||||
}
|
||||
|
||||
fun turnLight(controlTime: Int) {
|
||||
if (result == null || mContext == null) return
|
||||
val mogoLocation = CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84()
|
||||
if (mogoLocation != null) {
|
||||
val bearing = mogoLocation.heading
|
||||
CallerLogger.d("$M_V2X$TAG", "-- turnLight -- ")
|
||||
MogoTrafficLightManager.INSTANCE.turnLightToGreen(
|
||||
result!!.lightId, result!!.crossId, bearing, controlTime,
|
||||
// 100445, "10037", 90.0, controlTime, //衡阳25号路口测试数据
|
||||
{
|
||||
// 请求变灯成功,直接提示
|
||||
if (it.sn == MoGoAiCloudClientConfig.getInstance().sn && it.code == 0) {
|
||||
CallerLogger.d("$M_V2X$TAG", "变灯请求成功")
|
||||
val light = this.result?.currentRoadTrafficLight()
|
||||
if (light != null && light.isGreen()) {
|
||||
showWarning(
|
||||
EventTypeEnumNew.TYPE_VIP_IDENTIFICATION_EXTEND.poiType,
|
||||
EventTypeEnumNew.TYPE_VIP_IDENTIFICATION_EXTEND.content,
|
||||
EventTypeEnumNew.TYPE_VIP_IDENTIFICATION_EXTEND.tts
|
||||
)
|
||||
} else {
|
||||
showWarning(
|
||||
EventTypeEnumNew.TYPE_VIP_IDENTIFICATION_PASS.poiType,
|
||||
EventTypeEnumNew.TYPE_VIP_IDENTIFICATION_PASS.content,
|
||||
EventTypeEnumNew.TYPE_VIP_IDENTIFICATION_PASS.tts
|
||||
)
|
||||
}
|
||||
return@turnLightToGreen
|
||||
}
|
||||
|
||||
// 请求变灯失败,根据灯态来提示。 此处灯态未获取到
|
||||
if (this.result == null || this.result?.currentRoadTrafficLight() == null) {
|
||||
showWarning(
|
||||
EventTypeEnumNew.TYPE_VIP_ERROR_IDENTIFICATION.poiType,
|
||||
EventTypeEnumNew.TYPE_VIP_ERROR_IDENTIFICATION.content + ", 稍后重试",
|
||||
EventTypeEnumNew.TYPE_VIP_ERROR_IDENTIFICATION.tts
|
||||
)
|
||||
return@turnLightToGreen
|
||||
}
|
||||
|
||||
// 如果当前为红灯,则提示
|
||||
if (this.result!!.currentRoadTrafficLight()!!.isRed()) {
|
||||
val time = if (it.countDown / 60 >= 1) {
|
||||
"${it.countDown / 60}分${it.countDown % 60}秒后重试"
|
||||
} else {
|
||||
val temp = if (it.countDown == 0) {
|
||||
1
|
||||
} else {
|
||||
it.countDown
|
||||
}
|
||||
"${temp}秒后重试"
|
||||
}
|
||||
showWarning(
|
||||
EventTypeEnumNew.TYPE_VIP_ERROR_IDENTIFICATION.poiType,
|
||||
EventTypeEnumNew.TYPE_VIP_ERROR_IDENTIFICATION.content + time,
|
||||
EventTypeEnumNew.TYPE_VIP_ERROR_IDENTIFICATION.tts
|
||||
)
|
||||
} else {
|
||||
CallerLogger.d(
|
||||
"$M_V2X$TAG",
|
||||
"变灯请求失败,当前为非红灯不做展示 , light : ${result.toString()} , trafficLightControl : $it"
|
||||
)
|
||||
}
|
||||
},
|
||||
{ errorMsg ->
|
||||
CallerLogger.e("$M_V2X$TAG", "变灯请求失败 msg : $errorMsg")
|
||||
ToastUtils.showLong("服务异常,请稍后重试")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun showWarning(
|
||||
v2xType: String,
|
||||
alertContent: CharSequence,
|
||||
ttsContent: String,
|
||||
) {
|
||||
if (alertContent.toString().isEmpty() || ttsContent.isEmpty()) {
|
||||
Log.d("MsgBox-VipCarManager", "alertContent或ttsContent为空!")
|
||||
}
|
||||
CallerMsgBoxManager.saveMsgBox(
|
||||
MsgBoxBean(MsgBoxType.V2X, V2XMsg(v2xType, alertContent.toString(), ttsContent))
|
||||
)
|
||||
CallerHmiManager.warningV2X(v2xType, alertContent, ttsContent)
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
MogoAiCloudSocketManager.getInstance(mContext)
|
||||
.unregisterLifecycleListener(401025)
|
||||
mContext = null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mogo.eagle.function.biz.v2x.vip.network
|
||||
|
||||
import com.mogo.eagle.core.data.BaseResponse
|
||||
import com.mogo.eagle.core.data.v2x.VipRequest
|
||||
import retrofit2.http.*
|
||||
|
||||
interface VipApiService {
|
||||
|
||||
//查询是否为VIP车辆
|
||||
@GET("eagle-eye-dns/dataService/carUser/getVipStatusBySn")
|
||||
suspend fun requestVip(@Query("sn") sn: String): BaseResponse<VipRequest>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.mogo.eagle.function.biz.v2x.vip.network
|
||||
|
||||
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
|
||||
import com.mogo.commons.constants.HostConst
|
||||
import com.mogo.eagle.core.data.BaseResponse
|
||||
import com.mogo.eagle.core.data.v2x.VipRequest
|
||||
import com.mogo.eagle.core.network.MoGoRetrofitFactory
|
||||
import com.mogo.eagle.core.network.apiCall
|
||||
import com.mogo.eagle.core.network.request
|
||||
|
||||
|
||||
class VipNetWorkModel {
|
||||
|
||||
private fun getNetWorkApi(baseUrl: String = HostConst.getEagleHost()): VipApiService {
|
||||
return MoGoRetrofitFactory.getInstanceNoCallAdapter(baseUrl)
|
||||
.create(VipApiService::class.java)
|
||||
}
|
||||
|
||||
fun requestVip(onSuccess: ((VipRequest) -> Unit), onError: ((String) -> Unit)) {
|
||||
request<BaseResponse<VipRequest>> {
|
||||
loader {
|
||||
apiCall {
|
||||
getNetWorkApi().requestVip(MoGoAiCloudClientConfig.getInstance().sn)
|
||||
}
|
||||
}
|
||||
onSuccess {
|
||||
if (it.result != null) {
|
||||
onSuccess.invoke(it.result)
|
||||
} else {
|
||||
onError.invoke("requestRoadID result is null")
|
||||
}
|
||||
}
|
||||
onError {
|
||||
if (it.message != null) {
|
||||
onError.invoke(it.message!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |