Android汽车服务篇(二) CarPropertyService上篇

一. 简介

        上篇文章介绍了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

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

        顾名思义CarSensorManager主要对应的就是和车辆传感器相关的一些功能, 相比手机,车辆的传感器种类要更丰富多彩, 特别是随着汽车越来越智能化,自动驾驶等功能的加入,传感器的数量还会不断增加.

        车辆的智能控制功能都和传感器的数据有着密切的关系,如自动空调,自动控制灯光,驾驶座位自动调整等.

        做过android开发的,可能会有个疑问, 在手机平板终端等设备上,使用 SensorManager也是获取传感器的数据,   那么CarSensorManager它又是获取哪些传感器参数呢?

        实质上,在AAOS中,我们可以把CarSensorManager看做SensorManager的一个补充

传感器Manager 关联的传感器
CarSensorManager(车辆相关的) 车速, 发动机转速,油量,点火状态等
SensorManager 陀螺仪,加速度计,磁力传感器等

它们两者各司其职, 可以为开发者提供不同种类的传感器数据.

下面,我们继续看看CarSensorManager的使用API

3.1 获取CarSensorManager对象

        在Car连接成功后通过getCarManager方法获取CarSensorManager的实例

 CarSensorManager carSensorManager = (CarSensorManager)car.getCarManager(Car.SENSOR_SERVICE);

3.2 CarSensorManager中的属性介绍

在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"以上的权限

3.3 获取传感器数据

通过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() {
        }
    }
.....

3.4 监听传感器数据变化

除了主动获取传感器的数据外,还可以注册监听器接受传感器数据变化的通知. 方法如下:

        //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很好的支持了主动获取和订阅这两种获取传感器数据的方式,同时支持设置传感器事件上报的频率. 在大多数情况下,相信可以满足客户端的使用场景了.

四. 车内空调系统服务 CarHvacManager

        Hvac 全称供暖通风与空气调节(Heating Ventilation and Air Conditioning), 它是空调系统相关功能的服务, AAOS定义了标准的CarHvacManager API来提供相关的功能, 通过该服务可以实现对空调系统的监听和控制.  注意CarHvacManager所涉及的属性都是需要有系统级别的权限. 所以第三方应用目前是无法直接使用CarHvacManager的.

        老规矩,我们还是看看它是怎么使用的

4.1 获取CarHvacManager对象

通过以下方法获取CarHvacManager对象实例:

  Car car = Car.createCar(this);
  CarHvacManager carHvacManager = (CarHvacManager)car.getCarManager(Car.HVAC_SERVICE);

4.2 CarHvacManager的属性

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);
            }
        }

4.3 注册监听器

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参数进一步的判断.

当然在完成后,千万要记得移除监听器, 以免发生内存泄露.

你可能感兴趣的:(Android,Automotive,Android车载开发)