Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
p x
C-AVP2.0
Commits
c0af16dd
Commit
c0af16dd
authored
Dec 23, 2025
by
p x
Browse files
first
parent
0b4d4d4e
Pipeline
#3217
failed with stages
in 0 seconds
Changes
232
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
app/src/main/java/com/sd/cavphmi/highmap/TileJsonBean.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.highmap
/**
* 给unity 初始化json
*
* @property host
* @property tiles3d
* @constructor Create empty Tile json bean
*/
class
TileJsonBean
{
/* var host: String = MyContants.HOST_MAP
var tiles3d = listOf(
// "/gis_data/3dtiles/road/CurbStrip/tileset.json",
"/gis_data/3dtiles/road/LanePolygon/tileset.json",
"/gis_data/3dtiles/road/RoadSection/tileset.json",
"/gis_data/3dtiles/road/SafetyIsland/tileset.json",
"/gis_data/3dtiles/road/SepStrip/tileset.json",
"/gis_data/3dtiles/road/SideWalk/tileset.json",
"/gis_data/3dtiles/road/TraMarkA/tileset.json",
"/gis_data/3dtiles/road/TraMarkL/tileset.json",
"/gis_data/3dtiles/road/TraMarkP/tileset.json",
// "/gis_data/3dtiles/roadequip/FieldFacility/tileset.json",
// "/gis_data/3dtiles/roadequip/PlatForm/tileset.json",
// "/gis_data/3dtiles/roadequip/SafetyRail/tileset.json",
// "/gis_data/3dtiles/roadequip/SignStrct/tileset.json",//监控杆子和路标杆子
// "/gis_data/3dtiles/roadequip/StreetLight/tileset.json",//路灯
// "/gis_data/3dtiles/roadequip/TrafficLight/tileset.json",
// "/gis_data/3dtiles/roadequip/TrafficSign/tileset.json",//监控探头和路标牌子
// "/gis_data/3dtiles/roadequip/VideoCamera/tileset.json",
// "/gis_data/3dtiles/roadequip/xinhaodeng/tileset.json",
// "/gis_data/3dtiles/roadequip/baoganji/tileset.json",
// "/gis_data/3dtiles/roadequip/buguangdeng/tileset.json",
"/gis_data/3dtiles/roadequip/chongdianzhuang/tileset.json",
// "/gis_data/3dtiles/roadequip/jiaohuanji/tileset.json",
// "/gis_data/3dtiles/roadequip/xinhaoji/tileset.json",
"/gis_data/3dtiles/roadequip/yidongronghe/tileset.json",
"/gis_data/3dtiles/buildings/tileset.json",
"/gis_data/3dtiles/ground/tileset.json",
// "/gis_data/3dtiles/vegetation/Tree/tileset.json"//树
)*/
//我本地的
var
host
:
String
=
"http://192.168.60.218"
var
tiles3d
=
listOf
(
"/data/avp/01road/tileset.json"
,
"/data/avp/02shebei/tileset.json"
,
"/data/avp/04jianzhu/tileset.json"
)
// var tiles3d = listOf(
// "/data/adas/LanePolygon/tileset.json",
// "/data/adas/RoadSection/tileset.json",
// "/data/adas/Yizhuang_Unicom_ground1018/tileset.json"
// )
//方本地的
/* var host = "http://192.168.60.164:5003"
var host = "http://192.168.60.73:5003"
var tiles3d = listOf("/data/3dtiles/LanePolygon-o/tileset.json",
// "/data/3dtiles/RoadSection/tileset.json",
// "/data/3dtiles/SafetyIsland/tileset.json",
// "/data/3dtiles/SepStrip/tileset.json",
// "/data/3dtiles/SideWalk/tileset.json",
// "/data/3dtiles/TraMarkA/tileset.json",
"/data/3dtiles/TraMarkL-o/tileset.json",
// "/data/3dtiles/TraMarkP/tileset.json",
// "/data/3dtiles/SignStrct/tileset.json",
// "/data/3dtiles/TrafficLight/tileset.json",
// "/data/3dtiles/TrafficSign/tileset.json",
//
// "/data/3dtiles/Yizhuang_Unicom_building/tileset.json",
// "/data/3dtiles/Yizhuang_Unicom_Ground/tileset.json"
)*/
//四维的
/* var host = "http://gz.tasks.city/3dtiles"
var tiles3d = listOf(
// "/1/CurbStrip/tileset.json",
"/1/LanePolygon/tileset.json",
"/1/RoadSection/tileset.json",
"/1/SafetyIsland/tileset.json",
// "/1/SepStrip/tileset.json",
// "/1/SideWalk/tileset.json",
"/1/TraMarkA/tileset.json",
"/1/TraMarkL/tileset.json",
"/1/TraMarkP/tileset.json",
"/2/FieldFacility/tileset.json",
"/2/PlatForm/tileset.json",
// "/2/SafetyRail/tileset.json",
// "/2/SignStrct/tileset.json",
// "/2/StreetLight/tileset.json",
// "/2/TrafficLight/tileset.json",
// "/2/TrafficSign/tileset.json",
// "/2/VideoCamera/tileset.json",
// "/2/xinhaodeng/tileset.json",
// "/3/baoganji/tileset.json",
// "/3/buguangdeng/tileset.json",
// "/3/chongdianzhuang/tileset.json",
// "/3/jiaohuanji/tileset.json",
// "/3/jiaohuanji/tileset.json",
// "/3/yidongronghe.clt/tileset.json",
// "/4/Yizhuang_Unicom_building/tileset.json",
// "/4/Yizhuang_Unicom_Ground/tileset.json",
// "/4/Yizhuang_Unicom_Tree/tileset.json"
)*/
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/intfaces/OnConCan.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.intfaces
interface
OnConCan
{
fun
onCon
()
fun
onCan
()
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/intfaces/OnWebSocketCb.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.intfaces
interface
OnWebSocketCb
{
// fun onError(ex: Exception?
fun
onClose
(
code
:
Int
,
reason
:
String
?,
remote
:
Boolean
)
fun
onMsg
(
str
:
String
)
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/moudule/NetworkModule.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.moudule
import
com.sd.cavphmi.net.RetrofitApi.retrofitBuild
import
com.sd.cavphmi.net.httpmothod.ClientRetrofitMethod
import
dagger.Module
import
dagger.Provides
import
dagger.hilt.InstallIn
import
dagger.hilt.components.SingletonComponent
import
okhttp3.OkHttpClient
import
okhttp3.logging.HttpLoggingInterceptor
import
java.security.SecureRandom
import
java.security.cert.X509Certificate
import
javax.inject.Qualifier
import
javax.inject.Singleton
import
javax.net.ssl.SSLContext
import
javax.net.ssl.SSLSocketFactory
import
javax.net.ssl.TrustManager
import
javax.net.ssl.X509TrustManager
@Qualifier
@Retention
(
AnnotationRetention
.
BINARY
)
annotation
class
OriginOkHttpClient
//@Qualifier
//@Retention(AnnotationRetention.BINARY)
//annotation class AuthInterceptorOkHttpClient
@Qualifier
@Retention
(
AnnotationRetention
.
BINARY
)
annotation
class
NormalInterceptorOkHttpClient
@Module
@InstallIn
(
SingletonComponent
::
class
)
object
NetworkModule
{
private
var
logging
=
HttpLoggingInterceptor
()
init
{
logging
.
level
=
HttpLoggingInterceptor
.
Level
.
BODY
}
@OriginOkHttpClient
@Provides
fun
provideOriginOkHttpClient
():
OkHttpClient
{
var
sslData
=
getSSlSocketFactory
()
return
OkHttpClient
.
Builder
()
.
addInterceptor
(
logging
)
.
sslSocketFactory
(
sslData
.
socketFactory
,
sslData
.
trustAllCert
)
.
hostnameVerifier
{
hostname
,
session
->
true
}
.
build
()
}
@NormalInterceptorOkHttpClient
@Provides
fun
provideSeeInterceptorOkHttpClient
(
// headParamsInterceptor: HeadParamsInterceptor
// baseUrlInterceptor: BaseUrlInterceptor,
):
OkHttpClient
{
// 创建信任所有证书的 TrustManager
// val trustAllCerts = arrayOf<TrustManager>(
// object : X509TrustManager {
// override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
// override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
// override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
// }
// )
// // 初始化 SSLContext
// val sslContext = SSLContext.getInstance("TLS")
// sslContext.init(null, trustAllCerts, SecureRandom())
var
sslData
=
getSSlSocketFactory
()
return
OkHttpClient
.
Builder
()
// .addInterceptor(baseUrlInterceptor)
// .addInterceptor(headParamsInterceptor)
.
addInterceptor
(
logging
)
.
hostnameVerifier
{
hostname
,
session
->
true
}
.
sslSocketFactory
(
sslData
.
socketFactory
,
sslData
.
trustAllCert
)
.
build
()
}
//------------------API 方法---------------
@Singleton
@Provides
fun
provideClientRetrofitService
(
@OriginOkHttpClient
okHttpClient
:
OkHttpClient
):
ClientRetrofitMethod
{
return
retrofitBuild
.
client
(
okHttpClient
).
build
().
create
(
ClientRetrofitMethod
::
class
.
java
)
}
// @Singleton
// @Provides
// fun provideClientRetrofitSeeService(@NormalInterceptorOkHttpClient okHttpClient: OkHttpClient): ClientRetrofitMethodSee {
// return retrofitBuild.client(okHttpClient).build()
// .create(ClientRetrofitMethodSee::class.java)
// }
fun
getSSlSocketFactory
():
SslData
{
// 创建信任所有证书的 TrustManager
val
trustAllCerts
=
arrayOf
<
TrustManager
>(
object
:
X509TrustManager
{
override
fun
checkClientTrusted
(
chain
:
Array
<
X509Certificate
>,
authType
:
String
)
{}
override
fun
checkServerTrusted
(
chain
:
Array
<
X509Certificate
>,
authType
:
String
)
{}
override
fun
getAcceptedIssuers
():
Array
<
X509Certificate
>
=
arrayOf
()
}
)
// 初始化 SSLContext
val
sslContext
=
SSLContext
.
getInstance
(
"TLS"
)
sslContext
.
init
(
null
,
trustAllCerts
,
SecureRandom
())
return
SslData
(
sslContext
.
socketFactory
,
trustAllCerts
[
0
]
as
X509TrustManager
)
}
data class
SslData
(
val
socketFactory
:
SSLSocketFactory
,
var
trustAllCert
:
X509TrustManager
)
// 创建信任所有证书的 SSLSocketFactory
private
fun
createSSLSocketFactory
():
SSLSocketFactory
{
try
{
val
sslContext
=
SSLContext
.
getInstance
(
"TLS"
)
sslContext
.
init
(
null
,
arrayOf
<
TrustManager
>(
object
:
X509TrustManager
{
override
fun
checkClientTrusted
(
chain
:
Array
<
out
X509Certificate
?
>?,
authType
:
String
?
)
{
}
override
fun
checkServerTrusted
(
chain
:
Array
<
out
X509Certificate
?
>?,
authType
:
String
?
)
{
}
override
fun
getAcceptedIssuers
():
Array
<
out
X509Certificate
?
>?
{
return
arrayOfNulls
(
0
)
}
}),
SecureRandom
())
return
sslContext
.
getSocketFactory
()
}
catch
(
e
:
Exception
)
{
throw
RuntimeException
(
e
)
}
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/net/BaseUrlInterceptor.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
import
okhttp3.HttpUrl
import
okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import
okhttp3.Interceptor
import
okhttp3.Response
import
javax.inject.Inject
class
BaseUrlInterceptor
@Inject
constructor
()
:
Interceptor
{
override
fun
intercept
(
chain
:
Interceptor
.
Chain
):
Response
{
//获取原始request
var
original
=
chain
.
request
()
//从request中获取原有的HttpUrl实例oldHttpUrl
val
originalHttpUrl
=
original
.
url
// 获取request的创建者builder
var
builder
=
original
.
newBuilder
()
//从request中获取headers,通过给定的键url_name
val
headerValue
=
original
.
header
(
"urlname"
)
if
(!
headerValue
.
isNullOrEmpty
()
&&
headerValue
.
count
()>
0
){
val
newHttpUrl
=
headerValue
.
toHttpUrlOrNull
()
val
url
:
HttpUrl
=
originalHttpUrl
.
newBuilder
()
.
host
(
newHttpUrl
!!
.
host
)
// 修改Host部分
.
scheme
(
newHttpUrl
.
scheme
)
//
.
port
(
newHttpUrl
.
port
)
//
.
build
()
//如果有这个header,先将配置的header删除,因此header仅用作app和okhttp之间使用
builder
.
removeHeader
(
"urlname"
)
val
newRequest
=
builder
.
url
(
url
)
.
build
()
return
chain
.
proceed
(
newRequest
);
}
return
chain
.
proceed
(
builder
.
build
())
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/net/HeadParamsInterceptor.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
import
com.sd.cavphmi.utils.MyContants
import
okhttp3.Interceptor
import
okhttp3.Response
import
javax.inject.Inject
/**
* 公共参数拦截处理器 http://blog.csdn.net/spinchao/article/details/52932145
*/
class
HeadParamsInterceptor
@Inject
constructor
()
:
Interceptor
{
override
fun
intercept
(
chain
:
Interceptor
.
Chain
):
Response
{
// LogUtil.d("----------token=" + MyPres.token)
var
original
=
chain
.
request
()
// var path = original.url.encodedPath.substringAfterLast("/")
var
request
=
original
.
newBuilder
()
if
(
MyContants
.
HTTP_TOKEN
.
isNotEmpty
())
{
// request.header("token", MyContants.HTTP_TOKEN)
// request.header("Authorization", MyContants.HTTP_TOKEN)
}
// request.header("Referer", "${MyContants.HOST}/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
())
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/net/MyBaseResource.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
/**
* A generic class that holds a value with its loading status.
* @param <T>
</T> */
data class
MyBaseResource
<
out
T
>(
val
data
:
T
,
var
code
:
Int
,
var
msg
:
String
)
sealed
class
MyResult
<
out
T
>
{
data class
Success
<
out
T
>(
val
data
:
T
)
:
MyResult
<
T
>()
data class
Error
(
var
eCode
:
Int
,
var
msg
:
String
)
:
MyResult
<
Nothing
>()
}
app/src/main/java/com/sd/cavphmi/net/NetLoadStatus.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
/**
* Status of a resource that is provided to the UI.
*
*
* These are usually created by the Repository classes where they return
* `LiveData<Resource<T>>` to pass back the latest data to the UI with its fetch status.
*/
enum
class
NetLoadStatus
{
SUCCESS
,
ERROR
,
TOAST
,
LOADING
,
COMPLETE
,
EMPTY
,
NOMOREDATA
,
LOGINTIMEOUT
;
//登录超时
private
var
errorMsg
=
""
private
var
toastMsg
=
""
fun
setErrorMsg
(
error
:
String
)
{
errorMsg
=
error
}
fun
getErrorMsg
():
String
{
return
errorMsg
}
fun
getToastMsg
():
String
{
return
toastMsg
}
fun
setToastMsg
(
toastMsg
:
String
)
{
this
.
toastMsg
=
toastMsg
}
}
app/src/main/java/com/sd/cavphmi/net/RequestBodyUtil.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
import
com.google.gson.Gson
import
okhttp3.MediaType.Companion.toMediaTypeOrNull
import
okhttp3.RequestBody
import
okhttp3.RequestBody.Companion.toRequestBody
object
RequestBodyUtil
{
/**
* 将参数封装成requestBody形式上传参数
* @param param 参数
* @return RequestBody
*/
fun
toRequestBody
(
map
:
Map
<
String
,
Any
>):
RequestBody
{
val
gson
=
Gson
()
var
param
=
gson
.
toJson
(
map
)
return
param
.
toRequestBody
(
"application/json;charset=UTF-8"
.
toMediaTypeOrNull
())
}
fun
toRequestBody
(
any
:
Any
):
RequestBody
{
var
gson
=
Gson
()
return
gson
.
toJson
(
any
)
.
toRequestBody
(
"application/json;charset=UTF-8"
.
toMediaTypeOrNull
())
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/net/RetrofitApi.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
import
com.google.gson.GsonBuilder
import
com.sd.cavphmi.MyAppcation
import
com.sd.cavphmi.utils.MyContants
import
okhttp3.Cache
import
retrofit2.Retrofit
import
retrofit2.converter.gson.GsonConverterFactory
import
retrofit2.converter.scalars.ScalarsConverterFactory
import
java.io.File
object
RetrofitApi
{
// val CLIENT_BASIC = Credentials.basic("river-chief-server", "123456")
var
retrofitBuild
:
Retrofit
.
Builder
var
cache
:
Cache
init
{
//设置缓存路径
val
httpCacheDirectory
=
File
(
MyAppcation
.
instance
().
applicationContext
.
externalCacheDir
,
"okhttp"
)
//设置缓存
cache
=
Cache
(
httpCacheDirectory
,
50
*
1024
*
1024
)
val
mGson
=
GsonBuilder
()
// .registerTypeAdapter(HttpErrorBean::class.java, HttpErrorTypeAdapter())
// .setLenient() // 设置GSON的非严格模式setLenient()
.
create
()
retrofitBuild
=
Retrofit
.
Builder
()
.
baseUrl
(
MyContants
.
HOST
)
.
addConverterFactory
(
ScalarsConverterFactory
.
create
())
.
addConverterFactory
(
GsonConverterFactory
.
create
(
mGson
))
// .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
}
// fun getSSlSocketFactory(): SslData {
// val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(
// TrustManagerFactory.getDefaultAlgorithm()
// )
// trustManagerFactory.init(null as KeyStore?)
// val trustManagers: Array<TrustManager> = trustManagerFactory.getTrustManagers()
// check(!(trustManagers.size != 1 || trustManagers[0] !is X509TrustManager)) {
// ("Unexpected default trust managers:"
// + Arrays.toString(trustManagers))
// }
// val trustManager = trustManagers[0] as X509TrustManager
//
//
// val sslContext = SSLContext.getInstance("TLS")
// sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
// val sslSocketFactory = sslContext.socketFactory
//
// return SslData(sslSocketFactory, trustManager)
// }
//
// data class SslData(val sslSocketFactory: SSLSocketFactory, var trustManager: X509TrustManager)
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/net/SseManager.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
import
android.os.Handler
import
android.os.Looper
import
com.sd.cavphmi.moudule.NetworkModule
import
okhttp3.ConnectionPool
import
okhttp3.OkHttpClient
import
okhttp3.Request
import
okhttp3.RequestBody
import
okhttp3.Response
import
okhttp3.sse.EventSource
import
okhttp3.sse.EventSourceListener
import
okhttp3.sse.EventSources
import
java.util.concurrent.TimeUnit
class
SseManager
{
// private var logging = HttpLoggingInterceptor().apply {
// level = HttpLoggingInterceptor.Level.BODY
// }
constructor
()
{
var
sslData
=
NetworkModule
.
getSSlSocketFactory
()
okHttpClient
=
OkHttpClient
.
Builder
()
// .addInterceptor(logging)
.
connectTimeout
(
30
,
TimeUnit
.
SECONDS
)
.
writeTimeout
(
30
,
TimeUnit
.
SECONDS
)
.
readTimeout
(
0
,
TimeUnit
.
SECONDS
)
.
connectionPool
(
ConnectionPool
(
5
,
30
,
TimeUnit
.
SECONDS
))
// 连接池优化(可选)
.
pingInterval
(
20
,
TimeUnit
.
SECONDS
)
// TCP心跳间隔
.
retryOnConnectionFailure
(
true
)
/* .connectionSpecs(
listOf(
ConnectionSpec.CLEARTEXT,
ConnectionSpec.MODERN_TLS
)
) // 支持 HTTP/HTTPS*/
.
sslSocketFactory
(
sslData
.
socketFactory
,
sslData
.
trustAllCert
)
.
hostnameVerifier
{
hostname
,
session
->
true
}
.
build
()
}
private
var
okHttpClient
:
OkHttpClient
// SSE 连接实例( nullable,避免内存泄漏)
private
var
eventSource
:
EventSource
?
=
null
// private var lastEventId: String? = null // 记录最后一个事件 ID
private
val
listeners
=
mutableListOf
<
SseCallback2
?>()
// 客户端数据监听器
// 重连延迟(指数退避:1s → 2s → 4s → ... → 30s 上限)
private
var
retryDelayMillis
=
1000L
private
val
maxRetryDelay
=
30
*
1000L
// 最大重连延迟
// 连接状态回调(给外部使用)
private
var
callback
:
SseCallback2
?
=
null
fun
addListener
(
callback
:
SseCallback2
)
{
listeners
.
add
(
callback
)
}
// 初始化 SSE 请求
fun
connect
(
sseUrl
:
String
,
body
:
RequestBody
?,
headers
:
Map
<
String
,
String
>
=
emptyMap
())
{
// 1. 构建 SSE 请求(必须是 GET 方法,且支持 SSE 协议)
val
requestBuilder
=
Request
.
Builder
()
.
url
(
sseUrl
)
.
header
(
"Accept"
,
"text/event-stream"
)
// 关键:告知服务器接收 SSE 格式
.
header
(
"Cache-Control"
,
"no-cache"
)
// 禁用缓存,避免重复数据
.
header
(
"Connection"
,
"keep-alive"
)
// 保持长连接
if
(
body
!=
null
)
{
requestBuilder
.
post
(
body
)
}
// 添加自定义请求头(如 Token、User-Agent 等)
headers
.
forEach
{
(
key
,
value
)
->
requestBuilder
.
header
(
key
,
value
)
}
// 断线重连时携带上次最后一个事件 ID(避免漏数据)
// lastEventId?.let {
// requestBuilder.header("Last-Event-ID", it)
// }
val
request
=
requestBuilder
.
build
()
// 2. 构建 EventSource(OkHttp SSE 核心)
val
eventSourceListener
=
object
:
EventSourceListener
()
{
// 连接成功回调
override
fun
onOpen
(
eventSource
:
EventSource
,
response
:
Response
)
{
super
.
onOpen
(
eventSource
,
response
)
listeners
.
forEach
{
it
?.
onConnected
()
}
retryDelayMillis
=
1000L
// 重置重连延迟(连接成功后恢复初始值)
}
// 接收服务器消息(核心回调)
override
fun
onEvent
(
eventSource
:
EventSource
,
id
:
String
?,
type
:
String
?,
data
:
String
)
{
super
.
onEvent
(
eventSource
,
id
,
type
,
data
)
listeners
.
forEach
{
it
?.
onMessageReceived
(
data
,
type
?:
"message"
)
// type 是服务器定义的事件类型
}
}
// 连接断开回调(主动/被动断开都会触发)
override
fun
onClosed
(
eventSource
:
EventSource
)
{
super
.
onClosed
(
eventSource
)
listeners
.
forEach
{
it
?.
onDisconnected
()
}
// 主动断开时不自动重连(通过 flag 控制)
if
(!
isManualDisconnect
)
{
scheduleReconnect
(
sseUrl
,
body
,
headers
)
// 被动断开则重连
}
}
// 连接失败回调(网络异常、服务器错误等)
override
fun
onFailure
(
eventSource
:
EventSource
,
t
:
Throwable
?,
response
:
Response
?
)
{
super
.
onFailure
(
eventSource
,
t
,
response
)
val
errorMsg
=
t
?.
message
?:
"未知错误"
listeners
.
forEach
{
it
?.
onError
(
errorMsg
,
t
)
}
scheduleReconnect
(
sseUrl
,
body
,
headers
)
// 失败后自动重连
}
}
// 创建并启动 SSE 连接
eventSource
=
EventSources
.
createFactory
(
okHttpClient
).
newEventSource
(
request
,
eventSourceListener
)
}
// 主动断开连接
fun
disconnect
()
{
isManualDisconnect
=
true
eventSource
?.
cancel
()
// 关闭连接
eventSource
=
null
callback
?.
onDisconnected
()
}
// 调度重连(指数退避策略)
private
fun
scheduleReconnect
(
sseUrl
:
String
,
body
:
RequestBody
?,
headers
:
Map
<
String
,
String
>
)
{
callback
?.
onReconnecting
(
retryDelayMillis
)
// 使用 Handler 延迟重连(避免主线程阻塞)
Handler
(
Looper
.
getMainLooper
()).
postDelayed
({
if
(!
isManualDisconnect
)
{
connect
(
sseUrl
,
body
,
headers
)
// 重连
// 指数退避:延迟翻倍,不超过最大值
retryDelayMillis
=
minOf
(
retryDelayMillis
*
2
,
maxRetryDelay
)
}
},
retryDelayMillis
)
}
// 防止内存泄漏:释放资源
fun
release
()
{
disconnect
()
callback
=
null
}
companion
object
{
// // 单例实例
//// @Volatile
// private var instance: SseManager? = null
// 是否主动断开(控制重连逻辑)
private
var
isManualDisconnect
=
false
val
instance
:
SseManager
by
lazy
{
SseManager
()
}
// fun getInstance(context: Context, okHttpClient: OkHttpClient): SseManager {
// return instance ?: synchronized(this) {
// instance ?: SseManager(context.applicationContext, okHttpClient).also {
// instance = it
// }
// }
// }
}
// SSE 状态回调接口(外部实现)
interface
SseCallback2
{
fun
onConnected
()
// 连接成功
fun
onDisconnected
()
// 连接断开
fun
onMessageReceived
(
data
:
String
,
eventType
:
String
)
// 接收消息
fun
onError
(
errorMsg
:
String
,
throwable
:
Throwable
?)
// 错误回调
fun
onReconnecting
(
delayMillis
:
Long
)
// 重连中(可选)
}
}
app/src/main/java/com/sd/cavphmi/net/SseMultiConnectionManager.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net
import
android.os.Handler
import
android.os.Looper
import
com.sd.cavphmi.moudule.NetworkModule
import
okhttp3.ConnectionSpec
import
okhttp3.OkHttpClient
import
okhttp3.Request
import
okhttp3.RequestBody
import
okhttp3.sse.EventSource
import
okhttp3.sse.EventSourceListener
import
okhttp3.sse.EventSources
import
java.util.concurrent.ConcurrentHashMap
import
java.util.concurrent.TimeUnit
import
java.util.concurrent.locks.ReentrantLock
import
kotlin.concurrent.withLock
/**
* SSE 连接实体类:封装单个连接的核心信息
* @param connId 连接唯一标识(如 "chat", "notice", "status")
* @param sseUrl 连接的服务器地址
* @param eventSource SSE 连接实例(OkHttp 提供)
* @param callback 连接的回调接口(接收消息、状态)
*/
data class
SseConnection
(
val
connId
:
String
,
val
sseUrl
:
String
,
val
eventSource
:
EventSource
,
val
callback
:
SseCallback
)
/**
* SSE 回调接口:每个连接的独立回调
*/
interface
SseCallback
{
// 连接成功
fun
onConnected
(
connId
:
String
)
// 接收自定义事件(服务器指定 event 字段)
fun
onEventReceived
(
connId
:
String
,
eventType
:
String
?,
data
:
String
)
// 连接失败
fun
onFailed
(
connId
:
String
,
errorMsg
:
String
)
// 连接关闭
fun
onClosed
(
connId
:
String
)
fun
onReconnecting
(
delayMillis
:
Long
)
// 重连中(可选)
}
class
SseMultiConnectionManager
{
companion
object
{
// 是否主动断开(控制重连逻辑)
private
var
isManualDisconnect
=
false
val
instance
:
SseMultiConnectionManager
by
lazy
{
SseMultiConnectionManager
()
}
}
var
sslData
=
NetworkModule
.
getSSlSocketFactory
()
// OkHttp 客户端(全局复用,避免重复创建;配置长连接适配 SSE)
private
val
okHttpClient
=
OkHttpClient
.
Builder
()
.
connectTimeout
(
30
,
TimeUnit
.
SECONDS
)
.
readTimeout
(
0
,
TimeUnit
.
SECONDS
)
// 长连接延长读取超时
.
writeTimeout
(
30
,
TimeUnit
.
SECONDS
)
// .connectionPool(ConnectionPool(5, 30, TimeUnit.SECONDS)) // 连接池优化(可选)
// .pingInterval(20, TimeUnit.SECONDS) // TCP心跳间隔
.
retryOnConnectionFailure
(
false
)
// 多连接场景下禁用自动重试(避免冲突)
.
connectionSpecs
(
listOf
(
ConnectionSpec
.
CLEARTEXT
,
ConnectionSpec
.
MODERN_TLS
)
)
// 支持 HTTP/HTTPS
.
sslSocketFactory
(
sslData
.
socketFactory
,
sslData
.
trustAllCert
)
.
hostnameVerifier
{
hostname
,
session
->
true
}
.
build
()
// 存储所有活跃连接:key = connId(唯一标识),value = SseConnection
// 使用 ConcurrentHashMap 保证线程安全(支持并发读写)
private
val
activeConnections
=
ConcurrentHashMap
<
String
,
SseConnection
>()
// 重入锁:确保启动/关闭连接时的原子操作(避免并发问题)
private
val
connectionLock
=
ReentrantLock
()
// 重连延迟(指数退避:1s → 2s → 4s → ... → 30s 上限)
private
var
retryDelayMillis
=
1000L
private
val
maxRetryDelay
=
30
*
1000L
// 最大重连延迟
/**
* 启动一个新的 SSE 连接
* @param connId 连接唯一标识(如 "chat_123", "system_notice")
* @param sseUrl 连接的服务器地址
* @param callback 该连接的独立回调(处理消息和状态)
*/
fun
startConnection
(
connId
:
String
,
sseUrl
:
String
,
body
:
RequestBody
,
callback
:
SseCallback
)
{
connectionLock
.
withLock
{
// 加锁确保原子操作
// 1. 先关闭同名连接(避免重复创建)
if
(
activeConnections
.
containsKey
(
connId
))
{
stopConnection
(
connId
)
callback
.
onClosed
(
connId
)
}
// 2. 构建当前连接的 SSE 请求(必须是 GET + text/event-stream 头)
val
request
=
Request
.
Builder
()
.
url
(
sseUrl
)
.
post
(
body
)
.
header
(
"Accept"
,
"text/event-stream"
)
// 核心:SSE 格式标识
.
header
(
"Cache-Control"
,
"no-cache"
)
// 禁用缓存
.
header
(
"Connection"
,
"keep-alive"
)
// 保持长连接
// 可选:添加当前连接的独立头(如不同 Token、用户ID)
// .header("Authorization", "Bearer ${getTokenForConn(connId)}")
.
build
()
// 3. 创建当前连接的 EventSourceListener(绑定回调)
val
listener
=
object
:
EventSourceListener
()
{
override
fun
onOpen
(
eventSource
:
EventSource
,
response
:
okhttp3
.
Response
)
{
super
.
onOpen
(
eventSource
,
response
)
// println("-------hashCode = ${eventSource.hashCode()} ${eventSource.request().url}")
// 回调到当前连接的 callback(主线程)
callback
.
onConnected
(
connId
)
}
override
fun
onEvent
(
eventSource
:
EventSource
,
id
:
String
?,
type
:
String
?,
data
:
String
)
{
super
.
onEvent
(
eventSource
,
id
,
type
,
data
)
// 自定义事件回调(服务器指定 event 字段)
callback
.
onEventReceived
(
connId
,
type
,
data
)
}
override
fun
onFailure
(
eventSource
:
EventSource
,
t
:
Throwable
?,
response
:
okhttp3
.
Response
?
)
{
super
.
onFailure
(
eventSource
,
t
,
response
)
// 失败后移除连接(避免内存泄漏)
activeConnections
.
remove
(
connId
)
// 失败回调(错误信息拼接)
val
errorMsg
=
t
?.
message
?:
"Unknown error"
callback
.
onFailed
(
connId
,
errorMsg
)
// 主动断开时不自动重连(通过 flag 控制)
if
(!
isManualDisconnect
)
{
scheduleReconnect
(
connId
,
sseUrl
,
body
,
callback
)
// 被动断开则重连
}
}
override
fun
onClosed
(
eventSource
:
EventSource
)
{
super
.
onClosed
(
eventSource
)
callback
.
onClosed
(
connId
)
// 关闭后移除连接
activeConnections
.
remove
(
connId
)
}
}
// 4. 创建 EventSource 实例并存储到集合
val
eventSource
=
EventSources
.
createFactory
(
okHttpClient
)
.
newEventSource
(
request
,
listener
)
// 5. 存储连接信息到 ConcurrentHashMap
activeConnections
[
connId
]
=
SseConnection
(
connId
=
connId
,
sseUrl
=
sseUrl
,
eventSource
=
eventSource
,
callback
=
callback
)
}
}
// 调度重连(指数退避策略)
private
fun
scheduleReconnect
(
connId
:
String
,
sseUrl
:
String
,
body
:
RequestBody
,
sseCallback
:
SseCallback
)
{
sseCallback
.
onReconnecting
(
retryDelayMillis
)
// 使用 Handler 延迟重连(避免主线程阻塞)
Handler
(
Looper
.
getMainLooper
()).
postDelayed
({
if
(!
isManualDisconnect
)
{
startConnection
(
connId
,
sseUrl
,
body
,
sseCallback
)
// 重连
// 指数退避:延迟翻倍,不超过最大值
retryDelayMillis
=
minOf
(
retryDelayMillis
*
2
,
maxRetryDelay
)
}
},
retryDelayMillis
)
}
/**
* 关闭指定 ID 的 SSE 连接
* @param connId 连接唯一标识
*/
fun
stopConnection
(
connId
:
String
)
{
isManualDisconnect
=
true
connectionLock
.
withLock
{
val
connection
=
activeConnections
.
remove
(
connId
)
connection
?.
eventSource
?.
cancel
()
// 关闭连接
}
}
/**
* 关闭所有 SSE 连接(如 App 退出时)
*/
fun
stopAllConnections
()
{
isManualDisconnect
=
true
connectionLock
.
withLock
{
activeConnections
.
values
.
forEach
{
it
.
eventSource
.
cancel
()
}
activeConnections
.
clear
()
}
}
/**
* 检查连接是否活跃
* @param connId 连接唯一标识
* @return true = 活跃,false = 已关闭/未创建
*/
fun
isConnectionActive
(
connId
:
String
):
Boolean
{
return
activeConnections
.
containsKey
(
connId
)
}
/**
* 获取所有活跃连接的 ID
*/
fun
getActiveConnIds
():
List
<
String
>
{
return
activeConnections
.
keys
.
toList
()
}
}
app/src/main/java/com/sd/cavphmi/net/httpmothod/ClientRetrofitMethod.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.net.httpmothod
import
com.sd.cavphmi.bean.AvpStatuBean
import
com.sd.cavphmi.bean.BindCarBean
import
com.sd.cavphmi.bean.LoginSuccBean
import
com.sd.cavphmi.bean.SpaceInfoBean
import
com.sd.cavphmi.bean.VehDetailBean
import
okhttp3.RequestBody
import
retrofit2.http.Body
import
retrofit2.http.GET
import
retrofit2.http.POST
interface
ClientRetrofitMethod
{
// @Headers("Cache-Control:public,max-age=3600")
// @GET("http://59.175.163.12/serv-addr/server.json")
// fun getConfigurations(): Observable<List<ConfigurationBean>>
//
/**登录***/
@POST
(
"api/perm/admin/auth/passLogin"
)
suspend
fun
login
(
@Body
body
:
RequestBody
):
LoginSuccBean
/**车辆详情***/
@POST
(
"api/avpweb/v1/avp/overview/getVehicleInfo"
)
suspend
fun
getVehDetail
(
@Body
body
:
RequestBody
):
VehDetailBean
/**车位占用情况***/
@POST
(
"api/avpweb/v1/avp/overview/listSpaceInfoByCondition"
)
suspend
fun
getSpaceInfo
(
@Body
body
:
RequestBody
):
SpaceInfoBean
/**获取可绑定车辆列表***/
// @Headers("urlname:https://172.24.124.130:14443")
@POST
(
"api/avpweb/hmi/v1/queryVehicleList"
)
suspend
fun
getBindCar
():
BindCarBean
// suspend fun getBindCar(@Body body: RequestBody): List<BindCarItem>
/***http 长连接 sse 协议 入参 {"id":车俩id}***/
// @POST("api/avpweb/app/monitor/v1/monitorDrivenStatus")
// suspend fun getCarPoseSee(@Body body: RequestBody): String
/***获取订单信息**/
// @POST("avp/avpMonitor/getOrderParkingInfoForPlate")
// suspend fun getOrderData(@Body body: RequestBody): OrderBean
//
// /***获取网络质量**/
// @POST("avp/siteLine/getNetworkQuality")
// suspend fun getTimeOut(): Any
//
// /***获取路径规划**/
// @POST("avp/linePlaning/get")
// suspend fun getLinePlaning(@Body body: RequestBody): ParkLinePlan
/**
* 话题根据评论ID查询所有回复
*/
// @GET("cm/topic/reply/v1/getByCommentId")
// fun getTopicByAnswerId(@Query("id") id: String): Observable<BaseResponse<List<UserAnswer>>>
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/repositorys/AvpDataRepo.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.repositorys
import
com.sd.cavphmi.bean.BindResult
import
com.sd.cavphmi.bean.SpaceInfoBean
import
com.sd.cavphmi.bean.VehDetailBean
import
com.sd.cavphmi.bean.req.SpaceInfo
import
com.sd.cavphmi.net.MyResult
import
com.sd.cavphmi.net.RequestBodyUtil
import
com.sd.cavphmi.net.SseCallback
import
com.sd.cavphmi.net.SseManager
import
com.sd.cavphmi.net.SseManager.SseCallback2
import
com.sd.cavphmi.net.SseMultiConnectionManager
import
com.sd.cavphmi.net.httpmothod.ClientRetrofitMethod
import
com.sd.cavphmi.utils.MyContants
import
okhttp3.RequestBody
import
retrofit2.HttpException
import
javax.inject.Inject
/**AVP 接口**/
class
AvpDataRepo
@Inject
constructor
(
private
var
retrofitMethod
:
ClientRetrofitMethod
)
{
// private var simpleSSEClient = SimpleSSEClient.instance
private
var
sseManager2
=
SseManager
.
instance
// 初始化多连接管理器(全局单例更佳,可通过依赖注入)
private
val
sseManager
=
SseMultiConnectionManager
.
instance
// 连接 ID 定义(唯一标识每个连接)
private
val
CONN_ID_CAR
=
"CAR"
// 聊天连接
private
val
CONN_ID_AVPSTATU
=
"AVP_STATU"
// 系统通知连接
/**获取车辆详情
* @param id 正常应该是传场地ID,但是亦庄这个和太和桥车是一样的
*/
suspend
fun
getVehDetail
(
id
:
String
=
""
):
MyResult
<
VehDetailBean
>
{
// var map = mapOf("id" to id)
// var map = mapOf()
var
body
=
RequestBodyUtil
.
toRequestBody
(
mapOf
())
try
{
var
bean
=
retrofitMethod
.
getVehDetail
(
body
)
return
MyResult
.
Success
(
bean
)
}
catch
(
e
:
HttpException
)
{
// println("e.message = ${e.message}")
return
MyResult
.
Error
(
e
.
code
(),
e
.
message
()
?:
"error"
)
}
catch
(
e
:
Exception
)
{
return
MyResult
.
Error
(
MyContants
.
HTTP_ERROR
,
e
.
message
?:
"error"
)
}
}
/**
* 获取车位占用情况
*/
suspend
fun
getSpaceInfo
():
MyResult
<
SpaceInfoBean
>
{
try
{
var
spaceInfo
=
SpaceInfo
().
apply
{
state
=
1
}
var
body
=
RequestBodyUtil
.
toRequestBody
(
spaceInfo
)
var
bean
=
retrofitMethod
.
getSpaceInfo
(
body
)
return
MyResult
.
Success
(
bean
)
}
catch
(
e
:
HttpException
)
{
// println("e.message = ${e.message}")
return
MyResult
.
Error
(
e
.
code
(),
e
.
message
()
?:
"error"
)
}
catch
(
e
:
Exception
)
{
return
MyResult
.
Error
(
MyContants
.
HTTP_ERROR
,
e
.
message
?:
"error"
)
}
}
/**
* 获取可绑车辆
*/
suspend
fun
getBindCar
():
MyResult
<
List
<
BindResult
>>
{
try
{
// var body = RequestBodyUtil.toRequestBody(mapOf())
var
bean
=
retrofitMethod
.
getBindCar
()
return
MyResult
.
Success
(
bean
.
result
)
}
catch
(
e
:
HttpException
)
{
// println("e.message = ${e.message}")
return
MyResult
.
Error
(
e
.
code
(),
e
.
message
()
?:
"error"
)
}
catch
(
e
:
Exception
)
{
return
MyResult
.
Error
(
MyContants
.
HTTP_ERROR
,
e
.
message
?:
"error"
)
}
}
/**登录***/
suspend
fun
login
(
user
:
String
,
pwd
:
String
,
verifyCode
:
Int
):
MyResult
<
String
>
{
// if (id.isNullOrEmpty()) {
// return MyResult.Error(MyContants.HTTP_ERROR, "error")
// }
var
map
=
mapOf
(
"username"
to
user
,
"password"
to
pwd
,
"verifyCode"
to
verifyCode
)
var
body
=
RequestBodyUtil
.
toRequestBody
(
map
)
try
{
var
bean
=
retrofitMethod
.
login
(
body
)
return
MyResult
.
Success
(
bean
.
result
.
token
)
}
catch
(
e
:
HttpException
)
{
// println("e.message = ${e.message}")
return
MyResult
.
Error
(
e
.
code
(),
e
.
message
()
?:
"error"
)
}
catch
(
e
:
Exception
)
{
return
MyResult
.
Error
(
MyContants
.
HTTP_ERROR
,
e
.
message
?:
"error"
)
}
}
/**
* 获取AVP状态信息
* 我们车辆位姿数据用的是 车俩基础信息的id 可绑车辆接口 返回的是 avp车俩id
* 所以这里的id 是绑定车辆列表返回的id
*/
fun
getAvpStatus
(
url
:
String
,
body
:
RequestBody
,
sseCallback
:
SseCallback
)
{
sseManager
.
startConnection
(
CONN_ID_AVPSTATU
,
url
,
body
,
sseCallback
)
/* sseManager2.addListener(object : SseCallback2 {
override fun onConnected() {
println("------------getAvpStatus onConnected")
}
override fun onDisconnected() {
}
override fun onMessageReceived(data: String, eventType: String) {
println("----------getAvpStatus = ${data}")
}
override fun onError(errorMsg: String, throwable: Throwable?) {
println("------------getAvpStatus errorMsg")
}
override fun onReconnecting(delayMillis: Long) {
}
})
sseManager2.connect(url, body)*/
}
/**获取车辆位姿****/
fun
getCarPose
(
url
:
String
,
body
:
RequestBody
,
sseCallback
:
SseCallback
)
{
sseManager
.
startConnection
(
CONN_ID_CAR
,
url
,
body
,
sseCallback
)
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/repositorys/ParseSocketRepo.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.repositorys
import
com.google.gson.Gson
import
com.sd.cavphmi.bean.ParkLinePlan
import
com.sd.cavphmi.bean.SpaceNoBean
import
com.sd.cavphmi.bean.VehDetailBean
import
com.sd.cavphmi.net.MyResult
import
com.sd.cavphmi.net.RequestBodyUtil
import
com.sd.cavphmi.net.httpmothod.ClientRetrofitMethod
import
com.sd.cavphmi.utils.MyContants
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
import
retrofit2.HttpException
import
javax.inject.Inject
class
ParseSocketRepo
@Inject
constructor
(
private
var
clientRetrofitMethod
:
ClientRetrofitMethod
)
{
private
var
gson
=
Gson
()
// private var orderCalled = AtomicBoolean(false)
/**解析网络数据***/
suspend
fun
<
T
>
parseDataBean
(
str
:
String
,
clazz
:
Class
<
T
>):
T
{
return
withContext
(
Dispatchers
.
Default
)
{
gson
.
fromJson
(
str
,
clazz
)
}
}
//
// /**测试网络超时***/
// suspend fun getTimeOut(): MyResult<Int> {
// try {
// var star = System.currentTimeMillis()
// clientRetrofitMethod.getTimeOut()
// var end = System.currentTimeMillis()
// return MyResult.Success(end.minus(star).toInt())
// } catch (e: HttpException) {
// return MyResult.Error(e.code(), e.message() ?: "error")
// } catch (e: Exception) {
// return MyResult.Error(MyContants.HTTP_ERROR, e.message ?: "error")
// }
// }
//
// /***查询车位信息
// * 苏州hmi用的这个接口判断空闲车位
// * ***/
// suspend fun getSpaceData(): MyResult<SpaceNoBean> {
// var map = mutableMapOf("pageNo" to 20, "pageSize" to 1000)
// var body = RequestBodyUtil.toRequestBody(map)
// try {
// var bean = clientRetrofitMethod.getSpaceData(body)
// return MyResult.Success(bean.data)
// } catch (e: HttpException) {
//// println("e.message = ${e.message}")
// return MyResult.Error(e.code(), e.message() ?: "error")
// } catch (e: Exception) {
// return MyResult.Error(MyContants.HTTP_ERROR, e.message ?: "error")
// }
// }
//
// /***获取路径规划***/
// suspend fun getLinePlaning(vehiclePlate: String = "吉AC242"): MyResult<ParkLinePlan> {
// var map = mutableMapOf("vehiclePlate" to vehiclePlate)
// var body = RequestBodyUtil.toRequestBody(map)
// try {
// var bean = clientRetrofitMethod.getLinePlaning(body)
// return MyResult.Success(bean)
// } catch (e: HttpException) {
// println("e.message = ${e.message}")
// return MyResult.Error(e.code(), e.message() ?: "error")
// } catch (e: Exception) {
// return MyResult.Error(MyContants.HTTP_ERROR, e.message ?: "error")
// }
// }
// /**联网车辆状态数据***/
// suspend fun<T> genVehStatus():T {
//
// }
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/repositorys/SpaceNoRepo.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.repositorys
import
com.google.gson.Gson
import
com.sd.cavphmi.bean.SpaceNoBean
import
com.sd.cavphmi.net.MyResult
import
com.sd.cavphmi.net.RequestBodyUtil
import
com.sd.cavphmi.net.httpmothod.ClientRetrofitMethod
import
com.sd.cavphmi.websockets.MyWebSocketClient
import
retrofit2.HttpException
import
javax.inject.Inject
class
SpaceNoRepo
@Inject
constructor
(
var
clientRetrofitMethod
:
ClientRetrofitMethod
)
{
var
client
:
MyWebSocketClient
?
=
null
private
var
gson
=
Gson
()
// 2.2. 联网车辆位姿数据topic
fun
subVehicle
(){
}
fun
getSendData
(){
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/ui/BootActivity.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.ui
import
android.Manifest
import
android.content.Intent
import
android.os.Build
import
androidx.lifecycle.ViewModelProvider
import
com.permissionx.guolindev.PermissionX
import
com.sd.cavphmi.BR
import
com.sd.cavphmi.R
import
com.sd.cavphmi.base.BaseActivity
import
com.sd.cavphmi.base.MyBaseViewModel
import
com.sd.cavphmi.databinding.ActivityBootBinding
import
com.sd.cavphmi.utils.ToastHelper
import
dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class
BootActivity
:
BaseActivity
<
ActivityBootBinding
,
MyBaseViewModel
>()
{
// private val tcpUpVM: TcpUpVM by viewModels()
override
fun
getStatuBarColor
():
Int
{
return
-
1
}
override
fun
initContentView
():
Int
{
return
R
.
layout
.
activity_boot
}
override
fun
initViewModel
():
MyBaseViewModel
{
return
ViewModelProvider
(
this
).
get
(
MyBaseViewModel
::
class
.
java
)
}
override
fun
initVariableId
():
Int
{
return
BR
.
vm
}
override
fun
initView
()
{
requestPers
()
}
//到登录页面
private
fun
starLogin
()
{
var
jump
=
Intent
(
this
,
LoginActivity
::
class
.
java
)
startActivity
(
jump
)
finish
()
}
fun
requestPers
()
{
var
pers
=
mutableListOf
<
String
>(
// Manifest.permission.ACCESS_BACKGROUND_LOCATION,
// Manifest.permission.ACCESS_FINE_LOCATION,
// Manifest.permission.ACCESS_COARSE_LOCATION,
// Manifest.permission.READ_PHONE_STATE
)
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
R
)
{
pers
.
add
(
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
)
pers
.
add
(
Manifest
.
permission
.
MANAGE_EXTERNAL_STORAGE
)
}
else
{
pers
.
add
(
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
)
}
PermissionX
.
init
(
this
)
.
permissions
(
pers
.
toList
())
.
onExplainRequestReason
{
scope
,
deniedList
->
scope
.
showRequestReasonDialog
(
deniedList
,
"AVP 需要同意以下授权才能正常使用"
,
"好的"
,
"取消"
)
}
// .onForwardToSettings { scope, deniedList ->
// scope.showForwardToSettingsDialog(deniedList, "您需要手动在‘设置’中允许必要的权限", "OK", "Cancel")
// }
.
request
{
allGranted
,
grantedList
,
deniedList
->
if
(
allGranted
)
{
// ToastHelper.showShort(this, "All permissions are granted")
starLogin
()
}
else
{
ToastHelper
.
showShort
(
this
,
"权限被拒"
)
binding
.
root
.
postDelayed
({
finish
()
},
500
)
}
}
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/ui/ExitAppDialog.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.ui
import
android.app.Dialog
import
android.content.DialogInterface
import
android.os.Bundle
import
androidx.appcompat.app.AlertDialog
import
androidx.fragment.app.DialogFragment
import
com.sd.cavphmi.intfaces.OnConCan
class
ExitAppDialog
:
DialogFragment
()
{
var
onConCan
:
OnConCan
?
=
null
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
isCancelable
=
false
}
override
fun
onCreateDialog
(
savedInstanceState
:
Bundle
?):
Dialog
{
return
AlertDialog
.
Builder
(
requireContext
())
// dialog.setIcon(android.R.drawable.ic_dialog_info)
.
setTitle
(
"提示"
)
.
setMessage
(
"确定退出应用"
)
.
setPositiveButton
(
"确定"
)
{
dialog1
:
DialogInterface
?,
which
:
Int
->
onConCan
?.
onCon
()
}
.
setNegativeButton
(
"取消"
)
{
dialog
,
_
->
onConCan
?.
onCan
()
}.
create
()
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/ui/LoginActivity.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.ui
import
android.content.Intent
import
android.os.Bundle
import
androidx.activity.viewModels
import
androidx.appcompat.app.AppCompatActivity
import
androidx.lifecycle.Lifecycle
import
androidx.lifecycle.lifecycleScope
import
androidx.lifecycle.repeatOnLifecycle
import
com.jakewharton.rxbinding4.view.clicks
import
com.sd.cavphmi.databinding.ActivityLoginBinding
import
com.sd.cavphmi.ui.dialog.SeleBindCarDialog
import
com.sd.cavphmi.utils.MMKVUtil
import
com.sd.cavphmi.utils.MyContants
import
com.sd.cavphmi.viewmodels.LoginVm
import
com.sd.cavphmi.viewmodels.MainVm
import
dagger.hilt.android.AndroidEntryPoint
import
kotlinx.coroutines.launch
import
java.util.concurrent.TimeUnit
@AndroidEntryPoint
class
LoginActivity
:
AppCompatActivity
()
{
private
lateinit
var
binding
:
ActivityLoginBinding
private
val
loginVm
:
LoginVm
by
viewModels
()
private
val
mainVm
:
MainVm
by
viewModels
()
private
val
PWD
=
"5803d205ac27f33ea5f53afed4eb81880bee49f06129ea5437c1b940d18da8f1"
private
val
VERIFYCODE
=
285369
//车牌号选择
// private lateinit var seleBindCarDialog: SeleBindCarDialog
private
val
seleBindCarDialog
:
SeleBindCarDialog
by
lazy
{
SeleBindCarDialog
.
newInstance
()
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
binding
=
ActivityLoginBinding
.
inflate
(
layoutInflater
)
setContentView
(
binding
.
root
)
if
(
MMKVUtil
.
token
.
isNotEmpty
())
{
MyContants
.
HTTP_TOKEN
=
MMKVUtil
.
token
getBinderCars
()
}
// else {
var
lo
=
binding
.
btLogin
.
clicks
().
throttleFirst
(
1
,
TimeUnit
.
SECONDS
).
subscribe
{
login
()
}
// }
setListener
()
}
private
fun
login
()
{
// seleBindCarDialog.setPlates(plateNumbers)
// seleBindCarDialog.showNow(supportFragmentManager, "seleBindCarDialog")
// return
var
user
=
binding
.
etAccount
.
text
.
toString
()
// var pwd = binding.etPwd.text.toString()
// "4CIHV37pDF8sx0ZXYmYah6HSgys7F7ULSMmm39uzppc"
// var key = "Cusc@itmp-sm4key".toByteArray()
// var pp = SM4CryptoHelper.encryptECB(key, pwd.toByteArray())
lifecycleScope
.
launch
{
repeatOnLifecycle
(
Lifecycle
.
State
.
STARTED
)
{
loginVm
.
login
(
user
,
PWD
,
VERIFYCODE
).
collect
{
// println("-----------登录回调 = ${it}")
//获取可绑定车辆
if
(
it
==
1
)
{
getBinderCars
()
}
}
}
}
}
private
fun
setListener
()
{
// HTTP获取车位占用情况
binding
.
btSpaceinfo
.
setOnClickListener
{
mainVm
.
getSpaceInfo
()
}
// HTTP获取AVp状态信息 以后就用socket订阅了,获取找、泊车状态,拿到全局路径lines,和局部(避障)路径xxx
binding
.
btAvpstatu
.
setOnClickListener
{
mainVm
.
getAvpStatus
()
}
binding
.
btCarpos
.
setOnClickListener
{
mainVm
.
subVehicle
()
}
//获取可绑定车辆
binding
.
btGetbindcar
.
setOnClickListener
{
getBinderCars
()
}
//直接到首页
binding
.
btMain
.
setOnClickListener
{
startActivity
(
Intent
(
this
,
MainActivity
::
class
.
java
))
finish
()
}
}
//获取可绑定车辆
private
fun
getBinderCars
()
{
// seleBindCarDialog = SeleBindCarDialog.newInstance()
mainVm
.
getBindCar
().
observe
(
this
)
{
bindCars
->
var
plateNumbers
=
bindCars
.
map
{
it
.
plateNumber
}
seleBindCarDialog
.
setPlates
(
plateNumbers
)
seleBindCarDialog
.
itemClickListener
=
object
:
SeleBindCarDialog
.
OnItemClickListener
{
override
fun
onItemClick
(
position
:
Int
)
{
MyContants
.
VEHICLEID
=
bindCars
.
get
(
position
).
id
startActivity
(
Intent
(
this
@LoginActivity
,
MainActivity
::
class
.
java
))
finish
()
}
}
if
(!
seleBindCarDialog
.
isAdded
)
{
seleBindCarDialog
.
showNow
(
supportFragmentManager
,
"seleBindCarDialog"
)
}
// val dialog = CustomListDialog(this, "选择车辆", plateNumbers)
// dialog.setOnItemClickListener(object : CustomListDialog.OnItemClickListener {
// override fun onItemClick(position: Int, selectedItem: String) {
//// Toast.makeText(
//// this@LoginActivity,
//// "点击了第${position + 1}项: $selectedItem",
//// Toast.LENGTH_SHORT
//// ).show()
// MyContants.VEHICLEID = bindCars.get(position).id
// startActivity(Intent(this@LoginActivity, MainActivity::class.java))
// finish()
// }
// })
// dialog.show()
}
}
}
\ No newline at end of file
app/src/main/java/com/sd/cavphmi/ui/MainActivity.kt
0 → 100644
View file @
c0af16dd
package
com.sd.cavphmi.ui
import
android.content.res.Configuration
import
android.util.Log
import
android.view.KeyEvent
import
androidx.activity.viewModels
import
androidx.lifecycle.Lifecycle
import
androidx.lifecycle.ViewModelProvider
import
androidx.lifecycle.lifecycleScope
import
androidx.lifecycle.repeatOnLifecycle
import
com.minedata.minenavi.SDKInitializer
import
com.minedata.minenavi.SDKInitializer.InitListener
import
com.minedata.minenavi.map.MapView
import
com.minedata.minenavi.map.MineMap
import
com.minedata.minenavi.mapdal.LatLng
import
com.minedata.minenavi.util.Tools
import
com.sd.cavphmi.BR
import
com.sd.cavphmi.R
import
com.sd.cavphmi.base.BaseActivity
import
com.sd.cavphmi.base.MyBaseViewModel
import
com.sd.cavphmi.bean.AvpStatuBean
import
com.sd.cavphmi.bean.CarVehicle
import
com.sd.cavphmi.bean.PerceptionBean
import
com.sd.cavphmi.databinding.ActivityMainBinding
import
com.sd.cavphmi.highmap.HighMapApi
import
com.sd.cavphmi.highmap.LockStatu
import
com.sd.cavphmi.highmap.ParkStatu
import
com.sd.cavphmi.highmap.Spinfo
import
com.sd.cavphmi.highmap.UnityPtc
import
com.sd.cavphmi.intfaces.OnConCan
import
com.sd.cavphmi.ui.fragment.CarPanelFragment
import
com.sd.cavphmi.ui.fragment.ExoPlayFragment
import
com.sd.cavphmi.utils.AvpContants
import
com.sd.cavphmi.utils.DisplayUtil
import
com.sd.cavphmi.viewmodels.MainVm
import
com.sd.cavphmi.viewmodels.MapOpt
import
com.sd.cavphmi.viewmodels.MockVM
import
dagger.hilt.android.AndroidEntryPoint
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.launch
@AndroidEntryPoint
class
MainActivity
:
BaseActivity
<
ActivityMainBinding
,
MyBaseViewModel
>()
{
override
fun
getStatuBarColor
():
Int
{
return
-
1
}
override
fun
initContentView
():
Int
{
return
R
.
layout
.
activity_main
}
override
fun
initViewModel
():
MyBaseViewModel
{
return
ViewModelProvider
(
this
).
get
(
MyBaseViewModel
::
class
.
java
)
}
override
fun
initVariableId
():
Int
{
return
BR
.
vm
}
override
fun
onPause
()
{
super
.
onPause
()
binding
.
mapView
.
onPause
()
}
override
fun
onResume
()
{
super
.
onResume
()
binding
.
mapView
.
onResume
()
}
override
fun
onDestroy
()
{
super
.
onDestroy
()
mainVm
.
cleanRes
()
binding
.
mapView
.
onDestroy
()
}
//用作模拟
private
val
mockVM
:
MockVM
by
viewModels
()
//主页操作
private
val
mainVm
:
MainVm
by
viewModels
()
//地图操作类,用于绘制
private
val
mapOpt
:
MapOpt
by
viewModels
()
// private val avpMapVM: AvpMapVM by viewModels()
//是否进入泊车倒车状态
// private var isReversePark = false
//退出应用弹窗
private
lateinit
var
dialogFragment
:
ExitAppDialog
//汽车仪表
private
val
carPanelFragment
by
lazy
{
CarPanelFragment
.
newInstance
()
}
//exo播放器
private
val
exoPlayFragment
by
lazy
{
ExoPlayFragment
.
newInstance
()
}
override
fun
initView
()
{
mainVm
.
mockVM
=
mockVM
adaptWidth
()
//车辆仪表
var
ft
=
supportFragmentManager
.
beginTransaction
()
ft
.
add
(
R
.
id
.
map_car_pan
,
carPanelFragment
,
"1"
)
ft
.
commit
()
//添加视频播放器,以后看需要控制显示隐藏时机,默认隐藏
// showVideoFragment(true)
initialMap
()
}
private
fun
adaptWidth
()
{
var
width
=
DisplayUtil
.
getScreenWidthPx
()
var
cWidth
=
(
width
*
0.271
).
toInt
()
//车辆仪表
var
params
=
binding
.
mapCarPan
.
layoutParams
params
.
width
=
cWidth
binding
.
mapCarPan
.
layoutParams
=
params
//小地图
params
=
binding
.
smallFLayout
.
layoutParams
.
apply
{
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
()
{
SDKInitializer
.
debug
(
false
)
// 隐私合规接口
SDKInitializer
.
setAgreePrivacy
(
true
)
// SDKInitializer.setStyleUrl(MineMap.UrlType.satellite, MyContants.YZ_WMS)
SDKInitializer
.
initialize
(
this
,
object
:
InitListener
{
override
fun
onInitSuccess
()
{
// println("---Map onInitSuccess")
setUpMap
()
}
override
fun
onInitFailed
(
msg
:
String
?)
{
println
(
"---Map onInitFailed msg = ${msg}"
)
}
})
}
private
fun
setUpMap
()
{
binding
.
mapView
.
addMapRenderCallback
(
object
:
MapView
.
OnMapReadyListener
{
override
fun
onMapReady
(
mineMap
:
MineMap
?)
{
// mainVm.mMineMap = mineMap
mapOpt
.
mMineMap
=
mineMap
mockVM
.
mMineMap
=
mineMap
mineMap
?.
setZoomLevel
(
14f
)
//设置中心点
// val point = Tools.latLngToPoint(LatLng(39.80913878, 116.50166926))
val
point
=
Tools
.
latLngToPoint
(
LatLng
(
39.809135
,
116.502434
))
mineMap
?.
setPointToCenter
(
point
.
x
,
point
.
y
)
}
})
}
override
fun
getToData
()
{
if
(!
mainVm
.
isMock
)
{
//开启websocket
getTarget
()
getV2x
()
//开启2个HTTP sse
getCarVehicle
()
getAvpStatus
()
}
//获取车位占用情况
// getSpaceInfo()
}
//获取车位占用情况
private
fun
getSpaceInfo
()
{
mainVm
.
getSpaceInfo
().
observe
(
this
)
{
spaceInfo
->
//车辆占用情况
var
spinfos
=
spaceInfo
.
result
.
map
{
Spinfo
().
apply
{
code
=
it
.
code
state
=
true
}
}
HighMapApi
.
setParkStatu
(
ParkStatu
(
spinfos
))
}
}
//显示隐藏 视频
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
()
{
mockBt
()
}
//获取AVP状态
private
fun
getAvpStatus
()
{
lifecycleScope
.
launch
{
repeatOnLifecycle
(
Lifecycle
.
State
.
STARTED
)
{
mainVm
.
getAvpStatus
().
collect
{
avpStatu
->
showAvp
(
avpStatu
)
// 车内视频
// isCarVideo(businessStatus)
}
}
}
}
//显示AVP特效
private
fun
showAvp
(
avpStatu
:
AvpStatuBean
)
{
if
(
avpStatu
.
haulingStageState
==
null
||
avpStatu
.
vehicleContext
==
null
)
return
//业务类型
var
businessType
=
avpStatu
.
businessType
//NIL Park Call
//业务状态
var
businessStatus
=
avpStatu
.
haulingStageState
//获取档位
var
gearType
=
avpStatu
.
vehicleContext
.
vehicleDynamic
.
gearType
//画全局路径
mapOpt
.
drawAllLines
(
avpStatu
.
drivenDecision
,
businessStatus
)
//生成小地图路线
mapOpt
.
takeSmallMapLine
(
avpStatu
.
drivenDecision
,
businessStatus
)
//画终点
mapOpt
.
addEndMarker
(
avpStatu
.
drivenDecision
.
endPoint
,
businessStatus
)
//是否显示车位流光效果
mapOpt
.
showParkLight
(
businessType
,
businessStatus
,
avpStatu
.
space
)
//判断在泊车状态下的倒挡绘制倒车路线,改变镜头视角,,判断车是否到达停车点
mapOpt
.
drawReversePark
(
businessType
,
businessStatus
,
gearType
,
avpStatu
.
space
)
//重置变量
resetVariable
(
businessStatus
)
//根据AVP任务状态判停车特效是否关闭
// mapOpt.showEffectAvpStatu(businessType, businessStatus)
}
/***是否展示车内视频****/
private
fun
isCarVideo
(
businessStatus
:
String
)
{
if
(
businessStatus
==
AvpContants
.
TRANSPORT_PROGRESS
)
{
getVehDetail
()
}
else
{
// exoPlayFragment.videoUrl = cameraUrl
showVideoFragment
(
false
)
}
}
/***重置变量**/
private
fun
resetVariable
(
businessStatus
:
String
)
{
if
(
businessStatus
==
AvpContants
.
TRANSPORT_COMPLETED
||
businessStatus
==
AvpContants
.
TRANSPORT_CANCELED
)
{
mainVm
.
isGetVehDetail
=
false
// mapOpt.smallMapLine = false
mapOpt
.
sliceIndex
=
0
// mapOpt.isDrawAreaCount = false
}
}
//联网车辆位姿数据
private
fun
getCarVehicle
()
{
lifecycleScope
.
launch
{
repeatOnLifecycle
(
Lifecycle
.
State
.
STARTED
)
{
mainVm
.
subVehicle
().
collect
{
car
->
showVehicle
(
car
)
}
}
}
//召车的时候临时开一下
mainVm
.
targetPre
.
observe
(
this
)
{
showPre
(
it
)
}
}
//显示车辆位姿UI
private
fun
showVehicle
(
car
:
CarVehicle
)
{
if
(
car
.
vehiclePos
==
null
||
car
.
vehiclePos
?.
getOrNull
(
2
)
==
null
)
{
//隐藏小车
return
}
//画小地图小车
mapOpt
.
drawSmallCar
(
car
)
//刷新右下角小车位置
mapOpt
.
showNavingCarPosition
(
car
)
//生成车前方矩形
mapOpt
.
genFronArea
(
car
)
//刷新右下角小地图路径
mapOpt
.
upSmallMapLine
()
//AVP鹰眼基于剩余路线最小矩形框为中心展示。
mapOpt
.
drawEndArea
(
car
)
// println("----car.heading ${car.heading}")
//刷新主车位置
HighMapApi
.
setCarPosition
(
car
.
vehiclePos
!!
.
get
(
2
),
car
.
vehiclePos
!!
.
get
(
1
),
car
.
vehiclePos
!!
.
get
(
0
),
20.80189
// car.elevation
)
// setCarCamera(1)
}
//联网车辆感知物
private
fun
getTarget
()
{
mainVm
.
subTarget
().
observe
(
this
)
{
it
->
showPre
(
it
)
}
}
/**绘制感知物****/
private
fun
showPre
(
it
:
PerceptionBean
)
{
if
(
it
.
getOrNull
(
0
)
==
null
)
{
return
}
var
parts
=
it
.
flatMap
{
it
.
participants
}
if
(
parts
.
count
()
==
0
)
{
HighMapApi
.
clearPtcData
()
return
}
var
ptcList
=
parts
.
map
{
var
unityPtc
=
UnityPtc
().
apply
{
lat
=
it
.
latitude
lon
=
it
.
longitude
ptcid
=
it
.
ptcId
heading
=
it
.
heading
pType
=
1
if
(
it
.
ptcType
==
"car"
)
{
pType
=
1
}
else
if
(
it
.
ptcType
==
"pedestrian"
)
{
pType
=
2
}
}
return
@map
unityPtc
}
HighMapApi
.
setPtcData
(
ptcList
)
}
//开启v2x预警
private
fun
getV2x
()
{
mainVm
.
subStartV2x
().
observe
(
this
)
{
v2x
->
if
(
v2x
==
null
)
return
@observe
if
(
v2x
.
objects
?.
isEmpty
()
==
true
||
v2x
.
objects
?.
getOrNull
(
1
)
==
null
)
return
@observe
//获取预警感知目标物的id 第一个是自己 第二个是别人
var
v2xId
=
v2x
.
objects
?.
get
(
1
)
?.
id
// println("------------v2xId = ${v2xId}")
if
(
v2xId
==
null
)
{
return
@observe
}
Log
.
e
(
"V2x"
,
"-------------v2xId= ${v2xId}"
)
// v2xId = "f117fdfa-feff-0100-85dc-35850000acb0"
mainVm
.
startWarning
(
v2xId
)
}
}
//设置跟车视角
private
fun
setCarCamera
(
c
:
Int
)
{
if
(
c
==
1
)
{
HighMapApi
.
setCameraAngle
(
30f
)
HighMapApi
.
setCameraDistance
(
6f
)
}
else
if
(
c
==
2
)
{
HighMapApi
.
setCameraAngle
(
90f
)
HighMapApi
.
setCameraDistance
(
80f
)
}
}
//获取车辆详情,取车内摄像头地址打开左下角的车内视频
private
fun
getVehDetail
()
{
// if (car?.businessStatus.equals("EXITED")) {
// exoPlayFragment.videoUrl = ""
// showVideoFragment(false)
// return
// }
mainVm
.
getVehDetail
().
observe
(
this
)
{
vehDetail
->
if
(
vehDetail
.
result
.
vehicleInfos
.
count
()
==
0
)
return
@observe
var
cameraUrl
=
vehDetail
.
result
.
vehicleInfos
.
get
(
0
).
vehicleVideoUrl
println
(
"---cameraUrl = ${cameraUrl}"
)
if
(
exoPlayFragment
.
videoUrl
.
isNotEmpty
())
return
@observe
if
(!
cameraUrl
.
isNullOrEmpty
())
{
exoPlayFragment
.
videoUrl
=
cameraUrl
showVideoFragment
(
true
)
}
}
}
private
fun
mockBt
()
{
//获取AVP状态
binding
.
btAvpStatu
.
setOnClickListener
{
getAvpStatus
()
}
//联网车辆位姿数据
binding
.
btVehicle
.
setOnClickListener
{
getCarVehicle
()
}
//感知目标物
binding
.
btTarget
.
setOnClickListener
{
getTarget
()
}
// HTTP获取车辆详情
binding
.
btVehinfo
.
setOnClickListener
{
getVehDetail
()
}
//v2x 预警
binding
.
btV2x
.
setOnClickListener
{
getV2x
()
}
//车位四周流光
binding
.
btParkround
.
setOnClickListener
{
HighMapApi
.
setCameraAngle
(
75f
)
lifecycleScope
.
launch
{
HighMapApi
.
parkRoundLight
(
"B021"
)
delay
(
5000
)
HighMapApi
.
parkRoundLight
(
""
)
}
}
//停车位绘制
binding
.
btParkstatu
.
setOnClickListener
{
var
spinfos
=
listOf
(
Spinfo
().
apply
{
code
=
"B020"
state
=
true
},
Spinfo
().
apply
{
code
=
"B022"
state
=
true
})
HighMapApi
.
setParkStatu
(
ParkStatu
(
spinfos
))
}
//地锁绘制
binding
.
btLock
.
setOnClickListener
{
//释放http资源
// SimpleSSEClient.instance.cancelContect()
var
lockStatu
=
LockStatu
().
apply
{
code
=
"B021"
isHide
=
false
}
HighMapApi
.
setLockStatus
(
lockStatu
)
/* lifecycleScope.launch {
delay(3000)
lockStatu.up = false
HighMapApi.setLockStatus(lockStatu)
delay(3000)
lockStatu.isHide = true
HighMapApi.setLockStatus(lockStatu)
}*/
}
//模拟移动
// binding.btMove.setOnClickListener {
// mainVm.mockFzLine()
// }
//预警车
binding
.
warnCar
.
setOnClickListener
{
mainVm
.
mWarnCar
()
}
//预警人
binding
.
warnPeo
.
setOnClickListener
{
mainVm
.
mWarnPeo
()
}
}
/**
* Show video play
* @param isHide false:隐藏 true:显示
*/
private
fun
showVideoPlay
(
isHide
:
Boolean
)
{
// exoPlayFragment.videoUri=""
var
ft
=
supportFragmentManager
.
beginTransaction
()
if
(
isHide
)
{
ft
.
hide
(
exoPlayFragment
)
}
else
{
ft
.
show
(
exoPlayFragment
)
}
ft
.
commit
()
}
override
fun
onConfigurationChanged
(
newConfig
:
Configuration
)
{
super
.
onConfigurationChanged
(
newConfig
)
mainVm
.
windowConfiguration
.
value
=
newConfig
}
override
fun
onWindowFocusChanged
(
hasFocus
:
Boolean
)
{
super
.
onWindowFocusChanged
(
hasFocus
)
mainVm
.
hasFocus
.
value
=
hasFocus
}
override
fun
dispatchKeyEvent
(
event
:
KeyEvent
):
Boolean
{
if
((
event
.
getKeyCode
()
==
KeyEvent
.
KEYCODE_BACK
)
||
event
.
getKeyCode
()
==
KeyEvent
.
KEYCODE_HOME
)
{
// var ft = supportFragmentManager.beginTransaction()
dialogFragment
=
ExitAppDialog
()
dialogFragment
.
onConCan
=
object
:
OnConCan
{
override
fun
onCon
()
{
finish
()
}
override
fun
onCan
()
{
}
}
dialogFragment
.
show
(
supportFragmentManager
,
"exit"
)
return
true
}
else
{
return
super
.
dispatchKeyEvent
(
event
)
}
}
}
/* https://docs.qq.com/sheet/DVWdOYXZXdVVrQWts?tab=xxmysv socket文档
https://s.apifox.cn/e355c9e1-cdd1-49ab-acb2-54cfc66b1598/320994000e0 大屏文档
获取AVP状态信息 /v1/avp/overview/listAvpStatus 这个曲华烨要做成socket 的推送形式,通过这个接口获取全局路径和局部路径,车辆业务状态。
通过里面的vehicleId,调车辆详情(/v1/avp/overview/getVehicleInfo)获取车内视频流,
websocket 那几个连接,都需要传vehicleId,你也可以不传,不传就是获取所有的*/
//reType 不传就是飞渡,可以问张海胜,数据没有的问题可直接在51word群里反馈
//目前没有全局路径规划变化提醒,具体车位占用情况(用来在车位上绘制白模)
//需求文档里的气泡提醒,数据未必有,已实际数据为准
//【腾讯文档】AVP-HMI接口需求清单
//https://docs.qq.com/sheet/DVmNmZ3VhVEFxRkpV?tab=BB08J2
//高精地图沟通文档
//https://docs.qq.com/sheet/DQWhPRkdteGFNWVZi?tab=BB08J2
Prev
1
2
3
4
5
6
7
8
9
…
12
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment