上篇文章介绍了Android汽车服务篇(一) CarService , 接下来我们继续看看 CarPropertyService, 这个服务也是很重要的, 绝大部分与车辆硬件功能相关联的属性,如空调, 车舱功能, 车辆传感器等都是通过CarPropertyService来读取或者设置的.
CarPropertyManager 是CarPropertyService在客户端的代理, 通过CarPropertyManager提供的API,可以设置和获取车辆各个属性的状态. 结论的有力支撑还是得看源码
在packages/services/Car/service/src/com/android/car/ICarImpl.java的 getCarService方法中
@Override
public IBinder getCarService(String serviceName) {
....
case Car.CABIN_SERVICE:
case Car.HVAC_SERVICE:
case Car.INFO_SERVICE:
case Car.PROPERTY_SERVICE:
case Car.SENSOR_SERVICE:
case Car.VENDOR_EXTENSION_SERVICE:
return mCarPropertyService;
....
}
可以看到 CarPropertyService同时对应着 CarCabinManager, CarHvacManager, CarInfoManager, CarPropertyManager, CarSensorManager和 CarVendorExtensionManager这六个对象, 可以说是一个服务分担多个角色. 所以在Android10之后, 谷歌直接推荐使用CarPropertyManager.
本文对上面的6个Manager 分别介绍其属性和用法
CarInfoManager的用法, 我们先来介绍一下它的API
//测试CarInfoManager的API
private void testCarInfoManagerAPI() {
Car car = Car.createCar(this);
CarInfoManager carInfoManager = (CarInfoManager) car.getCarManager(Car.INFO_SERVICE);
//电池容量
float batteryCapacity = carInfoManager.getEvBatteryCapacity();
//充电连接器类型
int[] connectorTypes = carInfoManager.getEvConnectorTypes();
// 燃油容量
float fuelCapacity = carInfoManager.getFuelCapacity();
// 燃料类型
int[] fuelTypes = carInfoManager.getFuelTypes();
// 制造商
String manufacturer = carInfoManager.getManufacturer();
//车型年份
int modeYear = carInfoManager.getModelYearInInteger();
// 车型
String model = carInfoManager.getModel();
Log.e("test", "batteryCapacity :" +batteryCapacity
+ "connectorTypes size :" + connectorTypes.length + "fuelCapacity :" +fuelCapacity
+" fuelTypes size :" + fuelTypes.length + " manufacturer :" +manufacturer
+" int modeYear :" + modeYear + "String model :" +model);
}
CarInfoManager中的API不多,而且从方法的名称也很容易了解其具体的功能. 需要注意的是它对应权限的申请, 否则运行的时候会抛出异常, 因此需要在你的清单文件中增加对应的权限:
声明了相应的权限,并且获取CarInfoManager的实例后就能调用相关的接口了, 如果想要获取车辆的型号,能源型号,电池容量等信息,那就使用CarInfoManager吧
顾名思义CarSensorManager主要对应的就是和车辆传感器相关的一些功能, 相比手机,车辆的传感器种类要更丰富多彩, 特别是随着汽车越来越智能化,自动驾驶等功能的加入,传感器的数量还会不断增加.
车辆的智能控制功能都和传感器的数据有着密切的关系,如自动空调,自动控制灯光,驾驶座位自动调整等.
做过android开发的,可能会有个疑问, 在手机平板终端等设备上,使用 SensorManager也是获取传感器的数据, 那么CarSensorManager它又是获取哪些传感器参数呢?
实质上,在AAOS中,我们可以把CarSensorManager看做SensorManager的一个补充
传感器Manager | 关联的传感器 |
CarSensorManager(车辆相关的) | 车速, 发动机转速,油量,点火状态等 |
SensorManager | 陀螺仪,加速度计,磁力传感器等 |
它们两者各司其职, 可以为开发者提供不同种类的传感器数据.
下面,我们继续看看CarSensorManager的使用API
在Car连接成功后通过getCarManager方法获取CarSensorManager的实例
CarSensorManager carSensorManager = (CarSensorManager)car.getCarManager(Car.SENSOR_SERVICE);
在CarSensorManager中包含了汽车特有的传感器类型,如车速,发动机转速等,如下表中介绍:
属性 | 类型 | 权限 | 系统权限 |
SENSOR_TYPE_CAR_SPEED | 车速 | CAR_SPEED | 否 |
SENSOR_TYPE_RPM | 转速 | CAR_ENGINE_DETAILED | 是 |
SENSOR_TYPE_ODOMETER | 里程数 | CAR_MILEAGE | 是 |
SENSOR_TYPE_FUEL_LEVEL | 油量 | CAR_ENERGY | 否 |
SENSOR_TYPE_PARKING_BRAKE | 驻车制动 | CAR_POWERTRAIN | 否 |
SENSOR_TYPE_GEAR | 档位 | CAR_POWERTRAIN | 否 |
SENSOR_TYPE_NIGHT | 白天黑夜 | CAR_EXTERIOR_ENVIRONMENT | 否 |
SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE | 车外环境温度 | CAR_EXTERIOR_ENVIRONMENT | 否 |
SENSOR_TYPE_IGNITION_STATE | 点火状态 | CAR_POWERTRAIN | 否 |
SENSOR_TYPE_WHEEL_TICK_DISTANCE | 轮距 | CAR_SPEED | 否 |
SENSOR_TYPE_ABS_ACTIVE | ABS状态 | CAR_DYNAMICS_STATE | 是 |
SENSOR_TYPE_TRACTION_CONTROL_ACTIVE | 牵引力控制 | CAR_DYNAMICS_STATE | 是 |
SENSOR_TYPE_FUEL_DOOR_OPEN | 加油口状态 | CAR_ENERGY_PORTS | 否 |
SENSOR_TYPE_EV_BATTERY_LEVEL | 电量值 | CAR_ENERGY | 否 |
SENSOR_TYPE_EV_CHARGE_PORT_OPEN | 充电口状态 | CAR_ENERGY_PORTS | 否 |
SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED | 充电连接状态 | CAR_ENERGY_PORTS | 否 |
SENSOR_TYPE_EV_BATTERY_CHARGE_RATE | 充电速率 | CAR_ENERGY | 否 |
SENSOR_TYPE_ENGINE_OIL_LEVEL | 机油量 | CAR_ENGINE_DETAILED | 是 |
具体的可以查看CarSensorManager.java 中的所有的成员变量介绍.
表中的权限列,省略了包名部分: android.car.permission, 在清单文件中应该使用完整的声明:
如:"
表中的是否为系统权限: 指的是 Android 中保护级别为 "signature | privileged"以上的权限
通过CarSensorManager中定义的不同属性,可以获取相应的传感器参数. 这里以车速为例
private void testCarSensorManagerAPI() {
Car car = Car.createCar(this);
CarSensorManager carSensorManager = (CarSensorManager)car.getCarManager(Car.SENSOR_SERVICE);
if (carSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_CAR_SPEED)) {
CarSensorEvent event = carSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_CAR_SPEED);
if (event != null) {
CarSensorEvent.CarSpeedData data = event.getCarSpeedData(null);
Log.e("test", "Speed :" + data.carSpeed);
}
}
}
首先,通过isSensorSupported方法判断当前是否支持该传感器类型,如果返回false, 说明当前车辆上是不提供该传感器的数据
如果支持,就可以调用getLatestSensorEvent方法来获取最近一次的传感器数据.
CarSensorEvent中包含很多内部类,对应不同的传感器类型,通过对应的方法就可以获取到数据了.
..... //当然还有很多其他的内部类, 请查看源码
public static class CarEvChargePortConnectedData {
public long timestamp;
public boolean evChargePortIsConnected;
private CarEvChargePortConnectedData() {
}
}
public static class CarEvChargePortOpenData {
public long timestamp;
public boolean evChargePortIsOpen;
private CarEvChargePortOpenData() {
}
}
public static class CarEvBatteryLevelData {
public long timestamp;
public float evBatteryLevel;
private CarEvBatteryLevelData() {
}
}
.....
除了主动获取传感器的数据外,还可以注册监听器接受传感器数据变化的通知. 方法如下:
//new 一个监听器
CarSensorManager.OnSensorChangedListener mListener = new CarSpeedSensorListener();
//注册监听器
Car car = Car.createCar(this);
CarSensorManager carSensorManager = (CarSensorManager)car.getCarManager(Car.SENSOR_SERVICE);
carSensorManager.registerListener(mListener, CarSensorManager.SENSOR_TYPE_CAR_SPEED,
CarSensorManager.SENSOR_RATE_NORMAL);
class CarSpeedSensorListener implements CarSensorManager.OnSensorChangedListener {
@Override
public void onSensorChanged(CarSensorEvent carSensorEvent) {
Log.e("test", "onSensorChanged :" + carSensorEvent);
if (carSensorEvent.sensorType == CarSensorManager.SENSOR_TYPE_CAR_SPEED) {
CarSensorEvent.CarSpeedData data = carSensorEvent.getCarSpeedData(null);
Log.e("test", "Speed :" + data.carSpeed);
}
}
}
调用CarSensorManager中的 registerListener方法来注册监听器,参数中传入需要监听的传感器类型和接收频率.
关于接收频率,根据传感器的功能和类型不同,事件上报的特点,大致可以分为三类:
1. 持续上报的传感器类型(如当前车速)
2. 变化时上报的传感器事件(如油箱盖打开)
3. 一次性上报的传感器事件(如低电量)
CarSensorManager很好的支持了主动获取和订阅这两种获取传感器数据的方式,同时支持设置传感器事件上报的频率. 在大多数情况下,相信可以满足客户端的使用场景了.
Hvac 全称供暖通风与空气调节(Heating Ventilation and Air Conditioning), 它是空调系统相关功能的服务, AAOS定义了标准的CarHvacManager API来提供相关的功能, 通过该服务可以实现对空调系统的监听和控制. 注意CarHvacManager所涉及的属性都是需要有系统级别的权限. 所以第三方应用目前是无法直接使用CarHvacManager的.
老规矩,我们还是看看它是怎么使用的
通过以下方法获取CarHvacManager对象实例:
Car car = Car.createCar(this);
CarHvacManager carHvacManager = (CarHvacManager)car.getCarManager(Car.HVAC_SERVICE);
CarHvacManager中的属性不仅是"只读"的, 而且还是"可写"的, 也是说,通过设定特定值可以对相关的功能进行控制. 列举属性如下:
属性 | 类型 | 功能 |
ID_MIRROR_DEFROSTER_ON | bool | 后视镜除霜 |
ID_STEERING_WHEEL_HEAT | int | 方向盘加热 |
ID_OUTSIDE_AIR_TEMP | float | 车外温度 |
ID_TEMPERATURE_DISPLAY_UNITS | int | 温标(华氏度和摄氏度) |
ID_ZONED_TEMP_SETPOINT | float | 温度 |
ID_ZONED_TEMP_ACTUAL | float | 实际温度 |
ID_ZONED_HVAC_POWER_ON | bool | 空调系统开关 |
ID_ZONED_FAN_SPEED_SETPOINT | int | 风速 |
ID_ZONED_FAN_SPEED_RPM | int | 风扇转速 |
ID_ZONED_FAN_DIRECTION_AVAILABLE | vector | 可用风向 |
ID_ZONED_FAN_DIRECTION | int | 风向 |
ID_ZONED_SEAT_TEMP | int | 座椅温度 |
ID_ZONED_AC_ON | bool | AC开关 |
ID_ZONED_AUTOMATIC_MODE_ON | bool | 自动空调 |
ID_ZONED_AIR_RECIRCULATION_ON | bool | 空调循环 |
ID_ZONED_MAX_AC_ON | bool | 强力空调 |
ID_ZONED_DUAL_ZONE_ON | bool | 多区域空调 |
ID_ZONED_MAX_DEFROST_ON | bool | 强力除霜 |
ID_ZONED_HVAC_AUTO_RECIRC_ON | bool | 自动空气循环 |
ID_WINDOW_DEFROSTER_ON | bool | 车窗除霜 |
示例: 设置空调温度
在权限上, CarHvacManager中的大部分属性所关联的权限都是CONTROL_CAR_CLIMATE, 因此为了成功调节空调温度,首先需要在清单文件中声明此权限
需要说明的是该权限的保护级别是"signature | privileged". 因此想要获取此权限, 我们需要以系统应用的身份运行
这里的系统应用就是指拥有系统签名 或者 安装在 priv-app 目录下的应用
如果不清楚这块的话,可以翻一翻笔者的这篇文章: Android 权限(一):权限大全
Car car = Car.createCar(this);
CarHvacManager carHvacManager = (CarHvacManager)car.getCarManager(Car.HVAC_SERVICE);
List carPropertyConfigList = carHvacManager.getPropertyList();
int zone = VehicleAreaSeat.SEAT_ROW_1_LEFT;
boolean support = false;
float max = 0f;
float min = 0f;
for (CarPropertyConfig prop : carPropertyConfigList) {
//温度属性
if (prop.getPropertyId() == ID_ZONED_TEMP_SETPOINT) {
for (int areaID : prop.getAreaIds()) {
if ((zone & areaID) == zone) {
//获取正确的位置
zone = areaID;
support = true;
}
}
max = (Float)prop.getMaxValue();
min = (Float)prop.getMinValue();
break;
}
}
if(support && carHvacManager.isPropertyAvailable(ID_ZONED_TEMP_SETPOINT, zone)) {
//获取当前温度
float current = carHvacManager.getFloatProperty(ID_ZONED_TEMP_SETPOINT, zone);
++current;
if (max > current && min < current) {
//设置新的温度
carHvacManager.setFloatProperty(ID_ZONED_TEMP_SETPOINT, zone, current);
}
}
CarHvacManager同样提供了方法用于监听属性的变化. 注册监听器的方法如下:
//注册监听器
carHvacManager.registerCallback(new CarHvacManager.CarHvacEventCallback() {
@Override
public void onChangeEvent(CarPropertyValue carPropertyValue) {
}
@Override
public void onErrorEvent(int i, int i1) {
}
});
//移除监听器
carHvacManager.unregisterCallback(CarHvacManager.CarHvacEventCallback接口对象);
通过registerCallback方法可以在属性的值发生变化的时候获取回调. 它监听了CarHvacManager相关的所有属性的变化,如果要知道是哪个属性发生了变化就需要通过回调方法中CarPropertyValue参数进一步的判断.
当然在完成后,千万要记得移除监听器, 以免发生内存泄露.