[650] feat: 乘客屏 路侧 V2N 事件弹框完成功能实现,以及 Caller 调用接口;

This commit is contained in:
aibingbing
2024-06-20 10:34:49 +08:00
parent b7fa4ff81f
commit 67b99edbfd
9 changed files with 303 additions and 113 deletions

View File

@@ -8,20 +8,23 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.mogo.commons.voice.AIAssist
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.data.road.RoadV2NEventWindowBean
import com.mogo.eagle.core.data.v2x.RoadV2NEventWindowBean
import com.mogo.eagle.core.function.api.hmi.v2n.IRoadV2NEventWindowListener
import com.mogo.eagle.core.function.call.hmi.CallerRoadV2NEventWindowListenerManager
import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.util.DateTimeUtils
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
import kotlinx.android.synthetic.main.hmi_view_passenger_v2n_event.view.containerLivePlay
import kotlinx.android.synthetic.main.hmi_view_passenger_v2n_event.view.ivClose
import kotlinx.android.synthetic.main.hmi_view_passenger_v2n_event.view.ivPassengerV2XImage
import kotlinx.android.synthetic.main.hmi_view_passenger_v2n_event.view.roundRoadV2NEventContainer
import kotlinx.android.synthetic.main.hmi_view_passenger_v2n_event.view.tvPassengerV2XContent
import kotlinx.android.synthetic.main.hmi_view_passenger_v2n_event.view.tvPassengerV2XTime
import me.jessyan.autosize.utils.AutoSizeUtils
/**
* V2N通用事件弹框(乘客屏)
* V2N通用事件弹框
*/
class PassengerV2NEventView @JvmOverloads constructor(
context: Context,
@@ -45,11 +48,33 @@ class PassengerV2NEventView @JvmOverloads constructor(
}
private fun initView() {
background = if (isPassengerScreen) ContextCompat.getDrawable(
context,
R.drawable.hmi_v2n_event_bg_passenger
)
else ContextCompat.getDrawable(context, R.drawable.bg_v2n_event_driver)
if (isPassengerScreen) {
val layoutParam = ConstraintLayout.LayoutParams(
AutoSizeUtils.dp2px(
context, (600 + 37 + 37).toFloat()
),
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
roundRoadV2NEventContainer.layoutParams = layoutParam
roundRoadV2NEventContainer.background = ContextCompat.getDrawable(
context,
R.drawable.hmi_v2n_event_bg_passenger
)
val padding = AutoSizeUtils.dp2px(context, 37f)
roundRoadV2NEventContainer.setPadding(padding, padding, padding, padding)
} else {
val layoutParam = ConstraintLayout.LayoutParams(
AutoSizeUtils.dp2px(
context, (600 + 0 + 0).toFloat()
),
ConstraintLayout.LayoutParams.WRAP_CONTENT
)
roundRoadV2NEventContainer.layoutParams = layoutParam
roundRoadV2NEventContainer.background =
ContextCompat.getDrawable(context, R.drawable.bg_v2n_event_driver)
val padding = AutoSizeUtils.dp2px(context, 0f)
roundRoadV2NEventContainer.setPadding(padding, padding, padding, padding)
}
ivClose.setOnClickListener {
visibility = View.GONE
@@ -59,6 +84,30 @@ class PassengerV2NEventView @JvmOverloads constructor(
override fun onAttachedToWindow() {
super.onAttachedToWindow()
CallerRoadV2NEventWindowListenerManager.addListener(TAG, this)
//TODO
val eventId = CallerRoadV2NEventWindowListenerManager.show(
System.currentTimeMillis(),
R.drawable.v2x_icon_shigong_zhandao,
"前方 200米 道路积水",
true,
"172.168.1.20",
0.0,
0.0
)
UiThreadHandler.postDelayed({
CallerRoadV2NEventWindowListenerManager.dismiss(eventId)
val eventId1 = CallerRoadV2NEventWindowListenerManager.show(
System.currentTimeMillis(),
R.drawable.v2x_icon_jiaotongshigu_vr,
"前方 300米 发生交通事故",
true,
"172.168.1.20",
0.0,
0.0
)
}, 20 * 1000L)
}
override fun onDetachedFromWindow() {
@@ -68,8 +117,6 @@ class PassengerV2NEventView @JvmOverloads constructor(
override fun show(dataBean: RoadV2NEventWindowBean) {
currentEventUUID = dataBean.uuid
//TODO
ivPassengerV2XImage.setImageDrawable(
ContextCompat.getDrawable(
context,
@@ -79,11 +126,14 @@ class PassengerV2NEventView @JvmOverloads constructor(
tvPassengerV2XContent.text = dataBean.hintStr
tvPassengerV2XTime.text =
"更新时间:${DateTimeUtils.getTimeText(dataBean.timestamp, DateTimeUtils.HH_mm_ss)}"
containerLivePlay.startPlay("https://video.zhidaozhixing.com/hy/LI_008_070.flv?txSecret=28ece9ad0bd67d06a7d391ed42264a99&txTime=66922502")
if (dataBean.isNeedTTS) {
AIAssist.getInstance(context)
.speakTTSVoiceWithLevel(dataBean.hintStr, AIAssist.LEVEL0)
}
containerLivePlay.startRoadCameraLive(
dataBean.cameraIp,
dataBean.lon, dataBean.lat
)
visibility = View.VISIBLE
}
@@ -91,8 +141,7 @@ class PassengerV2NEventView @JvmOverloads constructor(
if (eventId == currentEventUUID) {
visibility = View.GONE
currentEventUUID = ""
//TODO
//停止播放
containerLivePlay.stopRoadCameraLive()
}
}
}

View File

@@ -9,6 +9,7 @@ import android.view.animation.AnimationUtils
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import com.mogo.eagle.core.data.config.FunctionBuildConfig
import com.mogo.eagle.core.function.business.roadcross.net.NDERoadV2NModel
import com.mogo.eagle.core.function.hmi.R
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
@@ -41,9 +42,6 @@ class V2NEventLivePlayView @JvmOverloads constructor(
// 是否播放成功
private var isPlaySuccess = false
// 拉流的url
private var flvUrl: String? = null
private val videoLoadingAnimation by lazy {
AnimationUtils.loadAnimation(context, R.anim.loading_rotate_animation);
}
@@ -97,22 +95,69 @@ class V2NEventLivePlayView @JvmOverloads constructor(
})
}
fun startPlay(flvUrl: String) {
this.flvUrl = flvUrl
/**
* 开始查询拉流url
*/
fun startRoadCameraLive(
cameraId: String, lon: Double, lat: Double
) {
CallerLogger.i(
"${SceneConstant.M_HMI}$TAG",
"startRoadCameraLive, cameraId=$cameraId, lon=$lon, lat=$lat"
)
startLoading()
NDERoadV2NModel.ndeRoadV2NModel.querySingleCameraLiveByCameraIp(cameraId, lon, lat,
onSuccess = {
startPlay(it?.liveUrl)
},
onError = {
CallerLogger.e(
"${SceneConstant.M_HMI}$TAG",
"查询视频播放地址error, msg=$it"
)
stopLoading()
showPlayFail()
//TODO
startPlay("https://video.zhidaozhixing.com/hy/LI_008_070.flv?txSecret=28ece9ad0bd67d06a7d391ed42264a99&txTime=66922502")
})
}
/**
* 结束拉流
*/
fun stopRoadCameraLive() {
CallerLogger.i(
"${SceneConstant.M_HMI}$TAG",
"stopRoadCameraLive"
)
stopLoading()
try {
svpPlayer?.gsyVideoManager?.stop()
NDERoadV2NModel.ndeRoadV2NModel.cancelRequest("querySingleCameraLiveByCameraIp")
} catch (e: Exception) {
CallerLogger.w(
"${SceneConstant.M_HMI}$TAG",
"onDetachedFromWindow, e=${e.message}"
)
}
}
private fun startPlay(flvUrl: String?) {
if (TextUtils.isEmpty(flvUrl)) {
CallerLogger.e(
"${SceneConstant.M_HMI}$TAG",
"播放视频异常, flvUrl=$flvUrl"
"播放视频数据异常, flvUrl=${flvUrl}"
)
stopLoading()
showPlayFail()
return
}
CallerLogger.w(
CallerLogger.i(
"${SceneConstant.M_HMI}$TAG",
"开始播放视频, flvUrl=$flvUrl"
"开始加载视频, flvUrl=${flvUrl}"
)
startLoading()
this.flvUrl?.also {
flvUrl?.also {
startLoadVideo(it)
}
}
@@ -153,7 +198,7 @@ class V2NEventLivePlayView @JvmOverloads constructor(
}
/**
* 加载完后 展示播放画面
* 加载视频流
*/
private fun startLoadVideo(flvUrl: String) {
gsyVideoOptionBuilder
@@ -180,19 +225,10 @@ class V2NEventLivePlayView @JvmOverloads constructor(
override fun onAttachedToWindow() {
super.onAttachedToWindow()
startLoading()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
stopLoading()
try {
svpPlayer?.gsyVideoManager?.stop()
} catch (e: Exception) {
CallerLogger.w(
"${SceneConstant.M_HMI}$TAG",
"onDetachedFromWindow, e=${e.message}"
)
}
stopRoadCameraLive()
}
}

View File

@@ -0,0 +1,25 @@
package com.mogo.eagle.core.function.business.roadcross.net
import com.mogo.eagle.core.data.BaseResponse
import com.mogo.eagle.core.data.road.RoadCameraLive
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
const val QUERY_SINGLE_LIVE = "/abilitySupport/rss/queryLive"
interface INDERoadV2NApiService {
/**
* 单ip查询设备直播流与缩略图
*/
@GET(QUERY_SINGLE_LIVE)
suspend fun querySingleCameraLiveByCameraIp(
@Header("MogoAuthKey") authKey: String,
@Header("MogoReqTime") time: String,
@Query("ip") ip: String,
@Query("lon") lon: Double,
@Query("lat") lat: Double
): BaseResponse<RoadCameraLive>
}

View File

@@ -0,0 +1,55 @@
package com.mogo.eagle.core.function.business.roadcross.net
import com.mogo.commons.constants.HostConst
import com.mogo.eagle.core.data.BaseResponse
import com.mogo.eagle.core.data.road.RoadCameraLive
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.Md5Util
import java.util.Locale
class NDERoadV2NModel private constructor() {
companion object {
val ndeRoadV2NModel by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
NDERoadV2NModel()
}
}
private fun getNetWorkApi(baseUrl: String = HostConst.getNDEHost()): INDERoadV2NApiService {
return MoGoRetrofitFactory.getInstanceNoCallAdapter(baseUrl)
.create(INDERoadV2NApiService::class.java)
}
fun querySingleCameraLiveByCameraIp(
cameraIp: String,
lon: Double,
lat: Double,
onSuccess: ((RoadCameraLive?) -> Unit),
onError: ((String) -> Unit)
) {
request<BaseResponse<RoadCameraLive>>("querySingleCameraLiveByCameraIp") {
loader {
apiCall {
val time = System.currentTimeMillis().toString()
val md5String = "${QUERY_SINGLE_LIVE.uppercase(Locale.getDefault())}$time"
getNetWorkApi().querySingleCameraLiveByCameraIp(
Md5Util.getMD5Result(md5String), time, cameraIp, lon, lat
)
}
}
onSuccess {
onSuccess.invoke(it.result)
}
onError {
onError.invoke(it.message.toString())
}
}
}
fun cancelRequest(tag: String) {
cancel(tag)
}
}

View File

@@ -2,95 +2,107 @@
<com.mogo.eagle.core.widget.RoundConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="@dimen/dp_600"
android:id="@+id/roundRoadV2NEventContainer"
android:layout_width="@dimen/dp_674"
android:layout_height="wrap_content"
android:background="@drawable/hmi_v2n_event_bg_passenger">
android:background="@drawable/hmi_v2n_event_bg_passenger"
android:padding="@dimen/dp_37">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/containerEvent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_50"
android:layout_marginTop="@dimen/dp_40"
android:layout_marginEnd="@dimen/dp_50"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/ivPassengerV2XImage"
android:layout_width="@dimen/dp_69"
android:layout_height="@dimen/dp_69"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/containerEvent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_50"
android:layout_marginTop="@dimen/dp_40"
android:layout_marginEnd="@dimen/dp_50"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tvPassengerV2XContent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/v2x_icon_shigong_zhandao" />
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/ivPassengerV2XImage"
android:layout_width="@dimen/dp_69"
android:layout_height="@dimen/dp_69"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tvPassengerV2XContent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/v2x_icon_shigong_zhandao" />
<TextView
android:id="@+id/tvPassengerV2XContent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_30"
android:ellipsize="end"
android:gravity="start"
android:maxLines="2"
android:textColor="#131415"
android:textSize="@dimen/dp_32"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@id/ivPassengerV2XImage"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="wrap"
app:layout_goneMarginStart="0dp"
tools:text="前方150米 道路施工 前方150米 道路施工 前方150米 道路施工" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.mogo.eagle.core.function.hmi.ui.v2n.V2NEventLivePlayView
android:id="@+id/containerLivePlay"
android:layout_width="@dimen/dp_498"
android:layout_height="@dimen/dp_298"
android:layout_marginStart="@dimen/dp_51"
android:layout_marginTop="@dimen/dp_24"
android:layout_marginEnd="@dimen/dp_51"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/containerEvent" />
<TextView
android:id="@+id/tvPassengerV2XContent"
android:layout_width="0dp"
android:id="@+id/tvPassengerV2XTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_30"
android:layout_marginStart="@dimen/dp_51"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginEnd="@dimen/dp_51"
android:layout_marginBottom="@dimen/dp_33"
android:ellipsize="end"
android:gravity="start"
android:maxLines="2"
android:maxLines="1"
android:textColor="#131415"
android:textSize="@dimen/dp_32"
android:textSize="@dimen/dp_24"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@id/ivPassengerV2XImage"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_default="wrap"
app:layout_goneMarginStart="0dp"
tools:text="前方150米 道路施工 前方150米 道路施工 前方150米 道路施工" />
app:layout_constraintTop_toBottomOf="@id/containerLivePlay"
tools:text="更新时间10:38:20" />
<ImageView
android:id="@+id/ivClose"
android:layout_width="@dimen/dp_32"
android:layout_height="@dimen/dp_32"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginEnd="@dimen/dp_20"
android:padding="@dimen/dp_2"
android:src="@drawable/hmi_v2n_event_icon_close_passenger"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.mogo.eagle.core.function.hmi.ui.v2n.V2NEventLivePlayView
android:id="@+id/containerLivePlay"
android:layout_width="@dimen/dp_498"
android:layout_height="@dimen/dp_298"
android:layout_marginStart="@dimen/dp_51"
android:layout_marginTop="@dimen/dp_24"
android:layout_marginEnd="@dimen/dp_51"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/containerEvent" />
<TextView
android:id="@+id/tvPassengerV2XTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dp_51"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginEnd="@dimen/dp_51"
android:layout_marginBottom="@dimen/dp_33"
android:ellipsize="end"
android:gravity="start"
android:maxLines="1"
android:textColor="#131415"
android:textSize="@dimen/dp_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/containerLivePlay"
tools:text="更新时间10:38:20" />
<ImageView
android:id="@+id/ivClose"
android:layout_width="@dimen/dp_32"
android:layout_height="@dimen/dp_32"
android:layout_marginTop="@dimen/dp_2"
android:layout_marginEnd="@dimen/dp_2"
android:padding="@dimen/dp_2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</com.mogo.eagle.core.widget.RoundConstraintLayout>