設(shè)計思路
使用自定義的dataclass 封裝信號數(shù)據(jù) 及其信號狀態(tài)
使用泛型分裝信號數(shù)據(jù)與業(yè)務(wù)數(shù)據(jù)之間的轉(zhuǎn)換關(guān)系 并提供基礎(chǔ)類型的快捷轉(zhuǎn)換方法
使用注解類修飾需要使用的業(yè)務(wù)數(shù)據(jù)類 使其自動發(fā)生注冊和初始化
主要管理類
import android.app.Application
import android.car.VehicleAreaDoor.DOOR_REAR
import android.content.Context
import android.os.Parcelable
import android.util.Log
/**
* CarPropertyManager: 全新的信號管理中心 (應(yīng)用層交互入口)
* 職責(zé):
* 1. 定義和配置所有車輛屬性的 PropertyHandler。
* 2. 提供統(tǒng)一的 init/release 方法,并管理初始化流程。
* 3. 將底層回調(diào)分發(fā)給對應(yīng)的 Handler。
*/
private const val TAG = "SystemUI-CarPropertyManager"
object CarPropertyManager {
// --- 工廠函數(shù),用于簡化 Handler 的創(chuàng)建 ---
private inline fun <reified ValueT, reified WrapperT : Parcelable> createPropertyHandler(
propertyId: Int,
defaultState: ValueT,
areaId: Int = 0,
noinline valueToWrapper: (ValueT) -> WrapperT,
noinline wrapperToValue: (WrapperT) -> ValueT?,
needInit: Boolean = true
): PropertyHandler<ValueT, WrapperT> {
return PropertyHandler(
propertyId = propertyId,
defaultState = defaultState,
areaId = areaId,
wrapperClass = WrapperT::class.java,
valueToWrapper = valueToWrapper,
wrapperToValue = wrapperToValue,
getter = {
MyCarAPIManager.getProperty<WrapperT>(propertyId, areaId)?.value?.let(
wrapperToValue
)
},
setter = { propValue -> MyCarAPIManager.setProperty(propValue) },
needInit = needInit
)
}
fun createProperty(propertyStr: String, defaultState: Any) {
val propertyId = getPropertyIdFromString(propertyStr) ?: return
Logger.d(TAG, "createProperty: $propertyId defaultState $defaultState")
when (defaultState) {
is Int -> {
createIntProperty(propertyId, defaultState).set(defaultState)
}
is Boolean -> {
createBooleanProperty(propertyId, defaultState).set(defaultState)
}
is Float -> {
createFloatProperty(propertyId, defaultState).set(defaultState)
}
}
}
private fun createIntProperty(
propertyId: Int,
defaultState: Int,
areaId: Int = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
needInit: Boolean = true
) =
createPropertyHandler<Int, IntWrapper>(
propertyId,
defaultState,
areaId,
{ IntWrapper(it) },
{ it.value },
needInit
)
private fun createBooleanProperty(
propertyId: Int,
defaultState: Boolean,
areaId: Int = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
needInit: Boolean = true
) =
createPropertyHandler<Boolean, BooleanWrapper>(
propertyId,
defaultState,
areaId,
{ BooleanWrapper(it) },
{ it.value },
needInit
)
private fun createFloatProperty(
propertyId: Int,
defaultState: Float,
areaId: Int = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
needInit: Boolean = true
) =
createPropertyHandler<Float, FloatWrapper>(
propertyId,
defaultState,
areaId,
{ FloatWrapper(it) },
{ it.value },
needInit
)
private fun createStringProperty(
propertyId: Int,
defaultState: String,
areaId: Int = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
needInit: Boolean = true
) =
createPropertyHandler<String, StringWrapper>(
propertyId,
defaultState,
areaId,
{ StringWrapper(it) },
{ it.value },
needInit
)
// 無線充電狀態(tài)
@CarProperty
val wirelessChargeState =
createIntProperty(PropertyIds.WPC_CHARGE_STATE, WirelessChargeState.CHARGING)
// 外部燈 todo 測試的id(外部燈光) 后續(xù)刪除
@CarProperty
val exteriorLightControlState = createIntProperty(
PropertyIds.EXTERIOR_LIGHT_CONTROL,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0
)
// 駕駛模式
@CarProperty
val driveModeState = createIntProperty(
PropertyIds.DRIVE_MODE_SETTING,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0
)
// 通知信號
@CarProperty
val notificationSignalPassthroughDismiss = createIntProperty(
NotificationPropertyIds.NOTIFICATION_SIGNAL_PASSTHROUGH_DISMISS,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0,
needInit = false
)
@CarProperty
val notificationSignalPassthroughDisplay = createIntProperty(
NotificationPropertyIds.NOTIFICATION_SIGNAL_PASSTHROUGH_DISPLAY,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0,
needInit = false
)
@CarProperty
val notificationSignalCsdDismiss = createIntProperty(
NotificationPropertyIds.NOTIFICATION_SIGNAL_CSD_DISMISS,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0,
needInit = false
)
@CarProperty
val notificationSignalCsdDisplay = createIntProperty(
NotificationPropertyIds.NOTIFICATION_SIGNAL_CSD_DISPLAY,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0,
needInit = false
)
@CarProperty
val notificationSignalData = mutableListOf<PropertyHandler<*, *>>().apply {
for (i in 0..77) {
add(
createIntProperty(
NotificationPropertyIds.NOTIFICATION_SIGNAL_DATA0 + i,
0,
needInit = false
)
)
}
}
@CarProperty
private val propertyIdMap = mapOf(
// 電池溫度調(diào)節(jié)
"ChgPreSetTempSwitchReq" to PropertyIds.BATTERY_PREHEATING_BUTTON,
// 啟動發(fā)電
"HVPwrDwnRstReq" to PropertyIds.CHARGING_START_ENGINE_SWITCH,
// 整車電源繼續(xù)使用信號
"LongTiRunngMod" to PropertyIds.VEHICLE_POWER_CONTINUE_USE,
// 開啟PM2.5凈化功能
"PM25FilterSwitchReq" to PropertyIds.VEHICLE_POWER_CONTINUE_USE,
// 關(guān)閉超級續(xù)航
"CloseSuperJourney" to PropertyIds.VEHICLE_POWER_CONTINUE_USE,
// 離車不下電
"LeaveWithoutDischarging" to PropertyIds.VEHICLE_POWER_CONTINUE_USE,
// 關(guān)閉燈光
"CloseLight" to PropertyIds.VEHICLE_POWER_CONTINUE_USE
)
// 車輛模式
@CarProperty
val carModeState = createIntProperty(
PropertyIds.AVAILABLE_CAR_MODE,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = CarMode.UNKNOWN
)
// 空調(diào)配置字
@CarProperty
val carConfigHvacVariants = createIntProperty(
PropertyIds.CAR_CONFIG_HVAC_VARIANTS,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0
)
// VIN
@CarProperty
val carInfoVin = createStringProperty(
PropertyIds.INFO_VIN,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = ""
)
// VehicleType: V451K
@CarProperty
val carInfoVehicleType = createStringProperty(
PropertyIds.VIRTUAL_CAR_INFO_GET_VEHICLE_TYPE,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = ""
)
// brand
@CarProperty
val carConfigBrand = createIntProperty(
PropertyIds.CAR_CONFIG_BRAND,
areaId = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
defaultState = 0
)
// 后備箱
@CarProperty
val rearTrunkState = createIntProperty(
PropertyIds.DOOR_MOVE,
RearTrunkState.UNKNOWN.code,
DOOR_REAR
)
// 油箱蓋
@CarProperty
val fuelCapSwitchState = createBooleanProperty(
PropertyIds.FUEL_CAP_SWITCH,
false
)
// 手套箱開關(guān)狀態(tài)
@CarProperty
val gloveBoxSwitchState = createBooleanProperty(PropertyIds.GLOVE_BOX_SWITCH, false)
// 手套箱密碼鎖
@CarProperty
val gloveBoxPasswordLockState = createBooleanProperty(PropertyIds.PRIVATE_LOCK, false)
// 哨兵模式
@CarProperty
val sentryModeState = createBooleanProperty(PropertyIds.SENTINEL_MODE_STATUS, false)
// 自動大燈
@CarProperty
val exteriorLightState = createIntProperty(
PropertyIds.EXTERIOR_LIGHT_CONTROL,
ExteriorLightControl.OFF.value
)
// 自動亮度
@CarProperty
val ambienceLightState = createBooleanProperty(PropertyIds.AMBIENCE_LIGHT_ONOFF, false)
// 無線充電開關(guān)
@CarProperty
val wpcPowerState = createBooleanProperty(PropertyIds.WPC_POWER_ON_OFF, false)
// 外后視鏡折疊狀態(tài)
@CarProperty
val mirrorFoldSettingState = createIntProperty(PropertyIds.MIRROR_EXTERIOR_FOLD_SETTING_STS, 1)
// 上下電狀態(tài)
@CarProperty
val powerState = createBooleanProperty(PropertyIds.POWER_ONOFF, true)
// 左側(cè)童鎖
@CarProperty
val leftChildLockState = createBooleanProperty(PropertyIds.CHILD_LOCK_ON, false, AreaDoor.DOOR_ROW_2_LEFT)
// 右側(cè)童鎖
@CarProperty
val rightChildLockState = createBooleanProperty(PropertyIds.CHILD_LOCK_ON, false, AreaDoor.DOOR_ROW_2_RIGHT)
// 閱讀燈
@CarProperty
val readLightState = createIntProperty(PropertyIds.READING_LIGHTS_CONTROL, 0)
// 屏幕亮度
@CarProperty
val displayBrightnessState = createIntProperty(PropertyIds.DISPLAY_BRIGHTNESS_CSD, defaultState = 0)
// 白天黑夜
@CarProperty
val dayNightModeState = createIntProperty(PropertyIds.DAY_NIGHT_MODE, defaultState = 0)
private fun getPropertyIdFromString(fieldName: String): Int? {
return propertyIdMap[fieldName]
}
// --- 創(chuàng)建一個 Map 來統(tǒng)一管理所有 Handler ---
private val propertyHandlerMap: MutableMap<String, PropertyHandler<*, *>> = mutableMapOf()
// --- 回調(diào)分發(fā)邏輯 ---
private fun handlePropertyChange(propertyValue: CarPropertyValue<*>) {
Log.d(TAG, "handlePropertyChange: $propertyValue")
try {
propertyHandlerMap.getValue("${propertyValue.propertyId}-${propertyValue.areaId}")
.handleValue(propertyValue)
} catch (e: Exception) {
Log.e(TAG, "handlePropertyChange error: ${e.message}")
}
}
// --- 核心反射注冊邏輯 ---
private fun autoRegisterProperties() {
Log.d(TAG, "autoRegisterProperties: ")
val fields = this.javaClass.declaredFields
for (field in fields) {
Log.d(TAG, "findField ${field.name} ")
// 查找?guī)в?@CarProperty 注解的字段
if (field.isAnnotationPresent(CarProperty::class.java)) {
field.isAccessible = true // 允許訪問 private 或 internal 字段
try {
val value = field.get(this)
// 普通的 PropertyHandler
if (value is PropertyHandler<*, *>) {
Log.d(TAG, "autoRegisterProperties: ${value.getMapKey()} ")
propertyHandlerMap[value.getMapKey()] = value
}
// List 里的 PropertyHandler
else if (value is Iterable<*>) {
value.filterIsInstance<PropertyHandler<*, *>>().forEach { handler ->
Log.d(TAG, "autoRegisterProperties: ${handler.getMapKey()} ")
propertyHandlerMap[handler.getMapKey()] = handler
}
}
} catch (e: Exception) {
Log.e(TAG, "Failed to auto-register property field: ${field.name}", e)
}
}
}
Log.d(TAG, "Auto-registered ${propertyHandlerMap.size} properties successfully.")
}
fun init(context: Context) {
Log.d(TAG, "Initializing...")
autoRegisterProperties()
MyCarAPIManager.init(
context = context,
onReady = {
Log.d(TAG, "Service is ready. Registering properties and getting initial values...")
// 1. 注冊所有需要的屬性監(jiān)聽
propertyHandlerMap.values.forEach { propertyHandler ->
Log.d(TAG, "registerCallback propertyHandler ${propertyHandler.propertyId}")
MyCarAPIManager.registerCallback(propertyHandler.propertyId)
}
// 2. 主動獲取一次所有屬性的初始值
propertyHandlerMap.values.forEach { it.init() }
// 3. 通知 ClientManager 開始初始化
ClientManager.getInstance().init(context as Application)
},
// onPropertyChanged 回調(diào):當(dāng)有屬性變化時執(zhí)行
onPropertyChanged = { propertyValue ->
handlePropertyChange(propertyValue)
}
)
}
fun release() {
Log.d(TAG, "Releasing...")
propertyHandlerMap.values.forEach { propertyHandler ->
MyCarAPIManager.unregisterCallback(propertyHandler.propertyId)
}
MyCarAPIManager.release()
}
}
基礎(chǔ)數(shù)據(jù)類
import android.os.Parcelable // 關(guān)鍵導(dǎo)入!
import android.util.Log
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
interface IPropertyHandler<T> {
val state: StateFlow<T>
val statusState: StateFlow<Int>
val needInit: Boolean
fun handleValue(propertyValue: CarPropertyValue<*>)
fun init()
fun set(value: T)
fun getMapKey(): String
}
/**
* 泛型處理器實現(xiàn)。
*
* @param ValueT 最終需要的、存儲在 StateFlow 中的值的類型 (e.g., Int)。
* @param WrapperT CarPropertyValue.value 的類型,必須是 Parcelable (e.g., IntWrapper)。
*/
private const val TAG = "SystemUI-PropertyHandler"
data class PropertyHandler<ValueT, WrapperT>(
val propertyId: Int,
private val defaultState: ValueT,
private val areaId: Int = AreaType.VEHICLE_AREA_TYPE_GLOBAL,
private val status: Int = CarPropertyValue.STATUS_AVAILABLE,
private val wrapperClass: Class<WrapperT>,
private val valueToWrapper: (ValueT) -> WrapperT,
private val wrapperToValue: (WrapperT) -> ValueT?,
private val getter: () -> ValueT?,
private val setter: (CarPropertyValue<*>) -> Unit,
override val needInit: Boolean = true
) : IPropertyHandler<ValueT> where WrapperT : Parcelable {
private val _state = MutableStateFlow(defaultState)
override val state: StateFlow<ValueT> = _state.asStateFlow()
private val _statusState = MutableStateFlow(CarPropertyValue.STATUS_UNAVAILABLE)
override val statusState: StateFlow<Int> = _statusState.asStateFlow()
override fun getMapKey(): String {
return "$propertyId-$areaId"
}
// 處理propertyChange
override fun handleValue(propertyValue: CarPropertyValue<*>) {
Log.d(TAG, "handleValue: $propertyId value:$propertyValue")
if (propertyValue.areaId != this.areaId) return
// 更新狀態(tài)
_statusState.update { _ -> propertyValue.status }
val valueFromCar = propertyValue.value
if (wrapperClass.isInstance(valueFromCar)) {
try {
@Suppress("UNCHECKED_CAST")
val typedWrapper = valueFromCar as WrapperT
val finalValue = wrapperToValue(typedWrapper)
finalValue?.let {
_state.update { _ -> it }
}
} catch (e: Exception) {
Log.e(TAG, "Failed to cast/extract for $propertyId", e)
}
}
}
/**
* 設(shè)置新值。調(diào)用外部傳入的 setter 函數(shù)。
*/
override fun set(value: ValueT) {
Log.d(TAG, "set: $propertyId $value")
val wrapper = valueToWrapper(value)
val carPropValue = CarPropertyValue(propertyId, areaId, status, wrapper)
setter(carPropValue)
}
override fun init() {
try {
if (needInit) {
val initialValue = getter()
initialValue?.let {
_state.update { _ -> it }
}
// 獲取初始狀態(tài)
val initialStatus = try {
MyCarAPIManager.getProperty<WrapperT>(propertyId, areaId)?.status
?: CarPropertyValue.STATUS_UNAVAILABLE
} catch (e: Exception) {
Logger.e(TAG, "Failed to get initial status for $propertyId", e)
CarPropertyValue.STATUS_UNAVAILABLE
}
_statusState.update { _ -> initialStatus }
Logger.d(TAG, "init propertyId $propertyId initialValue $initialValue initialStatus $initialStatus")
}
} catch (e: Exception) {
Logger.e(TAG, "initValueException $propertyId ${e.message}")
}
}
}
注解類
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class CarProperty