android 車載信號框架搭建

設(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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容