Add CarGenericManager and refactor HVAC to use it
Change-Id: I0af862f8da2259069a5be0d17efb1f82a208fa76
diff --git a/service/src/com/android/car/CarHvacService.java b/service/src/com/android/car/CarHvacService.java
index ab09f60..173e307 100644
--- a/service/src/com/android/car/CarHvacService.java
+++ b/service/src/com/android/car/CarHvacService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,182 +17,13 @@
package com.android.car;
import android.car.Car;
-import android.car.hardware.hvac.CarHvacEvent;
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.hvac.ICarHvac;
-import android.car.hardware.hvac.ICarHvacEventListener;
import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.car.hal.HvacHalService;
+import com.android.car.CarLog;
import com.android.car.hal.VehicleHal;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class CarHvacService extends ICarHvac.Stub
- implements CarServiceBase, HvacHalService.HvacHalListener {
- public static final boolean DBG = true;
- public static final String TAG = CarLog.TAG_HVAC + ".CarHvacService";
-
- private HvacHalService mHvacHal;
- private final Map<IBinder, ICarHvacEventListener> mListenersMap = new HashMap<>();
- private final Map<IBinder, HvacDeathRecipient> mDeathRecipientMap = new HashMap<>();
- private final Context mContext;
-
+public class CarHvacService extends CarPropertyServiceBase {
public CarHvacService(Context context) {
- mHvacHal = VehicleHal.getInstance().getHvacHal();
- mContext = context;
- }
-
- class HvacDeathRecipient implements IBinder.DeathRecipient {
- private static final String TAG = CarHvacService.TAG + ".HvacDeathRecipient";
- private IBinder mListenerBinder;
-
- HvacDeathRecipient(IBinder listenerBinder) {
- mListenerBinder = listenerBinder;
- }
-
- /**
- * Client died. Remove the listener from HAL service and unregister if this is the last
- * client.
- */
- @Override
- public void binderDied() {
- if (DBG) {
- Log.d(TAG, "binderDied " + mListenerBinder);
- }
- CarHvacService.this.unregisterListenerLocked(mListenerBinder);
- }
-
- void release() {
- mListenerBinder.unlinkToDeath(this, 0);
- }
- }
-
- @Override
- public synchronized void init() {
- }
-
- @Override
- public synchronized void release() {
- for (HvacDeathRecipient recipient : mDeathRecipientMap.values()) {
- recipient.release();
- }
- mDeathRecipientMap.clear();
- mListenersMap.clear();
- }
-
- @Override
- public void dump(PrintWriter writer) {
- // TODO
- }
-
- @Override
- public synchronized void registerListener(ICarHvacEventListener listener) {
- if (DBG) {
- Log.d(TAG, "registerListener");
- }
- ICarImpl.assertHvacPermission(mContext);
- if (listener == null) {
- Log.e(TAG, "registerListener: Listener is null.");
- throw new IllegalArgumentException("listener cannot be null.");
- }
-
- IBinder listenerBinder = listener.asBinder();
- if (mListenersMap.containsKey(listenerBinder)) {
- // Already registered, nothing to do.
- return;
- }
-
- HvacDeathRecipient deathRecipient = new HvacDeathRecipient(listenerBinder);
- try {
- listenerBinder.linkToDeath(deathRecipient, 0);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to link death for recipient. " + e);
- throw new IllegalStateException(Car.CAR_NOT_CONNECTED_EXCEPTION_MSG);
- }
- mDeathRecipientMap.put(listenerBinder, deathRecipient);
-
- if (mListenersMap.isEmpty()) {
- mHvacHal.setListener(this);
- }
-
- mListenersMap.put(listenerBinder, listener);
- }
-
- @Override
- public synchronized void unregisterListener(ICarHvacEventListener listener) {
- if (DBG) {
- Log.d(TAG, "unregisterListener");
- }
- ICarImpl.assertHvacPermission(mContext);
- if (listener == null) {
- Log.e(TAG, "unregisterListener: Listener is null.");
- throw new IllegalArgumentException("Listener is null");
- }
-
- IBinder listenerBinder = listener.asBinder();
- if (!mListenersMap.containsKey(listenerBinder)) {
- Log.e(TAG, "unregisterListener: Listener was not previously registered.");
- }
- unregisterListenerLocked(listenerBinder);
- }
-
- // Removes the listenerBinder from the current state.
- // The function assumes that the binder will exist both in listeners and death recipients list.
- private void unregisterListenerLocked(IBinder listenerBinder) {
- Object status = mListenersMap.remove(listenerBinder);
-
- if (status != null) {
- mDeathRecipientMap.get(listenerBinder).release();
- mDeathRecipientMap.remove(listenerBinder);
- }
-
- if (mListenersMap.isEmpty()) {
- mHvacHal.setListener(null);
- }
- }
-
- @Override
- public synchronized List<CarPropertyConfig> getHvacProperties() {
- ICarImpl.assertHvacPermission(mContext);
- return mHvacHal.getHvacProperties();
- }
-
- @Override
- public synchronized CarPropertyValue getProperty(int prop, int zone) {
- ICarImpl.assertHvacPermission(mContext);
- return mHvacHal.getHvacProperty(prop, zone);
- }
-
- @Override
- public synchronized void setProperty(CarPropertyValue prop) {
- ICarImpl.assertHvacPermission(mContext);
- mHvacHal.setHvacProperty(prop);
- }
-
- // Implement HvacHalListener interface
- @Override
- public synchronized void onPropertyChange(CarHvacEvent event) {
- for (ICarHvacEventListener l : mListenersMap.values()) {
- try {
- l.onEvent(event);
- } catch (RemoteException ex) {
- // If we could not send a record, its likely the connection snapped. Let the binder
- // death handle the situation.
- Log.e(TAG, "onEvent calling failed: " + ex);
- }
- }
- }
-
- @Override
- public synchronized void onError(int zone, int property) {
- // TODO:
+ super(context, VehicleHal.getInstance().getHvacHal(), Car.PERMISSION_CAR_HVAC, true,
+ CarLog.TAG_HVAC);
}
}
diff --git a/service/src/com/android/car/CarLog.java b/service/src/com/android/car/CarLog.java
index f818f6a..6b2a2e4 100644
--- a/service/src/com/android/car/CarLog.java
+++ b/service/src/com/android/car/CarLog.java
@@ -31,6 +31,7 @@
public static final String TAG_PACKAGE = "CAR.PACKAGE";
public static final String TAG_POWER = "CAR.POWER";
public static final String TAG_PROJECTION = "CAR.PROJECTION";
+ public static final String TAG_PROPERTY = "CAR.PROPERTY";
public static final String TAG_RADIO = "CAR.RADIO";
public static final String TAG_SENSOR = "CAR.SENSOR";
public static final String TAG_SERVICE = "CAR.SERVICE";
diff --git a/service/src/com/android/car/CarPropertyServiceBase.java b/service/src/com/android/car/CarPropertyServiceBase.java
new file mode 100644
index 0000000..4c2028a
--- /dev/null
+++ b/service/src/com/android/car/CarPropertyServiceBase.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import android.car.Car;
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.ICarProperty;
+import android.car.hardware.property.ICarPropertyEventListener;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.car.hal.PropertyHalServiceBase;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class implements the binder interface for ICarProperty.aidl to make it easier to create
+ * multiple managers that deal with Vehicle Properties. To create a new service, simply extend
+ * this class and call the super() constructor with the appropriate arguments for the new service.
+ * CarHvacService.java shows the basic usage.
+ */
+public class CarPropertyServiceBase extends ICarProperty.Stub
+ implements CarServiceBase, PropertyHalServiceBase.PropertyHalListener {
+ private final Context mContext;
+ private final boolean mDbg;
+ private final Map<IBinder, PropertyDeathRecipient> mDeathRecipientMap = new HashMap<>();
+ private final PropertyHalServiceBase mHal;
+ private final Map<IBinder, ICarPropertyEventListener> mListenersMap = new HashMap<>();
+ private final String mPermission;
+ private final String mTag;
+
+ public CarPropertyServiceBase(Context context, PropertyHalServiceBase hal, String permission,
+ boolean dbg, String tag) {
+ mContext = context;
+ mHal = hal;
+ mPermission = permission;
+ mDbg = dbg;
+ mTag = tag + ".service";
+ }
+
+ class PropertyDeathRecipient implements IBinder.DeathRecipient {
+ private IBinder mListenerBinder;
+
+ PropertyDeathRecipient(IBinder listenerBinder) {
+ mListenerBinder = listenerBinder;
+ }
+
+ /**
+ * Client died. Remove the listener from HAL service and unregister if this is the last
+ * client.
+ */
+ @Override
+ public void binderDied() {
+ if (mDbg) {
+ Log.d(mTag, "binderDied " + mListenerBinder);
+ }
+ CarPropertyServiceBase.this.unregisterListenerLocked(mListenerBinder);
+ }
+
+ void release() {
+ mListenerBinder.unlinkToDeath(this, 0);
+ }
+ }
+
+ @Override
+ public synchronized void init() {
+ }
+
+ @Override
+ public synchronized void release() {
+ for (PropertyDeathRecipient recipient : mDeathRecipientMap.values()) {
+ recipient.release();
+ }
+ mDeathRecipientMap.clear();
+ mListenersMap.clear();
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ // TODO
+ }
+
+ @Override
+ public synchronized void registerListener(ICarPropertyEventListener listener) {
+ if (mDbg) {
+ Log.d(mTag, "registerListener");
+ }
+ ICarImpl.assertPermission(mContext, mPermission);
+ if (listener == null) {
+ Log.e(mTag, "registerListener: Listener is null.");
+ throw new IllegalArgumentException("listener cannot be null.");
+ }
+
+ IBinder listenerBinder = listener.asBinder();
+ if (mListenersMap.containsKey(listenerBinder)) {
+ // Already registered, nothing to do.
+ return;
+ }
+
+ PropertyDeathRecipient deathRecipient = new PropertyDeathRecipient(listenerBinder);
+ try {
+ listenerBinder.linkToDeath(deathRecipient, 0);
+ } catch (RemoteException e) {
+ Log.e(mTag, "Failed to link death for recipient. " + e);
+ throw new IllegalStateException(Car.CAR_NOT_CONNECTED_EXCEPTION_MSG);
+ }
+ mDeathRecipientMap.put(listenerBinder, deathRecipient);
+
+ if (mListenersMap.isEmpty()) {
+ mHal.setListener(this);
+ }
+
+ mListenersMap.put(listenerBinder, listener);
+ }
+
+ @Override
+ public synchronized void unregisterListener(ICarPropertyEventListener listener) {
+ if (mDbg) {
+ Log.d(mTag, "unregisterListener");
+ }
+ ICarImpl.assertPermission(mContext, mPermission);
+ if (listener == null) {
+ Log.e(mTag, "unregisterListener: Listener is null.");
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ IBinder listenerBinder = listener.asBinder();
+ if (!mListenersMap.containsKey(listenerBinder)) {
+ Log.e(mTag, "unregisterListener: Listener was not previously registered.");
+ }
+ unregisterListenerLocked(listenerBinder);
+ }
+
+ // Removes the listenerBinder from the current state.
+ // The function assumes that binder will exist both in listeners and death recipients list.
+ private void unregisterListenerLocked(IBinder listenerBinder) {
+ boolean found = mListenersMap.remove(listenerBinder) != null;
+
+ if (found) {
+ mDeathRecipientMap.get(listenerBinder).release();
+ mDeathRecipientMap.remove(listenerBinder);
+ }
+
+ if (mListenersMap.isEmpty()) {
+ mHal.setListener(null);
+ }
+ }
+
+ @Override
+ public synchronized List<CarPropertyConfig> getPropertyList() {
+ ICarImpl.assertPermission(mContext, mPermission);
+ return mHal.getPropertyList();
+ }
+
+ @Override
+ public synchronized CarPropertyValue getProperty(int prop, int zone) {
+ ICarImpl.assertPermission(mContext, mPermission);
+ return mHal.getProperty(prop, zone);
+ }
+
+ @Override
+ public synchronized void setProperty(CarPropertyValue prop) {
+ ICarImpl.assertPermission(mContext, mPermission);
+ mHal.setProperty(prop);
+ }
+
+ // Implement PropertyHalListener interface
+ @Override
+ public synchronized void onPropertyChange(CarPropertyEvent event) {
+ for (ICarPropertyEventListener l : mListenersMap.values()) {
+ try {
+ l.onEvent(event);
+ } catch (RemoteException ex) {
+ // If we could not send a record, its likely the connection snapped. Let the binder
+ // death handle the situation.
+ Log.e(mTag, "onEvent calling failed: " + ex);
+ }
+ }
+ }
+
+ @Override
+ public synchronized void onError(int zone, int property) {
+ // TODO:
+ }
+}
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 7d34f2b..05e8f59 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -245,49 +245,32 @@
}
public static void assertVehicleHalMockPermission(Context context) {
- if (context.checkCallingOrSelfPermission(Car.PERMISSION_MOCK_VEHICLE_HAL)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("requires CAR_MOCK_VEHICLE_HAL permission");
- }
+ assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
}
public static void assertCameraPermission(Context context) {
- if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_CAMERA)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "requires " + Car.PERMISSION_CAR_CAMERA);
- }
+ assertPermission(context, Car.PERMISSION_CAR_CAMERA);
}
public static void assertNavigationManagerPermission(Context context) {
- if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_NAVIGATION_MANAGER)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "requires " + Car.PERMISSION_CAR_NAVIGATION_MANAGER);
- }
+ assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
}
public static void assertHvacPermission(Context context) {
- if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_HVAC)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "requires " + Car.PERMISSION_CAR_HVAC);
- }
+ assertPermission(context, Car.PERMISSION_CAR_HVAC);
}
private static void assertRadioPermission(Context context) {
- if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_RADIO)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "requires permission " + Car.PERMISSION_CAR_RADIO);
- }
+ assertPermission(context, Car.PERMISSION_CAR_RADIO);
}
public static void assertProjectionPermission(Context context) {
- if (context.checkCallingOrSelfPermission(Car.PERMISSION_CAR_PROJECTION)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "requires " + Car.PERMISSION_CAR_PROJECTION);
+ assertPermission(context, Car.PERMISSION_CAR_PROJECTION);
+ }
+
+ public static void assertPermission(Context context, String permission) {
+ if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("requires " + permission);
}
}
diff --git a/service/src/com/android/car/hal/HvacHalService.java b/service/src/com/android/car/hal/HvacHalService.java
index 98a15d1..1341506 100644
--- a/service/src/com/android/car/hal/HvacHalService.java
+++ b/service/src/com/android/car/hal/HvacHalService.java
@@ -15,193 +15,21 @@
*/
package com.android.car.hal;
-import static com.android.car.hal.CarPropertyUtils.toCarPropertyValue;
-import static com.android.car.hal.CarPropertyUtils.toVehiclePropValue;
-import static java.lang.Integer.toHexString;
-
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.hvac.CarHvacEvent;
import android.car.hardware.hvac.CarHvacManager.HvacPropertyId;
-import android.os.ServiceSpecificException;
-import android.util.Log;
-import android.util.SparseIntArray;
-import com.android.car.CarLog;
-import com.android.car.vehiclenetwork.VehicleNetwork;
import com.android.car.vehiclenetwork.VehicleNetworkConsts;
-import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
-import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
-public class HvacHalService extends HalServiceBase {
- private static final boolean DBG = true;
- private static final String TAG = CarLog.TAG_HVAC + ".HvacHalService";
- private HvacHalListener mListener;
- private final VehicleHal mVehicleHal;
-
- private final HashMap<Integer, CarPropertyConfig<?>> mProps = new HashMap<>();
- private final SparseIntArray mHalPropToValueType = new SparseIntArray();
-
- public interface HvacHalListener {
- void onPropertyChange(CarHvacEvent event);
- void onError(int zone, int property);
- }
+public class HvacHalService extends PropertyHalServiceBase {
+ private static final boolean DBG = true;
+ private static final String TAG = "HvacHalService";
public HvacHalService(VehicleHal vehicleHal) {
- mVehicleHal = vehicleHal;
- if (DBG) {
- Log.d(TAG, "started HvacHalService!");
- }
- }
-
- public void setListener(HvacHalListener listener) {
- synchronized (this) {
- mListener = listener;
- }
- }
-
- public List<CarPropertyConfig> getHvacProperties() {
- List<CarPropertyConfig> propList;
- synchronized (mProps) {
- propList = new ArrayList<>(mProps.values());
- }
- return propList;
- }
-
- public CarPropertyValue getHvacProperty(int hvacPropertyId, int areaId) {
- int halProp = hvacToHalPropId(hvacPropertyId);
-
- VehiclePropValue value = null;
- try {
- VehiclePropValue valueRequest = VehiclePropValue.newBuilder()
- .setProp(halProp)
- .setZone(areaId)
- .setValueType(mHalPropToValueType.get(halProp))
- .build();
-
- value = mVehicleHal.getVehicleNetwork().getProperty(valueRequest);
- } catch (ServiceSpecificException e) {
- Log.e(CarLog.TAG_HVAC, "get, property not ready 0x" + toHexString(halProp), e);
- }
-
- return value == null ? null : toCarPropertyValue(value, hvacPropertyId);
- }
-
- public void setHvacProperty(CarPropertyValue prop) {
- VehiclePropValue halProp = toVehiclePropValue(prop, hvacToHalPropId(prop.getPropertyId()));
- try {
- mVehicleHal.getVehicleNetwork().setProperty(halProp);
- } catch (ServiceSpecificException e) {
- Log.e(CarLog.TAG_HVAC, "set, property not ready 0x" + toHexString(halProp.getProp()), e);
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void init() {
- if (DBG) {
- Log.d(TAG, "init()");
- }
- synchronized (mProps) {
- // Subscribe to each of the HVAC properties
- for (Integer prop : mProps.keySet()) {
- mVehicleHal.subscribeProperty(this, prop, 0);
- }
- }
- }
-
- @Override
- public void release() {
- if (DBG) {
- Log.d(TAG, "release()");
- }
- synchronized (mProps) {
- for (Integer prop : mProps.keySet()) {
- mVehicleHal.unsubscribeProperty(this, prop);
- }
-
- // Clear the property list
- mProps.clear();
- }
- mListener = null;
- }
-
- @Override
- public synchronized List<VehiclePropConfig> takeSupportedProperties(
- List<VehiclePropConfig> allProperties) {
- List<VehiclePropConfig> taken = new LinkedList<>();
-
- for (VehiclePropConfig p : allProperties) {
- int hvacPropId;
- try {
- hvacPropId = halToHvacPropId(p.getProp());
- } catch (IllegalArgumentException e) {
- continue;
- }
- CarPropertyConfig hvacConfig = CarPropertyUtils.toCarPropertyConfig(p, hvacPropId);
-
- taken.add(p);
- mProps.put(p.getProp(), hvacConfig);
- mHalPropToValueType.put(p.getProp(), p.getValueType());
-
- if (DBG) {
- Log.d(TAG, "takeSupportedProperties: " + toHexString(p.getProp()));
- }
- }
- return taken;
- }
-
- @Override
- public void handleHalEvents(List<VehiclePropValue> values) {
- HvacHalListener listener;
- synchronized (this) {
- listener = mListener;
- }
- if (listener != null) {
- dispatchEventToListener(listener, values);
- }
- }
-
- private void dispatchEventToListener(HvacHalListener listener, List<VehiclePropValue> values) {
- for (VehiclePropValue v : values) {
- int prop = v.getProp();
-
- int hvacPropId;
- try {
- hvacPropId = halToHvacPropId(prop);
- } catch (IllegalArgumentException ex) {
- Log.e(TAG, "Property is not supported: 0x" + toHexString(prop), ex);
- continue;
- }
-
- CarHvacEvent event;
- CarPropertyValue<?> hvacProperty = toCarPropertyValue(v, hvacPropId);
- event = new CarHvacEvent(CarHvacEvent.HVAC_EVENT_PROPERTY_CHANGE, hvacProperty);
-
- listener.onPropertyChange(event);
- if (DBG) {
- Log.d(TAG, "dispatchEventToListener event: " + event);
- }
- }
- }
-
- @Override
- public void dump(PrintWriter writer) {
- writer.println("*HVAC HAL*");
- writer.println(" Properties available:");
- for (CarPropertyConfig prop : mProps.values()) {
- writer.println(" " + prop.toString());
- }
+ super(vehicleHal, TAG, DBG);
}
// Convert the HVAC public API property ID to HAL property ID
- private static int hvacToHalPropId(int hvacPropId) {
+ @Override
+ protected int managerToHalPropId(int hvacPropId) {
switch (hvacPropId) {
case HvacPropertyId.ZONED_FAN_SPEED_SETPOINT:
return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_FAN_SPEED;
@@ -228,12 +56,13 @@
case HvacPropertyId.ZONED_MAX_DEFROST_ON:
return VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_MAX_DEFROST_ON;
default:
- throw new IllegalArgumentException("hvacPropId " + hvacPropId + " is not supported");
+ throw new IllegalArgumentException("hvacPropId " + hvacPropId + " not supported");
}
}
// Convert he HAL specific property ID to HVAC public API
- private static int halToHvacPropId(int halPropId) {
+ @Override
+ protected int halToManagerPropId(int halPropId) {
switch (halPropId) {
case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_FAN_SPEED:
return HvacPropertyId.ZONED_FAN_SPEED_SETPOINT;
@@ -260,7 +89,7 @@
case VehicleNetworkConsts.VEHICLE_PROPERTY_HVAC_MAX_DEFROST_ON:
return HvacPropertyId.ZONED_MAX_DEFROST_ON;
default:
- throw new IllegalArgumentException("halPropId " + halPropId + " is not supported");
+ throw new IllegalArgumentException("halPropId " + halPropId + " not supported");
}
}
}
diff --git a/service/src/com/android/car/hal/PropertyHalServiceBase.java b/service/src/com/android/car/hal/PropertyHalServiceBase.java
new file mode 100644
index 0000000..bc93e56
--- /dev/null
+++ b/service/src/com/android/car/hal/PropertyHalServiceBase.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.hal;
+
+import static com.android.car.hal.CarPropertyUtils.toCarPropertyValue;
+import static com.android.car.hal.CarPropertyUtils.toVehiclePropValue;
+import static java.lang.Integer.toHexString;
+
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.os.ServiceSpecificException;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import com.android.car.CarLog;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Common interface for HAL services that send Vehicle Properties back and forth via ICarProperty.
+ * Services that communicate by passing vehicle properties back and forth via ICarProperty should
+ * extend this class.
+ */
+public abstract class PropertyHalServiceBase extends HalServiceBase {
+ private final boolean mDbg;
+ private final SparseIntArray mHalPropToValueType = new SparseIntArray();
+ private PropertyHalListener mListener;
+ private final ConcurrentHashMap<Integer, CarPropertyConfig<?>> mProps =
+ new ConcurrentHashMap<>();
+ private final String mTag;
+ private final VehicleHal mVehicleHal;
+
+ public interface PropertyHalListener {
+ void onPropertyChange(CarPropertyEvent event);
+ void onError(int zone, int property);
+ }
+
+ public PropertyHalServiceBase(VehicleHal vehicleHal, String tag, boolean dbg) {
+ mVehicleHal = vehicleHal;
+ mTag = "PropertyHalServiceBase." + tag;
+ mDbg = dbg;
+
+ if (mDbg) {
+ Log.d(mTag, "started PropertyHalServiceBase!");
+ }
+ }
+
+ public void setListener(PropertyHalListener listener) {
+ synchronized (this) {
+ mListener = listener;
+ }
+ }
+
+ public List<CarPropertyConfig> getPropertyList() {
+ return new ArrayList<>(mProps.values());
+ }
+
+ public CarPropertyValue getProperty(int mgrPropId, int areaId) {
+ int halPropId = managerToHalPropId(mgrPropId);
+
+ VehiclePropValue value = null;
+ try {
+ VehiclePropValue valueRequest = VehiclePropValue.newBuilder()
+ .setProp(halPropId)
+ .setZone(areaId)
+ .setValueType(mHalPropToValueType.get(halPropId))
+ .build();
+
+ value = mVehicleHal.getVehicleNetwork().getProperty(valueRequest);
+ } catch (ServiceSpecificException e) {
+ Log.e(CarLog.TAG_PROPERTY, "get, property not ready 0x" + toHexString(halPropId), e);
+ }
+
+ return value == null ? null : toCarPropertyValue(value, mgrPropId);
+ }
+
+ public void setProperty(CarPropertyValue prop) {
+ int halPropId = managerToHalPropId(prop.getPropertyId());
+ VehiclePropValue halProp = toVehiclePropValue(prop, halPropId);
+ try {
+ mVehicleHal.getVehicleNetwork().setProperty(halProp);
+ } catch (ServiceSpecificException e) {
+ Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(halPropId), e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void init() {
+ if (mDbg) {
+ Log.d(mTag, "init()");
+ }
+ // Subscribe to each of the properties
+ for (Integer prop : mProps.keySet()) {
+ mVehicleHal.subscribeProperty(this, prop, 0);
+ }
+ }
+
+ @Override
+ public void release() {
+ if (mDbg) {
+ Log.d(mTag, "release()");
+ }
+
+ for (Integer prop : mProps.keySet()) {
+ mVehicleHal.unsubscribeProperty(this, prop);
+ }
+
+ // Clear the property list
+ mProps.clear();
+
+ synchronized (this) {
+ mListener = null;
+ }
+ }
+
+ @Override
+ public List<VehiclePropConfig> takeSupportedProperties(
+ List<VehiclePropConfig> allProperties) {
+ List<VehiclePropConfig> taken = new LinkedList<>();
+
+ for (VehiclePropConfig p : allProperties) {
+ int mgrPropId;
+ int halPropId;
+
+ try {
+ // See if the property is handled by this HAL
+ mgrPropId = halToManagerPropId(p.getProp());
+ halPropId = managerToHalPropId(mgrPropId);
+ if (halPropId != p.getProp()) {
+ throw new IllegalArgumentException("propId " + p.getProp() + " becomes " +
+ halPropId);
+ }
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+ CarPropertyConfig config = CarPropertyUtils.toCarPropertyConfig(p, mgrPropId);
+
+ taken.add(p);
+ mProps.put(p.getProp(), config);
+ mHalPropToValueType.put(p.getProp(), p.getValueType());
+
+ if (mDbg) {
+ Log.d(mTag, "takeSupportedProperties: " + toHexString(p.getProp()));
+ }
+ }
+ return taken;
+ }
+
+ @Override
+ public void handleHalEvents(List<VehiclePropValue> values) {
+ PropertyHalListener listener;
+ synchronized (this) {
+ listener = mListener;
+ }
+ if (listener != null) {
+ for (VehiclePropValue v : values) {
+ int prop = v.getProp();
+ int mgrPropId;
+
+ try {
+ mgrPropId = halToManagerPropId(prop);
+ } catch (IllegalArgumentException ex) {
+ Log.e(mTag, "Property is not supported: 0x" + toHexString(prop), ex);
+ continue;
+ }
+
+ CarPropertyEvent event;
+ CarPropertyValue<?> propVal = toCarPropertyValue(v, mgrPropId);
+ event = new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE,
+ propVal);
+
+ listener.onPropertyChange(event);
+ if (mDbg) {
+ Log.d(mTag, "handleHalEvents event: " + event);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ writer.println(mTag);
+ writer.println(" Properties available:");
+ for (CarPropertyConfig prop : mProps.values()) {
+ writer.println(" " + prop.toString());
+ }
+ }
+
+ /**
+ * Convert manager property ID to Vehicle HAL property ID
+ */
+ abstract protected int managerToHalPropId(int managerPropId);
+
+ /**
+ * Convert Vehicle HAL property ID to manager property ID
+ */
+ abstract protected int halToManagerPropId(int halPropId);
+}