Create CarPropertyService and CarPropertyManager
CarPropertyService replaces Cabin, Hvac, Info, Sensor,
and VendorExtension services.
Bug: 78782959
Bug: 36649684
Bug: 68056035
Test: runtest -x packages/services/Car/tests/android_car_api_test
runtest -x packages/services/Car/tests/carservice_unit_test
Change-Id: Ic0a94805f83cc0222fb2bcf9674b6031bc050986
(cherry picked from commit c9ee6cda8a5ed73d82a0cdbd0e3154d76ec3db01)
diff --git a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
index eb2a981..f9c8a1e 100644
--- a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
+++ b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
@@ -38,16 +38,14 @@
import android.car.drivingstate.CarUxRestrictions;
import android.car.drivingstate.ICarUxRestrictionsChangeListener;
import android.car.hardware.CarPropertyValue;
-import android.car.hardware.CarSensorEvent;
-import android.car.hardware.CarSensorManager;
-import android.car.hardware.ICarSensorEventListener;
-import android.car.hardware.cabin.CarCabinManager;
import android.car.hardware.property.CarPropertyEvent;
import android.car.hardware.property.ICarPropertyEventListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
import android.os.ParcelUuid;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -118,12 +116,9 @@
private ReentrantLock mCarUserServiceAccessLock;
// Events that are listened to for triggering an auto-connect:
- // Cabin events like Door unlock coming from the Cabin Service.
- private final CarCabinService mCarCabinService;
- private final CarPropertyListener mCabinEventListener;
- // Sensor events like Ignition switch ON from the Car Sensor Service
- private final CarSensorService mCarSensorService;
- private final CarSensorEventListener mCarSensorEventListener;
+ // Door unlock and ignition switch ON come from Car Property Service
+ private final CarPropertyService mCarPropertyService;
+ private final CarPropertyListener mPropertyEventListener;
// PerUserCarService related listeners
private final UserServiceConnectionCallback mServiceCallback;
@@ -151,19 +146,17 @@
private Set<BluetoothDevice> mPairedButUnconnectedDevices = new HashSet<>();
public static BluetoothDeviceConnectionPolicy create(Context context,
- CarCabinService carCabinService, CarSensorService carSensorService,
- PerUserCarServiceHelper userServiceHelper, CarUxRestrictionsManagerService uxrService,
- CarBluetoothService bluetoothService) {
- return new BluetoothDeviceConnectionPolicy(context, carCabinService, carSensorService,
- userServiceHelper, uxrService, bluetoothService);
+ CarPropertyService carPropertyService, PerUserCarServiceHelper userServiceHelper,
+ CarUxRestrictionsManagerService uxrService, CarBluetoothService bluetoothService) {
+ return new BluetoothDeviceConnectionPolicy(context, carPropertyService, userServiceHelper,
+ uxrService, bluetoothService);
}
- private BluetoothDeviceConnectionPolicy(Context context, CarCabinService carCabinService,
- CarSensorService carSensorService, PerUserCarServiceHelper userServiceHelper,
- CarUxRestrictionsManagerService uxrService, CarBluetoothService bluetoothService) {
+ private BluetoothDeviceConnectionPolicy(Context context, CarPropertyService carPropertyService,
+ PerUserCarServiceHelper userServiceHelper, CarUxRestrictionsManagerService uxrService,
+ CarBluetoothService bluetoothService) {
mContext = context;
- mCarCabinService = carCabinService;
- mCarSensorService = carSensorService;
+ mCarPropertyService = carPropertyService;
mUserServiceHelper = userServiceHelper;
mUxRService = uxrService;
mCarBluetoothService = bluetoothService;
@@ -203,10 +196,8 @@
}
}
- // Listen to Cabin events for triggering auto connect
- mCabinEventListener = new CarPropertyListener();
- // Listen to Sensor Events for triggering auto connect
- mCarSensorEventListener = new CarSensorEventListener();
+ // Listen to events for triggering auto connect
+ mPropertyEventListener = new CarPropertyListener();
// Listen to UX Restrictions to know when to enable fast-pairing
mUxRListener = new CarUxRServiceListener();
// Listen to User switching to connect to per User device.
@@ -606,12 +597,12 @@
* Bluetooth connection attempts.
*/
private void setupEventListenersLocked() {
- // Setting up a listener for events from CarCabinService
- // For now, we listen to door unlock signal coming from {@link CarCabinService},
- // and Ignition state START from {@link CarSensorService}
- mCarCabinService.registerListener(mCabinEventListener);
- mCarSensorService.registerOrUpdateSensorListener(
- CarSensorManager.SENSOR_TYPE_IGNITION_STATE, 0, mCarSensorEventListener);
+ // Setting up a listener for events from CarPropertyService
+ // For now, we listen to door unlock signal and Ignition state START coming from
+ // {@link CarPropertyService}
+ mCarPropertyService.registerListener(VehicleProperty.DOOR_LOCK, 0, mPropertyEventListener);
+ mCarPropertyService.registerListener(VehicleProperty.IGNITION_STATE, 0,
+ mPropertyEventListener);
// Get Current restrictions and handle them
handleUxRestrictionsChanged(mUxRService.getCurrentUxRestrictions());
// Register for future changes to the UxRestrictions
@@ -620,58 +611,47 @@
}
/**
- * Handles events coming in from the {@link CarCabinService}
- * The events that can trigger Bluetooth Scanning from CarCabinService is Door Unlock.
- * Upon receiving the event that is of interest, initiate a connection attempt by calling
+ * Handles events coming in from the {@link CarPropertyService}
+ * The events that can trigger Bluetooth Scanning from CarPropertyService are Door Unlock and
+ * Igntion START. Upon an event of interest, initiate a connection attempt by calling
* the policy {@link BluetoothDeviceConnectionPolicy}
*/
@VisibleForTesting
class CarPropertyListener extends ICarPropertyEventListener.Stub {
@Override
- public void onEvent(CarPropertyEvent event) throws RemoteException {
- if (DBG) {
- Log.d(TAG, "Cabin change Event : " + event.getEventType());
- }
- Boolean locked;
- CarPropertyValue value = event.getCarPropertyValue();
- Object o = value.getValue();
-
- if (value.getPropertyId() == CarCabinManager.ID_DOOR_LOCK) {
- if (o instanceof Boolean) {
- locked = (Boolean) o;
- if (DBG) {
- Log.d(TAG, "Door Lock: " + locked);
- }
- // Attempting a connection only on a door unlock
- if (!locked) {
- initiateConnection();
- }
- }
- }
- }
- }
-
- /**
- * Handles events coming in from the {@link CarSensorService}
- * The events that can trigger Bluetooth Scanning from CarSensorService is Ignition START.
- * Upon receiving the event that is of interest, initiate a connection attempt by calling
- * the policy {@link BluetoothDeviceConnectionPolicy}
- */
- private class CarSensorEventListener extends ICarSensorEventListener.Stub {
- @Override
- public void onSensorChanged(List<CarSensorEvent> events) throws RemoteException {
- if (events != null & !events.isEmpty()) {
- CarSensorEvent event = events.get(0);
+ public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+ for (CarPropertyEvent event : events) {
if (DBG) {
- Log.d(TAG, "Sensor event Type : " + event.sensorType);
+ Log.d(TAG, "Cabin change Event : " + event.getEventType());
}
- if (event.sensorType == CarSensorManager.SENSOR_TYPE_IGNITION_STATE) {
- if (DBG) {
- Log.d(TAG, "Sensor value : " + event.intValues[0]);
- }
- if (event.intValues[0] == CarSensorEvent.IGNITION_STATE_START) {
- initiateConnection();
- }
+ CarPropertyValue value = event.getCarPropertyValue();
+ Object o = value.getValue();
+
+ switch (value.getPropertyId()) {
+ case VehicleProperty.DOOR_LOCK:
+ if (o instanceof Boolean) {
+ Boolean locked = (Boolean) o;
+ if (DBG) {
+ Log.d(TAG, "Door Lock: " + locked);
+ }
+ // Attempting a connection only on a door unlock
+ if (!locked) {
+ initiateConnection();
+ }
+ }
+ break;
+ case VehicleProperty.IGNITION_STATE:
+ if (o instanceof Integer) {
+ Integer state = (Integer) o;
+ if (DBG) {
+ Log.d(TAG, "Sensor value : " + state);
+ }
+ // Attempting a connection only on IgntionState START
+ if (state == VehicleIgnitionState.START) {
+ initiateConnection();
+ }
+ }
+ break;
}
}
}
@@ -746,9 +726,9 @@
if (DBG) {
Log.d(TAG, "closeEventListeners()");
}
- mCarCabinService.unregisterListener(mCabinEventListener);
- mCarSensorService.unregisterSensorListener(CarSensorManager.SENSOR_TYPE_IGNITION_STATE,
- mCarSensorEventListener);
+ mCarPropertyService.unregisterListener(VehicleProperty.DOOR_LOCK, mPropertyEventListener);
+ mCarPropertyService.unregisterListener(VehicleProperty.IGNITION_STATE,
+ mPropertyEventListener);
mUserServiceHelper.unregisterServiceCallback(mServiceCallback);
}
@@ -781,7 +761,7 @@
@VisibleForTesting
CarPropertyListener getCarPropertyListener() {
- return mCabinEventListener;
+ return mPropertyEventListener;
}
@VisibleForTesting
diff --git a/service/src/com/android/car/CarBluetoothService.java b/service/src/com/android/car/CarBluetoothService.java
index 0702045..d36db43 100644
--- a/service/src/com/android/car/CarBluetoothService.java
+++ b/service/src/com/android/car/CarBluetoothService.java
@@ -59,12 +59,11 @@
private final BluetoothDeviceConnectionPolicy mBluetoothDeviceConnectionPolicy;
private static final boolean DBG = false;
- public CarBluetoothService(Context context, CarCabinService carCabinService,
- CarSensorService carSensorService, PerUserCarServiceHelper userSwitchService,
- CarUxRestrictionsManagerService uxrService) {
+ public CarBluetoothService(Context context, CarPropertyService carPropertyService,
+ PerUserCarServiceHelper userSwitchService, CarUxRestrictionsManagerService uxrService) {
mContext = context;
mBluetoothDeviceConnectionPolicy = BluetoothDeviceConnectionPolicy.create(mContext,
- carCabinService, carSensorService, userSwitchService, uxrService, this);
+ carPropertyService, userSwitchService, uxrService, this);
}
@Override
diff --git a/service/src/com/android/car/CarCabinService.java b/service/src/com/android/car/CarCabinService.java
deleted file mode 100644
index 316f926..0000000
--- a/service/src/com/android/car/CarCabinService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.content.Context;
-
-import com.android.car.hal.CabinHalService;
-
-public class CarCabinService extends CarPropertyServiceBase {
- private final static boolean DBG = false;
-
- public CarCabinService(Context context, CabinHalService cabinHal) {
- super(context, cabinHal, Car.PERMISSION_ADJUST_CAR_CABIN, DBG, CarLog.TAG_CABIN);
- }
-}
diff --git a/service/src/com/android/car/CarDrivingStateService.java b/service/src/com/android/car/CarDrivingStateService.java
index 575e1c6..7f0eeea 100644
--- a/service/src/com/android/car/CarDrivingStateService.java
+++ b/service/src/com/android/car/CarDrivingStateService.java
@@ -21,10 +21,13 @@
import android.car.drivingstate.CarDrivingStateEvent.CarDrivingState;
import android.car.drivingstate.ICarDrivingState;
import android.car.drivingstate.ICarDrivingStateChangeListener;
-import android.car.hardware.CarSensorEvent;
-import android.car.hardware.CarSensorManager;
-import android.car.hardware.ICarSensorEventListener;
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.ICarPropertyEventListener;
import android.content.Context;
+import android.hardware.automotive.vehicle.V2_0.VehicleGear;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -36,66 +39,76 @@
import java.util.List;
/**
- * A service that infers the current driving state of the vehicle. It doesn't directly listen to
- * vehicle properties from VHAL to do so. Instead, it computes the driving state from listening to
- * the relevant sensors from {@link CarSensorService}
+ * A service that infers the current driving state of the vehicle. It computes the driving state
+ * from listening to relevant properties from {@link CarPropertyService}
*/
public class CarDrivingStateService extends ICarDrivingState.Stub implements CarServiceBase {
private static final String TAG = "CarDrivingState";
private static final boolean DBG = false;
private static final int MAX_TRANSITION_LOG_SIZE = 20;
+ private static final int PROPERTY_UPDATE_RATE = 5; // Update rate in Hz
+ private static final int NOT_RECEIVED = -1;
private final Context mContext;
- private CarSensorService mSensorService;
+ private CarPropertyService mPropertyService;
// List of clients listening to driving state events.
- private final List<DrivingStateClient> mDivingStateClients = new ArrayList<>();
- // Array of sensors that the service needs to listen to from CarSensorService for deriving
+ private final List<DrivingStateClient> mDrivingStateClients = new ArrayList<>();
+ // Array of properties that the service needs to listen to from CarPropertyService for deriving
// the driving state. ToDo (ramperry@) - fine tune this list - b/69859926
- private static final int[] mRequiredSensors = {
- CarSensorManager.SENSOR_TYPE_CAR_SPEED,
- CarSensorManager.SENSOR_TYPE_GEAR};
+ private static final int[] REQUIRED_PROPERTIES = {
+ VehicleProperty.PERF_VEHICLE_SPEED,
+ VehicleProperty.GEAR_SELECTION};
private CarDrivingStateEvent mCurrentDrivingState;
- private CarSensorEvent mLastGear;
- private CarSensorEvent mLastSpeed;
// For dumpsys logging
private final LinkedList<Utils.TransitionLog> mTransitionLogs = new LinkedList<>();
+ private int mLastGear;
+ private long mLastGearTimestamp = NOT_RECEIVED;
+ private float mLastSpeed;
+ private long mLastSpeedTimestamp = NOT_RECEIVED;
- public CarDrivingStateService(Context context, CarSensorService sensorService) {
+ public CarDrivingStateService(Context context, CarPropertyService propertyService) {
mContext = context;
- mSensorService = sensorService;
+ mPropertyService = propertyService;
mCurrentDrivingState = createDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
}
@Override
public void init() {
- if (!checkSensorSupport()) {
+ if (!checkPropertySupport()) {
Log.e(TAG, "init failure. Driving state will always be fully restrictive");
return;
}
- subscribeToSensors();
+ subscribeToProperties();
}
@Override
public synchronized void release() {
- for (int sensor : mRequiredSensors) {
- mSensorService.unregisterSensorListener(sensor, mICarSensorEventListener);
+ for (int property : REQUIRED_PROPERTIES) {
+ mPropertyService.unregisterListener(property, mICarPropertyEventListener);
}
- for (DrivingStateClient client : mDivingStateClients) {
+ for (DrivingStateClient client : mDrivingStateClients) {
client.listenerBinder.unlinkToDeath(client, 0);
}
- mDivingStateClients.clear();
+ mDrivingStateClients.clear();
mCurrentDrivingState = createDrivingStateEvent(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
}
/**
- * Checks if the {@link CarSensorService} supports the required sensors.
+ * Checks if the {@link CarPropertyService} supports the required properties.
*
* @return {@code true} if supported, {@code false} if not
*/
- private synchronized boolean checkSensorSupport() {
- int sensorList[] = mSensorService.getSupportedSensors();
- for (int sensor : mRequiredSensors) {
- if (!CarSensorManager.isSensorSupported(sensorList, sensor)) {
- Log.e(TAG, "Required sensor not supported: " + sensor);
+ private synchronized boolean checkPropertySupport() {
+ List<CarPropertyConfig> configs = mPropertyService.getPropertyList();
+ for (int propertyId : REQUIRED_PROPERTIES) {
+ boolean found = false;
+ for (CarPropertyConfig config : configs) {
+ if (config.getPropertyId() == propertyId) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ Log.e(TAG, "Required property not supported: " + propertyId);
return false;
}
}
@@ -103,13 +116,12 @@
}
/**
- * Subscribe to the {@link CarSensorService} for required sensors.
+ * Subscribe to the {@link CarPropertyService} for required sensors.
*/
- private synchronized void subscribeToSensors() {
- for (int sensor : mRequiredSensors) {
- mSensorService.registerOrUpdateSensorListener(sensor,
- CarSensorManager.SENSOR_RATE_UI,
- mICarSensorEventListener);
+ private synchronized void subscribeToProperties() {
+ for (int propertyId : REQUIRED_PROPERTIES) {
+ mPropertyService.registerListener(propertyId, PROPERTY_UPDATE_RATE,
+ mICarPropertyEventListener);
}
}
@@ -142,7 +154,7 @@
Log.e(TAG, "Cannot link death recipient to binder " + e);
return;
}
- mDivingStateClients.add(client);
+ mDrivingStateClients.add(client);
}
}
@@ -158,7 +170,7 @@
ICarDrivingStateChangeListener listener) {
IBinder binder = listener.asBinder();
// Find the listener by comparing the binder object they host.
- for (DrivingStateClient client : mDivingStateClients) {
+ for (DrivingStateClient client : mDrivingStateClients) {
if (client.isHoldingBinder(binder)) {
return client;
}
@@ -186,7 +198,7 @@
return;
}
listener.asBinder().unlinkToDeath(client, 0);
- mDivingStateClients.remove(client);
+ mDrivingStateClients.remove(client);
}
/**
@@ -222,7 +234,7 @@
}
listenerBinder.unlinkToDeath(this, 0);
synchronized (CarDrivingStateService.this) {
- mDivingStateClients.remove(this);
+ mDrivingStateClients.remove(this);
}
}
@@ -265,29 +277,60 @@
}
/**
- * {@link CarSensorEvent} listener registered with the {@link CarSensorService} for getting
- * sensor change notifications.
+ * {@link CarPropertyEvent} listener registered with the {@link CarPropertyService} for getting
+ * property change notifications.
*/
- private final ICarSensorEventListener mICarSensorEventListener =
- new ICarSensorEventListener.Stub() {
+ private final ICarPropertyEventListener mICarPropertyEventListener =
+ new ICarPropertyEventListener.Stub() {
@Override
- public void onSensorChanged(List<CarSensorEvent> events) {
- for (CarSensorEvent event : events) {
- Log.d(TAG, "Sensor Changed:" + event.sensorType);
- handleSensorEvent(event);
+ public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+ for (CarPropertyEvent event : events) {
+ handlePropertyEvent(event);
}
}
};
/**
- * Handle the sensor events coming from the {@link CarSensorService}.
- * Compute the driving state, map it to the corresponding UX Restrictions and dispatch the
- * events to the registered clients.
+ * Handle events coming from {@link CarPropertyService}. Compute the driving state, map it to
+ * the corresponding UX Restrictions and dispatch the events to the registered clients.
*/
- private synchronized void handleSensorEvent(CarSensorEvent event) {
- switch (event.sensorType) {
- case CarSensorManager.SENSOR_TYPE_GEAR:
- case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
+ private synchronized void handlePropertyEvent(CarPropertyEvent event) {
+ switch (event.getEventType()) {
+ case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
+ CarPropertyValue value = event.getCarPropertyValue();
+ int propId = value.getPropertyId();
+ long curTimestamp = value.getTimestamp();
+ Log.d(TAG, "Property Changed: propId=" + propId);
+ switch (propId) {
+ case VehicleProperty.PERF_VEHICLE_SPEED:
+ float curSpeed = (Float) value.getValue();
+ if (DBG) {
+ Log.d(TAG, "Speed: " + curSpeed + "@" + curTimestamp);
+ }
+ if (curTimestamp > mLastSpeedTimestamp) {
+ mLastSpeedTimestamp = curTimestamp;
+ mLastSpeed = curSpeed;
+ } else if (DBG) {
+ Log.d(TAG, "Ignoring speed with older timestamp:" + curTimestamp);
+ }
+ break;
+ case VehicleProperty.GEAR_SELECTION:
+ int curGear = (Integer) value.getValue();
+ if (DBG) {
+ Log.d(TAG, "Gear: " + curGear + "@" + curTimestamp);
+ }
+ if (curTimestamp > mLastGearTimestamp) {
+ mLastGearTimestamp = curTimestamp;
+ mLastGear = (Integer) value.getValue();
+ } else if (DBG) {
+ Log.d(TAG, "Ignoring Gear with older timestamp:" + curTimestamp);
+ }
+ break;
+ default:
+ Log.e(TAG, "Received property event for unhandled propId=" + propId);
+ break;
+ }
+
int drivingState = inferDrivingStateLocked();
// Check if the driving state has changed. If it has, update our records and
// dispatch the new events to the listeners.
@@ -295,22 +338,21 @@
Log.d(TAG, "Driving state new->old " + drivingState + "->"
+ mCurrentDrivingState.eventValue);
}
- if (drivingState == mCurrentDrivingState.eventValue) {
- break;
- }
- addTransitionLog(TAG, mCurrentDrivingState.eventValue, drivingState,
- System.currentTimeMillis());
- // Update if there is a change in state.
- mCurrentDrivingState = createDrivingStateEvent(drivingState);
-
- if (DBG) {
- Log.d(TAG, "dispatching to " + mDivingStateClients.size() + " clients");
- }
- for (DrivingStateClient client : mDivingStateClients) {
- client.dispatchEventToClients(mCurrentDrivingState);
+ if (drivingState != mCurrentDrivingState.eventValue) {
+ addTransitionLog(TAG, mCurrentDrivingState.eventValue, drivingState,
+ System.currentTimeMillis());
+ // Update if there is a change in state.
+ mCurrentDrivingState = createDrivingStateEvent(drivingState);
+ if (DBG) {
+ Log.d(TAG, "dispatching to " + mDrivingStateClients.size() + " clients");
+ }
+ for (DrivingStateClient client : mDrivingStateClients) {
+ client.dispatchEventToClients(mCurrentDrivingState);
+ }
}
break;
default:
+ // Unhandled event
break;
}
}
@@ -333,42 +375,6 @@
*/
@CarDrivingState
private int inferDrivingStateLocked() {
- int drivingState = CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
- CarSensorEvent currentGear = mSensorService.getLatestSensorEvent(
- CarSensorManager.SENSOR_TYPE_GEAR);
- CarSensorEvent currentSpeed = mSensorService.getLatestSensorEvent(
- CarSensorManager.SENSOR_TYPE_CAR_SPEED);
-
- // Ignoring data with older timestamps if we get them out of order.
- if (currentSpeed != null) {
- if (DBG) {
- Log.d(TAG, "Speed: " + currentSpeed.floatValues[0] + "@" + currentSpeed.timestamp);
- }
- if (mLastSpeed != null && currentSpeed.timestamp < mLastSpeed.timestamp) {
- if (DBG) {
- Log.d(TAG, "Ignoring speed with older timestamp:" + currentSpeed.timestamp);
- }
- // assign the last speed to current speed, since that has a more recent timestamp
- // and let the logic flow through.
- currentSpeed = mLastSpeed;
- } else {
- mLastSpeed = currentSpeed;
- }
- }
-
- if (currentGear != null) {
- if (DBG) {
- Log.d(TAG, "Gear: " + currentGear.intValues[0] + "@" + currentGear.timestamp);
- }
- if (mLastGear != null && currentGear.timestamp < mLastGear.timestamp) {
- if (DBG) {
- Log.d(TAG, "Ignoring Gear with older timestamp:" + currentGear.timestamp);
- }
- currentGear = mLastGear;
- } else {
- mLastGear = currentGear;
- }
- }
/*
Simple logic to start off deriving driving state:
1. If gear == parked, then Driving State is parked.
@@ -378,29 +384,22 @@
2c. if speed unavailable, then driving state is unknown
This logic needs to be tested and iterated on. Tracked in b/69859926
*/
- if (currentGear != null) {
- if (isGearInParking(currentGear)) {
- drivingState = CarDrivingStateEvent.DRIVING_STATE_PARKED;
- } else if (currentSpeed == null) {
- drivingState = CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
- } else {
- if (currentSpeed.floatValues[0] == 0f) {
- drivingState = CarDrivingStateEvent.DRIVING_STATE_IDLING;
- } else {
- drivingState = CarDrivingStateEvent.DRIVING_STATE_MOVING;
- }
- }
+ if (DBG) {
+ Log.d(TAG, "Last known Gear:" + mLastGear + " Last known speed:" + mLastSpeed);
}
- return drivingState;
- }
+ if (mLastGearTimestamp == NOT_RECEIVED) {
+ return CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
+ } else if (mLastGear == VehicleGear.GEAR_PARK) {
+ return CarDrivingStateEvent.DRIVING_STATE_PARKED;
+ }
- private boolean isSpeedZero(CarSensorEvent event) {
- return event.floatValues[0] == 0f;
- }
-
- private boolean isGearInParking(CarSensorEvent event) {
- int gear = event.intValues[0];
- return gear == CarSensorEvent.GEAR_PARK;
+ if (mLastSpeedTimestamp == NOT_RECEIVED) {
+ return CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
+ } else if (mLastSpeed == 0f) {
+ return CarDrivingStateEvent.DRIVING_STATE_IDLING;
+ } else {
+ return CarDrivingStateEvent.DRIVING_STATE_MOVING;
+ }
}
private static CarDrivingStateEvent createDrivingStateEvent(int eventValue) {
diff --git a/service/src/com/android/car/CarHvacService.java b/service/src/com/android/car/CarHvacService.java
deleted file mode 100644
index cb5922b..0000000
--- a/service/src/com/android/car/CarHvacService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.content.Context;
-
-import com.android.car.hal.HvacHalService;
-
-public class CarHvacService extends CarPropertyServiceBase {
- private final static boolean DBG = false;
-
- public CarHvacService(Context context, HvacHalService hvacHal) {
- super(context, hvacHal, Car.PERMISSION_CONTROL_CAR_CLIMATE, DBG, CarLog.TAG_HVAC);
- }
-}
diff --git a/service/src/com/android/car/CarInfoService.java b/service/src/com/android/car/CarInfoService.java
deleted file mode 100644
index a05f343..0000000
--- a/service/src/com/android/car/CarInfoService.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015 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.CarInfoManager;
-import android.car.ICarInfo;
-import android.content.Context;
-import android.os.Bundle;
-import android.provider.Settings;
-
-import com.android.car.hal.InfoHalService;
-import com.android.car.internal.FeatureConfiguration;
-import com.android.car.internal.FeatureUtil;
-
-import java.io.PrintWriter;
-
-public class CarInfoService extends ICarInfo.Stub implements CarServiceBase {
-
- private final InfoHalService mInfoHal;
- private final Context mContext;
-
- public CarInfoService(Context context, InfoHalService infoHal) {
- mInfoHal = infoHal;
- mContext = context;
- }
-
- @Override
- public Bundle getBasicInfo() {
- return mInfoHal.getBasicInfo();
- }
-
- @Override
- public String getStringInfo(String key) {
- switch (key) {
- case CarInfoManager.INFO_KEY_PRODUCT_CONFIGURATION:
- FeatureUtil.assertFeature(
- FeatureConfiguration.ENABLE_PRODUCT_CONFIGURATION_INFO);
- // still protect with if-feature code. code under if can be dropped by
- // proguard if necessary.
- if (FeatureConfiguration.ENABLE_PRODUCT_CONFIGURATION_INFO) {
- //TODO get it from HAL layer
- return null;
- }
- break;
- default: // just throw exception
- break;
- }
- throw new IllegalArgumentException("Unsupported key:" + key);
- }
-
- @Override
- public void init() {
- Bundle info = mInfoHal.getBasicInfo();
- // do not update ID immediately even if user clears it.
- info.putString(CarInfoManager.BASIC_INFO_KEY_VEHICLE_ID,
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ANDROID_ID));
- }
-
- @Override
- public synchronized void release() {
- //nothing to do
- }
-
- @Override
- public void dump(PrintWriter writer) {
- writer.println("*CarInfoService*");
- writer.println("**Check HAL dump");
- }
-}
-
diff --git a/service/src/com/android/car/CarLocationService.java b/service/src/com/android/car/CarLocationService.java
index 92c83bc..6d93b40 100644
--- a/service/src/com/android/car/CarLocationService.java
+++ b/service/src/com/android/car/CarLocationService.java
@@ -16,13 +16,15 @@
package com.android.car;
-import android.car.hardware.CarSensorEvent;
-import android.car.hardware.CarSensorManager;
-import android.car.hardware.ICarSensorEventListener;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.ICarPropertyEventListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
import android.location.Location;
import android.location.LocationManager;
import android.os.Handler;
@@ -64,19 +66,19 @@
private final Context mContext;
private final CarPowerManagementService mCarPowerManagementService;
- private final CarSensorService mCarSensorService;
- private final CarSensorEventListener mCarSensorEventListener;
+ private final CarPropertyService mCarPropertyService;
+ private final CarPropertyEventListener mCarPropertyEventListener;
private int mTaskCount = 0;
private HandlerThread mHandlerThread;
private Handler mHandler;
public CarLocationService(Context context, CarPowerManagementService carPowerManagementService,
- CarSensorService carSensorService) {
+ CarPropertyService carPropertyService) {
logd("constructed");
mContext = context;
mCarPowerManagementService = carPowerManagementService;
- mCarSensorService = carSensorService;
- mCarSensorEventListener = new CarSensorEventListener();
+ mCarPropertyService = carPropertyService;
+ mCarPropertyEventListener = new CarPropertyEventListener();
}
@Override
@@ -87,16 +89,16 @@
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
mContext.registerReceiver(this, filter);
- mCarSensorService.registerOrUpdateSensorListener(
- CarSensorManager.SENSOR_TYPE_IGNITION_STATE, 0, mCarSensorEventListener);
+ mCarPropertyService.registerListener(VehicleProperty.IGNITION_STATE, 0,
+ mCarPropertyEventListener);
mCarPowerManagementService.registerPowerEventProcessingHandler(this);
}
@Override
public void release() {
logd("release");
- mCarSensorService.unregisterSensorListener(CarSensorManager.SENSOR_TYPE_IGNITION_STATE,
- mCarSensorEventListener);
+ mCarPropertyService.unregisterListener(VehicleProperty.IGNITION_STATE,
+ mCarPropertyEventListener);
mContext.unregisterReceiver(this);
}
@@ -104,7 +106,7 @@
public void dump(PrintWriter writer) {
writer.println(TAG);
writer.println("Context: " + mContext);
- writer.println("CarSensorService: " + mCarSensorService);
+ writer.println("CarPropertyService: " + mCarPropertyService);
}
@Override
@@ -313,15 +315,20 @@
}
}
- private class CarSensorEventListener extends ICarSensorEventListener.Stub {
+ private class CarPropertyEventListener extends ICarPropertyEventListener.Stub {
@Override
- public void onSensorChanged(List<CarSensorEvent> events) throws RemoteException {
- CarSensorEvent event = events.get(0);
- if (event.sensorType == CarSensorManager.SENSOR_TYPE_IGNITION_STATE) {
- logd("sensor ignition value: " + event.intValues[0]);
- if (event.intValues[0] == CarSensorEvent.IGNITION_STATE_OFF) {
- logd("ignition off");
- asyncOperation(() -> storeLocation());
+ public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+ for (CarPropertyEvent event : events) {
+ if (event.getEventType() == CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE) {
+ CarPropertyValue value = event.getCarPropertyValue();
+ if (value.getPropertyId() == VehicleProperty.IGNITION_STATE) {
+ int ignitionState = (Integer) value.getValue();
+ logd("property ignition value: " + ignitionState);
+ if (ignitionState == VehicleIgnitionState.OFF) {
+ logd("ignition off");
+ asyncOperation(() -> storeLocation());
+ }
+ }
}
}
}
diff --git a/service/src/com/android/car/CarNightService.java b/service/src/com/android/car/CarNightService.java
index 212bb1a..e43ed3d 100644
--- a/service/src/com/android/car/CarNightService.java
+++ b/service/src/com/android/car/CarNightService.java
@@ -18,10 +18,12 @@
import android.annotation.IntDef;
import android.app.UiModeManager;
-import android.car.hardware.CarSensorEvent;
-import android.car.hardware.CarSensorManager;
-import android.car.hardware.ICarSensorEventListener;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.ICarPropertyEventListener;
import android.content.Context;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.os.RemoteException;
import android.util.Log;
import java.io.PrintWriter;
@@ -29,7 +31,6 @@
import java.lang.annotation.RetentionPolicy;
import java.util.List;
-
public class CarNightService implements CarServiceBase {
public static final boolean DBG = false;
@@ -46,38 +47,44 @@
private int mForcedMode = FORCED_SENSOR_MODE;
private final Context mContext;
private final UiModeManager mUiModeManager;
- private CarSensorService mCarSensorService;
+ private CarPropertyService mCarPropertyService;
- private final ICarSensorEventListener mICarSensorEventListener =
- new ICarSensorEventListener.Stub() {
+ private final ICarPropertyEventListener mICarPropertyEventListener =
+ new ICarPropertyEventListener.Stub() {
@Override
- public void onSensorChanged(List<CarSensorEvent> events) {
- if (!events.isEmpty()) {
- CarSensorEvent event = events.get(events.size() - 1);
- handleSensorEvent(event);
+ public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+ for (CarPropertyEvent event : events) {
+ handlePropertyEvent(event);
}
}
};
- public synchronized void handleSensorEvent(CarSensorEvent event) {
+ /**
+ * Handle CarPropertyEvents
+ * @param event
+ */
+ public synchronized void handlePropertyEvent(CarPropertyEvent event) {
if (event == null) {
return;
}
- if (event.sensorType == CarSensorManager.SENSOR_TYPE_NIGHT) {
- if (event.intValues[0] == 0) {
- mNightSetting = UiModeManager.MODE_NIGHT_NO;
- if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent DAY");
- }
- else {
- mNightSetting = UiModeManager.MODE_NIGHT_YES;
- if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent NIGHT");
- }
-
- if (mUiModeManager != null && (mForcedMode == FORCED_SENSOR_MODE)) {
- mUiModeManager.setNightMode(mNightSetting);
- if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent APPLIED");
- } else {
- if (DBG) Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent IGNORED");
+ if (event.getEventType() == CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE) {
+ // Only handle onChange events
+ CarPropertyValue value = event.getCarPropertyValue();
+ if (value.getPropertyId() == VehicleProperty.NIGHT_MODE) {
+ boolean nightMode = (Boolean) value.getValue();
+ if (nightMode) {
+ mNightSetting = UiModeManager.MODE_NIGHT_YES;
+ if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent NIGHT");
+ } else {
+ mNightSetting = UiModeManager.MODE_NIGHT_NO;
+ if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent DAY");
+ }
+ if (mUiModeManager != null && (mForcedMode == FORCED_SENSOR_MODE)) {
+ mUiModeManager.setNightMode(mNightSetting);
+ if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent APPLIED");
+ } else {
+ if (DBG) Log.d(CarLog.TAG_SENSOR, "CAR dayNight handleSensorEvent IGNORED");
+ }
}
}
}
@@ -108,9 +115,9 @@
return mUiModeManager.getNightMode();
}
- CarNightService(Context context, CarSensorService sensorService) {
+ CarNightService(Context context, CarPropertyService propertyService) {
mContext = context;
- mCarSensorService = sensorService;
+ mCarPropertyService = propertyService;
mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
if (mUiModeManager == null) {
Log.w(CarLog.TAG_SENSOR, "Failed to get UI_MODE_SERVICE");
@@ -122,11 +129,8 @@
if (DBG) {
Log.d(CarLog.TAG_SENSOR,"CAR dayNight init.");
}
- mCarSensorService.registerOrUpdateSensorListener(CarSensorManager.SENSOR_TYPE_NIGHT,
- CarSensorManager.SENSOR_RATE_NORMAL, mICarSensorEventListener);
- CarSensorEvent currentState = mCarSensorService.getLatestSensorEvent(
- CarSensorManager.SENSOR_TYPE_NIGHT);
- handleSensorEvent(currentState);
+ mCarPropertyService.registerListener(VehicleProperty.NIGHT_MODE, 0,
+ mICarPropertyEventListener);
}
@Override
diff --git a/service/src/com/android/car/CarPropertyService.java b/service/src/com/android/car/CarPropertyService.java
new file mode 100644
index 0000000..68c4b8c
--- /dev/null
+++ b/service/src/com/android/car/CarPropertyService.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2018 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 static java.lang.Integer.toHexString;
+
+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 android.util.Pair;
+import android.util.SparseArray;
+
+import com.android.car.hal.PropertyHalService;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * 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.
+ * {@link CarHvacService} shows the basic usage.
+ */
+public class CarPropertyService extends ICarProperty.Stub
+ implements CarServiceBase, PropertyHalService.PropertyHalListener {
+ private static final boolean DBG = true;
+ private static final String TAG = "Property.service";
+ private final Context mContext;
+ private final Map<IBinder, Client> mClientMap = new ConcurrentHashMap<>();
+ private Map<Integer, CarPropertyConfig<?>> mConfigs;
+ private final PropertyHalService mHal;
+ private boolean mListenerIsSet = false;
+ private final Map<Integer, List<Client>> mPropIdClientMap = new ConcurrentHashMap<>();
+ private final Object mLock = new Object();
+
+ public CarPropertyService(Context context, PropertyHalService hal) {
+ if (DBG) {
+ Log.d(TAG, "CarPropertyService started!");
+ }
+ mHal = hal;
+ mContext = context;
+ }
+
+ // Helper class to keep track of listeners to this service
+ private class Client implements IBinder.DeathRecipient {
+ private final ICarPropertyEventListener mListener;
+ private final IBinder mListenerBinder;
+ private final SparseArray<Float> mRateMap = new SparseArray<Float>(); // key is propId
+
+ Client(ICarPropertyEventListener listener) {
+ mListener = listener;
+ mListenerBinder = listener.asBinder();
+
+ try {
+ mListenerBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to link death for recipient. " + e);
+ throw new IllegalStateException(Car.CAR_NOT_CONNECTED_EXCEPTION_MSG);
+ }
+ mClientMap.put(mListenerBinder, this);
+ }
+
+ void addProperty(int propId, float rate) {
+ mRateMap.put(propId, rate);
+ }
+
+ /**
+ * 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);
+ }
+
+ for (int i = 0; i < mRateMap.size(); i++) {
+ int propId = mRateMap.keyAt(i);
+ CarPropertyService.this.unregisterListenerBinderLocked(propId, mListenerBinder);
+ }
+ this.release();
+ }
+
+ ICarPropertyEventListener getListener() {
+ return mListener;
+ }
+
+ IBinder getListenerBinder() {
+ return mListenerBinder;
+ }
+
+ float getRate(int propId) {
+ // Return 0 if no key found, since that is the slowest rate.
+ return mRateMap.get(propId, (float) 0);
+ }
+
+ void release() {
+ mListenerBinder.unlinkToDeath(this, 0);
+ mClientMap.remove(mListenerBinder);
+ }
+
+ void removeProperty(int propId) {
+ mRateMap.remove(propId);
+ if (mRateMap.size() == 0) {
+ // Last property was released, remove the client.
+ this.release();
+ }
+ }
+ }
+
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public void release() {
+ for (Client c : mClientMap.values()) {
+ c.release();
+ }
+ mClientMap.clear();
+ mPropIdClientMap.clear();
+ mHal.setListener(null);
+ mListenerIsSet = false;
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ }
+
+ @Override
+ public void registerListener(int propId, float rate, ICarPropertyEventListener listener) {
+ if (DBG) {
+ Log.d(TAG, "registerListener: propId=0x" + toHexString(propId) + " rate=" + rate);
+ }
+ if (mConfigs.get(propId) == null) {
+ // Do not attempt to register an invalid propId
+ Log.e(TAG, "registerListener: propId is not in config list: " + propId);
+ return;
+ }
+ ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
+ if (listener == null) {
+ Log.e(TAG, "registerListener: Listener is null.");
+ throw new IllegalArgumentException("listener cannot be null.");
+ }
+
+ IBinder listenerBinder = listener.asBinder();
+
+ synchronized (mLock) {
+ // Get the client for this listener
+ Client client = mClientMap.get(listenerBinder);
+ if (client == null) {
+ client = new Client(listener);
+ }
+ client.addProperty(propId, rate);
+ // Insert the client into the propId --> clients map
+ List<Client> clients = mPropIdClientMap.get(propId);
+ if (clients == null) {
+ clients = new CopyOnWriteArrayList<Client>();
+ mPropIdClientMap.put(propId, clients);
+ }
+ if (!clients.contains(client)) {
+ clients.add(client);
+ }
+ // Set the HAL listener if necessary
+ if (!mListenerIsSet) {
+ mHal.setListener(this);
+ }
+ // Set the new rate
+ if (rate > mHal.getSampleRate(propId)) {
+ mHal.subscribeProperty(propId, rate);
+ }
+ }
+
+ // Send the latest value(s) to the registering listener only
+ List<CarPropertyEvent> events = new LinkedList<CarPropertyEvent>();
+ for (int areaId : mConfigs.get(propId).getAreaIds()) {
+ CarPropertyValue value = mHal.getProperty(propId, areaId);
+ CarPropertyEvent event = new CarPropertyEvent(
+ CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
+ events.add(event);
+ }
+ try {
+ listener.onEvent(events);
+ } catch (RemoteException ex) {
+ // If we cannot send a record, its likely the connection snapped. Let the binder
+ // death handle the situation.
+ Log.e(TAG, "onEvent calling failed: " + ex);
+ }
+ }
+
+ @Override
+ public void unregisterListener(int propId, ICarPropertyEventListener listener) {
+ if (DBG) {
+ Log.d(TAG, "unregisterListener propId=0x" + toHexString(propId));
+ }
+ ICarImpl.assertPermission(mContext, mHal.getReadPermission(propId));
+ if (listener == null) {
+ Log.e(TAG, "unregisterListener: Listener is null.");
+ throw new IllegalArgumentException("Listener is null");
+ }
+
+ IBinder listenerBinder = listener.asBinder();
+ synchronized (mLock) {
+ unregisterListenerBinderLocked(propId, listenerBinder);
+ }
+ }
+
+ private void unregisterListenerBinderLocked(int propId, IBinder listenerBinder) {
+ Client client = mClientMap.get(listenerBinder);
+ List<Client> propertyClients = mPropIdClientMap.get(propId);
+ if (mConfigs.get(propId) == null) {
+ // Do not attempt to register an invalid propId
+ Log.e(TAG, "unregisterListener: propId is not in config list:0x" + toHexString(propId));
+ return;
+ }
+ if ((client == null) || (propertyClients == null)) {
+ Log.e(TAG, "unregisterListenerBinderLocked: Listener was not previously registered.");
+ } else {
+ if (propertyClients.remove(client)) {
+ client.removeProperty(propId);
+ } else {
+ Log.e(TAG, "unregisterListenerBinderLocked: Listener was not registered for "
+ + "propId=0x" + toHexString(propId));
+ }
+
+ if (propertyClients.isEmpty()) {
+ // Last listener for this property unsubscribed. Clean up
+ mHal.unsubscribeProperty(propId);
+ mPropIdClientMap.remove(propId);
+ if (mPropIdClientMap.isEmpty()) {
+ // No more properties are subscribed. Turn off the listener.
+ mHal.setListener(null);
+ mListenerIsSet = false;
+ }
+ } else {
+ // Other listeners are still subscribed. Calculate the new rate
+ float maxRate = 0;
+ for (Client c : propertyClients) {
+ float rate = c.getRate(propId);
+ if (rate > maxRate) {
+ maxRate = rate;
+ }
+ }
+ // Set the new rate
+ mHal.subscribeProperty(propId, maxRate);
+ }
+ }
+ }
+
+ /**
+ * Return the list of properties that the caller may access.
+ */
+ @Override
+ public List<CarPropertyConfig> getPropertyList() {
+ List<CarPropertyConfig> returnList = new ArrayList<CarPropertyConfig>();
+ if (mConfigs == null) {
+ // Cache the configs list to avoid subsequent binder calls
+ mConfigs = mHal.getPropertyList();
+ }
+ for (CarPropertyConfig c : mConfigs.values()) {
+ if (ICarImpl.hasPermission(mContext, mHal.getReadPermission(c.getPropertyId()))) {
+ // Only add properties the list if the process has permissions to read it
+ returnList.add(c);
+ }
+ }
+ if (DBG) {
+ Log.d(TAG, "getPropertyList returns " + returnList.size() + " configs");
+ }
+ return returnList;
+ }
+
+ @Override
+ public CarPropertyValue getProperty(int prop, int zone) {
+ if (mConfigs.get(prop) == null) {
+ // Do not attempt to register an invalid propId
+ Log.e(TAG, "getProperty: propId is not in config list:0x" + toHexString(prop));
+ return null;
+ }
+ ICarImpl.assertPermission(mContext, mHal.getReadPermission(prop));
+ return mHal.getProperty(prop, zone);
+ }
+
+ @Override
+ public void setProperty(CarPropertyValue prop) {
+ int propId = prop.getPropertyId();
+ if (mConfigs.get(propId) == null) {
+ // Do not attempt to register an invalid propId
+ Log.e(TAG, "setProperty: propId is not in config list:0x" + toHexString(propId));
+ return;
+ }
+ ICarImpl.assertPermission(mContext, mHal.getWritePermission(propId));
+ mHal.setProperty(prop);
+ }
+
+ // Implement PropertyHalListener interface
+ @Override
+ public void onPropertyChange(List<CarPropertyEvent> events) {
+ Map<IBinder, Pair<ICarPropertyEventListener, List<CarPropertyEvent>>> eventsToDispatch =
+ new HashMap<>();
+
+ for (CarPropertyEvent event : events) {
+ int propId = event.getCarPropertyValue().getPropertyId();
+ List<Client> clients = mPropIdClientMap.get(propId);
+ if (clients == null) {
+ Log.e(TAG, "onPropertyChange: no listener registered for propId=0x"
+ + toHexString(propId));
+ continue;
+ }
+
+ for (Client c : clients) {
+ IBinder listenerBinder = c.getListenerBinder();
+ Pair<ICarPropertyEventListener, List<CarPropertyEvent>> p =
+ eventsToDispatch.get(listenerBinder);
+ if (p == null) {
+ // Initialize the linked list for the listener
+ p = new Pair<>(c.getListener(), new LinkedList<CarPropertyEvent>());
+ eventsToDispatch.put(listenerBinder, p);
+ }
+ p.second.add(event);
+ }
+ }
+ // Parse the dispatch list to send events
+ for (Pair<ICarPropertyEventListener, List<CarPropertyEvent>> p: eventsToDispatch.values()) {
+ try {
+ p.first.onEvent(p.second);
+ } catch (RemoteException ex) {
+ // If we cannot send a record, its likely the connection snapped. Let binder
+ // death handle the situation.
+ Log.e(TAG, "onEvent calling failed: " + ex);
+ }
+ }
+ }
+
+ @Override
+ public void onPropertySetError(int property, int area) {
+ List<Client> clients = mPropIdClientMap.get(property);
+ if (clients != null) {
+ List<CarPropertyEvent> eventList = new LinkedList<>();
+ eventList.add(createErrorEvent(property, area));
+ for (Client c : clients) {
+ try {
+ c.getListener().onEvent(eventList);
+ } catch (RemoteException ex) {
+ // If we cannot send a record, its likely the connection snapped. Let the binder
+ // death handle the situation.
+ Log.e(TAG, "onEvent calling failed: " + ex);
+ }
+ }
+ } else {
+ Log.e(TAG, "onPropertySetError called with no listener registered for propId=0x"
+ + toHexString(property));
+ }
+ }
+
+ private static CarPropertyEvent createErrorEvent(int property, int area) {
+ return new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_ERROR,
+ new CarPropertyValue<>(property, area, null));
+ }
+}
diff --git a/service/src/com/android/car/CarPropertyServiceBase.java b/service/src/com/android/car/CarPropertyServiceBase.java
deleted file mode 100644
index 02ab7c9..0000000
--- a/service/src/com/android/car/CarPropertyServiceBase.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 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.
- * {@link CarHvacService} 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 ConcurrentHashMap<>();
- private final PropertyHalServiceBase mHal;
- private final Map<IBinder, ICarPropertyEventListener> mListenersMap = new ConcurrentHashMap<>();
- private final String mPermission;
- private final String mTag;
-
- private final Object mLock = new Object();
-
- 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 void init() {
- }
-
- @Override
- public void release() {
- for (PropertyDeathRecipient recipient : mDeathRecipientMap.values()) {
- recipient.release();
- }
- mDeathRecipientMap.clear();
- mListenersMap.clear();
- }
-
- @Override
- public void dump(PrintWriter writer) {
- }
-
- @Override
- public 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();
-
- synchronized (mLock) {
- 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 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();
- synchronized (mLock) {
- 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 List<CarPropertyConfig> getPropertyList() {
- ICarImpl.assertPermission(mContext, mPermission);
- return mHal.getPropertyList();
- }
-
- @Override
- public CarPropertyValue getProperty(int prop, int zone) {
- ICarImpl.assertPermission(mContext, mPermission);
- return mHal.getProperty(prop, zone);
- }
-
- @Override
- public void setProperty(CarPropertyValue prop) {
- ICarImpl.assertPermission(mContext, mPermission);
- mHal.setProperty(prop);
- }
-
- private ICarPropertyEventListener[] getListeners() {
- synchronized (mLock) {
- int size = mListenersMap.values().size();
- return mListenersMap.values().toArray(new ICarPropertyEventListener[size]);
- }
- }
-
- // Implement PropertyHalListener interface
- @Override
- public void onPropertyChange(CarPropertyEvent event) {
- for (ICarPropertyEventListener listener : getListeners()) {
- try {
- listener.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 void onPropertySetError(int property, int area) {
- for (ICarPropertyEventListener listener : getListeners()) {
- try {
- listener.onEvent(createErrorEvent(property, area));
- } 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);
- }
- }
- }
-
- private static CarPropertyEvent createErrorEvent(int property, int area) {
- return new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_ERROR,
- new CarPropertyValue<>(property, area, null));
- }
-}
diff --git a/service/src/com/android/car/CarSensorService.java b/service/src/com/android/car/CarSensorService.java
deleted file mode 100644
index 4b0227e..0000000
--- a/service/src/com/android/car/CarSensorService.java
+++ /dev/null
@@ -1,844 +0,0 @@
-/*
- * Copyright (C) 2015 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 static com.android.car.Listeners.ClientWithRate;
-
-import android.car.Car;
-import android.car.hardware.CarSensorConfig;
-import android.car.hardware.CarSensorEvent;
-import android.car.hardware.CarSensorManager;
-import android.car.hardware.ICarSensor;
-import android.car.hardware.ICarSensorEventListener;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-
-import com.android.car.hal.SensorHalService;
-import com.android.internal.annotations.GuardedBy;
-
-import com.google.android.collect.Lists;
-
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.ConcurrentModificationException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.ReentrantLock;
-
-
-public class CarSensorService extends ICarSensor.Stub
- implements CarServiceBase, SensorHalService.SensorListener {
-
- /**
- * When set, sensor service sets its own dispatching rate limit.
- * VehicleNetworkService is already doing this, so not necessary to set it for now.
- */
- private static final boolean ENABLE_DISPATCHING_LIMIT = false;
-
- /** {@link #mSensorLock} is not waited forever for handling disconnection */
- private static final long MAX_SENSOR_LOCK_WAIT_MS = 1000;
-
- /** lock to access sensor structures */
- private final ReentrantLock mSensorLock = new ReentrantLock();
- /** hold clients callback */
- @GuardedBy("mSensorLock")
- private final LinkedList<SensorClient> mClients = new LinkedList<>();
-
- /** key: sensor type. */
- @GuardedBy("mSensorLock")
- private final SparseArray<Listeners<SensorClient>> mSensorListeners = new SparseArray<>();
- /** key: sensor type. */
- @GuardedBy("mSensorLock")
- private final SparseArray<SensorRecord> mSensorRecords = new SparseArray<>();
-
- private final SensorHalService mSensorHal;
- private int[] mCarProvidedSensors;
- private int[] mSupportedSensors;
- private final AtomicBoolean mSensorDiscovered = new AtomicBoolean(false);
-
- private final Context mContext;
-
- private final HandlerThread mHandlerThread;
- private final SensorDispatchHandler mSensorDispatchHandler;
-
- public CarSensorService(Context context, SensorHalService sensorHal) {
- mContext = context;
- if (ENABLE_DISPATCHING_LIMIT) {
- mHandlerThread = new HandlerThread("SENSOR", Process.THREAD_PRIORITY_AUDIO);
- mHandlerThread.start();
- mSensorDispatchHandler = new SensorDispatchHandler(mHandlerThread.getLooper());
- } else {
- mHandlerThread = null;
- mSensorDispatchHandler = null;
- }
- // This triggers sensor hal init as well.
- mSensorHal = sensorHal;
- }
-
- @Override
- public void init() {
- mSensorLock.lock();
- try {
- mSensorHal.registerSensorListener(this);
- mCarProvidedSensors = mSensorHal.getSupportedSensors();
- mSupportedSensors = refreshSupportedSensorsLocked();
-
- addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT, getInitialNightMode());
- addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_IGNITION_STATE,
- getInitialIgnitionState());
- } finally {
- mSensorLock.unlock();
- }
- }
-
- private CarSensorEvent getInitialIgnitionState() {
- return mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_IGNITION_STATE);
- }
-
- private CarSensorEvent getInitialNightMode() {
- CarSensorEvent event = mSensorHal.getCurrentSensorValue(CarSensorManager.SENSOR_TYPE_NIGHT);
- if (event == null) {
- Log.e(CarLog.TAG_SENSOR, "Daynight sensor not ready!");
-
- // Create a place holder event that puts us in NIGHT mode at startup if we failed
- // to get the actual VHAL value.
- event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT, 0, 0, 1, 0);
- event.intValues[0] = 1; // 1 means night mode!
- }
- Log.i(CarLog.TAG_SENSOR, "initial daynight: " +
- (event.intValues[0] == 1 ? "Night" : "Day"));
-
- return event;
- }
-
- @GuardedBy("mSensorLock")
- private void addNewSensorRecordLocked(int type, CarSensorEvent event) {
- SensorRecord record = new SensorRecord();
- record.lastEvent = event;
- mSensorRecords.put(type,record);
- }
-
- @Override
- public void release() {
- if (mHandlerThread != null) {
- mHandlerThread.quit();
- }
- tryHoldSensorLock();
- try {
- for (int i = mSensorListeners.size() - 1; i >= 0; --i) {
- Listeners listener = mSensorListeners.valueAt(i);
- listener.release();
- }
- mSensorListeners.clear();
- mSensorRecords.clear();
- mClients.clear();
- } finally {
- releaseSensorLockSafely();
- }
- }
-
- private void tryHoldSensorLock() {
- try {
- mSensorLock.tryLock(MAX_SENSOR_LOCK_WAIT_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- //ignore
- }
- }
-
- private void releaseSensorLockSafely() {
- if (mSensorLock.isHeldByCurrentThread()) {
- mSensorLock.unlock();
- }
- }
-
- private void processSensorData(List<CarSensorEvent> events) {
- ArrayMap<SensorClient, List<CarSensorEvent>> eventsByClient = new ArrayMap<>();
-
- mSensorLock.lock();
- for (CarSensorEvent event: events) {
- SensorRecord record = mSensorRecords.get(event.sensorType);
- if (record != null) {
- if (record.lastEvent == null) {
- record.lastEvent = event;
- } else if (record.lastEvent.timestamp < event.timestamp) {
- record.lastEvent = event;
- //TODO recycle event, bug: 32094595
- } else { // wrong timestamp, throw away this.
- //TODO recycle new event, bug: 32094595
- continue;
- }
-
- Listeners<SensorClient> listeners = mSensorListeners.get(event.sensorType);
- if (listeners == null) {
- continue;
- }
-
- for (ClientWithRate<SensorClient> clientWithRate : listeners.getClients()) {
- SensorClient client = clientWithRate.getClient();
- List<CarSensorEvent> clientEvents = eventsByClient.get(client);
- if (clientEvents == null) {
- clientEvents = new LinkedList<>();
- eventsByClient.put(client, clientEvents);
- }
- clientEvents.add(event);
- }
- }
- }
- mSensorLock.unlock();
-
- for (ArrayMap.Entry<SensorClient, List<CarSensorEvent>> entry : eventsByClient.entrySet()) {
- SensorClient client = entry.getKey();
- List<CarSensorEvent> clientEvents = entry.getValue();
-
- client.dispatchSensorUpdate(clientEvents);
- }
- }
-
- /**
- * Received sensor data from car.
- */
- @Override
- public void onSensorEvents(List<CarSensorEvent> events) {
- if (ENABLE_DISPATCHING_LIMIT) {
- mSensorDispatchHandler.handleSensorEvents(events);
- } else {
- processSensorData(events);
- }
- }
-
- @Override
- public int[] getSupportedSensors() {
- mSensorLock.lock();
- int[] supportedSensors = mSupportedSensors;
- mSensorLock.unlock();
- return supportedSensors;
- }
-
- @Override
- public boolean registerOrUpdateSensorListener(int sensorType, int rate,
- ICarSensorEventListener listener) {
- boolean shouldStartSensors = false;
- SensorRecord sensorRecord = null;
- SensorClient sensorClient = null;
- Integer oldRate = null;
- Listeners<SensorClient> sensorListeners = null;
- mSensorLock.lock();
- try {
- sensorRecord = mSensorRecords.get(sensorType);
- if (sensorRecord == null) {
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.INFO)) {
- Log.i(CarLog.TAG_SENSOR, "Requested sensor " + sensorType + " not supported");
- }
- return false;
- }
- if (Binder.getCallingUid() != Process.myUid()) {
- switch (getSensorPermission(sensorType)) {
- case PackageManager.PERMISSION_DENIED:
- throw new SecurityException("client does not have permission:"
- + getPermissionName(sensorType)
- + " pid:" + Binder.getCallingPid()
- + " uid:" + Binder.getCallingUid());
- case PackageManager.PERMISSION_GRANTED:
- break;
- }
- }
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "registerOrUpdateSensorListener " + sensorType + " " +
- listener);
- }
- sensorClient = findSensorClientLocked(listener);
- ClientWithRate<SensorClient> sensorClientWithRate = null;
- sensorListeners = mSensorListeners.get(sensorType);
- if (sensorClient == null) {
- sensorClient = new SensorClient(listener);
- try {
- listener.asBinder().linkToDeath(sensorClient, 0);
- } catch (RemoteException e) {
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.INFO)) {
- Log.i(CarLog.TAG_SENSOR, "Adding listener failed.");
- }
- return false;
- }
- mClients.add(sensorClient);
- }
- // If we have a cached event for this sensor, send the event.
- SensorRecord record = mSensorRecords.get(sensorType);
- if (record != null && record.lastEvent != null) {
- sensorClient.dispatchSensorUpdate(Lists.newArrayList(record.lastEvent));
- }
- if (sensorListeners == null) {
- sensorListeners = new Listeners<>(rate);
- mSensorListeners.put(sensorType, sensorListeners);
- shouldStartSensors = true;
- } else {
- oldRate = sensorListeners.getRate();
- sensorClientWithRate = sensorListeners.findClientWithRate(sensorClient);
- }
- if (sensorClientWithRate == null) {
- sensorClientWithRate = new ClientWithRate<>(sensorClient, rate);
- sensorListeners.addClientWithRate(sensorClientWithRate);
- } else {
- sensorClientWithRate.setRate(rate);
- }
- if (sensorListeners.getRate() > rate) {
- sensorListeners.setRate(rate);
- shouldStartSensors = sensorSupportRate(sensorType);
- }
- sensorClient.addSensor(sensorType);
- } finally {
- mSensorLock.unlock();
- }
- // start sensor outside lock as it can take time.
- if (shouldStartSensors) {
- if (!startSensor(sensorRecord, sensorType, rate)) {
- // failed. so remove from active sensor list.
- mSensorLock.lock();
- try {
- sensorClient.removeSensor(sensorType);
- if (oldRate != null) {
- sensorListeners.setRate(oldRate);
- } else {
- mSensorListeners.remove(sensorType);
- }
- } finally {
- mSensorLock.unlock();
- }
- return false;
- }
- }
- return true;
- }
-
- private boolean sensorSupportRate(int sensorType) {
- switch (sensorType) {
- case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
- case CarSensorManager.SENSOR_TYPE_RPM:
- case CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE:
- return true;
- case CarSensorManager.SENSOR_TYPE_ODOMETER:
- case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
- case CarSensorManager.SENSOR_TYPE_PARKING_BRAKE:
- case CarSensorManager.SENSOR_TYPE_GEAR:
- case CarSensorManager.SENSOR_TYPE_NIGHT:
- case CarSensorManager.SENSOR_TYPE_ENVIRONMENT:
- return false;
- default:
- Log.w(CarLog.TAG_SENSOR, "sensorSupportRate not listed sensor:" + sensorType);
- return false;
- }
- }
-
- private int getSensorPermission(int sensorType) {
- String permission = getPermissionName(sensorType);
- int result = PackageManager.PERMISSION_GRANTED;
- if (permission != null) {
- return mContext.checkCallingOrSelfPermission(permission);
- }
- // If no permission is required, return granted.
- return result;
- }
-
- //TODO handle per property OEM permission. bug: 32094983
- private String getPermissionName(int sensorType) {
- if ((sensorType >= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_START) &&
- (sensorType <= CarSensorManager.SENSOR_TYPE_VENDOR_EXTENSION_END)) {
- return Car.PERMISSION_VENDOR_EXTENSION;
- }
- String permission = null;
- switch (sensorType) {
- case CarSensorManager.SENSOR_TYPE_ENGINE_OIL_LEVEL:
- case CarSensorManager.SENSOR_TYPE_RPM:
- permission = Car.PERMISSION_CAR_ENGINE_DETAILED;
- break;
- case CarSensorManager.SENSOR_TYPE_FUEL_DOOR_OPEN:
- case CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_OPEN:
- case CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED:
- permission = Car.PERMISSION_ENERGY_PORTS;
- break;
- case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
- case CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE:
- permission = Car.PERMISSION_SPEED;
- break;
- case CarSensorManager.SENSOR_TYPE_ODOMETER:
- permission = Car.PERMISSION_MILEAGE;
- break;
- case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
- case CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL:
- case CarSensorManager.SENSOR_TYPE_EV_BATTERY_CHARGE_RATE:
- permission = Car.PERMISSION_ENERGY;
- break;
- case CarSensorManager.SENSOR_TYPE_ABS_ACTIVE:
- case CarSensorManager.SENSOR_TYPE_TRACTION_CONTROL_ACTIVE:
- permission = Car.PERMISSION_CAR_DYNAMICS_STATE;
- break;
- default:
- break;
- }
- return permission;
- }
-
- private boolean startSensor(SensorRecord record, int sensorType, int rate) {
- //TODO handle sensor rate properly. bug: 32095903
- //Some sensors which report only when there is change should be always set with maximum
- //rate. For now, set every sensor to the maximum.
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.VERBOSE)) {
- Log.v(CarLog.TAG_SENSOR, "startSensor " + sensorType + " with rate " + rate);
- }
- if (mSensorHal != null) {
- if (!mSensorHal.isReady()) {
- Log.w(CarLog.TAG_SENSOR, "Sensor channel not available.");
- return false;
- }
- if (record.enabled) {
- return true;
- }
- if (mSensorHal.requestSensorStart(sensorType, 0)) {
- record.enabled = true;
- return true;
- }
- }
- Log.w(CarLog.TAG_SENSOR, "requestSensorStart failed, sensor type:" + sensorType);
- return false;
- }
-
- @Override
- public void unregisterSensorListener(int sensorType, ICarSensorEventListener listener) {
- boolean shouldStopSensor = false;
- boolean shouldRestartSensor = false;
- SensorRecord record = null;
- int newRate = 0;
- mSensorLock.lock();
- try {
- record = mSensorRecords.get(sensorType);
- if (record == null) {
- // unregister not supported sensor. ignore.
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "unregister for unsupported sensor");
- }
- return;
- }
- SensorClient sensorClient = findSensorClientLocked(listener);
- if (sensorClient == null) {
- // never registered or already unregistered.
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "unregister for not existing client");
- }
- return;
- }
- sensorClient.removeSensor(sensorType);
- if (sensorClient.getNumberOfActiveSensor() == 0) {
- sensorClient.release();
- mClients.remove(sensorClient);
- }
- Listeners<SensorClient> sensorListeners = mSensorListeners.get(sensorType);
- if (sensorListeners == null) {
- // sensor not active
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "unregister for non-active sensor");
- }
- return;
- }
- ClientWithRate<SensorClient> clientWithRate =
- sensorListeners.findClientWithRate(sensorClient);
- if (clientWithRate == null) {
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "unregister for not registered sensor");
- }
- return;
- }
- sensorListeners.removeClientWithRate(clientWithRate);
- if (sensorListeners.getNumberOfClients() == 0) {
- shouldStopSensor = true;
- mSensorListeners.remove(sensorType);
- } else if (sensorListeners.updateRate()) { // rate changed
- newRate = sensorListeners.getRate();
- shouldRestartSensor = sensorSupportRate(sensorType);
- }
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "unregister succeeded");
- }
- } finally {
- mSensorLock.unlock();
- }
- if (shouldStopSensor) {
- stopSensor(record, sensorType);
- } else if (shouldRestartSensor) {
- startSensor(record, sensorType, newRate);
- }
- }
-
- @Override
- public CarSensorConfig getSensorConfig(int sensorType) {
- if (Binder.getCallingUid() != Process.myUid()) {
- switch (getSensorPermission(sensorType)) {
- case PackageManager.PERMISSION_DENIED:
- throw new SecurityException("client does not have permission:"
- + getPermissionName(sensorType)
- + " pid:" + Binder.getCallingPid()
- + " uid:" + Binder.getCallingUid());
- case PackageManager.PERMISSION_GRANTED:
- break;
- }
- }
- return(mSensorHal.getSensorConfig(sensorType));
- }
-
- private void stopSensor(SensorRecord record, int sensorType) {
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "stopSensor " + sensorType);
- }
- if (mSensorHal == null || !mSensorHal.isReady()) {
- Log.w(CarLog.TAG_SENSOR, "Sensor channel not available.");
- return;
- }
- if (!record.enabled) {
- return;
- }
- record.enabled = false;
- // make lastEvent invalid as old data can be sent to client when subscription is restarted
- // later.
- record.lastEvent = null;
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "stopSensor requestStop " + sensorType);
- }
- mSensorHal.requestSensorStop(sensorType);
- }
-
- @Override
- public CarSensorEvent getLatestSensorEvent(int sensorType) {
- SensorRecord record = null;
- mSensorLock.lock();
- try {
- record = mSensorRecords.get(sensorType);
- } finally {
- mSensorLock.unlock();
- }
- if (record != null) {
- return record.lastEvent;
- }
- return null;
- }
-
- @GuardedBy("mSensorLock")
- private int[] refreshSupportedSensorsLocked() {
- int numCarSensors = (mCarProvidedSensors == null) ? 0 : mCarProvidedSensors.length;
-
- int[] supportedSensors = new int[numCarSensors];
- int index = 0;
-
- for (int i = 0; i < numCarSensors; i++) {
- int sensor = mCarProvidedSensors[i];
-
- if (mSensorRecords.get(sensor) == null) {
- SensorRecord record = new SensorRecord();
- mSensorRecords.put(sensor, record);
- }
- supportedSensors[index] = sensor;
- index++;
- }
-
- return supportedSensors;
- }
-
- private boolean isSensorRealLocked(int sensorType) {
- if (mCarProvidedSensors != null) {
- for (int sensor : mCarProvidedSensors) {
- if (sensor == sensorType ) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Find SensorClient from client list and return it.
- * This should be called with mClients locked.
- * @param listener
- * @return null if not found.
- */
- @GuardedBy("mSensorLock")
- private SensorClient findSensorClientLocked(ICarSensorEventListener listener) {
- IBinder binder = listener.asBinder();
- for (SensorClient sensorClient : mClients) {
- if (sensorClient.isHoldingListenerBinder(binder)) {
- return sensorClient;
- }
- }
- return null;
- }
-
- private void removeClient(SensorClient sensorClient) {
- mSensorLock.lock();
- try {
- for (int sensor: sensorClient.getSensorArray()) {
- unregisterSensorListener(sensor,
- sensorClient.getICarSensorEventListener());
- }
- mClients.remove(sensorClient);
- } finally {
- mSensorLock.unlock();
- }
- }
-
- private class SensorDispatchHandler extends Handler {
- private static final long SENSOR_DISPATCH_MIN_INTERVAL_MS = 16; // over 60Hz
-
- private static final int MSG_SENSOR_DATA = 0;
-
- private long mLastSensorDispatchTime = -1;
- private int mFreeListIndex = 0;
- private final LinkedList<CarSensorEvent>[] mSensorDataList = new LinkedList[2];
-
- private SensorDispatchHandler(Looper looper) {
- super(looper);
- for (int i = 0; i < mSensorDataList.length; i++) {
- mSensorDataList[i] = new LinkedList<CarSensorEvent>();
- }
- }
-
- private synchronized void handleSensorEvents(List<CarSensorEvent> data) {
- LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
- list.addAll(data);
- requestDispatchLocked();
- }
-
- private synchronized void handleSensorEvent(CarSensorEvent event) {
- LinkedList<CarSensorEvent> list = mSensorDataList[mFreeListIndex];
- list.add(event);
- requestDispatchLocked();
- }
-
- private void requestDispatchLocked() {
- Message msg = obtainMessage(MSG_SENSOR_DATA);
- long now = SystemClock.uptimeMillis();
- long delta = now - mLastSensorDispatchTime;
- if (delta > SENSOR_DISPATCH_MIN_INTERVAL_MS) {
- sendMessage(msg);
- } else {
- sendMessageDelayed(msg, SENSOR_DISPATCH_MIN_INTERVAL_MS - delta);
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SENSOR_DATA:
- doHandleSensorData();
- break;
- default:
- break;
- }
- }
-
- private void doHandleSensorData() {
- List<CarSensorEvent> listToDispatch = null;
- synchronized (this) {
- mLastSensorDispatchTime = SystemClock.uptimeMillis();
- int nonFreeListIndex = mFreeListIndex ^ 0x1;
- List<CarSensorEvent> nonFreeList = mSensorDataList[nonFreeListIndex];
- List<CarSensorEvent> freeList = mSensorDataList[mFreeListIndex];
- if (nonFreeList.size() > 0) {
- Log.w(CarLog.TAG_SENSOR, "non free list not empty");
- // copy again, but this should not be normal case
- nonFreeList.addAll(freeList);
- listToDispatch = nonFreeList;
- freeList.clear();
- } else if (freeList.size() > 0) {
- listToDispatch = freeList;
- mFreeListIndex = nonFreeListIndex;
- }
- }
- // leave this part outside lock so that time-taking dispatching can be done without
- // blocking sensor event notification.
- if (listToDispatch != null) {
- processSensorData(listToDispatch);
- listToDispatch.clear();
- }
- }
-
- }
-
- /** internal instance for pending client request */
- private class SensorClient implements Listeners.IListener {
- /** callback for sensor events */
- private final ICarSensorEventListener mListener;
- private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
-
- /** when false, it is already released */
- private volatile boolean mActive = true;
-
- SensorClient(ICarSensorEventListener listener) {
- this.mListener = listener;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof SensorClient &&
- mListener.asBinder() == ((SensorClient) o).mListener.asBinder()) {
- return true;
- }
- return false;
- }
-
- boolean isHoldingListenerBinder(IBinder listenerBinder) {
- return mListener.asBinder() == listenerBinder;
- }
-
- void addSensor(int sensor) {
- mActiveSensors.put(sensor, true);
- }
-
- void removeSensor(int sensor) {
- mActiveSensors.delete(sensor);
- }
-
- int getNumberOfActiveSensor() {
- return mActiveSensors.size();
- }
-
- int[] getSensorArray() {
- int[] sensors = new int[mActiveSensors.size()];
- for (int i = sensors.length - 1; i >= 0; --i) {
- sensors[i] = mActiveSensors.keyAt(i);
- }
- return sensors;
- }
-
- ICarSensorEventListener getICarSensorEventListener() {
- return mListener;
- }
-
- /**
- * Client dead. should remove all sensor requests from client
- */
- @Override
- public void binderDied() {
- mListener.asBinder().unlinkToDeath(this, 0);
- removeClient(this);
- }
-
- void dispatchSensorUpdate(List<CarSensorEvent> events) {
- if (events.size() == 0) {
- return;
- }
- if (mActive) {
- try {
- mListener.onSensorChanged(events);
- } catch (RemoteException e) {
- //ignore. crash will be handled by death handler
- }
- } else {
- if (Log.isLoggable(CarLog.TAG_SENSOR, Log.DEBUG)) {
- Log.d(CarLog.TAG_SENSOR, "sensor update while client is already released");
- }
- }
- }
-
- @Override
- public void release() {
- if (mActive) {
- mListener.asBinder().unlinkToDeath(this, 0);
- mActiveSensors.clear();
- mActive = false;
- }
- }
- }
-
- private static class SensorRecord {
- /** Record the lastly received sensor event */
- CarSensorEvent lastEvent = null;
- /** sensor was enabled by at least one client */
- boolean enabled = false;
- }
-
- @Override
- public void dump(PrintWriter writer) {
- writer.println("*CarSensorService*");
- writer.println("supported sensors:" + Arrays.toString(mSupportedSensors));
- writer.println("**last events for sensors**");
- if (mSensorRecords != null) {
- try {
- int sensorRecordSize = mSensorRecords.size();
- for (int i = 0; i < sensorRecordSize; i++) {
- int sensor = mSensorRecords.keyAt(i);
- SensorRecord record = mSensorRecords.get(sensor);
- if (record != null && record.lastEvent != null) {
- writer.println("sensor: " + sensor
- + " active: " + record.enabled);
- writer.println(" " + record.lastEvent.toString());
- }
- Listeners listeners = mSensorListeners.get(sensor);
- if (listeners != null) {
- writer.println(" rate: " + listeners.getRate());
- }
- }
- } catch (ConcurrentModificationException e) {
- writer.println("concurrent modification happened");
- }
- } else {
- writer.println("null records");
- }
- writer.println("**clients**");
- try {
- for (SensorClient client: mClients) {
- if (client != null) {
- try {
- writer.println("binder:" + client.mListener
- + " active sensors:" + Arrays.toString(client.getSensorArray()));
- } catch (ConcurrentModificationException e) {
- writer.println("concurrent modification happened");
- }
- } else {
- writer.println("null client");
- }
- }
- } catch (ConcurrentModificationException e) {
- writer.println("concurrent modification happened");
- }
- writer.println("**sensor listeners**");
- try {
- int sensorListenerSize = mSensorListeners.size();
- for (int i = 0; i < sensorListenerSize; i++) {
- int sensor = mSensorListeners.keyAt(i);
- Listeners sensorListeners = mSensorListeners.get(sensor);
- if (sensorListeners != null) {
- writer.println(" Sensor:" + sensor
- + " num client:" + sensorListeners.getNumberOfClients()
- + " rate:" + sensorListeners.getRate());
- }
- }
- } catch (ConcurrentModificationException e) {
- writer.println("concurrent modification happened");
- }
- }
-}
diff --git a/service/src/com/android/car/CarUxRestrictionsManagerService.java b/service/src/com/android/car/CarUxRestrictionsManagerService.java
index 289706d..449a485 100644
--- a/service/src/com/android/car/CarUxRestrictionsManagerService.java
+++ b/service/src/com/android/car/CarUxRestrictionsManagerService.java
@@ -23,10 +23,11 @@
import android.car.drivingstate.ICarDrivingStateChangeListener;
import android.car.drivingstate.ICarUxRestrictionsChangeListener;
import android.car.drivingstate.ICarUxRestrictionsManager;
-import android.car.hardware.CarSensorEvent;
-import android.car.hardware.CarSensorManager;
-import android.car.hardware.ICarSensorEventListener;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.ICarPropertyEventListener;
import android.content.Context;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -48,9 +49,10 @@
private static final String TAG = "CarUxR";
private static final boolean DBG = false;
private static final int MAX_TRANSITION_LOG_SIZE = 20;
+ private static final int PROPERTY_UPDATE_RATE = 5; // Update rate in Hz
private final Context mContext;
private final CarDrivingStateService mDrivingStateService;
- private final CarSensorService mCarSensorService;
+ private final CarPropertyService mCarPropertyService;
private final CarUxRestrictionsServiceHelper mHelper;
// List of clients listening to UX restriction events.
private final List<UxRestrictionsClient> mUxRClients = new ArrayList<>();
@@ -62,13 +64,13 @@
public CarUxRestrictionsManagerService(Context context, CarDrivingStateService drvService,
- CarSensorService sensorService) {
+ CarPropertyService propertyService) {
mContext = context;
mDrivingStateService = drvService;
- mCarSensorService = sensorService;
+ mCarPropertyService = propertyService;
mHelper = new CarUxRestrictionsServiceHelper(mContext, R.xml.car_ux_restrictions_map);
// Unrestricted until driving state information is received. During boot up, we don't want
- // everything to be blocked until data is available from CarSensorManager. If we start
+ // everything to be blocked until data is available from CarPropertyManager. If we start
// driving and we don't get speed or gear information, we have bigger problems.
mCurrentUxRestrictions = mHelper.createUxRestrictionsEvent(false,
CarUxRestrictions.UX_RESTRICTIONS_BASELINE);
@@ -88,9 +90,9 @@
// subscribe to driving State
mDrivingStateService.registerDrivingStateChangeListener(
mICarDrivingStateChangeEventListener);
- // subscribe to Sensor service for speed
- mCarSensorService.registerOrUpdateSensorListener(CarSensorManager.SENSOR_TYPE_CAR_SPEED,
- CarSensorManager.SENSOR_RATE_UI, mICarSensorEventListener);
+ // subscribe to property service for speed
+ mCarPropertyService.registerListener(VehicleProperty.PERF_VEHICLE_SPEED,
+ PROPERTY_UPDATE_RATE, mICarPropertyEventListener);
}
@Override
@@ -280,10 +282,10 @@
return;
}
int drivingState = event.eventValue;
- CarSensorEvent speed = mCarSensorService.getLatestSensorEvent(
- CarSensorManager.SENSOR_TYPE_CAR_SPEED);
- if (speed != null) {
- mCurrentMovingSpeed = speed.floatValues[0];
+ CarPropertyValue value = mCarPropertyService.getProperty(VehicleProperty.PERF_VEHICLE_SPEED,
+ 0);
+ if (value != null) {
+ mCurrentMovingSpeed = (Float) value.getValue();
} else if (drivingState == CarDrivingStateEvent.DRIVING_STATE_PARKED
|| drivingState == CarDrivingStateEvent.DRIVING_STATE_UNKNOWN) {
// If speed is unavailable, but the driving state is parked or unknown, it can still be
@@ -303,17 +305,19 @@
}
/**
- * {@link CarSensorEvent} listener registered with the {@link CarSensorService} for getting
+ * {@link CarPropertyEvent} listener registered with the {@link CarPropertyService} for getting
* speed change notifications.
*/
- private final ICarSensorEventListener mICarSensorEventListener =
- new ICarSensorEventListener.Stub() {
+ private final ICarPropertyEventListener mICarPropertyEventListener =
+ new ICarPropertyEventListener.Stub() {
@Override
- public void onSensorChanged(List<CarSensorEvent> events) {
- for (CarSensorEvent event : events) {
- if (event != null
- && event.sensorType == CarSensorManager.SENSOR_TYPE_CAR_SPEED) {
- handleSpeedChange(event.floatValues[0]);
+ public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+ for (CarPropertyEvent event : events) {
+ if ((event.getEventType()
+ == CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE)
+ && (event.getCarPropertyValue().getPropertyId()
+ == VehicleProperty.PERF_VEHICLE_SPEED)) {
+ handleSpeedChange((Float) event.getCarPropertyValue().getValue());
}
}
}
diff --git a/service/src/com/android/car/CarVendorExtensionService.java b/service/src/com/android/car/CarVendorExtensionService.java
deleted file mode 100644
index 2e2d074..0000000
--- a/service/src/com/android/car/CarVendorExtensionService.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.content.Context;
-
-import com.android.car.hal.VendorExtensionHalService;
-
-/**
- * Service responsible for handling custom properties that were defined in vehicle HAL by OEMs.
- */
-public class CarVendorExtensionService extends CarPropertyServiceBase {
-
- private final static boolean DEBUG = false;
-
- public CarVendorExtensionService(Context context, VendorExtensionHalService vendorHal) {
- super(context, vendorHal, Car.PERMISSION_VENDOR_EXTENSION, DEBUG, CarLog.TAG_VENDOR_EXT);
- }
-}
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 9db071b..6c2ba36 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -61,21 +61,17 @@
private final CarPowerManagementService mCarPowerManagementService;
private final CarPackageManagerService mCarPackageManagerService;
private final CarInputService mCarInputService;
- private final CarSensorService mCarSensorService;
private final CarDrivingStateService mCarDrivingStateService;
private final CarUxRestrictionsManagerService mCarUXRestrictionsService;
- private final CarInfoService mCarInfoService;
private final CarAudioService mCarAudioService;
private final CarProjectionService mCarProjectionService;
- private final CarCabinService mCarCabinService;
- private final CarHvacService mCarHvacService;
+ private final CarPropertyService mCarPropertyService;
private final CarNightService mCarNightService;
private final AppFocusService mAppFocusService;
private final GarageModeService mGarageModeService;
private final InstrumentClusterService mInstrumentClusterService;
private final CarLocationService mCarLocationService;
private final SystemStateControllerService mSystemStateControllerService;
- private final CarVendorExtensionService mCarVendorExtensionService;
private final CarBluetoothService mCarBluetoothService;
private final PerUserCarServiceHelper mPerUserCarServiceHelper;
private final CarDiagnosticService mCarDiagnosticService;
@@ -110,10 +106,10 @@
mSystemActivityMonitoringService = new SystemActivityMonitoringService(serviceContext);
mCarPowerManagementService = new CarPowerManagementService(mContext, mHal.getPowerHal(),
systemInterface);
- mCarSensorService = new CarSensorService(serviceContext, mHal.getSensorHal());
- mCarDrivingStateService = new CarDrivingStateService(serviceContext, mCarSensorService);
+ mCarPropertyService = new CarPropertyService(serviceContext, mHal.getPropertyHal());
+ mCarDrivingStateService = new CarDrivingStateService(serviceContext, mCarPropertyService);
mCarUXRestrictionsService = new CarUxRestrictionsManagerService(serviceContext,
- mCarDrivingStateService, mCarSensorService);
+ mCarDrivingStateService, mCarPropertyService);
mCarPackageManagerService = new CarPackageManagerService(serviceContext,
mCarUXRestrictionsService,
mSystemActivityMonitoringService);
@@ -121,22 +117,17 @@
mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService);
mGarageModeService = new GarageModeService(mContext, mCarPowerManagementService);
mCarLocationService = new CarLocationService(mContext, mCarPowerManagementService,
- mCarSensorService);
- mCarInfoService = new CarInfoService(serviceContext, mHal.getInfoHal());
+ mCarPropertyService);
mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService);
mCarAudioService = new CarAudioService(serviceContext);
- mCarCabinService = new CarCabinService(serviceContext, mHal.getCabinHal());
- mCarHvacService = new CarHvacService(serviceContext, mHal.getHvacHal());
- mCarNightService = new CarNightService(serviceContext, mCarSensorService);
+ mCarNightService = new CarNightService(serviceContext, mCarPropertyService);
mInstrumentClusterService = new InstrumentClusterService(serviceContext,
mAppFocusService, mCarInputService);
mSystemStateControllerService = new SystemStateControllerService(serviceContext,
mCarPowerManagementService, mCarAudioService, this);
- mCarVendorExtensionService = new CarVendorExtensionService(serviceContext,
- mHal.getVendorExtensionHal());
mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext);
- mCarBluetoothService = new CarBluetoothService(serviceContext, mCarCabinService,
- mCarSensorService, mPerUserCarServiceHelper, mCarUXRestrictionsService);
+ mCarBluetoothService = new CarBluetoothService(serviceContext, mCarPropertyService,
+ mPerUserCarServiceHelper, mCarUXRestrictionsService);
mVmsSubscriberService = new VmsSubscriberService(serviceContext, mHal.getVmsHal());
mVmsPublisherService = new VmsPublisherService(serviceContext, mHal.getVmsHal());
mCarDiagnosticService = new CarDiagnosticService(serviceContext, mHal.getDiagnosticHal());
@@ -149,23 +140,19 @@
mAllServices = new CarServiceBase[] {
mSystemActivityMonitoringService,
mCarPowerManagementService,
- mCarSensorService,
+ mCarPropertyService,
mCarDrivingStateService,
mCarUXRestrictionsService,
mCarPackageManagerService,
mCarInputService,
mCarLocationService,
mGarageModeService,
- mCarInfoService,
mAppFocusService,
mCarAudioService,
- mCarCabinService,
- mCarHvacService,
mCarNightService,
mInstrumentClusterService,
mCarProjectionService,
mSystemStateControllerService,
- mCarVendorExtensionService,
mCarBluetoothService,
mCarDiagnosticService,
mPerUserCarServiceHelper,
@@ -220,26 +207,23 @@
switch (serviceName) {
case Car.AUDIO_SERVICE:
return mCarAudioService;
- case Car.SENSOR_SERVICE:
- return mCarSensorService;
- case Car.INFO_SERVICE:
- return mCarInfoService;
case Car.APP_FOCUS_SERVICE:
return mAppFocusService;
case Car.PACKAGE_SERVICE:
return mCarPackageManagerService;
- case Car.CABIN_SERVICE:
- assertCabinPermission(mContext);
- return mCarCabinService;
case Car.DIAGNOSTIC_SERVICE:
assertAnyDiagnosticPermission(mContext);
return mCarDiagnosticService;
- case Car.HVAC_SERVICE:
- assertHvacPermission(mContext);
- return mCarHvacService;
case Car.POWER_SERVICE:
assertPowerPermission(mContext);
return mCarPowerManagementService;
+ 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;
case Car.CAR_NAVIGATION_SERVICE:
assertNavigationManagerPermission(mContext);
IInstrumentClusterNavigation navService =
@@ -251,9 +235,6 @@
case Car.PROJECTION_SERVICE:
assertProjectionPermission(mContext);
return mCarProjectionService;
- case Car.VENDOR_EXTENSION_SERVICE:
- assertVendorExtensionPermission(mContext);
- return mCarVendorExtensionService;
case Car.VMS_SUBSCRIBER_SERVICE:
assertVmsSubscriberPermission(mContext);
return mVmsSubscriberService;
@@ -306,10 +287,6 @@
assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
}
- public static void assertCabinPermission(Context context) {
- assertPermission(context, Car.PERMISSION_ADJUST_CAR_CABIN);
- }
-
public static void assertNavigationManagerPermission(Context context) {
assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
}
@@ -318,10 +295,6 @@
assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
}
- public static void assertHvacPermission(Context context) {
- assertPermission(context, Car.PERMISSION_CONTROL_CAR_CLIMATE);
- }
-
public static void assertPowerPermission(Context context) {
assertPermission(context, Car.PERMISSION_CAR_POWER);
}
@@ -330,10 +303,6 @@
assertPermission(context, Car.PERMISSION_CAR_PROJECTION);
}
- public static void assertVendorExtensionPermission(Context context) {
- assertPermission(context, Car.PERMISSION_VENDOR_EXTENSION);
- }
-
public static void assertAnyDiagnosticPermission(Context context) {
assertAnyPermission(context,
Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL,
@@ -358,6 +327,18 @@
}
}
+ /**
+ * Checks to see if the caller has a permission.
+ * @param context
+ * @param permission
+ *
+ * @return boolean TRUE if caller has the permission.
+ */
+ public static boolean hasPermission(Context context, String permission) {
+ return context.checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
public static void assertAnyPermission(Context context, String... permissions) {
for (String permission : permissions) {
if (context.checkCallingOrSelfPermission(permission) ==
diff --git a/service/src/com/android/car/hal/CabinHalService.java b/service/src/com/android/car/hal/CabinHalService.java
deleted file mode 100644
index 2cdf5d5..0000000
--- a/service/src/com/android/car/hal/CabinHalService.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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 android.car.hardware.cabin.CarCabinManager;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
-
-public class CabinHalService extends PropertyHalServiceBase {
- private static final boolean DBG = false;
- private static final String TAG = "CAR.CABIN.HAL";
-
- private final ManagerToHalPropIdMap mMgrHalPropIdMap = ManagerToHalPropIdMap.create(
- CarCabinManager.ID_DOOR_POS,
- VehicleProperty.DOOR_POS,
-
- CarCabinManager.ID_DOOR_MOVE,
- VehicleProperty.DOOR_MOVE,
-
- CarCabinManager.ID_DOOR_LOCK,
- VehicleProperty.DOOR_LOCK,
-
- CarCabinManager.ID_MIRROR_Z_POS,
- VehicleProperty.MIRROR_Z_POS,
-
- CarCabinManager.ID_MIRROR_Z_MOVE,
- VehicleProperty.MIRROR_Z_MOVE,
-
- CarCabinManager.ID_MIRROR_Y_POS,
- VehicleProperty.MIRROR_Y_POS,
-
- CarCabinManager.ID_MIRROR_Y_MOVE,
- VehicleProperty.MIRROR_Y_MOVE,
-
- CarCabinManager.ID_MIRROR_LOCK,
- VehicleProperty.MIRROR_LOCK,
-
- CarCabinManager.ID_MIRROR_FOLD,
- VehicleProperty.MIRROR_FOLD,
-
- CarCabinManager.ID_SEAT_MEMORY_SELECT,
- VehicleProperty.SEAT_MEMORY_SELECT,
-
- CarCabinManager.ID_SEAT_MEMORY_SET,
- VehicleProperty.SEAT_MEMORY_SET,
-
- CarCabinManager.ID_SEAT_BELT_BUCKLED,
- VehicleProperty.SEAT_BELT_BUCKLED,
-
- CarCabinManager.ID_SEAT_BELT_HEIGHT_POS,
- VehicleProperty.SEAT_BELT_HEIGHT_POS,
-
- CarCabinManager.ID_SEAT_BELT_HEIGHT_MOVE,
- VehicleProperty.SEAT_BELT_HEIGHT_MOVE,
-
- CarCabinManager.ID_SEAT_FORE_AFT_POS,
- VehicleProperty.SEAT_FORE_AFT_POS,
-
- CarCabinManager.ID_SEAT_FORE_AFT_MOVE,
- VehicleProperty.SEAT_FORE_AFT_MOVE,
-
- CarCabinManager.ID_SEAT_BACKREST_ANGLE_1_POS,
- VehicleProperty.SEAT_BACKREST_ANGLE_1_POS,
-
- CarCabinManager.ID_SEAT_BACKREST_ANGLE_1_MOVE,
- VehicleProperty.SEAT_BACKREST_ANGLE_1_MOVE,
-
- CarCabinManager.ID_SEAT_BACKREST_ANGLE_2_POS,
- VehicleProperty.SEAT_BACKREST_ANGLE_2_POS,
-
- CarCabinManager.ID_SEAT_BACKREST_ANGLE_2_MOVE,
- VehicleProperty.SEAT_BACKREST_ANGLE_2_MOVE,
-
- CarCabinManager.ID_SEAT_HEIGHT_POS,
- VehicleProperty.SEAT_HEIGHT_POS,
-
- CarCabinManager.ID_SEAT_HEIGHT_MOVE,
- VehicleProperty.SEAT_HEIGHT_MOVE,
-
- CarCabinManager.ID_SEAT_DEPTH_POS,
- VehicleProperty.SEAT_DEPTH_POS,
-
- CarCabinManager.ID_SEAT_DEPTH_MOVE,
- VehicleProperty.SEAT_DEPTH_MOVE,
-
- CarCabinManager.ID_SEAT_TILT_POS,
- VehicleProperty.SEAT_TILT_POS,
-
- CarCabinManager.ID_SEAT_TILT_MOVE,
- VehicleProperty.SEAT_TILT_MOVE,
-
- CarCabinManager.ID_SEAT_LUMBAR_FORE_AFT_POS,
- VehicleProperty.SEAT_LUMBAR_FORE_AFT_POS,
-
- CarCabinManager.ID_SEAT_LUMBAR_FORE_AFT_MOVE,
- VehicleProperty.SEAT_LUMBAR_FORE_AFT_MOVE,
-
- CarCabinManager.ID_SEAT_LUMBAR_SIDE_SUPPORT_POS,
- VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS,
-
- CarCabinManager.ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
- VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
-
- CarCabinManager.ID_SEAT_HEADREST_HEIGHT_POS,
- VehicleProperty.SEAT_HEADREST_HEIGHT_POS,
-
- CarCabinManager.ID_SEAT_HEADREST_HEIGHT_MOVE,
- VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE,
-
- CarCabinManager.ID_SEAT_HEADREST_ANGLE_POS,
- VehicleProperty.SEAT_HEADREST_ANGLE_POS,
-
- CarCabinManager.ID_SEAT_HEADREST_ANGLE_MOVE,
- VehicleProperty.SEAT_HEADREST_ANGLE_MOVE,
-
- CarCabinManager.ID_SEAT_HEADREST_FORE_AFT_POS,
- VehicleProperty.SEAT_HEADREST_FORE_AFT_POS,
-
- CarCabinManager.ID_SEAT_HEADREST_FORE_AFT_MOVE,
- VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE,
-
- CarCabinManager.ID_WINDOW_POS,
- VehicleProperty.WINDOW_POS,
-
- CarCabinManager.ID_WINDOW_MOVE,
- VehicleProperty.WINDOW_MOVE,
-
- CarCabinManager.ID_WINDOW_LOCK,
- VehicleProperty.WINDOW_LOCK
- );
-
- public CabinHalService(VehicleHal vehicleHal) {
- super(vehicleHal, TAG, DBG);
- }
-
- // Convert the Cabin public API property ID to HAL property ID
- @Override
- protected int managerToHalPropId(int propId) {
- return mMgrHalPropIdMap.getHalPropId(propId);
- }
-
- // Convert he HAL specific property ID to Cabin public API
- @Override
- protected int halToManagerPropId(int halPropId) {
- return mMgrHalPropIdMap.getManagerPropId(halPropId);
- }
-}
diff --git a/service/src/com/android/car/hal/CarPropertyUtils.java b/service/src/com/android/car/hal/CarPropertyUtils.java
index 8b5c446..f12da3a 100644
--- a/service/src/com/android/car/hal/CarPropertyUtils.java
+++ b/service/src/com/android/car/hal/CarPropertyUtils.java
@@ -51,11 +51,15 @@
if (Boolean.class == clazz) {
return new CarPropertyValue<>(propertyId, areaId, status, timestamp,
v.int32Values.get(0) == 1);
+ } else if (Boolean[].class == clazz) {
+ Boolean[] values = new Boolean[v.int32Values.size()];
+ int i = 0;
+ for (int val : v.int32Values) {
+ values[i] = val == 1;
+ }
+ return new CarPropertyValue<>(propertyId, areaId, status, timestamp, values);
} else if (String.class == clazz) {
return new CarPropertyValue<>(propertyId, areaId, status, timestamp, v.stringValue);
- } else if (Long.class == clazz) {
- return new CarPropertyValue<>(propertyId, areaId, status, timestamp,
- v.int64Values.get(0));
} else if (byte[].class == clazz) {
byte[] halData = toByteArray(v.bytes);
return new CarPropertyValue<>(propertyId, areaId, status, timestamp, halData);
@@ -76,15 +80,23 @@
Object o = carProp.getValue();
if (o instanceof Boolean) {
- v.int32Values.add(((Boolean )o) ? 1 : 0);
+ v.int32Values.add(((Boolean) o) ? 1 : 0);
+ } else if (o instanceof Boolean[]) {
+ for (Boolean b : (Boolean[]) o) {
+ v.int32Values.add(((Boolean) o) ? 1 : 0);
+ }
} else if (o instanceof Integer) {
v.int32Values.add((Integer) o);
- } else if (o instanceof Float) {
- v.floatValues.add((Float) o);
} else if (o instanceof Integer[]) {
Collections.addAll(v.int32Values, (Integer[]) o);
+ } else if (o instanceof Float) {
+ v.floatValues.add((Float) o);
} else if (o instanceof Float[]) {
Collections.addAll(v.floatValues, (Float[]) o);
+ } else if (o instanceof Long) {
+ v.int64Values.add((Long) o);
+ } else if (o instanceof Long[]) {
+ Collections.addAll(v.int64Values, (Long[]) o);
} else if (o instanceof String) {
v.stringValue = (String) o;
} else if (o instanceof byte[]) {
@@ -203,10 +215,12 @@
}
private static List getRawValueList(Class<?> clazz, VehiclePropValue.RawValue value) {
- if (classMatched(Float.class, clazz)) {
+ if (classMatched(Float.class, clazz) || classMatched(Float[].class, clazz)) {
return value.floatValues;
- } else if (classMatched(Integer.class, clazz)) {
+ } else if (classMatched(Integer.class, clazz) || classMatched(Integer[].class, clazz)) {
return value.int32Values;
+ } else if (classMatched(Long.class, clazz) || classMatched(Long[].class, clazz)) {
+ return value.int64Values;
} else {
throw new IllegalArgumentException("Unexpected type: " + clazz);
}
diff --git a/service/src/com/android/car/hal/HvacHalService.java b/service/src/com/android/car/hal/HvacHalService.java
deleted file mode 100644
index 0a7bd6b..0000000
--- a/service/src/com/android/car/hal/HvacHalService.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015 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 android.car.hardware.hvac.CarHvacManager;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
-
-public class HvacHalService extends PropertyHalServiceBase {
- private static final boolean DBG = false;
- private static final String TAG = "HvacHalService";
-
- private final ManagerToHalPropIdMap mMgrHalPropIdMap = ManagerToHalPropIdMap.create(
- CarHvacManager.ID_MIRROR_DEFROSTER_ON, VehicleProperty.HVAC_SIDE_MIRROR_HEAT,
-
- CarHvacManager.ID_STEERING_WHEEL_HEAT, VehicleProperty.HVAC_STEERING_WHEEL_HEAT,
-
- CarHvacManager.ID_OUTSIDE_AIR_TEMP, VehicleProperty.ENV_OUTSIDE_TEMPERATURE,
-
- CarHvacManager.ID_TEMPERATURE_DISPLAY_UNITS,
- VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS,
-
- CarHvacManager.ID_ZONED_TEMP_SETPOINT, VehicleProperty.HVAC_TEMPERATURE_SET,
-
- CarHvacManager.ID_ZONED_TEMP_ACTUAL, VehicleProperty.HVAC_TEMPERATURE_CURRENT,
-
- CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, VehicleProperty.HVAC_FAN_SPEED,
-
- CarHvacManager.ID_ZONED_FAN_SPEED_RPM, VehicleProperty.HVAC_ACTUAL_FAN_SPEED_RPM,
-
- CarHvacManager.ID_ZONED_FAN_DIRECTION_AVAILABLE,
- VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE,
-
- CarHvacManager.ID_ZONED_FAN_DIRECTION, VehicleProperty.HVAC_FAN_DIRECTION,
-
- CarHvacManager.ID_ZONED_SEAT_TEMP, VehicleProperty.HVAC_SEAT_TEMPERATURE,
-
- CarHvacManager.ID_ZONED_AC_ON, VehicleProperty.HVAC_AC_ON,
-
- CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON, VehicleProperty.HVAC_AUTO_ON,
-
- CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON,VehicleProperty.HVAC_RECIRC_ON,
-
- CarHvacManager.ID_ZONED_MAX_AC_ON, VehicleProperty.HVAC_MAX_AC_ON,
-
- CarHvacManager.ID_ZONED_DUAL_ZONE_ON, VehicleProperty.HVAC_DUAL_ON,
-
- CarHvacManager.ID_ZONED_MAX_DEFROST_ON, VehicleProperty.HVAC_MAX_DEFROST_ON,
-
- CarHvacManager.ID_ZONED_HVAC_POWER_ON, VehicleProperty.HVAC_POWER_ON,
-
- CarHvacManager.ID_ZONED_HVAC_AUTO_RECIRC_ON, VehicleProperty.HVAC_AUTO_RECIRC_ON,
-
- CarHvacManager.ID_WINDOW_DEFROSTER_ON, VehicleProperty.HVAC_DEFROSTER
- );
-
- public HvacHalService(VehicleHal vehicleHal) {
- super(vehicleHal, TAG, DBG);
- }
-
- // Convert the HVAC public API property ID to HAL property ID
- @Override
- protected int managerToHalPropId(int hvacPropId) {
- return mMgrHalPropIdMap.getHalPropId(hvacPropId);
- }
-
- // Convert he HAL specific property ID to HVAC public API
- @Override
- protected int halToManagerPropId(int halPropId) {
- return mMgrHalPropIdMap.getManagerPropId(halPropId);
- }
-}
diff --git a/service/src/com/android/car/hal/InfoHalService.java b/service/src/com/android/car/hal/InfoHalService.java
deleted file mode 100644
index 779757f..0000000
--- a/service/src/com/android/car/hal/InfoHalService.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2015 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 android.car.CarInfoManager;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.car.CarLog;
-
-import java.io.PrintWriter;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
-
-public class InfoHalService extends HalServiceBase {
-
- private final VehicleHal mHal;
- private Bundle mBasicInfo = new Bundle();
-
- public InfoHalService(VehicleHal hal) {
- mHal = hal;
- }
-
- @Override
- public void init() {
- //nothing to do
- }
-
- @Override
- public synchronized void release() {
- mBasicInfo = new Bundle();
- }
-
- @Override
- public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
- Collection<VehiclePropConfig> allProperties) {
- List<VehiclePropConfig> supported = new LinkedList<>();
- for (VehiclePropConfig p: allProperties) {
- switch (p.prop) {
- case VehicleProperty.INFO_MAKE:
- readPropertyToBundle(p.prop, CarInfoManager.BASIC_INFO_KEY_MANUFACTURER);
- break;
- case VehicleProperty.INFO_MODEL:
- readPropertyToBundle(p.prop, CarInfoManager.BASIC_INFO_KEY_MODEL);
- break;
- case VehicleProperty.INFO_MODEL_YEAR:
- readPropertyToBundle(p.prop, CarInfoManager.BASIC_INFO_KEY_MODEL_YEAR);
- break;
- case VehicleProperty.INFO_FUEL_CAPACITY:
- readPropertyToBundle(p.prop, CarInfoManager.BASIC_INFO_FUEL_CAPACITY);
- break;
- case VehicleProperty.INFO_FUEL_TYPE:
- readPropertyToBundle(p.prop, CarInfoManager.BASIC_INFO_FUEL_TYPES);
- break;
- case VehicleProperty.INFO_EV_BATTERY_CAPACITY:
- readPropertyToBundle(p.prop, CarInfoManager.BASIC_INFO_EV_BATTERY_CAPACITY);
- break;
- case VehicleProperty.INFO_EV_CONNECTOR_TYPE:
- readPropertyToBundle(p.prop, CarInfoManager.BASIC_INFO_EV_CONNECTOR_TYPES);
- break;
- default: // not supported
- break;
- }
- }
- return supported;
- }
-
- private void readPropertyToBundle(int prop, String key) {
- try {
- int propType = prop & VehiclePropertyType.MASK;
-
- switch(propType) {
- case VehiclePropertyType.STRING:
- mBasicInfo.putString(key, mHal.get(String.class, prop));
- break;
- case VehiclePropertyType.FLOAT:
- mBasicInfo.putFloat(key, mHal.get(float.class, prop));
- break;
- case VehiclePropertyType.INT32:
- mBasicInfo.putInt(key, mHal.get(int.class, prop));
- break;
- case VehiclePropertyType.INT32_VEC:
- mBasicInfo.putIntArray(key, mHal.get(int[].class, prop));
- break;
- default: // not supported
- throw(new IllegalArgumentException("Property type " + propType + " is not" +
- "supported"));
- }
- } catch (PropertyTimeoutException e) {
- Log.e(CarLog.TAG_INFO, "Unable to read property", e);
- }
- }
-
- @Override
- public void handleHalEvents(List<VehiclePropValue> values) {
- for (VehiclePropValue v : values) {
- logUnexpectedEvent(v.prop);
- }
- }
-
- @Override
- public void dump(PrintWriter writer) {
- writer.println("*InfoHal*");
- writer.println("**BasicInfo:" + mBasicInfo);
- }
-
- public synchronized Bundle getBasicInfo() {
- return mBasicInfo;
- }
-
- private void logUnexpectedEvent(int property) {
- Log.w(CarLog.TAG_INFO, "unexpected HAL event for property 0x" +
- Integer.toHexString(property));
- }
-}
diff --git a/service/src/com/android/car/hal/PropertyHalService.java b/service/src/com/android/car/hal/PropertyHalService.java
new file mode 100644
index 0000000..ad81507
--- /dev/null
+++ b/service/src/com/android/car/hal/PropertyHalService.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2018 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.annotation.Nullable;
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyEvent;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.car.CarLog;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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 class PropertyHalService extends HalServiceBase {
+ private final boolean mDbg = true;
+ private final LinkedList<CarPropertyEvent> mEventsToDispatch = new LinkedList<>();
+ private final Map<Integer, CarPropertyConfig<?>> mProps =
+ new ConcurrentHashMap<>();
+ private final SparseArray<Float> mRates = new SparseArray<Float>();
+ private static final String TAG = "PropertyHalService";
+ private final VehicleHal mVehicleHal;
+ private final PropertyHalServiceIds mPropIds;
+
+ @GuardedBy("mLock")
+ private PropertyHalListener mListener;
+
+ private Set<Integer> mSubscribedPropIds;
+
+ private final Object mLock = new Object();
+
+ /**
+ * Converts manager property ID to Vehicle HAL property ID.
+ * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
+ */
+ private int managerToHalPropId(int propId) {
+ if (mProps.containsKey(propId)) {
+ return propId;
+ } else {
+ return NOT_SUPPORTED_PROPERTY;
+ }
+ }
+
+ /**
+ * Converts Vehicle HAL property ID to manager property ID.
+ * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
+ */
+ private int halToManagerPropId(int halPropId) {
+ if (mProps.containsKey(halPropId)) {
+ return halPropId;
+ } else {
+ return NOT_SUPPORTED_PROPERTY;
+ }
+ }
+
+ /**
+ * PropertyHalListener used to send events to CarPropertyService
+ */
+ public interface PropertyHalListener {
+ /**
+ * This event is sent whenever the property value is updated
+ * @param event
+ */
+ void onPropertyChange(List<CarPropertyEvent> events);
+ /**
+ * This event is sent when the set property call fails
+ * @param property
+ * @param area
+ */
+ void onPropertySetError(int property, int area);
+ }
+
+ public PropertyHalService(VehicleHal vehicleHal) {
+ mPropIds = new PropertyHalServiceIds();
+ mSubscribedPropIds = new HashSet<Integer>();
+ mVehicleHal = vehicleHal;
+ if (mDbg) {
+ Log.d(TAG, "started PropertyHalService");
+ }
+ }
+
+ /**
+ * Set the listener for the HAL service
+ * @param listener
+ */
+ public void setListener(PropertyHalListener listener) {
+ synchronized (mLock) {
+ mListener = listener;
+ }
+ }
+
+ /**
+ *
+ * @return List<CarPropertyConfig> List of configs available.
+ */
+ public Map<Integer, CarPropertyConfig<?>> getPropertyList() {
+ if (mDbg) {
+ Log.d(TAG, "getPropertyList");
+ }
+ return mProps;
+ }
+
+ /**
+ * Returns property or null if property is not ready yet.
+ * @param mgrPropId
+ * @param areaId
+ */
+ @Nullable
+ public CarPropertyValue getProperty(int mgrPropId, int areaId) {
+ int halPropId = managerToHalPropId(mgrPropId);
+ if (halPropId == NOT_SUPPORTED_PROPERTY) {
+ throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
+ }
+
+ VehiclePropValue value = null;
+ try {
+ value = mVehicleHal.get(halPropId, areaId);
+ } catch (PropertyTimeoutException e) {
+ Log.e(CarLog.TAG_PROPERTY, "get, property not ready 0x" + toHexString(halPropId), e);
+ }
+
+ return value == null ? null : toCarPropertyValue(value, mgrPropId);
+ }
+
+ /**
+ * Returns sample rate for the property
+ * @param propId
+ */
+ public float getSampleRate(int propId) {
+ return mVehicleHal.getSampleRate(propId);
+ }
+
+ /**
+ * Get the read permission string for the property.
+ * @param propId
+ */
+ @Nullable
+ public String getReadPermission(int propId) {
+ return mPropIds.getReadPermission(propId);
+ }
+
+ /**
+ * Get the write permission string for the property.
+ * @param propId
+ */
+ @Nullable
+ public String getWritePermission(int propId) {
+ return mPropIds.getWritePermission(propId);
+ }
+
+ /**
+ * Set the property value.
+ * @param prop
+ */
+ public void setProperty(CarPropertyValue prop) {
+ int halPropId = managerToHalPropId(prop.getPropertyId());
+ if (halPropId == NOT_SUPPORTED_PROPERTY) {
+ throw new IllegalArgumentException("Invalid property Id : 0x"
+ + toHexString(prop.getPropertyId()));
+ }
+ VehiclePropValue halProp = toVehiclePropValue(prop, halPropId);
+ try {
+ mVehicleHal.set(halProp);
+ } catch (PropertyTimeoutException e) {
+ Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(halPropId), e);
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Subscribe to this property at the specified update rate.
+ * @param propId
+ * @param rate
+ */
+ public void subscribeProperty(int propId, float rate) {
+ if (mDbg) {
+ Log.d(TAG, "subscribeProperty propId=0x" + toHexString(propId) + ", rate=" + rate);
+ }
+ int halPropId = managerToHalPropId(propId);
+ if (halPropId == NOT_SUPPORTED_PROPERTY) {
+ throw new IllegalArgumentException("Invalid property Id : 0x"
+ + toHexString(propId));
+ }
+ // Validate the min/max rate
+ CarPropertyConfig cfg = mProps.get(propId);
+ if (rate > cfg.getMaxSampleRate()) {
+ rate = cfg.getMaxSampleRate();
+ } else if (rate < cfg.getMinSampleRate()) {
+ rate = cfg.getMinSampleRate();
+ }
+ synchronized (mSubscribedPropIds) {
+ mSubscribedPropIds.add(halPropId);
+ }
+ mVehicleHal.subscribeProperty(this, halPropId, rate);
+ }
+
+ /**
+ * Unsubscribe the property and turn off update events for it.
+ * @param propId
+ */
+ public void unsubscribeProperty(int propId) {
+ if (mDbg) {
+ Log.d(TAG, "unsubscribeProperty propId=0x" + toHexString(propId));
+ }
+ int halPropId = managerToHalPropId(propId);
+ if (halPropId == NOT_SUPPORTED_PROPERTY) {
+ throw new IllegalArgumentException("Invalid property Id : 0x"
+ + toHexString(propId));
+ }
+ synchronized (mSubscribedPropIds) {
+ if (mSubscribedPropIds.contains(halPropId)) {
+ mSubscribedPropIds.remove(halPropId);
+ mVehicleHal.unsubscribeProperty(this, halPropId);
+ }
+ }
+ }
+
+ @Override
+ public void init() {
+ if (mDbg) {
+ Log.d(TAG, "init()");
+ }
+ }
+
+ @Override
+ public void release() {
+ if (mDbg) {
+ Log.d(TAG, "release()");
+ }
+ synchronized (mSubscribedPropIds) {
+ for (Integer prop : mSubscribedPropIds) {
+ mVehicleHal.unsubscribeProperty(this, prop);
+ }
+ mSubscribedPropIds.clear();
+ }
+ mProps.clear();
+
+ synchronized (mLock) {
+ mListener = null;
+ }
+ }
+
+ @Override
+ public Collection<VehiclePropConfig> takeSupportedProperties(
+ Collection<VehiclePropConfig> allProperties) {
+ List<VehiclePropConfig> taken = new LinkedList<>();
+
+ for (VehiclePropConfig p : allProperties) {
+ if (mPropIds.isSupportedProperty(p.prop)) {
+ CarPropertyConfig config = CarPropertyUtils.toCarPropertyConfig(p, p.prop);
+ taken.add(p);
+ mProps.put(p.prop, config);
+ if (mDbg) {
+ Log.d(TAG, "takeSupportedProperties: " + toHexString(p.prop));
+ }
+ }
+ }
+ if (mDbg) {
+ Log.d(TAG, "takeSupportedProperties() took " + taken.size() + " properties");
+ }
+ return taken;
+ }
+
+ @Override
+ public void handleHalEvents(List<VehiclePropValue> values) {
+ PropertyHalListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
+ for (VehiclePropValue v : values) {
+ int mgrPropId = halToManagerPropId(v.prop);
+ if (mgrPropId == NOT_SUPPORTED_PROPERTY) {
+ Log.e(TAG, "Property is not supported: 0x" + toHexString(v.prop));
+ continue;
+ }
+ CarPropertyValue<?> propVal = toCarPropertyValue(v, mgrPropId);
+ CarPropertyEvent event = new CarPropertyEvent(
+ CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, propVal);
+ if (event != null) {
+ mEventsToDispatch.add(event);
+ }
+ }
+ listener.onPropertyChange(mEventsToDispatch);
+ mEventsToDispatch.clear();
+ }
+ }
+
+ @Override
+ public void handlePropertySetError(int property, int area) {
+ PropertyHalListener listener;
+ synchronized (mLock) {
+ listener = mListener;
+ }
+ if (listener != null) {
+ listener.onPropertySetError(property, area);
+ }
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ writer.println(TAG);
+ writer.println(" Properties available:");
+ for (CarPropertyConfig prop : mProps.values()) {
+ writer.println(" " + prop.toString());
+ }
+ }
+}
diff --git a/service/src/com/android/car/hal/PropertyHalServiceBase.java b/service/src/com/android/car/hal/PropertyHalServiceBase.java
deleted file mode 100644
index 07b722c..0000000
--- a/service/src/com/android/car/hal/PropertyHalServiceBase.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * 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.annotation.Nullable;
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyEvent;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.util.Log;
-
-import com.android.car.CarLog;
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-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 ConcurrentHashMap<Integer, CarPropertyConfig<?>> mProps =
- new ConcurrentHashMap<>();
- private final String mTag;
- private final VehicleHal mVehicleHal;
-
- @GuardedBy("mLock")
- private PropertyHalListener mListener;
- private final Object mLock = new Object();
-
- public interface PropertyHalListener {
- void onPropertyChange(CarPropertyEvent event);
- void onPropertySetError(int property, int area);
- }
-
- protected 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 (mLock) {
- mListener = listener;
- }
- }
-
- public List<CarPropertyConfig> getPropertyList() {
- return new ArrayList<>(mProps.values());
- }
-
- /**
- * Returns property or null if property is not ready yet.
- */
- @Nullable
- public CarPropertyValue getProperty(int mgrPropId, int areaId) {
- int halPropId = managerToHalPropId(mgrPropId);
- if (halPropId == NOT_SUPPORTED_PROPERTY) {
- throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId));
- }
-
- VehiclePropValue value = null;
- try {
- value = mVehicleHal.get(halPropId, areaId);
- } catch (PropertyTimeoutException 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());
- if (halPropId == NOT_SUPPORTED_PROPERTY) {
- throw new IllegalArgumentException("Invalid property Id : 0x"
- + toHexString(prop.getPropertyId()));
- }
- VehiclePropValue halProp = toVehiclePropValue(prop, halPropId);
- try {
- mVehicleHal.set(halProp);
- } catch (PropertyTimeoutException 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);
- }
- }
-
- @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 (mLock) {
- mListener = null;
- }
- }
-
- @Override
- public Collection<VehiclePropConfig> takeSupportedProperties(
- Collection<VehiclePropConfig> allProperties) {
- List<VehiclePropConfig> taken = new LinkedList<>();
-
- for (VehiclePropConfig p : allProperties) {
- int mgrPropId = halToManagerPropId(p.prop);
-
- if (mgrPropId == NOT_SUPPORTED_PROPERTY) {
- continue; // The property is not handled by this HAL.
- }
-
- CarPropertyConfig config = CarPropertyUtils.toCarPropertyConfig(p, mgrPropId);
-
- taken.add(p);
- mProps.put(p.prop, config);
-
- if (mDbg) {
- Log.d(mTag, "takeSupportedProperties: " + toHexString(p.prop));
- }
- }
- return taken;
- }
-
- @Override
- public void handleHalEvents(List<VehiclePropValue> values) {
- PropertyHalListener listener;
- synchronized (mLock) {
- listener = mListener;
- }
- if (listener != null) {
- for (VehiclePropValue v : values) {
- int prop = v.prop;
- int mgrPropId = halToManagerPropId(prop);
-
- if (mgrPropId == NOT_SUPPORTED_PROPERTY) {
- Log.e(mTag, "Property is not supported: 0x" + toHexString(prop));
- 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 handlePropertySetError(int property, int area) {
- PropertyHalListener listener;
- synchronized (mLock) {
- listener = mListener;
- }
- if (listener != null) {
- listener.onPropertySetError(property, area);
- }
- }
-
- @Override
- public void dump(PrintWriter writer) {
- writer.println(mTag);
- writer.println(" Properties available:");
- for (CarPropertyConfig prop : mProps.values()) {
- writer.println(" " + prop.toString());
- }
- }
-
- /**
- * Converts manager property ID to Vehicle HAL property ID.
- * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
- */
- abstract protected int managerToHalPropId(int managerPropId);
-
- /**
- * Converts Vehicle HAL property ID to manager property ID.
- * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}.
- */
- abstract protected int halToManagerPropId(int halPropId);
-}
diff --git a/service/src/com/android/car/hal/PropertyHalServiceIds.java b/service/src/com/android/car/hal/PropertyHalServiceIds.java
new file mode 100644
index 0000000..651afea
--- /dev/null
+++ b/service/src/com/android/car/hal/PropertyHalServiceIds.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2018 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 android.annotation.Nullable;
+import android.car.Car;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
+import android.util.Pair;
+import android.util.SparseArray;
+
+/**
+ * Helper class to define which property IDs are used by PropertyHalService. This class binds the
+ * read and write permissions to the property ID.
+ */
+public class PropertyHalServiceIds {
+ // Index (key is propertyId, and the value is readPermission, writePermission
+ private final SparseArray<Pair<String, String>> mProps;
+
+ public PropertyHalServiceIds() {
+ mProps = new SparseArray<>();
+
+ // Add propertyId and read/write permissions
+ // Cabin Properties
+ mProps.put(VehicleProperty.DOOR_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_DOORS,
+ Car.PERMISSION_CONTROL_CAR_DOORS));
+ mProps.put(VehicleProperty.DOOR_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_DOORS,
+ Car.PERMISSION_CONTROL_CAR_DOORS));
+ mProps.put(VehicleProperty.DOOR_LOCK, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_DOORS,
+ Car.PERMISSION_CONTROL_CAR_DOORS));
+ mProps.put(VehicleProperty.MIRROR_Z_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_MIRRORS,
+ Car.PERMISSION_CONTROL_CAR_MIRRORS));
+ mProps.put(VehicleProperty.MIRROR_Z_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_MIRRORS,
+ Car.PERMISSION_CONTROL_CAR_MIRRORS));
+ mProps.put(VehicleProperty.MIRROR_Y_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_MIRRORS,
+ Car.PERMISSION_CONTROL_CAR_MIRRORS));
+ mProps.put(VehicleProperty.MIRROR_Y_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_MIRRORS,
+ Car.PERMISSION_CONTROL_CAR_MIRRORS));
+ mProps.put(VehicleProperty.MIRROR_LOCK, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_MIRRORS,
+ Car.PERMISSION_CONTROL_CAR_MIRRORS));
+ mProps.put(VehicleProperty.MIRROR_FOLD, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_MIRRORS,
+ Car.PERMISSION_CONTROL_CAR_MIRRORS));
+ mProps.put(VehicleProperty.SEAT_MEMORY_SELECT, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_MEMORY_SET, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_BELT_BUCKLED, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_BELT_HEIGHT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_BELT_HEIGHT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_FORE_AFT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_FORE_AFT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_1_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_1_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_2_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_BACKREST_ANGLE_2_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEIGHT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEIGHT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_DEPTH_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_DEPTH_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_TILT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_TILT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_LUMBAR_FORE_AFT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_LUMBAR_FORE_AFT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEADREST_ANGLE_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_SEATS,
+ Car.PERMISSION_CONTROL_CAR_SEATS));
+ mProps.put(VehicleProperty.WINDOW_POS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_WINDOWS,
+ Car.PERMISSION_CONTROL_CAR_WINDOWS));
+ mProps.put(VehicleProperty.WINDOW_MOVE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_WINDOWS,
+ Car.PERMISSION_CONTROL_CAR_WINDOWS));
+ mProps.put(VehicleProperty.WINDOW_LOCK, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_WINDOWS,
+ Car.PERMISSION_CONTROL_CAR_WINDOWS));
+
+ // HVAC properties
+ mProps.put(VehicleProperty.HVAC_FAN_SPEED, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_FAN_DIRECTION, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_TEMPERATURE_CURRENT, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_TEMPERATURE_SET, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_DEFROSTER, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_AC_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_MAX_AC_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_MAX_DEFROST_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_RECIRC_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_DUAL_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_AUTO_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_SEAT_TEMPERATURE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_SIDE_MIRROR_HEAT, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_STEERING_WHEEL_HEAT, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_TEMPERATURE_DISPLAY_UNITS, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_ACTUAL_FAN_SPEED_RPM, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_POWER_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_FAN_DIRECTION_AVAILABLE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_AUTO_RECIRC_ON, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.HVAC_SEAT_VENTILATION, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+ mProps.put(VehicleProperty.ENV_OUTSIDE_TEMPERATURE, new Pair<>(
+ Car.PERMISSION_CONTROL_CAR_CLIMATE,
+ Car.PERMISSION_CONTROL_CAR_CLIMATE));
+
+ // Info properties
+ mProps.put(VehicleProperty.INFO_VIN, new Pair<>(
+ Car.PERMISSION_IDENTIFICATION,
+ Car.PERMISSION_IDENTIFICATION));
+ mProps.put(VehicleProperty.INFO_MAKE, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_MODEL, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_MODEL_YEAR, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_FUEL_CAPACITY, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_FUEL_TYPE, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_EV_BATTERY_CAPACITY, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_EV_CONNECTOR_TYPE, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_FUEL_DOOR_LOCATION, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_EV_PORT_LOCATION, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+ mProps.put(VehicleProperty.INFO_DRIVER_SEAT, new Pair<>(
+ Car.PERMISSION_CAR_INFO,
+ Car.PERMISSION_CAR_INFO));
+
+ // Sensor properties
+ mProps.put(VehicleProperty.PERF_ODOMETER, new Pair<>(
+ Car.PERMISSION_MILEAGE,
+ Car.PERMISSION_MILEAGE));
+ mProps.put(VehicleProperty.PERF_VEHICLE_SPEED, new Pair<>(
+ Car.PERMISSION_SPEED,
+ Car.PERMISSION_SPEED));
+ mProps.put(VehicleProperty.ENGINE_COOLANT_TEMP, new Pair<>(
+ Car.PERMISSION_CAR_ENGINE_DETAILED,
+ Car.PERMISSION_CAR_ENGINE_DETAILED));
+ mProps.put(VehicleProperty.ENGINE_OIL_LEVEL, new Pair<>(
+ Car.PERMISSION_CAR_ENGINE_DETAILED,
+ Car.PERMISSION_CAR_ENGINE_DETAILED));
+ mProps.put(VehicleProperty.ENGINE_OIL_TEMP, new Pair<>(
+ Car.PERMISSION_CAR_ENGINE_DETAILED,
+ Car.PERMISSION_CAR_ENGINE_DETAILED));
+ mProps.put(VehicleProperty.ENGINE_RPM, new Pair<>(
+ Car.PERMISSION_CAR_ENGINE_DETAILED,
+ Car.PERMISSION_CAR_ENGINE_DETAILED));
+ mProps.put(VehicleProperty.WHEEL_TICK, new Pair<>(
+ Car.PERMISSION_SPEED,
+ Car.PERMISSION_SPEED));
+ mProps.put(VehicleProperty.FUEL_LEVEL, new Pair<>(
+ Car.PERMISSION_ENERGY,
+ Car.PERMISSION_ENERGY));
+ mProps.put(VehicleProperty.FUEL_DOOR_OPEN, new Pair<>(
+ Car.PERMISSION_ENERGY_PORTS,
+ Car.PERMISSION_ENERGY_PORTS));
+ mProps.put(VehicleProperty.EV_BATTERY_LEVEL, new Pair<>(
+ Car.PERMISSION_ENERGY,
+ Car.PERMISSION_ENERGY));
+ mProps.put(VehicleProperty.EV_CHARGE_PORT_OPEN, new Pair<>(
+ Car.PERMISSION_ENERGY_PORTS,
+ Car.PERMISSION_ENERGY_PORTS));
+ mProps.put(VehicleProperty.EV_CHARGE_PORT_CONNECTED, new Pair<>(
+ Car.PERMISSION_ENERGY_PORTS,
+ Car.PERMISSION_ENERGY_PORTS));
+ mProps.put(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, new Pair<>(
+ Car.PERMISSION_ENERGY,
+ Car.PERMISSION_ENERGY));
+ mProps.put(VehicleProperty.RANGE_REMAINING, new Pair<>(
+ Car.PERMISSION_ENERGY,
+ Car.PERMISSION_ENERGY));
+ mProps.put(VehicleProperty.TIRE_PRESSURE, new Pair<>(
+ Car.PERMISSION_TIRES,
+ Car.PERMISSION_TIRES));
+ mProps.put(VehicleProperty.GEAR_SELECTION, new Pair<>(
+ Car.PERMISSION_POWERTRAIN,
+ Car.PERMISSION_POWERTRAIN));
+ mProps.put(VehicleProperty.CURRENT_GEAR, new Pair<>(
+ Car.PERMISSION_POWERTRAIN,
+ Car.PERMISSION_POWERTRAIN));
+ mProps.put(VehicleProperty.PARKING_BRAKE_ON, new Pair<>(
+ Car.PERMISSION_POWERTRAIN,
+ Car.PERMISSION_POWERTRAIN));
+ mProps.put(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, new Pair<>(
+ Car.PERMISSION_POWERTRAIN,
+ Car.PERMISSION_POWERTRAIN));
+ mProps.put(VehicleProperty.FUEL_LEVEL_LOW, new Pair<>(
+ Car.PERMISSION_ENERGY,
+ Car.PERMISSION_ENERGY));
+ mProps.put(VehicleProperty.NIGHT_MODE, new Pair<>(
+ Car.PERMISSION_EXTERIOR_ENVIRONMENT,
+ Car.PERMISSION_EXTERIOR_ENVIRONMENT));
+ mProps.put(VehicleProperty.TURN_SIGNAL_STATE, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.IGNITION_STATE, new Pair<>(
+ Car.PERMISSION_CAR_POWER,
+ Car.PERMISSION_CAR_POWER));
+ mProps.put(VehicleProperty.ABS_ACTIVE, new Pair<>(
+ Car.PERMISSION_CAR_DYNAMICS_STATE,
+ Car.PERMISSION_CAR_DYNAMICS_STATE));
+ mProps.put(VehicleProperty.TRACTION_CONTROL_ACTIVE, new Pair<>(
+ Car.PERMISSION_CAR_DYNAMICS_STATE,
+ Car.PERMISSION_CAR_DYNAMICS_STATE));
+ mProps.put(VehicleProperty.ENV_OUTSIDE_TEMPERATURE, new Pair<>(
+ Car.PERMISSION_EXTERIOR_ENVIRONMENT,
+ Car.PERMISSION_EXTERIOR_ENVIRONMENT));
+ mProps.put(VehicleProperty.HEADLIGHTS_STATE, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.HIGH_BEAM_LIGHTS_STATE, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.FOG_LIGHTS_STATE, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.HAZARD_LIGHTS_STATE, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.HEADLIGHTS_SWITCH, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.HIGH_BEAM_LIGHTS_SWITCH, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.FOG_LIGHTS_SWITCH, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
+ mProps.put(VehicleProperty.HAZARD_LIGHTS_SWITCH, new Pair<>(
+ Car.PERMISSION_EXTERIOR_LIGHTS,
+ Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS));
+ }
+
+ /**
+ * Returns read permission string for given property ID.
+ */
+ @Nullable
+ public String getReadPermission(int propId) {
+ Pair<String, String> p = mProps.get(propId);
+ if (p != null) {
+ // Property ID exists. Return read permission.
+ return p.first;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns write permission string for given property ID.
+ */
+ @Nullable
+ public String getWritePermission(int propId) {
+ Pair<String, String> p = mProps.get(propId);
+ if (p != null) {
+ // Property ID exists. Return write permission.
+ return p.second;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return true if property is a vendor property and was added
+ */
+ public boolean insertVendorProperty(int propId) {
+ if ((propId & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.VENDOR) {
+ mProps.put(propId, new Pair<>(
+ Car.PERMISSION_VENDOR_EXTENSION, Car.PERMISSION_VENDOR_EXTENSION));
+ return true;
+ } else {
+ // This is not a vendor extension property, it is not added
+ return false;
+ }
+ }
+
+ /**
+ * Check if property ID is in the list of known IDs that PropertyHalService is interested it.
+ */
+ public boolean isSupportedProperty(int propId) {
+ if (mProps.get(propId) != null) {
+ // Property is in the list of supported properties
+ return true;
+ } else {
+ // If it's a vendor property, insert it into the propId list and handle it
+ return insertVendorProperty(propId);
+ }
+ }
+}
diff --git a/service/src/com/android/car/hal/SensorHalService.java b/service/src/com/android/car/hal/SensorHalService.java
deleted file mode 100644
index f368955..0000000
--- a/service/src/com/android/car/hal/SensorHalService.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (C) 2015 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 java.lang.Integer.toHexString;
-
-import android.annotation.Nullable;
-import android.car.hardware.CarSensorConfig;
-import android.car.hardware.CarSensorEvent;
-import android.car.hardware.CarSensorManager;
-import android.hardware.automotive.vehicle.V2_0.VehicleGear;
-import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
-import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
-import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.SparseIntArray;
-
-import com.android.car.CarLog;
-import com.android.car.CarSensorEventFactory;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Sensor HAL implementation for physical sensors in car.
- */
-public class SensorHalService extends SensorHalServiceBase {
- private static final String TAG = CarLog.concatTag(CarLog.TAG_SENSOR, SensorHalService.class);
- private static final boolean DBG_EVENTS = false;
-
- /**
- * Listener for monitoring sensor event. Only sensor service will implement this.
- */
- public interface SensorListener {
- /**
- * Sensor events are available.
- *
- * @param events
- */
- void onSensorEvents(List<CarSensorEvent> events);
- }
-
- // Manager property Id to HAL property Id mapping.
- private final static ManagerToHalPropIdMap mManagerToHalPropIdMap =
- ManagerToHalPropIdMap.create(
- CarSensorManager.SENSOR_TYPE_CAR_SPEED, VehicleProperty.PERF_VEHICLE_SPEED,
- CarSensorManager.SENSOR_TYPE_RPM, VehicleProperty.ENGINE_RPM,
- CarSensorManager.SENSOR_TYPE_ODOMETER, VehicleProperty.PERF_ODOMETER,
- CarSensorManager.SENSOR_TYPE_GEAR, VehicleProperty.GEAR_SELECTION,
- CarSensorManager.SENSOR_TYPE_NIGHT, VehicleProperty.NIGHT_MODE,
- CarSensorManager.SENSOR_TYPE_PARKING_BRAKE, VehicleProperty.PARKING_BRAKE_ON,
- CarSensorManager.SENSOR_TYPE_FUEL_LEVEL, VehicleProperty.FUEL_LEVEL,
- CarSensorManager.SENSOR_TYPE_IGNITION_STATE, VehicleProperty.IGNITION_STATE,
- CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE, VehicleProperty.WHEEL_TICK,
- CarSensorManager.SENSOR_TYPE_ABS_ACTIVE, VehicleProperty.ABS_ACTIVE,
- CarSensorManager.SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
- VehicleProperty.TRACTION_CONTROL_ACTIVE,
- CarSensorManager.SENSOR_TYPE_FUEL_DOOR_OPEN, VehicleProperty.FUEL_DOOR_OPEN,
- CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL, VehicleProperty.EV_BATTERY_LEVEL,
- CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_OPEN, VehicleProperty.EV_CHARGE_PORT_OPEN,
- CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
- VehicleProperty.EV_CHARGE_PORT_CONNECTED,
- CarSensorManager.SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
- VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE,
- CarSensorManager.SENSOR_TYPE_ENGINE_OIL_LEVEL, VehicleProperty.ENGINE_OIL_LEVEL
- );
-
- private final static SparseIntArray mMgrGearToHalMap = initSparseIntArray(
- VehicleGear.GEAR_NEUTRAL, CarSensorEvent.GEAR_NEUTRAL,
- VehicleGear.GEAR_REVERSE, CarSensorEvent.GEAR_REVERSE,
- VehicleGear.GEAR_PARK, CarSensorEvent.GEAR_PARK,
- VehicleGear.GEAR_DRIVE, CarSensorEvent.GEAR_DRIVE,
- VehicleGear.GEAR_1, CarSensorEvent.GEAR_FIRST,
- VehicleGear.GEAR_2, CarSensorEvent.GEAR_SECOND,
- VehicleGear.GEAR_3, CarSensorEvent.GEAR_THIRD,
- VehicleGear.GEAR_4, CarSensorEvent.GEAR_FOURTH,
- VehicleGear.GEAR_5, CarSensorEvent.GEAR_FIFTH,
- VehicleGear.GEAR_6, CarSensorEvent.GEAR_SIXTH,
- VehicleGear.GEAR_7, CarSensorEvent.GEAR_SEVENTH,
- VehicleGear.GEAR_8, CarSensorEvent.GEAR_EIGHTH,
- VehicleGear.GEAR_9, CarSensorEvent.GEAR_NINTH);
-
- private final static SparseIntArray mMgrIgnitionStateToHalMap = initSparseIntArray(
- VehicleIgnitionState.UNDEFINED, CarSensorEvent.IGNITION_STATE_UNDEFINED,
- VehicleIgnitionState.LOCK, CarSensorEvent.IGNITION_STATE_LOCK,
- VehicleIgnitionState.OFF, CarSensorEvent.IGNITION_STATE_OFF,
- VehicleIgnitionState.ACC, CarSensorEvent.IGNITION_STATE_ACC,
- VehicleIgnitionState.ON, CarSensorEvent.IGNITION_STATE_ON,
- VehicleIgnitionState.START, CarSensorEvent.IGNITION_STATE_START);
-
- private SensorListener mSensorListener;
-
- private int[] mMicrometersPerWheelTick = {0, 0, 0, 0};
-
- @Override
- public void init() {
- VehiclePropConfig config;
- // Populate internal values if available
- synchronized (this) {
- config = mSensorToPropConfig.get(CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE);
- }
- if (config == null) {
- Log.e(TAG, "init: unable to get property config for SENSOR_TYPE_WHEEL_TICK_DISTANCE");
- } else {
- for (int i = 0; i < 4; i++) {
- mMicrometersPerWheelTick[i] = config.configArray.get(i +
- INDEX_WHEEL_DISTANCE_FRONT_LEFT);
- }
- }
- super.init();
- }
-
- public SensorHalService(VehicleHal hal) {
- super(hal);
- }
-
- public synchronized void registerSensorListener(SensorListener listener) {
- mSensorListener = listener;
- }
-
- @Override
- protected int getTokenForProperty(VehiclePropConfig halProperty) {
- int sensor = mManagerToHalPropIdMap.getManagerPropId(halProperty.prop);
- if (sensor != SENSOR_TYPE_INVALID
- && halProperty.changeMode != VehiclePropertyChangeMode.STATIC
- && ((halProperty.access & VehiclePropertyAccess.READ) != 0)) {
- return sensor;
- }
- return SENSOR_TYPE_INVALID;
- }
-
- // Should be used only inside handleHalEvents method.
- private final LinkedList<CarSensorEvent> mEventsToDispatch = new LinkedList<>();
-
- @Override
- public void handleHalEvents(List<VehiclePropValue> values) {
- for (VehiclePropValue v : values) {
- CarSensorEvent event = createCarSensorEvent(v);
- if (event != null) {
- mEventsToDispatch.add(event);
- }
- }
- SensorListener sensorListener;
- synchronized (this) {
- sensorListener = mSensorListener;
- }
- if (DBG_EVENTS) Log.d(TAG, "handleHalEvents, listener: " + sensorListener);
- if (sensorListener != null) {
- sensorListener.onSensorEvents(mEventsToDispatch);
- }
- mEventsToDispatch.clear();
- }
-
- @Nullable
- private Integer mapHalEnumValueToMgr(int propId, int halValue) {
- int mgrValue = halValue;
-
- switch (propId) {
- case VehicleProperty.GEAR_SELECTION:
- mgrValue = mMgrGearToHalMap.get(halValue, -1);
- break;
- case VehicleProperty.IGNITION_STATE:
- mgrValue = mMgrIgnitionStateToHalMap.get(halValue, -1);
- default:
- break; // Do nothing
- }
- return mgrValue == -1 ? null : mgrValue;
- }
-
- @Nullable
- private CarSensorEvent createCarSensorEvent(VehiclePropValue v) {
- int property = v.prop;
- int sensorType = mManagerToHalPropIdMap.getManagerPropId(property);
- if (sensorType == SENSOR_TYPE_INVALID) {
- throw new RuntimeException("no sensor defined for property 0x" + toHexString(property));
- }
- // Handle the valid sensor
- int dataType = property & VehiclePropertyType.MASK;
- CarSensorEvent event = null;
- switch (dataType) {
- case VehiclePropertyType.BOOLEAN:
- event = CarSensorEventFactory.createBooleanEvent(sensorType, v.timestamp,
- v.value.int32Values.get(0) == 1);
- break;
- case VehiclePropertyType.MIXED:
- event = CarSensorEventFactory.createMixedEvent(sensorType, v.timestamp, v);
- break;
- case VehiclePropertyType.INT32:
- Integer mgrVal = mapHalEnumValueToMgr(property, v.value.int32Values.get(0));
- event = mgrVal == null ? null
- : CarSensorEventFactory.createIntEvent(sensorType, v.timestamp, mgrVal);
- break;
- case VehiclePropertyType.FLOAT:
- event = CarSensorEventFactory.createFloatEvent(sensorType, v.timestamp,
- v.value.floatValues.get(0));
- break;
- case VehiclePropertyType.INT64_VEC:
- event = CarSensorEventFactory.createInt64VecEvent(sensorType, v.timestamp,
- v.value.int64Values);
- break;
- default:
- Log.w(TAG, "createCarSensorEvent: unsupported type: 0x" + toHexString(dataType));
- break;
- }
- // Perform property specific actions
- switch (property) {
- case VehicleProperty.WHEEL_TICK:
- // Apply the um/tick scaling factor, then divide by 1000 to generate mm
- for (int i = 0; i < 4; i++) {
- // ResetCounts is at longValues[0]
- if (event.longValues[i + CarSensorEvent.INDEX_WHEEL_DISTANCE_FRONT_LEFT] !=
- Long.MAX_VALUE) {
- event.longValues[i + CarSensorEvent.INDEX_WHEEL_DISTANCE_FRONT_LEFT] *=
- mMicrometersPerWheelTick[i];
- event.longValues[i + CarSensorEvent.INDEX_WHEEL_DISTANCE_FRONT_LEFT] /=
- 1000;
- }
- }
- break;
- }
- if (DBG_EVENTS) Log.i(TAG, "Sensor event created: " + event);
- return event;
- }
-
- @Nullable
- public CarSensorEvent getCurrentSensorValue(int sensorType) {
- VehiclePropValue propValue = getCurrentSensorVehiclePropValue(sensorType);
- return (null != propValue) ? createCarSensorEvent(propValue) : null;
- }
-
- @Override
- protected float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) {
- switch (prop.changeMode) {
- case VehiclePropertyChangeMode.ON_CHANGE:
- return 0;
- }
- float rate = 1.0f;
- switch (carSensorManagerRate) {
- case CarSensorManager.SENSOR_RATE_FASTEST:
- rate = prop.maxSampleRate;
- break;
- case CarSensorManager.SENSOR_RATE_FAST:
- rate = 10f; // every 100ms
- break;
- case CarSensorManager.SENSOR_RATE_UI:
- rate = 5f; // every 200ms
- break;
- default: // fall back to default.
- break;
- }
- if (rate > prop.maxSampleRate) {
- rate = prop.maxSampleRate;
- }
- if (rate < prop.minSampleRate) {
- rate = prop.minSampleRate;
- }
- return rate;
- }
-
- @Override
- public void dump(PrintWriter writer) {
- writer.println("*Sensor HAL*");
- writer.println("**Supported properties**");
- for (int i = 0; i < mSensorToPropConfig.size(); i++) {
- writer.println(mSensorToPropConfig.valueAt(i).toString());
- }
- for (int i = 0; i < mMicrometersPerWheelTick.length; i++) {
- writer.println("mMicrometersPerWheelTick[" + i + "] = " + mMicrometersPerWheelTick[i]);
- }
- }
-
- private static SparseIntArray initSparseIntArray(int... keyValuePairs) {
- int inputLength = keyValuePairs.length;
- if (inputLength % 2 != 0) {
- throw new IllegalArgumentException("Odd number of key-value elements");
- }
-
- SparseIntArray map = new SparseIntArray(inputLength / 2);
- for (int i = 0; i < keyValuePairs.length; i += 2) {
- map.put(keyValuePairs[i], keyValuePairs[i + 1]);
- }
- return map;
- }
-
- private static final int INDEX_WHEEL_DISTANCE_ENABLE_FLAG = 0;
- private static final int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1;
- private static final int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2;
- private static final int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3;
- private static final int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4;
- private static final int WHEEL_TICK_DISTANCE_BUNDLE_SIZE = 6;
-
- private Bundle createWheelDistanceTickBundle(ArrayList<Integer> configArray) {
- Bundle b = new Bundle(WHEEL_TICK_DISTANCE_BUNDLE_SIZE);
- b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS,
- configArray.get(INDEX_WHEEL_DISTANCE_ENABLE_FLAG));
- b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK,
- configArray.get(INDEX_WHEEL_DISTANCE_FRONT_LEFT));
- b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK,
- configArray.get(INDEX_WHEEL_DISTANCE_FRONT_RIGHT));
- b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK,
- configArray.get(INDEX_WHEEL_DISTANCE_REAR_RIGHT));
- b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK,
- configArray.get(INDEX_WHEEL_DISTANCE_REAR_LEFT));
- return b;
- }
-
-
- public CarSensorConfig getSensorConfig(int sensorType) {
- VehiclePropConfig cfg;
- synchronized (this) {
- cfg = mSensorToPropConfig.get(sensorType);
- }
- if (cfg == null) {
- /* Invalid sensor type. */
- throw new IllegalArgumentException("Unknown sensorType = " + sensorType);
- } else {
- Bundle b;
- switch(sensorType) {
- case CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE:
- b = createWheelDistanceTickBundle(cfg.configArray);
- break;
- default:
- /* Unhandled config. Create empty bundle */
- b = Bundle.EMPTY;
- break;
- }
- return new CarSensorConfig(sensorType, b);
- }
- }
-}
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index aedf137..f73d07c 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -69,13 +69,9 @@
private static final int NO_AREA = -1;
private final HandlerThread mHandlerThread;
- private final SensorHalService mSensorHal;
- private final InfoHalService mInfoHal;
- private final CabinHalService mCabinHal;
private final PowerHalService mPowerHal;
- private final HvacHalService mHvacHal;
+ private final PropertyHalService mPropertyHal;
private final InputHalService mInputHal;
- private final VendorExtensionHalService mVendorExtensionHal;
private final VmsHalService mVmsHal;
private DiagnosticHalService mDiagnosticHal = null;
@@ -98,21 +94,13 @@
mHandlerThread.start();
// passing this should be safe as long as it is just kept and not used in constructor
mPowerHal = new PowerHalService(this);
- mSensorHal = new SensorHalService(this);
- mInfoHal = new InfoHalService(this);
- mCabinHal = new CabinHalService(this);
- mHvacHal = new HvacHalService(this);
+ mPropertyHal = new PropertyHalService(this);
mInputHal = new InputHalService(this);
- mVendorExtensionHal = new VendorExtensionHalService(this);
mVmsHal = new VmsHalService(this);
mDiagnosticHal = new DiagnosticHalService(this);
mAllServices.addAll(Arrays.asList(mPowerHal,
- mSensorHal,
- mInfoHal,
- mCabinHal,
- mHvacHal,
mInputHal,
- mVendorExtensionHal,
+ mPropertyHal,
mDiagnosticHal,
mVmsHal));
@@ -121,18 +109,13 @@
/** Dummy version only for testing */
@VisibleForTesting
- public VehicleHal(PowerHalService powerHal, SensorHalService sensorHal, InfoHalService infoHal,
- CabinHalService cabinHal, DiagnosticHalService diagnosticHal,
- HvacHalService hvacHal, HalClient halClient) {
+ public VehicleHal(PowerHalService powerHal, DiagnosticHalService diagnosticHal,
+ HalClient halClient, PropertyHalService propertyHal) {
mHandlerThread = null;
mPowerHal = powerHal;
- mSensorHal = sensorHal;
- mInfoHal = infoHal;
- mCabinHal = cabinHal;
+ mPropertyHal = propertyHal;
mDiagnosticHal = diagnosticHal;
- mHvacHal = hvacHal;
mInputHal = null;
- mVendorExtensionHal = null;
mVmsHal = null;
mHalClient = halClient;
mDiagnosticHal = diagnosticHal;
@@ -207,36 +190,20 @@
// keep the looper thread as should be kept for the whole life cycle.
}
- public SensorHalService getSensorHal() {
- return mSensorHal;
- }
-
- public InfoHalService getInfoHal() {
- return mInfoHal;
- }
-
- public CabinHalService getCabinHal() {
- return mCabinHal;
- }
-
public DiagnosticHalService getDiagnosticHal() { return mDiagnosticHal; }
public PowerHalService getPowerHal() {
return mPowerHal;
}
- public HvacHalService getHvacHal() {
- return mHvacHal;
+ public PropertyHalService getPropertyHal() {
+ return mPropertyHal;
}
public InputHalService getInputHal() {
return mInputHal;
}
- public VendorExtensionHalService getVendorExtensionHal() {
- return mVendorExtensionHal;
- }
-
public VmsHalService getVmsHal() { return mVmsHal; }
private void assertServiceOwnerLocked(HalServiceBase service, int property) {
@@ -403,6 +370,23 @@
return mHalClient.getValue(requestedPropValue);
}
+ /**
+ *
+ * @param propId Property ID to return the current sample rate for.
+ *
+ * @return float Returns the current sample rate of the specified propId, or -1 if the
+ * property is not currently subscribed.
+ */
+ public float getSampleRate(int propId) {
+ SubscribeOptions opts = mSubscribedProperties.get(propId);
+ if (opts == null) {
+ // No sample rate for this property
+ return -1;
+ } else {
+ return opts.sampleRate;
+ }
+ }
+
void set(VehiclePropValue propValue) throws PropertyTimeoutException {
mHalClient.setValue(propValue);
}
diff --git a/service/src/com/android/car/hal/VendorExtensionHalService.java b/service/src/com/android/car/hal/VendorExtensionHalService.java
deleted file mode 100644
index ab351be..0000000
--- a/service/src/com/android/car/hal/VendorExtensionHalService.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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 android.hardware.automotive.vehicle.V2_0.VehiclePropertyGroup;
-
-/**
- * Implementation of {@link HalServiceBase} that responsible for custom properties that were defined
- * by OEMs.
- */
-public class VendorExtensionHalService extends PropertyHalServiceBase {
-
- private final static String TAG = VendorExtensionHalService.class.getSimpleName();
- private final static boolean DEBUG = false;
-
- VendorExtensionHalService(VehicleHal vehicleHal) {
- super(vehicleHal, TAG, DEBUG);
- }
-
- @Override
- protected int managerToHalPropId(int managerPropId) {
- return isVendorProperty(managerPropId) ? managerPropId : NOT_SUPPORTED_PROPERTY;
- }
-
- @Override
- protected int halToManagerPropId(int halPropId) {
- return isVendorProperty(halPropId) ? halPropId : NOT_SUPPORTED_PROPERTY;
- }
-
- private static boolean isVendorProperty(int property) {
- return (property & VehiclePropertyGroup.MASK) == VehiclePropertyGroup.VENDOR;
- }
-}
\ No newline at end of file