Car API 是Android系统中使用Android Automotive特性的系统接口,代码路径在:packages/services/Car/car-lib
从前面知道,Car API 提供了很多的接口类,这里介绍Android Automotive的核心接口之一的CarPropertyManager
。
我们先来介绍一下怎么使用Car API
private void initCarApi() {
if (mCarApi != null && mCarApi.isConnected()) {
mCarApi.disconnect();
mCarApi = null;
}
mCarApi = Car.createCar(this, null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, (Car car, boolean ready) -> {
if (ready) {
initManagers(car);
}
});
}
private void initManagers(Car car) {
synchronized (mPropertyManagerReady) {
mHvacManager = (CarHvacManager) car.getCarManager(
android.car.Car.HVAC_SERVICE);
mPowerManager = (CarPowerManager) car.getCarManager(
android.car.Car.POWER_SERVICE);
mPropertyManager = (CarPropertyManager) car.getCarManager(
android.car.Car.PROPERTY_SERVICE);
mSensorManager = (CarSensorManager) car.getCarManager(
android.car.Car.SENSOR_SERVICE);
mCarAppFocusManager =
(CarAppFocusManager) car.getCarManager(Car.APP_FOCUS_SERVICE);
mCarProjectionManager =
(CarProjectionManager) car.getCarManager(Car.PROJECTION_SERVICE);
mPropertyManagerReady.notifyAll();
}
}
使用Car API一般需要三个流程。
mCarApi = Car.createCar
使用Car
的静态方法获取到Car
实例
public static Car createCar(@NonNull Context context,
@Nullable Handler handler, long waitTimeoutMs,
@NonNull statusChangeListener)
CAR_WAIT_TIMEOUT_WAIT_FOREVER
表示在呼叫中永久等待,直到汽车服务CarService
就绪。
当汽车服务CarService
就绪后,会回调CarServiceLifecycleListener
的void onLifecycleChanged(@NonNull Car car, boolean ready)
接口。
在onLifecycleChanged
回调中,获取子Manager
接口实例,调用子Manager
实例接口实现功能。
用于Android Automotive架构的顶级API接口,此API仅适用具有FEATURE_AUTOMOTIVE的设备。
所有应用在希望使用Android Automotive特性的时候,必须要用过这个API来实现。Car是一个总的功能入口。
Car API 的入口函数,里面含有大量的Manager,通过getCarManager(String)
获取实例CarPropertyManager
也需要用这种方式获取。
public static Car createCar(Context context)
获取Car实例
public static Car createCar(Context context, @Nullable Handler handler)
获取Car实例
public static Car createCar(@NonNull Context context, @Nullable Handler handler, long waitTimeoutMs, @NonNull CarServiceLifecycleListener statusChangeListener)
获取Car实例
public Object getCarManager(String serviceName)
获取子Manager
public boolean isConnected()
判断是否和CarService
保持连接
public void disconnect()
断开和CarService
的连接
CreateCar
方法来获取Car实例,看看代码里都做了什么
public static Car createCar(Context context, @Nullable Handler handler) {
assertNonNullContext(context);
Car car = null;
IBinder service = null;
boolean started = false;
int retryCount = 0;
while (true) {
service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
if (car == null) {
// service can be still null. The constructor is safe for null service.
car = new Car(context, ICar.Stub.asInterface(service),
null /*serviceConnectionListener*/, null /*statusChangeListener*/, handler);
}
if (service != null) {
if (!started) { // specialization for most common case.
// Do this to crash client when car service crashes.
car.startCarService();
return car;
}
break;
}
if (!started) {
car.startCarService();
started = true;
}
retryCount++;
if (retryCount > CAR_SERVICE_BINDER_POLLING_MAX_RETRY) {
Log.e(TAG_CAR, "cannot get car_service, waited for car service (ms):"
+ CAR_SERVICE_BINDER_POLLING_INTERVAL_MS
* CAR_SERVICE_BINDER_POLLING_MAX_RETRY,
new RuntimeException());
return null;
}
try {
Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS);
} catch (InterruptedException e) {
Log.e(CarLibLog.TAG_CAR, "interrupted while waiting for car_service",
new RuntimeException());
return null;
}
}
// Can be accessed from mServiceConnectionListener in main thread.
synchronized (car) {
if (car.mService == null) {
car.mService = ICar.Stub.asInterface(service);
Log.w(TAG_CAR,
"waited for car_service (ms):"
+ CAR_SERVICE_BINDER_POLLING_INTERVAL_MS * retryCount,
new RuntimeException());
}
car.mConnectionState = STATE_CONNECTED;
}
return car;
}
while (true) {
API接口里有个死循环也是万万没想到的啊!
service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
首先获取CarService的服务实例,这里直接通过ServiceManager
比较方便。问题是不一定能取到。
car = new Car(context, ICar.Stub.asInterface(service), null /*serviceConnectionListener*/, null /*statusChangeListener*/, handler);
这里前面方法中声明,所以判断一定是null
,会new一个Car实例。
car.startCarService();
这里实际是去用Bind的方式启动CarService
。
if (retryCount > CAR_SERVICE_BINDER_POLLING_MAX_RETRY) {
这里会有个判断重试的次数,如果超过次数还没取到CarService服务,则会返回null
。sleep
的时间是50ms,重试100次,也就是获取Car
实例最长时间长达5s。
private static final long CAR_SERVICE_BINDER_POLLING_INTERVAL_MS = 50;
private static final long CAR_SERVICE_BINDER_POLLING_MAX_RETRY = 100
去启动CarService
,这里用到的实际是Bind的形式bindServiceAsUser
private void startCarService() {
Intent intent = new Intent();
intent.setPackage(CAR_SERVICE_PACKAGE);
intent.setAction(Car.CAR_SERVICE_INTERFACE_NAME);
boolean bound = mContext.bindServiceAsUser(intent, mServiceConnectionListener,
Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF);
synchronized (mLock) {
if (!bound) {
mConnectionRetryCount++;
if (mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY) {
Log.w(TAG_CAR, "cannot bind to car service after max retry");
mMainThreadEventHandler.post(mConnectionRetryFailedRunnable);
} else {
mEventHandler.postDelayed(mConnectionRetryRunnable,
CAR_SERVICE_BIND_RETRY_INTERVAL_MS);
}
} else {
mEventHandler.removeCallbacks(mConnectionRetryRunnable);
mMainThreadEventHandler.removeCallbacks(mConnectionRetryFailedRunnable);
mConnectionRetryCount = 0;
mServiceBound = true;
}
}
}
这里有个判断mConnectionRetryCount > CAR_SERVICE_BIND_MAX_RETRY
,就是当启动CarService
失败是会重试的,重试多了还不行,则会调用mConnectionRetryFailedRunnable
。这里定义是20次。
private static final long CAR_SERVICE_BIND_MAX_RETRY = 20;
mConnectionRetryFailedRunnable
的定义是会回调onServiceDisconnected
private final Runnable mConnectionRetryFailedRunnable = new Runnable() { @Override public void run() { mServiceConnectionListener.onServiceDisconnected(new ComponentName(CAR_SERVICE_PACKAGE, CAR_SERVICE_CLASS)); }};
connect
方法实际就是调用startCarService
方法,因为connect
是公开的,startCarService
是私有的。
connect
已经弃用了,我们知道startCarService
就是和CarService
建立连接,因为在CreatCar
里已经保证获取到CarService
,所以connect
不在必要。
@Deprecated
public void connect() throws IllegalStateException {
synchronized (mLock) {
if (mConnectionState != STATE_DISCONNECTED) {
throw new IllegalStateException("already connected or connecting");
}
mConnectionState = STATE_CONNECTING;
startCarService();
}
}
createCar
还有个重载方法,这个方法可以自己定义和CarService
连接的超时时间,并且会收到和CarService
连接状态的变化通知。
public static Car createCar(@NonNull Context context,
@Nullable Handler handler, long waitTimeoutMs,
@NonNull CarServiceLifecycleListener statusChangeListener) {
assertNonNullContext(context);
Objects.requireNonNull(statusChangeListener);
Car car = null;
IBinder service = null;
boolean started = false;
int retryCount = 0;
long maxRetryCount = 0;
if (waitTimeoutMs > 0) {
maxRetryCount = waitTimeoutMs / CAR_SERVICE_BINDER_POLLING_INTERVAL_MS;
// at least wait once if it is positive value.
if (maxRetryCount == 0) {
maxRetryCount = 1;
}
}
boolean isMainThread = Looper.myLooper() == Looper.getMainLooper();
while (true) {
service = ServiceManager.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
if (car == null) {
// service can be still null. The constructor is safe for null service.
car = new Car(context, ICar.Stub.asInterface(service), null, statusChangeListener,
handler);
}
if (service != null) {
if (!started) { // specialization for most common case : car service already ready
car.dispatchCarReadyToMainThread(isMainThread);
// Needs this for CarServiceLifecycleListener. Note that ServiceConnection
// will skip the callback as valid mService is set already.
car.startCarService();
return car;
}
// service available after starting.
break;
}
if (!started) {
car.startCarService();
started = true;
}
retryCount++;
if (waitTimeoutMs < 0 && retryCount >= CAR_SERVICE_BINDER_POLLING_MAX_RETRY
&& retryCount % CAR_SERVICE_BINDER_POLLING_MAX_RETRY == 0) {
// Log warning if car service is not alive even for waiting forever case.
Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
+ retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
new RuntimeException());
} else if (waitTimeoutMs >= 0 && retryCount > maxRetryCount) {
if (waitTimeoutMs > 0) {
Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
+ waitTimeoutMs,
new RuntimeException());
}
return car;
}
try {
Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Log.w(TAG_CAR, "interrupted", new RuntimeException());
return car;
}
}
// Can be accessed from mServiceConnectionListener in main thread.
synchronized (car.mLock) {
Log.w(TAG_CAR,
"waited for car_service (ms):"
+ retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
new RuntimeException());
// ServiceConnection has handled everything.
if (car.mService != null) {
return car;
}
// mService check in ServiceConnection prevents calling
// onLifecycleChanged. So onLifecycleChanged should be called explicitly
// but do it outside lock.
car.mService = ICar.Stub.asInterface(service);
car.mConnectionState = STATE_CONNECTED;
}
car.dispatchCarReadyToMainThread(isMainThread);
return car;
}
boolean isMainThread = Looper.myLooper() == Looper.getMainLooper()
判断当前线程是否时主线程
car.dispatchCarReadyToMainThread(isMainThread);
保证回调的内容在主线程。
private void dispatchCarReadyToMainThread(boolean isMainThread) {
if (isMainThread) {
mStatusChangeCallback.onLifecycleChanged(this, true);
} else {
// should dispatch to main thread.
mMainThreadEventHandler.post(
() -> mStatusChangeCallback.onLifecycleChanged(this, true));
}
}
getCarManager
通过一个字符串(比如public static final String PROPERTY_SERVICE = "property";
)获取子Manager对象。
public Object getCarManager(String serviceName) {
CarManagerBase manager;
synchronized (mLock) {
if (mService == null) {
Log.w(TAG_CAR, "getCarManager not working while car service not ready");
return null;
}
manager = mServiceMap.get(serviceName);
if (manager == null) {
try {
IBinder binder = mService.getCarService(serviceName);
if (binder == null) {
Log.w(TAG_CAR, "getCarManager could not get binder for service:"
+ serviceName);
return null;
}
manager = createCarManagerLocked(serviceName, binder);
if (manager == null) {
Log.w(TAG_CAR, "getCarManager could not create manager for service:"
+ serviceName);
return null;
}
mServiceMap.put(serviceName, manager);
} catch (RemoteException e) {
handleRemoteExceptionFromCarService(e);
}
}
}
return manager;
}
IBinder binder = mService.getCarService(serviceName);
这里是用CarService中拿对应子服务的Binder对象。CarPropertyManager
是提供与车辆特定属性交互的应用程序接口。实际连接的CarService
中的CarPropertyService
。
代码路径:packages/services/Car/car-lib/src/android/car/hardware/property/CarPropertyManager.java
public boolean registerCallback(@NonNull CarPropertyEventCallback callback, int propertyId, @FloatRange(from = 0.0, to = 100.0) float rate)
public void unregisterCallback(@NonNull CarPropertyEventCallback callback)
public void unregisterCallback(@NonNull CarPropertyEventCallback callback, int propertyId)
public List<CarPropertyConfig> getPropertyList()
public List<CarPropertyConfig> getPropertyList(@NonNull ArraySet<Integer> propertyIds)
public CarPropertyConfig<?> getCarPropertyConfig(int propId)
public int getAreaId(int propId, int area)
public String getReadPermission(int propId)
public String getWritePermission(int propId)
public boolean isPropertyAvailable(int propId, int area)
public boolean getBooleanProperty(int prop, int area)
public float getFloatProperty(int prop, int area)
public int getIntProperty(int prop, int area)
public int[] getIntArrayProperty(int prop, int area)
public <E> CarPropertyValue<E> getProperty(@NonNull Class<E> clazz, int propId, int areaId)
public <E> CarPropertyValue<E> getProperty(int propId, int areaId)
public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val)
public void setBooleanProperty(int prop, int areaId, boolean val)
public void setFloatProperty(int prop, int areaId, float val)
public void setIntProperty(int prop, int areaId, int val)
public void onCarDisconnected()
接口
//构造方法
public CarPropertyManager(Car car, @NonNull ICarProperty service);
//返回areaId包含属性的属性区域
public int getAreaId(int propId, int area);
//返回boolen类型的属性值
public boolean getBooleanProperty(int prop, int area);
//根据propertyId获取CarPropertyConfig
public CarPropertyConfig<?> getCarPropertyConfig(int propId);
//返回float类型的属性值
public float getFloatProperty(int prop, int area);
//返回int[]类型的属性值
public int[] getIntArrayProperty(int prop, int area);
//返回int类型的属性值
public int getIntProperty(int prop, int area);
//返回CarPropertyValue
public <E> CarPropertyValue<E> getProperty(@NonNull Class<E> clazz, int propId, int areaId);
//返回CarPropertyValue
public <E> CarPropertyValue<E> getProperty(int propId, int areaId);
//返回车辆属性列表
public List<CarPropertyConfig> getPropertyList(@NonNull ArraySet<Integer> propertyIds);
//返回给定属性ID的读取权限
public String getReadPermission(int propId);
//返回给定属性ID的写入权限
public String getWritePermission(int propId);
//根据汽车的当前状态检查给定属性是否可用或禁用
public boolean isPropertyAvailable(int propId, int area);
//和车辆服务断开连接
public void onCarDisconnected();
//注册侦听器以获取属性更新。
public boolean registerCallback(@NonNull CarPropertyEventCallback callback, int propertyId, @FloatRange(from = 0.0, to = 100.0) float rate);
//设置boolean类型的值
public void setBooleanProperty(int prop, int areaId, boolean val);
//设置float类型的值
public void setFloatProperty(int prop, int areaId, float val);
//设置int类型的值
public void setIntProperty(int prop, int areaId, int val);
//设置其它类型的值
public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val);
//取消监听器
public void unregisterCallback(@NonNull CarPropertyEventCallback callback);
//取消某个id的监听器
public void unregisterCallback(@NonNull CarPropertyEventCallback callback, int propertyId);
public CarPropertyManager(Car car, @NonNull ICarProperty service) {
super(car);
mService = service;
mAppTargetSdk = getContext().getApplicationInfo().targetSdkVersion;
try {
List<CarPropertyConfig> configs = mService.getPropertyList();
for (CarPropertyConfig carPropertyConfig : configs) {
mConfigMap.put(carPropertyConfig.getPropertyId(), carPropertyConfig);
}
} catch (RemoteException e) {
Log.e(TAG, "getPropertyList exception ", e);
throw new RuntimeException(e);
}
Handler eventHandler = getEventHandler();
if (eventHandler == null) {
mHandler = null;
return;
}
mHandler = new SingleMessageHandler<CarPropertyEvent>(eventHandler.getLooper(),
MSG_GENERIC_EVENT) {
@Override
protected void handleEvent(CarPropertyEvent event) {
CarPropertyListeners listeners;
synchronized (mActivePropertyListener) {
listeners = mActivePropertyListener.get(
event.getCarPropertyValue().getPropertyId());
}
if (listeners != null) {
switch (event.getEventType()) {
case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
listeners.onPropertyChanged(event);
break;
case CarPropertyEvent.PROPERTY_EVENT_ERROR:
listeners.onErrorEvent(event);
break;
default:
throw new IllegalArgumentException();
}
}
}
};
}
mService = service
初始化mService
,该变量时类Car
传进来的。List<CarPropertyConfig> configs = mService.getPropertyList();
获取全部车辆属性的配置mConfigMap.put(carPropertyConfig.getPropertyId(), carPropertyConfig);
将配置存入mConfigMap
Handler eventHandler = getEventHandler()
获取Handler
对象,eventHandler
是创建Car
时,由应用传进来的,如果没有传或者传入时null
,会默认使用主线程的Handler
mHandler = new SingleMessageHandler
创建一个回调车辆属性变化事件的Handler
,回调会在传入Handler
所在的线程。获取一个车辆属性值,这里会直接调用到CarPropertyService
public <E> CarPropertyValue<E> getProperty(int propId, int areaId) {
checkSupportedProperty(propId);
try {
CarPropertyValue<E> propVal = mService.getProperty(propId, areaId);
return propVal;
} catch (RemoteException e) {
return handleRemoteExceptionFromCarService(e, null);
} catch (ServiceSpecificException e) {
if (mAppTargetSdk < Build.VERSION_CODES.R) {
if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
return null;
} else {
throw new IllegalStateException(String.format("Failed to get property: 0x%x, "
+ "areaId: 0x%x", propId, areaId));
}
}
return handleCarServiceSpecificException(e.errorCode, propId, areaId, null);
}
}
设置一个车辆属性值,这里会直接调用到CarPropertyService
public <E> void setProperty(@NonNull Class<E> clazz, int propId, int areaId, @NonNull E val) {
if (DBG) {
Log.d(TAG, "setProperty, propId: 0x" + toHexString(propId)
+ ", areaId: 0x" + toHexString(areaId) + ", class: " + clazz + ", val: " + val);
}
checkSupportedProperty(propId);
try {
if (mCarPropertyEventToService == null) {
mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
}
mService.setProperty(new CarPropertyValue<>(propId, areaId, val),
mCarPropertyEventToService);
} catch (RemoteException e) {
handleRemoteExceptionFromCarService(e);
} catch (ServiceSpecificException e) {
if (mAppTargetSdk < Build.VERSION_CODES.R) {
if (e.errorCode == VehicleHalStatusCode.STATUS_TRY_AGAIN) {
throw new RuntimeException(String.format("Failed to set property: 0x%x, "
+ "areaId: 0x%x", propId, areaId));
} else {
throw new IllegalStateException(String.format("Failed to set property: 0x%x, "
+ "areaId: 0x%x", propId, areaId));
}
}
handleCarServiceSpecificException(e.errorCode, propId, areaId, null);
}
}
订阅一个车辆属性值变化,这里会调用到CarPropertyService
public boolean registerCallback(@NonNull CarPropertyEventCallback callback,
int propertyId, @FloatRange(from = 0.0, to = 100.0) float rate) {
synchronized (mActivePropertyListener) {
if (mCarPropertyEventToService == null) {
mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
}
CarPropertyConfig config = mConfigMap.get(propertyId);
if (config == null) {
Log.e(TAG, "registerListener: propId is not in config list: " + propertyId);
return false;
}
if (config.getChangeMode() == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE) {
rate = SENSOR_RATE_ONCHANGE;
}
boolean needsServerUpdate = false;
CarPropertyListeners listeners;
listeners = mActivePropertyListener.get(propertyId);
if (listeners == null) {
listeners = new CarPropertyListeners(rate);
mActivePropertyListener.put(propertyId, listeners);
needsServerUpdate = true;
}
if (listeners.addAndUpdateRate(callback, rate)) {
needsServerUpdate = true;
}
if (needsServerUpdate) {
if (!registerOrUpdatePropertyListener(propertyId, rate)) {
return false;
}
}
}
return true;
}
CarCabinManager
弃用,使用CarPropertyManager替代
CarHvacManager
弃用,使用CarPropertyManager替代
CarSensorManager
弃用,使用CarPropertyManager替代
CarVendorExtensionManager
弃用,使用CarPropertyManager替代
应用订阅车辆属性变化的接口
public interface CarPropertyEventCallback {
/**
* Called when a property is updated
* @param value Property that has been updated.
*/
void onChangeEvent(CarPropertyValue value);
/**
* Called when an error is detected when setting a property.
*
* @param propId Property ID which is detected an error.
* @param zone Zone which is detected an error.
*
* @see CarPropertyEventCallback#onErrorEvent(int, int, int)
*/
void onErrorEvent(int propId, int zone);
/**
* Called when an error is detected when setting a property.
*
* <p>Clients which changed the property value in the areaId most recently will receive
* this callback. If multiple clients set a property for the same area id simultaneously,
* which one takes precedence is undefined. Typically, the last set operation
* (in the order that they are issued to car's ECU) overrides the previous set operations.
* The delivered error reflects the error happened in the last set operation.
*
* @param propId Property ID which is detected an error.
* @param areaId AreaId which is detected an error.
* @param errorCode Error code is raised in the car.
*/
default void onErrorEvent(int propId, int areaId, @CarSetPropertyErrorCode int errorCode) {
if (DBG) {
Log.d(TAG, "onErrorEvent propertyId: 0x" + toHexString(propId) + " areaId:0x"
+ toHexString(areaId) + " ErrorCode: " + errorCode);
}
onErrorEvent(propId, areaId);
}
}
void onChangeEvent(CarPropertyValue value);
void onErrorEvent(int propId, int zone);
default void onErrorEvent(int propId, int areaId, @CarSetPropertyErrorCode int errorCode)
车辆属性的配置信息封装类。
public final class CarPropertyConfig<T> implements Parcelable {
private final int mAccess;
private final int mAreaType;
private final int mChangeMode;
private final ArrayList<Integer> mConfigArray;
private final String mConfigString;
private final float mMaxSampleRate;
private final float mMinSampleRate;
private final int mPropertyId;
private final SparseArray<AreaConfig<T>> mSupportedAreas;
private final Class<T> mType;
车辆属性数据对象的封装类。里面有property、area、status、mtimestamp、value等信息。
public final class CarPropertyValue<T> implements Parcelable {
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private final int mPropertyId;
private final int mAreaId;
private final int mStatus;
private final long mTimestamp;
private final T mValue;
VehiclePropertyIds
是复制自android.hardware.automotive.vehicle-V2.0-java_gen_java/gen/android/hardware/automotive/vehicle/V2_0
。VHAL的车辆属性变化时,需要更新该文件。
该文件描述了所有支持的车辆属性,并且直接显示了types.hal文件中定义属性的最终值。上层应用可以直接调用API。
代码路径:packages/services/Car/car-lib/src/android/car/VehiclePropertyIds.java
常用方法
public int getPropertyId()
public int getAreaId()
public @PropertyStatus int getStatus()
public long getTimestamp()
public T getValue()
还有一些和车辆属性相关的类如下
VehiclePropertyIds
VehicleAreaType
VehicleAreaDoor
VehicleAreaMirror
VehicleAreaSeat
VehicleAreaWheel
VehicleAreaWindow
VehiclePropertyAccess
VehicleUnit
CarPropertyValue
car-lib中定义的一个类,用于car-lib和service通信的数据结构
代码路径:
packages/services/Car/car-lib/src/android/car/hardware/CarPropertyValue.java
packages/services/Car/car-lib/src/android/car/hardware/CarPropertyValue.aidl
CarPropertyConfig
表示有关汽车特性的常规信息,例如汽车区域的数据类型和最小/最大范围(如果适用)。这个类应该是不可变的,可打包的,并且可以传递。
代码路径:
packages/services/Car/car-lib/src/android/car/hardware/CarPropertyConfig.java
packages/services/Car/car-lib/src/android/car/hardware/CarPropertyConfig.aidl
private final int mAccess; //定义属性是读还是写,或者两者都是
private final int mAreaType; //p.prop & VehicleArea.MASK
private final int mChangeMode; //定义属性的更改模式
private final ArrayList<Integer> mConfigArray; //包含其他配置参数
private final String mConfigString; //某些属性可能需要传递其他信息
private final float mMaxSampleRate; //最大采样率
private final float mMinSampleRate; //最小采样率
private final int mPropertyId; //属性标识符 p.prop
private final SparseArray<AreaConfig<T>> mSupportedAreas; //包含每个区域的配置
private final Class<T> mType; //p.prop & VehiclePropertyType.MASK
VehiclePropConfig
和CarPropertyConfig
"CarPropertyConfig{"
+ "mPropertyId=" + mPropertyId /*id int*/
+ ", mAccess=" + mAccess /*读写权限 int*/
+ ", mAreaType=" + mAreaType /*区域类型 int*/
+ ", mChangeMode=" + mChangeMode /*变化模式 int*/
+ ", mConfigArray=" + mConfigArray /*配置参数 ArrayList<Integer>*/
+ ", mConfigString=" + mConfigString /*某些属性可能需要此属性传值 String*/
+ ", mMaxSampleRate=" + mMaxSampleRate /*最大采样率 float*/
+ ", mMinSampleRate=" + mMinSampleRate /*最小采样率 float*/
+ ", mSupportedAreas=" + mSupportedAreas /*属性的区域ID数 SparseArray<AreaConfig<T>>*/
+ ", mType=" + mType /*属性值的数据类型 Class<T>*/
+ '}';
VehiclePropConfig
是HIDL接口中定义的车辆属性配置,用于和HAL层以下通信
CarPropertyConfig
是AIDL中定义的车辆属性配置,用于和应用层通信
注意:
car-lib的接口实现不同Android版本存在一些差异,调用的时候需要适配一下。
Car API的使用可以参考packages/services/Car/tests
目录下的EmbeddedKitchenSinkApp工程。
Android Q之前调用Car.createCar
之后还需要调用connect
接口, 并且Android Q开始,放弃了android.support.car.Car
的使用。Android R开始,不再需要调用connect
接口并且connect
接口被加上了@Deprecated
标签, 不再推荐使用.