Commit a8ab6745 authored by p x's avatar p x
Browse files

添加居中提示字的逻辑

parent 4e15cda9
...@@ -13,7 +13,7 @@ android { ...@@ -13,7 +13,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "com.sd.cavphmi" applicationId = "com.sd.cavphmi"
minSdk = 29 minSdk = 31
targetSdk = 35 targetSdk = 35
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
...@@ -50,6 +50,17 @@ android { ...@@ -50,6 +50,17 @@ android {
abortOnError = false abortOnError = false
checkReleaseBuilds = false checkReleaseBuilds = false
} }
applicationVariants.all {
outputs.all {
if (this is com.android.build.gradle.internal.api.ApkVariantOutputImpl) {
val config = project.android.defaultConfig
val versionName = config.versionName
// val formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd_HHmm")
// val createTime = LocalDateTime.now().format(formatter)
outputFileName = "avp_${versionName}.apk"
}
}
}
} }
...@@ -60,8 +71,9 @@ dependencies { ...@@ -60,8 +71,9 @@ dependencies {
implementation(libs.material) implementation(libs.material)
implementation(libs.androidx.activity) implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout) implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.navigation.fragment.ktx) // implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx) // implementation(libs.androidx.navigation.ui.ktx)
androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
......
package com.sd.cavphmi package com.sd.cavphmi
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.gson.Gson
import com.sd.cavphmi.bean.mock.MRoutes
import com.sd.cavphmi.utils.FileIoUtils
import com.sd.cavphmi.utils.Proj4jCoord
import com.sd.cavphmi.utils.SM4CryptoHelper import com.sd.cavphmi.utils.SM4CryptoHelper
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.Assert.*
/** /**
* Instrumented test, which will execute on an Android device. * Instrumented test, which will execute on an Android device.
* *
...@@ -24,10 +29,60 @@ class ExampleInstrumentedTest { ...@@ -24,10 +29,60 @@ class ExampleInstrumentedTest {
} }
@Test @Test
fun loginCpy(){ fun loginCpy() {
var pwd="vUO2dStZDhbd*88FfT84" var pwd = "vUO2dStZDhbd*88FfT84"
var key="Cusc@itmp-sm4key".toByteArray() var key = "Cusc@itmp-sm4key".toByteArray()
var pp=SM4CryptoHelper.encryptECB(key,pwd.toByteArray()) var pp = SM4CryptoHelper.encryptECB(key, pwd.toByteArray())
println("------------------pp = ${pp}") println("------------------pp = ${pp}")
} }
@Test
fun calculateTouYing() {
// 02runTest
TestScope(UnconfinedTestDispatcher()).launch {
var gson = Gson()
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
var str =
FileIoUtils.getAsset(appContext, "mock/Car_fangzhen.txt") //Qgis里取的点和四维取得点混合
val mRoutes = gson.fromJson<MRoutes>(str, MRoutes::class.java)
// val testPoint = doubleArrayOf(116.38810256578773, 39.92848759523565) // 北海公园
val testPoint = mutableListOf<DoubleArray>()
// 坐标点串 (02坐标系)
val coordinateSeries = mutableListOf<DoubleArray>()
mRoutes.rs.forEachIndexed { index, it ->
var tLng = it[0]
var tLag = it[1]
if (index in 0..50) {
tLng = tLng + 0.00001 * index
tLag = tLag + 0.00001 * index
coordinateSeries.add(doubleArrayOf(tLng, tLag))
} else {
tLng = tLng + 0.000001 * index
tLag = tLag - 0.000001 * index
coordinateSeries.add(doubleArrayOf(tLng, tLag))
}
// coordinateSeries.add(doubleArrayOf(tLng, tLag))
testPoint.add(doubleArrayOf(it[0], it[1]))
}
// coordinateSeries.add(doubleArrayOf(116.38811674159075, 39.93087909844135))
// coordinateSeries.add(doubleArrayOf(116.38513982313117, 39.928482159906224))
// coordinateSeries.add(doubleArrayOf(116.38808130208565, 39.928291923094065))
// coordinateSeries.add(doubleArrayOf(116.39202682873122, 39.92837661180238))
// 计算投影
// double[] result = CoordinateProjectionUtils.calculatePointProjection(testPoint, coordinateSeries);
testPoint.forEachIndexed { index, it ->
val result = Proj4jCoord.calculatePointProjection(it, coordinateSeries)
println("车当前下标: (" + index + ") " + "车当前位置:" + it[0] + " " + it[1] + " 最近线段索引: " + result[2].toInt())
// println("投影点坐标: (" + result[0] + ", " + result[1] + ")")
// println("最近线段索引: " + result[2].toInt())
println("最小距离: " + result[3] + " 米")
}
}
}
} }
\ No newline at end of file
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.SuZhouAvp" android:theme="@style/Theme.SuZhouAvp"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31"> tools:targetApi="31">
<uses-library <uses-library
...@@ -79,7 +80,7 @@ ...@@ -79,7 +80,7 @@
android:hardwareAccelerated="false" android:hardwareAccelerated="false"
android:launchMode="singleTask" android:launchMode="singleTask"
android:resizeableActivity="false" android:resizeableActivity="false"
android:screenOrientation="fullUser" /> android:screenOrientation="landscape"/>
<activity <activity
android:name=".ui.BootActivity" android:name=".ui.BootActivity"
......
...@@ -32,8 +32,8 @@ class CarPanelBean { ...@@ -32,8 +32,8 @@ class CarPanelBean {
var speed = ObservableField(37) var speed = ObservableField(37)
/***档位**/ /***档位**/
var tapPos = ObservableField<Int>(GearStatus.D) var tapPos = ObservableField<Int>()
var gear = 0 // var gear = ObservableField<Int>()
//剩余电量 //剩余电量
var remainSoc = ObservableField<Int>(70) var remainSoc = ObservableField<Int>(70)
......
...@@ -22,5 +22,5 @@ data class VehicleInfo( ...@@ -22,5 +22,5 @@ data class VehicleInfo(
val vehicleImgUrl: Any, val vehicleImgUrl: Any,
val vehicleOwnerName: Any, val vehicleOwnerName: Any,
val vehicleOwnerPhone: Any, val vehicleOwnerPhone: Any,
val vehicleVideoUrl: String val vehicleVideoUrl: String//车内视频
) )
\ No newline at end of file
...@@ -22,11 +22,14 @@ object ShowCarPanelObject { ...@@ -22,11 +22,14 @@ object ShowCarPanelObject {
tv.setText(speed.toString()) tv.setText(speed.toString())
} }
/***档位* //档位 gear
* **/
@JvmStatic @JvmStatic
@BindingAdapter("showTapPos") @BindingAdapter("showTapPos")
fun showTapPos(tv: TextView, @GearStatus gear: Int) { fun showTapPos(tv: TextView, gear: Int) {
if (gear == 7) {
tv.setTextColor("#66000000".toColorInt())
return
}
var tag = tv.tag.toString().toInt() var tag = tv.tag.toString().toInt()
// println("--------tag = ${tag} gear = ${gear}") // println("--------tag = ${tag} gear = ${gear}")
if (tag == gear) { if (tag == gear) {
...@@ -124,21 +127,20 @@ object ShowCarPanelObject { ...@@ -124,21 +127,20 @@ object ShowCarPanelObject {
} }
/***高精地图里的车辆仪表界面***/ /***高精地图里的车辆仪表界面***/
@JvmStatic @JvmStatic
@BindingAdapter(value = ["showMapCarPan", "isStartNai"], requireAll = false) @BindingAdapter(value = ["showMapCarPan", "isStartNai"], requireAll = false)
fun showMapCarPan(fl: FrameLayout, isHighMap: Boolean,isStartNai: Boolean) { fun showMapCarPan(fl: FrameLayout, isHighMap: Boolean, isStartNai: Boolean) {
// println("---------showHeading = ${heading}") // println("---------showHeading = ${heading}")
if (isHighMap){ if (isHighMap) {
// if (isStartNai){ // if (isStartNai){
fl.visibility= View.VISIBLE fl.visibility = View.VISIBLE
// var params=fl.layoutParams as RelativeLayout.LayoutParams // var params=fl.layoutParams as RelativeLayout.LayoutParams
// params.height= DisplayUtil.dp2px(106f) // params.height= DisplayUtil.dp2px(106f)
// fl.layoutParams=params // fl.layoutParams=params
// } // }
} else { } else {
fl.visibility= View.GONE fl.visibility = View.GONE
} }
} }
......
...@@ -56,8 +56,8 @@ object NetworkModule { ...@@ -56,8 +56,8 @@ object NetworkModule {
@NormalInterceptorOkHttpClient @NormalInterceptorOkHttpClient
@Provides @Provides
fun provideNormalInterceptorOkHttpClient( fun provideNormalInterceptorOkHttpClient(
headParamsInterceptor: HeadParamsInterceptor, headParamsInterceptor: HeadParamsInterceptor
baseUrlInterceptor: BaseUrlInterceptor, // baseUrlInterceptor: BaseUrlInterceptor,
): OkHttpClient { ): OkHttpClient {
// 创建信任所有证书的 TrustManager // 创建信任所有证书的 TrustManager
val trustAllCerts = arrayOf<TrustManager>( val trustAllCerts = arrayOf<TrustManager>(
...@@ -73,7 +73,7 @@ object NetworkModule { ...@@ -73,7 +73,7 @@ object NetworkModule {
return OkHttpClient.Builder() return OkHttpClient.Builder()
.cache(RetrofitApi.cache) .cache(RetrofitApi.cache)
.addInterceptor(baseUrlInterceptor) // .addInterceptor(baseUrlInterceptor)
.addInterceptor(headParamsInterceptor) .addInterceptor(headParamsInterceptor)
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager) .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { hostname, session -> true } .hostnameVerifier { hostname, session -> true }
......
...@@ -17,9 +17,9 @@ class BaseUrlInterceptor @Inject constructor() : Interceptor { ...@@ -17,9 +17,9 @@ class BaseUrlInterceptor @Inject constructor() : Interceptor {
var builder = original.newBuilder() var builder = original.newBuilder()
//从request中获取headers,通过给定的键url_name //从request中获取headers,通过给定的键url_name
val headerValue = original.header("urlname").toString() val headerValue = original.header("urlname")
if (!headerValue.isBlank() && headerValue.count() > 0){ if (!headerValue.isNullOrEmpty() && headerValue.count()>0){
val newHttpUrl = headerValue.toHttpUrlOrNull() val newHttpUrl = headerValue.toHttpUrlOrNull()
val url: HttpUrl = originalHttpUrl.newBuilder() val url: HttpUrl = originalHttpUrl.newBuilder()
......
...@@ -21,8 +21,14 @@ class HeadParamsInterceptor @Inject constructor() : Interceptor { ...@@ -21,8 +21,14 @@ class HeadParamsInterceptor @Inject constructor() : Interceptor {
request.header("token", MyContants.HTTP_TOKEN) request.header("token", MyContants.HTTP_TOKEN)
request.header("Authorization", MyContants.HTTP_TOKEN) request.header("Authorization", MyContants.HTTP_TOKEN)
} }
// request.header("Referer", "${MyContants.HOST}/itdts-portal-v5/intelligence-parking") // request.header("Referer", "${MyContants.HOST}/itdts-portal-v5/intelligence-parking"
request.header("Referer", "https://itg-yz.cu-sc.com:13443/itdts-portal-v5/intelligence-parking") // var path = original.url.toUrl().path
// if (path.equals("/api/avpweb/v1/avp/overview/getVehicleInfo")) {
// request.header(
// "Referer",
// "https://itg-yz.cu-sc.com:13443/itdts-portal-v5/intelligence-parking"
// )
// }
return chain.proceed(request.build()) return chain.proceed(request.build())
} }
......
...@@ -23,26 +23,25 @@ interface ClientRetrofitMethod { ...@@ -23,26 +23,25 @@ interface ClientRetrofitMethod {
// fun getConfigurations(): Observable<List<ConfigurationBean>> // fun getConfigurations(): Observable<List<ConfigurationBean>>
// //
/**登录***/ /**登录***/
@POST("api/opr/login") @POST("api/perm/admin/auth/passLogin")
suspend fun login(@Body body: RequestBody): LoginSuccBean suspend fun login(@Body body: RequestBody): LoginSuccBean
/**车辆详情***/ /**车辆详情***/
// @POST("v1/avp/overview/getVehicleInfo")
@POST("api/avpweb/v1/avp/overview/getVehicleInfo") @POST("api/avpweb/v1/avp/overview/getVehicleInfo")
suspend fun getVehDetail(@Body body: RequestBody): VehDetailBean suspend fun getVehDetail(@Body body: RequestBody): VehDetailBean
/**车位占用情况***/ /**车位占用情况***/
@POST("api/avpweb/v1/avp/overview/listSpaceInfoByCondition") @POST("api/avpweb/v1/avp/overview/listSpaceInfoByCondition")
suspend fun getSpaceInfo(@Body body: RequestBody): SpaceInfoBean suspend fun getSpaceInfo(): SpaceInfoBean
/**获取已绑定车辆列表***/ /**获取已绑定车辆列表***/
@Headers("urlname:https://172.24.124.130:14443") // @Headers("urlname:https://172.24.124.130:14443")
@POST("api/avpweb//hmi/v1/queryVehicleList") @POST("api/avpweb/hmi/v1/queryVehicleList")
suspend fun getBindCar(): List<BindCarItem> suspend fun getBindCar(): List<BindCarItem>
// suspend fun getBindCar(@Body body: RequestBody): List<BindCarItem> // suspend fun getBindCar(@Body body: RequestBody): List<BindCarItem>
/**AVP状态***/ /**AVP状态***/
@GET("hmi/monitor/v1/taskStatus") @GET("api/avpweb/hmi/monitor/v1/taskStatus")
suspend fun getAvpStatus(): AvpStatuBean suspend fun getAvpStatus(): AvpStatuBean
......
...@@ -38,7 +38,7 @@ class AvpDataRepo @Inject constructor(private var clientRetrofitMethod: ClientRe ...@@ -38,7 +38,7 @@ class AvpDataRepo @Inject constructor(private var clientRetrofitMethod: ClientRe
suspend fun getSpaceInfo(): MyResult<SpaceInfoBean> { suspend fun getSpaceInfo(): MyResult<SpaceInfoBean> {
try { try {
var body = RequestBodyUtil.toRequestBody(mapOf()) var body = RequestBodyUtil.toRequestBody(mapOf())
var bean = clientRetrofitMethod.getSpaceInfo(body) var bean = clientRetrofitMethod.getSpaceInfo()
return MyResult.Success(bean) return MyResult.Success(bean)
} catch (e: HttpException) { } catch (e: HttpException) {
// println("e.message = ${e.message}") // println("e.message = ${e.message}")
......
...@@ -32,15 +32,11 @@ class LoginActivity : AppCompatActivity() { ...@@ -32,15 +32,11 @@ class LoginActivity : AppCompatActivity() {
var key = "Cusc@itmp-sm4key".toByteArray() var key = "Cusc@itmp-sm4key".toByteArray()
var pp = SM4CryptoHelper.encryptECB(key, pwd.toByteArray()) var pp = SM4CryptoHelper.encryptECB(key, pwd.toByteArray())
loginVm.login(user, pp, 276135).observe(this) { loginVm.login(user, pp, 285369).observe(this) {
// startActivity(Intent(this,MainActivity::class.java)) // startActivity(Intent(this,MainActivity::class.java))
} }
} }
// HTTP获取车辆详情
binding.btVehinfo.setOnClickListener {
mainVm.getVehDetail()
}
// HTTP获取车位占用情况 // HTTP获取车位占用情况
binding.btSpaceinfo.setOnClickListener { binding.btSpaceinfo.setOnClickListener {
mainVm.getSpaceInfo() mainVm.getSpaceInfo()
...@@ -49,6 +45,7 @@ class LoginActivity : AppCompatActivity() { ...@@ -49,6 +45,7 @@ class LoginActivity : AppCompatActivity() {
binding.btAvpstatu.setOnClickListener { binding.btAvpstatu.setOnClickListener {
mainVm.getAvpStatus() mainVm.getAvpStatus()
} }
//获取可绑定车辆
binding.btGetbindcar.setOnClickListener { binding.btGetbindcar.setOnClickListener {
getBinderCars() getBinderCars()
} }
...@@ -62,16 +59,19 @@ class LoginActivity : AppCompatActivity() { ...@@ -62,16 +59,19 @@ class LoginActivity : AppCompatActivity() {
private fun getBinderCars() { private fun getBinderCars() {
mainVm.getBindCar().observe(this) { mainVm.getBindCar().observe(this) {
var list = it.map { it.id.toString() }
val dialog = CustomListDialog(this, "选择车辆", list)
dialog.setOnItemClickListener(object : CustomListDialog.OnItemClickListener {
override fun onItemClick(position: Int, selectedItem: String) {
Toast.makeText(
this@LoginActivity,
"点击了第${position + 1}项: $selectedItem",
Toast.LENGTH_SHORT
).show()
}
})
dialog.show()
} }
// var list = listOf("skywell.1ggvlp16.car10", "skywell.1ggvlp16.car8")
// val dialog = CustomListDialog(this, "选择车辆", list)
// dialog.setOnItemClickListener(object : CustomListDialog.OnItemClickListener {
// override fun onItemClick(position: Int, selectedItem: String) {
// Toast.makeText(this@LoginActivity, "点击了第${position + 1}项: $selectedItem", Toast.LENGTH_SHORT).show()
// }
// })
// dialog.show()
} }
......
package com.sd.cavphmi.ui package com.sd.cavphmi.ui
import android.view.KeyEvent import android.view.KeyEvent
import android.widget.RelativeLayout
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
...@@ -75,6 +74,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -75,6 +74,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
//用作模拟 //用作模拟
private val mockVM: MockVM by viewModels() private val mockVM: MockVM by viewModels()
//主页操作
private val mainVm: MainVm by viewModels() private val mainVm: MainVm by viewModels()
//地图操作类,用于绘制 //地图操作类,用于绘制
...@@ -100,34 +100,30 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -100,34 +100,30 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
ft.add(R.id.map_car_pan, carPanelFragment, "1") ft.add(R.id.map_car_pan, carPanelFragment, "1")
ft.commit() ft.commit()
//设置视频播放器长和宽
var height = DisplayUtil.getScreenHeightPx().div(3) - 20
var width = height.times(2) - 30
var params = binding.videoFrag.layoutParams as RelativeLayout.LayoutParams
params.width = width
params.height = height
binding.videoFrag.layoutParams = params
//添加视频播放器,以后看需要控制显示隐藏时机,默认隐藏 //添加视频播放器,以后看需要控制显示隐藏时机,默认隐藏
var ft2 = supportFragmentManager.beginTransaction() showVideoFragment(true)
ft2.add(R.id.video_frag, exoPlayFragment, "player")
ft2.hide(exoPlayFragment)
ft2.commit()
initialMap() initialMap()
} }
private fun adaptWidth() { private fun adaptWidth() {
// DisplayUtil.forceMeasure(binding.root) var width = DisplayUtil.getScreenWidthPx()
//// var height = 0 var cWidth = (width * 0.271).toInt()
// var width = binding.root.measuredWidth //车辆仪表
// var cWidth = (width * 0.27).toInt() var params = binding.mapCarPan.layoutParams
////车辆仪表 params.width = cWidth
// var params = binding.mapCarPan.layoutParams.apply { binding.mapCarPan.layoutParams = params
// width = cWidth //小地图
// } params = binding.smallFLayout.layoutParams.apply {
// binding.mapCarPan.layoutParams = params this.width = (width * 0.17).toInt()
this.height = (this.width * 0.75).toInt()
}
binding.smallFLayout.layoutParams = params
//车内视频frag
params = binding.videoFrag.layoutParams.apply {
this.width = (width * 0.314).toInt()
this.height = (this.width * 0.54).toInt()
}
binding.videoFrag.layoutParams = params
} }
private fun initialMap() { private fun initialMap() {
...@@ -164,6 +160,24 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -164,6 +160,24 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
override fun getToData() { override fun getToData() {
//开启websocket //开启websocket
// mainVm.startWS() // mainVm.startWS()
//获取车位占用情况
mainVm.getSpaceInfo().observe(this) { spaceInfo ->
}
}
//显示隐藏 视频
private fun showVideoFragment(show: Boolean) {
var ft = supportFragmentManager.beginTransaction()
if (!exoPlayFragment.isAdded) {
ft.add(R.id.video_frag, exoPlayFragment, "player")
}
if (show) {
ft.show(exoPlayFragment)
} else {
ft.hide(exoPlayFragment)
}
ft.commit()
} }
override fun initListener() { override fun initListener() {
...@@ -175,6 +189,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -175,6 +189,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
mainVm.getAvpStatus().observe(this) { avpStatu -> mainVm.getAvpStatus().observe(this) { avpStatu ->
//业务类型 //业务类型
var businessType = avpStatu.businessType//NIL Park Call var businessType = avpStatu.businessType//NIL Park Call
//业务状态
var businessStatus = var businessStatus =
avpStatu.businessStatus//NIL WAITING PROCESSING COMPLETED CANCELLED FAILED avpStatu.businessStatus//NIL WAITING PROCESSING COMPLETED CANCELLED FAILED
//获取档位 //获取档位
...@@ -215,7 +230,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -215,7 +230,7 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
} }
} }
//联网车辆感知物
private fun getTarget() { private fun getTarget() {
mainVm.subTarget().observe(this) { mainVm.subTarget().observe(this) {
if (it.isEmpty()) { if (it.isEmpty()) {
...@@ -230,9 +245,10 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -230,9 +245,10 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
lon = it.longitude lon = it.longitude
ptcid = it.ptcId ptcid = it.ptcId
heading = it.heading heading = it.heading
pType = 1
if (it.ptcType == "car") { if (it.ptcType == "car") {
pType = 1 pType = 1
} else { } else if (it.ptcType == "pedestrian") {
pType = 2 pType = 2
} }
} }
...@@ -247,14 +263,25 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -247,14 +263,25 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
mainVm.subStartV2x().observe(this) { v2x -> mainVm.subStartV2x().observe(this) { v2x ->
if (v2x.objects?.isEmpty() == true) if (v2x.objects?.isEmpty() == true)
return@observe return@observe
//获取预警感知目标物的id 第二个是 //获取预警感知目标物的id 第一个是自己 第二个是别人
var v2xId = v2x.objects!!.get(1).id var v2xId = v2x.objects!!.get(1).id
v2xId = "f117fdfa-feff-0100-85dc-35850000acb0" // v2xId = "f117fdfa-feff-0100-85dc-35850000acb0"
mainVm.startWarning(v2xId) mainVm.startWarning(v2xId)
} }
} }
//获取车辆详情,取车内摄像头地址打开左下角的车内视频
private fun getVehDetail() {
mainVm.getVehDetail().observe(this) { vehDetail ->
var cameraUrl = vehDetail.result.vehicleInfos?.get(0)?.vehicleVideoUrl
println("---cameraUrl = ${cameraUrl}")
if (!cameraUrl.isNullOrEmpty()) {
exoPlayFragment.videoUrl = cameraUrl
showVideoFragment(true)
}
}
}
private fun mockBt() { private fun mockBt() {
//获取AVP状态 //获取AVP状态
binding.btAvpStatu.setOnClickListener { binding.btAvpStatu.setOnClickListener {
...@@ -268,6 +295,10 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() { ...@@ -268,6 +295,10 @@ class MainActivity : BaseActivity<ActivityMainBinding, MyBaseViewModel>() {
binding.btTarget.setOnClickListener { binding.btTarget.setOnClickListener {
getTarget() getTarget()
} }
// HTTP获取车辆详情
binding.btVehinfo.setOnClickListener {
getVehDetail()
}
//v2x 预警 //v2x 预警
binding.btV2x.setOnClickListener { binding.btV2x.setOnClickListener {
getV2x() getV2x()
......
...@@ -48,15 +48,15 @@ class CarPanelFragment : BaseFragment<FragmentCarPanelBinding, MyBaseViewModel>( ...@@ -48,15 +48,15 @@ class CarPanelFragment : BaseFragment<FragmentCarPanelBinding, MyBaseViewModel>(
mainVm.carVehicle.observe(this) { mainVm.carVehicle.observe(this) {
carPanelVM.setCarPanelBean(it) carPanelVM.setCarPanelBean(it)
} }
mainVm.avpStatu.observe(this) { // mainVm.avpStatu.observe(this) {
var gearType = it.vehicleContext.vehicleDynamic.gearType // var gearType = it.vehicleContext.vehicleDynamic.gearType
carPanelVM.setGearType(gearType) // carPanelVM.setGearType(gearType)
} // }
} }
override fun getToData() { override fun getToData() {
// carPanelVM.mock()
} }
companion object { companion object {
......
package com.sd.cavphmi.ui.fragment
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.toColorInt
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import com.sd.cavphmi.bean.AvpStatuBean
import com.sd.cavphmi.databinding.FragmentDistantTipBinding
import com.sd.cavphmi.utils.MyMapUtils
import com.sd.cavphmi.viewmodels.MainVm
import kotlinx.coroutines.launch
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
/**
*距离提示
*/
class DistantTipFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDistantTipBinding.inflate(inflater, container, false)
return binding.root
// Inflate the layout for this fragment
// return inflater.inflate(R.layout.fragment_distant_tip, container, false)
}
private lateinit var binding: FragmentDistantTipBinding
//主页操作
private val mainVm: MainVm by activityViewModels()
private val spannableString = SpannableStringBuilder()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainVm.avpStatu.observe(viewLifecycleOwner) { avpStatu ->
showTip(avpStatu)
}
}
private fun showTip(avpStatu: AvpStatuBean) {
//业务类型
var businessType = avpStatu.businessType//NIL Park Call
//业务状态
var businessStatus =
avpStatu.businessStatus//NIL WAITING PROCESSING COMPLETED CANCELLED FAILED
lifecycleScope.launch {
val vehicleDynamic = avpStatu.vehicleContext.vehicleDynamic
val endPoint = avpStatu.drivenDecision.trajectory.endPoint
//计算车到终点的距离
var distance = MyMapUtils.cauMyLocDistance(
vehicleDynamic.latitude,
vehicleDynamic.longitude,
endPoint.latitude,
endPoint.longitude
)
if (businessType == "Park") {
when (businessStatus) {
// "WAITING" -> {
// binding.tvTip.text = "正在前往您的车位,距离终点${distance}m"
// }
"PROCESSING" -> {
takeStr(distance, 1)
}
"COMPLETED" -> {
clearTipStr()
}
}
} else if (businessType == "Call") {
when (businessStatus) {
// "WAITING" -> {
// binding.tvTip.text = "正在前往您召车点,距离乘客${distance}m"
// }
"PROCESSING" -> {
takeStr(distance, 2)
}
"COMPLETED" -> {
clearTipStr()
}
}
}
}
}
/**
* 生成提示字符串
* @param x 1=泊车 2=招车
*/
private fun takeStr(distance: Double, x: Int) {
if (distance < 3) {
clearTipStr()
return
}
if (x == 1) {
spannableString.append("正在前往您的车位,距离终点${distance}m")
} else if (x == 2) {
spannableString.append("正在前往您召车点,距离乘客${distance}m")
}
var colorSpan1 = ForegroundColorSpan("#000000".toColorInt())
spannableString.setSpan(
colorSpan1,
0, 12, // 起始索引
Spannable.SPAN_INCLUSIVE_INCLUSIVE // 范围模式
)
var colorSpan2 = ForegroundColorSpan("#3385FE".toColorInt())
spannableString.setSpan(
colorSpan2,
13, spannableString.count(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
)
binding.tvTip.text = spannableString
}
//清除提示字符串
private fun clearTipStr() {
spannableString.clear()
binding.tvTip.text = ""
}
private fun testStr() {
val text = "正在前往您的车位,距离终点6m"
val spannableString = SpannableStringBuilder().append(text)
// val spannableString = SpannableString(text)
var colorSpan1 = ForegroundColorSpan("#000000".toColorInt())
spannableString.setSpan(
colorSpan1,
0, 12, // 起始索引(包含)、结束索引(不包含)
Spannable.SPAN_INCLUSIVE_INCLUSIVE // 范围模式(见下文说明)
)
var colorSpan2 = ForegroundColorSpan("#3385FE".toColorInt())
spannableString.setSpan(
colorSpan2,
13, spannableString.count(), // 起始索引(包含)、结束索引(不包含)
Spannable.SPAN_INCLUSIVE_EXCLUSIVE // 范围模式(见下文说明)
)
binding.tvTip.text = spannableString
}
companion object {
@JvmStatic
fun newInstance() = DistantTipFragment()
}
}
\ No newline at end of file
...@@ -15,20 +15,20 @@ import com.sd.cavphmi.databinding.FragmentExoPlayBinding ...@@ -15,20 +15,20 @@ import com.sd.cavphmi.databinding.FragmentExoPlayBinding
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val VIDEO_PARAM1 = "video" private const val VIDEO_URL = "videoUrl"
private const val ARG_PARAM2 = "param2" private const val ARG_PARAM2 = "param2"
/** /**
*车内视频播放器 *车内视频播放器
*/ */
class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>() { class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>() {
private var videoUrl: String = ""
// private var param2: String? = null // private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
arguments?.let { arguments?.let {
videoUrl = it.getString(VIDEO_PARAM1, "") videoUrl = it.getString(VIDEO_URL, "")
// param2 = it.getString(ARG_PARAM2) // param2 = it.getString(ARG_PARAM2)
} }
} }
...@@ -64,40 +64,53 @@ class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>() ...@@ -64,40 +64,53 @@ class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>()
binding.playerView.onPause() binding.playerView.onPause()
} }
override fun onStop() {
super.onStop()
binding.playerView.onPause()
releasePlayer()
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
binding.playerView.getAdViewGroup().removeAllViews() // binding.playerView.getAdViewGroup().removeAllViews()
releasePlayer()
} }
private lateinit var player: ExoPlayer private var player: ExoPlayer? = null
// private var videoUrl = "http://172.24.124.88/yizhuang/2d83a14117e54d3b981f7d50bdc42c47.live.flv"
var videoUrl =
"https://itg-yz.cu-sc.com:13443/video/yizhuang/0b130981fd754f7e817797235f399264.live.flv"
//用于测试,实际可以传参进来 //用于测试,实际可以传参进来
var videoUri = "https://faw.cuscavp.cn:8443/hdl/live/3.flv" private var videoUri = "https://faw.cuscavp.cn:8443/hdl/live/3.flv"
override fun initView() { override fun initView() {
// DisplayUtil.forceMeasure(binding.playerView)
// 重要:必须使用 texture_view 才能显示圆角
binding.playerView.apply {
// setShutterBackgroundColor(Color.TRANSPARENT)
// clipToOutline = true
// clipChildren=true
// outlineProvider = object : ViewOutlineProvider() {
// override fun getOutline(view: View, outline: Outline) {
// outline.setRoundRect(10, 200,400, 800, 40f)
// }
// }
// setBackgroundResource(R.drawable.rect_no_col_10)
}
initializePlayer() initializePlayer()
} }
fun initializePlayer() { fun initializePlayer() {
if (player == null) {
val playerBuilder = val playerBuilder =
ExoPlayer.Builder(requireContext()) ExoPlayer.Builder(requireContext())
.setMediaSourceFactory(createMediaSourceFactory()) .setMediaSourceFactory(createMediaSourceFactory())
player = playerBuilder.build() player = playerBuilder.build()
player.addListener(playerEventListener) player!!.addListener(playerEventListener)
player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true); player?.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
player.setPlayWhenReady(true) player?.setPlayWhenReady(true)
binding.playerView.setPlayer(player) binding.playerView.setPlayer(player)
// Build the media item. // Build the media item.
val mediaItem = MediaItem.Builder() val mediaItem = MediaItem.Builder()
.setUri(videoUri) .setUri(videoUrl)
.setLiveConfiguration( .setLiveConfiguration(
MediaItem.LiveConfiguration.Builder() MediaItem.LiveConfiguration.Builder()
.setMaxPlaybackSpeed(1.02f) .setMaxPlaybackSpeed(1.02f)
...@@ -106,22 +119,50 @@ class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>() ...@@ -106,22 +119,50 @@ class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>()
) )
.build() .build()
player.setMediaItem(mediaItem) player?.setMediaItem(mediaItem)
player.prepare() player?.prepare()
}
// Start the playback. // Start the playback.
// player.play() // player.play()
} }
fun releasePlayer() { fun releasePlayer() {
player.release() binding.playerView.setPlayer(/* player= */ null)
binding.playerView.setPlayer(/* player= */ null); player?.release()
player = null
} }
private var playerEventListener=object : Player.Listener{ private var playerEventListener = object : Player.Listener {
override fun onPlayerError(error: PlaybackException) { override fun onPlayerError(error: PlaybackException) {
super.onPlayerError(error) super.onPlayerError(error)
println("------ExoPlayFragment.onPlayerError = ${error.message}")
}
override fun onPlaybackStateChanged(playbackState: Int) {
super.onPlaybackStateChanged(playbackState)
when (playbackState) {
Player.STATE_READY -> {
// 播放器准备好时隐藏占位图
// placeholderImage.visibility = View.GONE
}
Player.STATE_BUFFERING, Player.STATE_IDLE -> {
// 缓冲或空闲时显示占位图
// placeholderImage.visibility = View.VISIBLE
}
}
}
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
super.onPlayWhenReadyChanged(playWhenReady, reason)
println("------ExoPlayFragment playWhenReady = ${playWhenReady}")
}
override fun onRenderedFirstFrame() {
super.onRenderedFirstFrame()
println("------ExoPlayFragment.onRenderedFirstFrame")
} }
} }
...@@ -129,14 +170,12 @@ class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>() ...@@ -129,14 +170,12 @@ class ExoPlayFragment : BaseFragment<FragmentExoPlayBinding, MyBaseViewModel>()
companion object { companion object {
@JvmStatic @JvmStatic
fun newInstance() = ExoPlayFragment() fun newInstance() = ExoPlayFragment()
/* // @JvmStatic
@JvmStatic // fun newInstance(videoUrl: String) =
fun newInstance(video: String) = // ExoPlayFragment().apply {
ExoPlayFragment().apply { // arguments = Bundle().apply {
arguments = Bundle().apply { // putString(VIDEO_URL, videoUrl)
putString(VIDEO_PARAM1, video) // }
} // }
}
*/
} }
} }
\ No newline at end of file
...@@ -83,6 +83,7 @@ class WarnFragment : BaseFragment<FragmentWarnBinding, MyBaseViewModel>() { ...@@ -83,6 +83,7 @@ class WarnFragment : BaseFragment<FragmentWarnBinding, MyBaseViewModel>() {
} }
} }
//显示预警气泡
private fun showEarlyDetail(v2xStartBean: V2xStartBean) { private fun showEarlyDetail(v2xStartBean: V2xStartBean) {
var warningBean = WarningBean.instance var warningBean = WarningBean.instance
warningBean.img = R.drawable.chao_su warningBean.img = R.drawable.chao_su
......
package com.sd.cavphmi.ui.view
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import android.view.ViewOutlineProvider
import androidx.media3.ui.PlayerView
class RoundedPlayerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : PlayerView(context, attrs, defStyleAttr) {
private val path = Path()
private val rect = RectF()
private val radius = 16f.dpToPx(context) // 圆角半径(转换为像素)
init {
// 对于 ExoPlayer 3,需要关闭硬件加速或使用其他方式
// setLayerType(LAYER_TYPE_SOFTWARE, null)
// updateOutline()
}
// override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec)
// // 可以在这里根据圆角调整测量逻辑
// val width = MeasureSpec.getSize(MeasureSpec.AT_MOST)
// val height = MeasureSpec.getSize(MeasureSpec.AT_MOST)
//
// setMeasuredDimension(width, height)
//
// updateOutline()
// }
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
// updateOutline()
}
private fun updateOutline() {
// 启用轮廓裁剪
clipToOutline = true
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(0, 0, view.width, view.height, radius)
}
}
}
// dp 转 px 工具方法
private fun Float.dpToPx(context: Context): Float {
return this * context.resources.displayMetrics.density
}
}
...@@ -78,7 +78,7 @@ object FileIoUtils { ...@@ -78,7 +78,7 @@ object FileIoUtils {
/** /**
* 读取asset 文件 * 读取asset 文件
*/ */
suspend fun getAsset(context: Context, fileName: String): String { fun getAsset(context: Context, fileName: String): String {
val assetManager = context.assets val assetManager = context.assets
var inputStream: InputStream? = null var inputStream: InputStream? = null
var str = "" var str = ""
......
...@@ -8,11 +8,9 @@ object MyContants { ...@@ -8,11 +8,9 @@ object MyContants {
//测试环境 //测试环境
// var HOST = "https://itg-dev.cu-sc.com:19443/" // var HOST = "https://itg-dev.cu-sc.com:19443/"
//开发环境切勿动 //HTTP地址
var HOST = "https://itg-yz.cu-sc.com:13443" var HOST = "https://172.24.124.130:19443"
//智网生产环境地址用于拼接3dtile.json
var HOST_HTTP_3 = "https://itg-yz.cu-sc.com:13443"
// /***测试环境socket token***/ // /***测试环境socket token***/
// private val WSTOKEN = // private val WSTOKEN =
// "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiI0MTc0NDY3NGNlOGM0MDZmOTVkZTVkYWYyMWVlOWQ0ZiIsImNyZWF0ZVRpbWUiOjE3NTUwNzYxMTgxMjQsInVzZXJUeXBlIjoxLCJzb3VyY2UiOjAsInB3ZEV4cGlyZWQiOmZhbHNlLCJ1c2VybmFtZSI6ImNoZW5ieTUxIn0.aPYHCxXgQHj4eYGGZnce5MPJCtmMoRcIIHcNXzMMOHE" // "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiI0MTc0NDY3NGNlOGM0MDZmOTVkZTVkYWYyMWVlOWQ0ZiIsImNyZWF0ZVRpbWUiOjE3NTUwNzYxMTgxMjQsInVzZXJUeXBlIjoxLCJzb3VyY2UiOjAsInB3ZEV4cGlyZWQiOmZhbHNlLCJ1c2VybmFtZSI6ImNoZW5ieTUxIn0.aPYHCxXgQHj4eYGGZnce5MPJCtmMoRcIIHcNXzMMOHE"
...@@ -26,26 +24,27 @@ object MyContants { ...@@ -26,26 +24,27 @@ object MyContants {
//跟踪车辆的ID 15(模拟) skywell.1ggvlp16.car10 skywell.1ggvlp16.car8 //跟踪车辆的ID 15(模拟) skywell.1ggvlp16.car10 skywell.1ggvlp16.car8
//用来拼接websocket //用来拼接websocket
var BASE_HOST = var BASE_HOST = "172.24.124.130:19443"
if (IS_DEBUG) "172.24.124.130:19443" else "itg-yz.cu-sc.com:19443" // if (IS_DEBUG) "itg-dev.cu-sc.com:19443" else "itg-yz.cu-sc.com:19443"
// if (IS_DEBUG) "172.24.124.130:19443" else "itg-yz.cu-sc.com:19443"
// if (IS_DEBUG) "itg-yz.cu-sc.com:13443" else "itg-yz.cu-sc.com:19443"
//websocket地址 //websocket地址
private var WSHOST = private var WSHOST = "wss://${BASE_HOST}/wsplus/socket?token=121&reType=freedo&"
if (IS_DEBUG) "wss://${BASE_HOST}/wsplus/socket?token=121&reType=freedo&" else "wss://${BASE_HOST}/wsplus/socket?token=121&reType=freedo&" // if (IS_DEBUG) "wss://${BASE_HOST}/wsplus/socket?token=121&reType=freedo&" else "wss://${BASE_HOST}/wsplus/socket?token=121&reType=freedo&"
//车辆编号 //车辆编号 YZMN003
var VEHICLEID = "YZMN003" var VEHICLEID = "15"
/**网联车辆位姿 用于实车测试喽数据***/ /**网联车辆位姿 用于实车测试喽数据 &vehicleId=${VEHICLEID}***/
var WS_VEH_LOC = "${WSHOST}msgType=2&vehicleId=${VEHICLEID}" var WS_VEH_LOC = "${WSHOST}msgType=2&vehicleId=${VEHICLEID}"
/***感知目标物 &intersectionCode=17 停车场 不传就是整个园区***/ /***感知目标物 &intersectionCode=17 停车场 不传就是整个园区***/
// var WS_FEEL_TARGET = "${WSHOST}msgType=1&intersectionCode=17" // var WS_FEEL_TARGET = "${WSHOST}msgType=1&intersectionCode=17"
var WS_FEEL_TARGET = "${WSHOST}&msgType=1" var WS_FEEL_TARGET = "${WSHOST}&msgType=1"
/***V2X预警 VEHICLEID 传了就是获取某一辆车的预警 &VEHICLEID=***/ /***V2X预警 VEHICLEID 传了就是获取某一辆车的预警 &vehicleId=${VEHICLEID}"=***/
var WS_V2X = "${WSHOST}msgType=4" var WS_V2X = "${WSHOST}msgType=4&vehicleId=${VEHICLEID}"
/***网联车辆状态 &VEHICLEID=''***/ /***网联车辆状态 &VEHICLEID=''***/
var WS_VEH_STATU = "${WSHOST}msgType=6" var WS_VEH_STATU = "${WSHOST}msgType=6"
...@@ -59,7 +58,6 @@ object MyContants { ...@@ -59,7 +58,6 @@ object MyContants {
/***交通信号灯 &intersectionCode=''***/ /***交通信号灯 &intersectionCode=''***/
var WS_TRAFFIC_LIGHT = "${WSHOST}msgType=3&" var WS_TRAFFIC_LIGHT = "${WSHOST}msgType=3&"
/***已经**/ /***已经**/
const val ALREADT_ONCE = -1 const val ALREADT_ONCE = -1
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment