Merge "Move CAR_IDENTIFICATION to signature" into pi-dev
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 71eb12c..9cd2e4c 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -229,11 +229,11 @@
public final class CarUxRestrictionsManager {
method public android.car.drivingstate.CarUxRestrictions getCurrentCarUxRestrictions() throws android.car.CarNotConnectedException;
- method public synchronized void registerListener(android.car.drivingstate.CarUxRestrictionsManager.onUxRestrictionsChangedListener) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
+ method public synchronized void registerListener(android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
method public synchronized void unregisterListener() throws android.car.CarNotConnectedException;
}
- public static abstract interface CarUxRestrictionsManager.onUxRestrictionsChangedListener {
+ public static abstract interface CarUxRestrictionsManager.OnUxRestrictionsChangedListener {
method public abstract void onUxRestrictionsChanged(android.car.drivingstate.CarUxRestrictions);
}
@@ -245,20 +245,20 @@
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.car.hardware.CarSensorEvent> CREATOR;
- field public static final int GEAR_DRIVE = 100; // 0x64
- field public static final int GEAR_EIGHTH = 8; // 0x8
- field public static final int GEAR_FIFTH = 5; // 0x5
- field public static final int GEAR_FIRST = 1; // 0x1
- field public static final int GEAR_FOURTH = 4; // 0x4
- field public static final int GEAR_NEUTRAL = 0; // 0x0
- field public static final int GEAR_NINTH = 9; // 0x9
- field public static final int GEAR_PARK = 101; // 0x65
- field public static final int GEAR_REVERSE = 102; // 0x66
- field public static final int GEAR_SECOND = 2; // 0x2
- field public static final int GEAR_SEVENTH = 7; // 0x7
- field public static final int GEAR_SIXTH = 6; // 0x6
- field public static final int GEAR_TENTH = 10; // 0xa
- field public static final int GEAR_THIRD = 3; // 0x3
+ field public static final int GEAR_DRIVE = 8; // 0x8
+ field public static final int GEAR_EIGHTH = 2048; // 0x800
+ field public static final int GEAR_FIFTH = 256; // 0x100
+ field public static final int GEAR_FIRST = 16; // 0x10
+ field public static final int GEAR_FOURTH = 128; // 0x80
+ field public static final int GEAR_NEUTRAL = 1; // 0x1
+ field public static final int GEAR_NINTH = 4096; // 0x1000
+ field public static final int GEAR_PARK = 4; // 0x4
+ field public static final int GEAR_REVERSE = 2; // 0x2
+ field public static final int GEAR_SECOND = 32; // 0x20
+ field public static final int GEAR_SEVENTH = 1024; // 0x400
+ field public static final int GEAR_SIXTH = 512; // 0x200
+ field public static final int GEAR_TENTH = 8192; // 0x2000
+ field public static final int GEAR_THIRD = 64; // 0x40
field public static final int IGNITION_STATE_ACC = 3; // 0x3
field public static final int IGNITION_STATE_LOCK = 1; // 0x1
field public static final int IGNITION_STATE_OFF = 2; // 0x2
@@ -287,34 +287,34 @@
public final class CarSensorManager {
method public android.car.hardware.CarSensorEvent getLatestSensorEvent(int) throws android.car.CarNotConnectedException;
+ method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
method public int[] getSupportedSensors() throws android.car.CarNotConnectedException;
method public boolean isSensorSupported(int) throws android.car.CarNotConnectedException;
method public static boolean isSensorSupported(int[], int);
method public boolean registerListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int, int) throws android.car.CarNotConnectedException, java.lang.IllegalArgumentException;
method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener);
method public void unregisterListener(android.car.hardware.CarSensorManager.OnSensorChangedListener, int);
- field public static final int SENSOR_RATE_FAST = 1; // 0x1
- field public static final int SENSOR_RATE_FASTEST = 0; // 0x0
- field public static final int SENSOR_RATE_NORMAL = 3; // 0x3
- field public static final int SENSOR_RATE_UI = 2; // 0x2
- field public static final int SENSOR_TYPE_ABS_ACTIVE = 24; // 0x18
- field public static final int SENSOR_TYPE_CAR_SPEED = 2; // 0x2
+ field public static final int SENSOR_RATE_FAST = 10; // 0xa
+ field public static final int SENSOR_RATE_FASTEST = 100; // 0x64
+ field public static final int SENSOR_RATE_NORMAL = 1; // 0x1
+ field public static final int SENSOR_RATE_UI = 5; // 0x5
+ field public static final int SENSOR_TYPE_ABS_ACTIVE = 287310858; // 0x1120040a
+ field public static final int SENSOR_TYPE_CAR_SPEED = 291504647; // 0x11600207
field public static final int SENSOR_TYPE_ENVIRONMENT = 12; // 0xc
- field public static final int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE = 31; // 0x1f
- field public static final int SENSOR_TYPE_EV_BATTERY_LEVEL = 28; // 0x1c
- field public static final int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED = 30; // 0x1e
- field public static final int SENSOR_TYPE_EV_CHARGE_PORT_OPEN = 29; // 0x1d
- field public static final int SENSOR_TYPE_FUEL_DOOR_OPEN = 27; // 0x1b
- field public static final int SENSOR_TYPE_FUEL_LEVEL = 5; // 0x5
- field public static final int SENSOR_TYPE_GEAR = 7; // 0x7
- field public static final int SENSOR_TYPE_IGNITION_STATE = 22; // 0x16
- field public static final int SENSOR_TYPE_NIGHT = 9; // 0x9
- field public static final int SENSOR_TYPE_ODOMETER = 4; // 0x4
- field public static final int SENSOR_TYPE_PARKING_BRAKE = 6; // 0x6
- field public static final int SENSOR_TYPE_RPM = 3; // 0x3
- field public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 25; // 0x19
- field public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 1879048191; // 0x6fffffff
- field public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 23; // 0x17
+ field public static final int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE = 291504908; // 0x1160030c
+ field public static final int SENSOR_TYPE_EV_BATTERY_LEVEL = 291504905; // 0x11600309
+ field public static final int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED = 287310603; // 0x1120030b
+ field public static final int SENSOR_TYPE_EV_CHARGE_PORT_OPEN = 287310602; // 0x1120030a
+ field public static final int SENSOR_TYPE_FUEL_DOOR_OPEN = 287310600; // 0x11200308
+ field public static final int SENSOR_TYPE_FUEL_LEVEL = 291504903; // 0x11600307
+ field public static final int SENSOR_TYPE_GEAR = 289408000; // 0x11400400
+ field public static final int SENSOR_TYPE_IGNITION_STATE = 289408009; // 0x11400409
+ field public static final int SENSOR_TYPE_NIGHT = 287310855; // 0x11200407
+ field public static final int SENSOR_TYPE_ODOMETER = 291504644; // 0x11600204
+ field public static final int SENSOR_TYPE_PARKING_BRAKE = 287310850; // 0x11200402
+ field public static final int SENSOR_TYPE_RPM = 291504901; // 0x11600305
+ field public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 287310859; // 0x1120040b
+ field public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 290521862; // 0x11510306
}
public static abstract interface CarSensorManager.OnSensorChangedListener {
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index e18e573..d611932 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -32,6 +32,7 @@
field public static final java.lang.String PERMISSION_VMS_SUBSCRIBER = "android.car.permission.VMS_SUBSCRIBER";
field public static final java.lang.String POWER_SERVICE = "power";
field public static final java.lang.String PROJECTION_SERVICE = "projection";
+ field public static final java.lang.String PROPERTY_SERVICE = "property";
field public static final java.lang.String STORAGE_MONITORING_SERVICE = "storage_monitoring";
field public static final java.lang.String TEST_SERVICE = "car-service-test";
field public static final java.lang.String VENDOR_EXTENSION_SERVICE = "vendor_extension";
@@ -83,8 +84,8 @@
public final class VehicleAreaType {
field public static final int VEHICLE_AREA_TYPE_DOOR = 4; // 0x4
+ field public static final int VEHICLE_AREA_TYPE_GLOBAL = 0; // 0x0
field public static final int VEHICLE_AREA_TYPE_MIRROR = 5; // 0x5
- field public static final int VEHICLE_AREA_TYPE_NONE = 0; // 0x0
field public static final int VEHICLE_AREA_TYPE_SEAT = 3; // 0x3
field public static final int VEHICLE_AREA_TYPE_WHEEL = 6; // 0x6
field public static final int VEHICLE_AREA_TYPE_WINDOW = 2; // 0x2
@@ -559,7 +560,7 @@
method public void registerCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) throws android.car.CarNotConnectedException;
method public <E> void setGlobalProperty(java.lang.Class<E>, int, E) throws android.car.CarNotConnectedException;
method public <E> void setProperty(java.lang.Class<E>, int, int, E) throws android.car.CarNotConnectedException;
- method public void unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback);
+ method public void unregisterCallback(android.car.hardware.CarVendorExtensionManager.CarVendorExtensionCallback) throws android.car.CarNotConnectedException;
}
public static abstract interface CarVendorExtensionManager.CarVendorExtensionCallback {
@@ -581,46 +582,46 @@
method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
method public void setIntProperty(int, int, int) throws android.car.CarNotConnectedException;
- method public synchronized void unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback);
- field public static final int ID_DOOR_LOCK = 3; // 0x3
- field public static final int ID_DOOR_MOVE = 2; // 0x2
- field public static final int ID_DOOR_POS = 1; // 0x1
- field public static final int ID_MIRROR_FOLD = 4102; // 0x1006
- field public static final int ID_MIRROR_LOCK = 4101; // 0x1005
- field public static final int ID_MIRROR_Y_MOVE = 4100; // 0x1004
- field public static final int ID_MIRROR_Y_POS = 4099; // 0x1003
- field public static final int ID_MIRROR_Z_MOVE = 4098; // 0x1002
- field public static final int ID_MIRROR_Z_POS = 4097; // 0x1001
- field public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 8201; // 0x2009
- field public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 8200; // 0x2008
- field public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 8203; // 0x200b
- field public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 8202; // 0x200a
- field public static final int ID_SEAT_BELT_BUCKLED = 8195; // 0x2003
- field public static final int ID_SEAT_BELT_HEIGHT_MOVE = 8197; // 0x2005
- field public static final int ID_SEAT_BELT_HEIGHT_POS = 8196; // 0x2004
- field public static final int ID_SEAT_DEPTH_MOVE = 8207; // 0x200f
- field public static final int ID_SEAT_DEPTH_POS = 8206; // 0x200e
- field public static final int ID_SEAT_FORE_AFT_MOVE = 8199; // 0x2007
- field public static final int ID_SEAT_FORE_AFT_POS = 8198; // 0x2006
- field public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 8217; // 0x2019
- field public static final int ID_SEAT_HEADREST_ANGLE_POS = 8216; // 0x2018
- field public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 8219; // 0x201b
- field public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 8218; // 0x201a
- field public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 8215; // 0x2017
- field public static final int ID_SEAT_HEADREST_HEIGHT_POS = 8214; // 0x2016
- field public static final int ID_SEAT_HEIGHT_MOVE = 8205; // 0x200d
- field public static final int ID_SEAT_HEIGHT_POS = 8204; // 0x200c
- field public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 8211; // 0x2013
- field public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 8210; // 0x2012
- field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 8213; // 0x2015
- field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 8212; // 0x2014
- field public static final int ID_SEAT_MEMORY_SELECT = 8193; // 0x2001
- field public static final int ID_SEAT_MEMORY_SET = 8194; // 0x2002
- field public static final int ID_SEAT_TILT_MOVE = 8209; // 0x2011
- field public static final int ID_SEAT_TILT_POS = 8208; // 0x2010
- field public static final int ID_WINDOW_LOCK = 12291; // 0x3003
- field public static final int ID_WINDOW_MOVE = 12290; // 0x3002
- field public static final int ID_WINDOW_POS = 12289; // 0x3001
+ method public synchronized void unregisterCallback(android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback) throws android.car.CarNotConnectedException;
+ field public static final int ID_DOOR_LOCK = 371198722; // 0x16200b02
+ field public static final int ID_DOOR_MOVE = 373295873; // 0x16400b01
+ field public static final int ID_DOOR_POS = 373295872; // 0x16400b00
+ field public static final int ID_MIRROR_FOLD = 287312709; // 0x11200b45
+ field public static final int ID_MIRROR_LOCK = 287312708; // 0x11200b44
+ field public static final int ID_MIRROR_Y_MOVE = 339741507; // 0x14400b43
+ field public static final int ID_MIRROR_Y_POS = 339741506; // 0x14400b42
+ field public static final int ID_MIRROR_Z_MOVE = 339741505; // 0x14400b41
+ field public static final int ID_MIRROR_Z_POS = 339741504; // 0x14400b40
+ field public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 356518792; // 0x15400b88
+ field public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 356518791; // 0x15400b87
+ field public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 356518794; // 0x15400b8a
+ field public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 356518793; // 0x15400b89
+ field public static final int ID_SEAT_BELT_BUCKLED = 354421634; // 0x15200b82
+ field public static final int ID_SEAT_BELT_HEIGHT_MOVE = 356518788; // 0x15400b84
+ field public static final int ID_SEAT_BELT_HEIGHT_POS = 356518787; // 0x15400b83
+ field public static final int ID_SEAT_DEPTH_MOVE = 356518798; // 0x15400b8e
+ field public static final int ID_SEAT_DEPTH_POS = 356518797; // 0x15400b8d
+ field public static final int ID_SEAT_FORE_AFT_MOVE = 356518790; // 0x15400b86
+ field public static final int ID_SEAT_FORE_AFT_POS = 356518789; // 0x15400b85
+ field public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 356518808; // 0x15400b98
+ field public static final int ID_SEAT_HEADREST_ANGLE_POS = 356518807; // 0x15400b97
+ field public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 356518810; // 0x15400b9a
+ field public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 356518809; // 0x15400b99
+ field public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 356518806; // 0x15400b96
+ field public static final int ID_SEAT_HEADREST_HEIGHT_POS = 356518805; // 0x15400b95
+ field public static final int ID_SEAT_HEIGHT_MOVE = 356518796; // 0x15400b8c
+ field public static final int ID_SEAT_HEIGHT_POS = 356518795; // 0x15400b8b
+ field public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 356518802; // 0x15400b92
+ field public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 356518801; // 0x15400b91
+ field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804; // 0x15400b94
+ field public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803; // 0x15400b93
+ field public static final int ID_SEAT_MEMORY_SELECT = 356518784; // 0x15400b80
+ field public static final int ID_SEAT_MEMORY_SET = 356518785; // 0x15400b81
+ field public static final int ID_SEAT_TILT_MOVE = 356518800; // 0x15400b90
+ field public static final int ID_SEAT_TILT_POS = 356518799; // 0x15400b8f
+ field public static final int ID_WINDOW_LOCK = 322964420; // 0x13400bc4
+ field public static final int ID_WINDOW_MOVE = 322964417; // 0x13400bc1
+ field public static final int ID_WINDOW_POS = 322964416; // 0x13400bc0
}
public static abstract interface CarCabinManager.CarCabinEventCallback {
@@ -638,7 +639,6 @@
method public int getIntProperty(int, int) throws android.car.CarNotConnectedException;
method public java.util.List<android.car.hardware.CarPropertyConfig> getPropertyList() throws android.car.CarNotConnectedException;
method public boolean isPropertyAvailable(int, int) throws android.car.CarNotConnectedException;
- method public static boolean isZonedProperty(int);
method public synchronized void registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback) throws android.car.CarNotConnectedException;
method public void setBooleanProperty(int, int, boolean) throws android.car.CarNotConnectedException;
method public void setFloatProperty(int, int, float) throws android.car.CarNotConnectedException;
@@ -647,26 +647,26 @@
field public static final int FAN_DIRECTION_DEFROST = 4; // 0x4
field public static final int FAN_DIRECTION_FACE = 1; // 0x1
field public static final int FAN_DIRECTION_FLOOR = 2; // 0x2
- field public static final int ID_MIRROR_DEFROSTER_ON = 1; // 0x1
- field public static final int ID_OUTSIDE_AIR_TEMP = 3; // 0x3
- field public static final int ID_STEERING_WHEEL_HEAT = 2; // 0x2
- field public static final int ID_TEMPERATURE_DISPLAY_UNITS = 4; // 0x4
- field public static final int ID_WINDOW_DEFROSTER_ON = 20481; // 0x5001
- field public static final int ID_ZONED_AC_ON = 16393; // 0x4009
- field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 16395; // 0x400b
- field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 16394; // 0x400a
- field public static final int ID_ZONED_DUAL_ZONE_ON = 16397; // 0x400d
- field public static final int ID_ZONED_FAN_DIRECTION = 16391; // 0x4007
- field public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 16390; // 0x4006
- field public static final int ID_ZONED_FAN_SPEED_RPM = 16389; // 0x4005
- field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 16388; // 0x4004
- field public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 16399; // 0x400f
- field public static final int ID_ZONED_HVAC_POWER_ON = 16387; // 0x4003
- field public static final int ID_ZONED_MAX_AC_ON = 16396; // 0x400c
- field public static final int ID_ZONED_MAX_DEFROST_ON = 16398; // 0x400e
- field public static final int ID_ZONED_SEAT_TEMP = 16392; // 0x4008
- field public static final int ID_ZONED_TEMP_ACTUAL = 16386; // 0x4002
- field public static final int ID_ZONED_TEMP_SETPOINT = 16385; // 0x4001
+ field public static final int ID_MIRROR_DEFROSTER_ON = 339739916; // 0x1440050c
+ field public static final int ID_OUTSIDE_AIR_TEMP = 291505923; // 0x11600703
+ field public static final int ID_STEERING_WHEEL_HEAT = 289408269; // 0x1140050d
+ field public static final int ID_TEMPERATURE_DISPLAY_UNITS = 289408270; // 0x1140050e
+ field public static final int ID_WINDOW_DEFROSTER_ON = 320865540; // 0x13200504
+ field public static final int ID_ZONED_AC_ON = 354419973; // 0x15200505
+ field public static final int ID_ZONED_AIR_RECIRCULATION_ON = 354419976; // 0x15200508
+ field public static final int ID_ZONED_AUTOMATIC_MODE_ON = 354419978; // 0x1520050a
+ field public static final int ID_ZONED_DUAL_ZONE_ON = 354419977; // 0x15200509
+ field public static final int ID_ZONED_FAN_DIRECTION = 356517121; // 0x15400501
+ field public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 356582673; // 0x15410511
+ field public static final int ID_ZONED_FAN_SPEED_RPM = 356517135; // 0x1540050f
+ field public static final int ID_ZONED_FAN_SPEED_SETPOINT = 356517120; // 0x15400500
+ field public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 354419986; // 0x15200512
+ field public static final int ID_ZONED_HVAC_POWER_ON = 354419984; // 0x15200510
+ field public static final int ID_ZONED_MAX_AC_ON = 354419974; // 0x15200506
+ field public static final int ID_ZONED_MAX_DEFROST_ON = 354419975; // 0x15200507
+ field public static final int ID_ZONED_SEAT_TEMP = 356517131; // 0x1540050b
+ field public static final int ID_ZONED_TEMP_ACTUAL = 358614274; // 0x15600502
+ field public static final int ID_ZONED_TEMP_SETPOINT = 358614275; // 0x15600503
}
public static abstract interface CarHvacManager.CarHvacEventCallback {
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 5d16640..738a423 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -29,6 +29,7 @@
import android.car.hardware.cabin.CarCabinManager;
import android.car.hardware.hvac.CarHvacManager;
import android.car.hardware.power.CarPowerManager;
+import android.car.hardware.property.CarPropertyManager;
import android.car.media.CarAudioManager;
import android.car.navigation.CarNavigationStatusManager;
import android.car.settings.CarConfigurationManager;
@@ -126,6 +127,12 @@
* @hide
*/
@SystemApi
+ public static final String PROPERTY_SERVICE = "property";
+
+ /**
+ * @hide
+ */
+ @SystemApi
public static final String VENDOR_EXTENSION_SERVICE = "vendor_extension";
/**
@@ -766,6 +773,10 @@
case PROJECTION_SERVICE:
manager = new CarProjectionManager(binder, mEventHandler);
break;
+ case PROPERTY_SERVICE:
+ manager = new CarPropertyManager(binder, mEventHandler, false,
+ "CarPropertyManager");
+ break;
case VENDOR_EXTENSION_SERVICE:
manager = new CarVendorExtensionManager(binder, mEventHandler);
break;
diff --git a/car-lib/src/android/car/CarInfoManager.java b/car-lib/src/android/car/CarInfoManager.java
index 47d90c9..b228ca7 100644
--- a/car-lib/src/android/car/CarInfoManager.java
+++ b/car-lib/src/android/car/CarInfoManager.java
@@ -16,45 +16,46 @@
package android.car;
+import static java.lang.Integer.toHexString;
+
import android.annotation.Nullable;
-import android.car.EvConnectorType;
-import android.car.FuelType;
-import android.car.annotation.FutureFeature;
import android.car.annotation.ValueTypeDef;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.ICarProperty;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-
-
-import com.android.internal.annotations.GuardedBy;
+import android.util.Log;
/**
* Utility to retrieve various static information from car. Each data are grouped as {@link Bundle}
* and relevant data can be checked from {@link Bundle} using pre-specified keys.
*/
-public final class CarInfoManager implements CarManagerBase {
+public final class CarInfoManager implements CarManagerBase{
+ private static final boolean DBG = false;
+ private static final String TAG = "CarInfoManager";
/**
* Key for manufacturer of the car. Passed in basic info Bundle.
* @hide
*/
- @ValueTypeDef(type = String.class)
- public static final String BASIC_INFO_KEY_MANUFACTURER = "android.car.manufacturer";
+ @ValueTypeDef(type = Integer.class)
+ public static final int BASIC_INFO_KEY_MANUFACTURER = 0x11100101;
/**
* Key for model name of the car. This information may not necessarily allow distinguishing
* different car models as the same name may be used for different cars depending on
* manufacturers. Passed in basic info Bundle.
* @hide
*/
- @ValueTypeDef(type = String.class)
- public static final String BASIC_INFO_KEY_MODEL = "android.car.model";
+ @ValueTypeDef(type = Integer.class)
+ public static final int BASIC_INFO_KEY_MODEL = 0x11100102;
/**
* Key for model year of the car in AC. Passed in basic info Bundle.
* @hide
*/
@ValueTypeDef(type = Integer.class)
- public static final String BASIC_INFO_KEY_MODEL_YEAR = "android.car.model-year";
+ public static final int BASIC_INFO_KEY_MODEL_YEAR = 0x11400103;
/**
* Key for unique identifier for the car. This is not VIN, and id is persistent until user
* resets it. Passed in basic info Bundle.
@@ -92,38 +93,38 @@
* @hide
*/
@ValueTypeDef(type = Integer.class)
- public static final String BASIC_INFO_FUEL_CAPACITY = "android.car.fuel-capacity";
+ public static final int BASIC_INFO_FUEL_CAPACITY = 0x11600104;
/**
* Key for Fuel Types. This is an array of fuel types the vehicle supports.
* Passed in basic info Bundle.
* @hide
*/
@ValueTypeDef(type = Integer.class)
- public static final String BASIC_INFO_FUEL_TYPES = "android.car.fuel-types";
+ public static final int BASIC_INFO_FUEL_TYPES = 0x11410105;
/**
* Key for EV Battery Capacity in WH. Passed in basic info Bundle.
* @hide
*/
@ValueTypeDef(type = Integer.class)
- public static final String BASIC_INFO_EV_BATTERY_CAPACITY = "android.car.ev-battery-capacity";
+ public static final int BASIC_INFO_EV_BATTERY_CAPACITY = 0x11600106;
/**
* Key for EV Connector Types. This is an array of connector types the vehicle supports.
* Passed in basic info Bundle.
* @hide
*/
@ValueTypeDef(type = Integer.class)
- public static final String BASIC_INFO_EV_CONNECTOR_TYPES = "android.car.ev-connector-types";
+ public static final int BASIC_INFO_EV_CONNECTOR_TYPES = 0x11410107;
- private final ICarInfo mService;
-
- @GuardedBy("this")
- private Bundle mBasicInfo;
+ private final ICarProperty mService;
/**
* @return Manufacturer of the car. Null if not available.
*/
- public @android.annotation.Nullable String getManufacturer() throws CarNotConnectedException {
- return getBasicInfo().getString(BASIC_INFO_KEY_MANUFACTURER);
+ @Nullable
+ public String getManufacturer() throws CarNotConnectedException {
+ CarPropertyValue<String> carProp = getProperty(String.class,
+ BASIC_INFO_KEY_MANUFACTURER, 0);
+ return carProp != null ? carProp.getValue() : null;
}
/**
@@ -131,24 +132,30 @@
* may not necessarily allow distinguishing different car models as the same
* name may be used for different cars depending on manufacturers.
*/
- public @Nullable String getModel() throws CarNotConnectedException {
- return getBasicInfo().getString(BASIC_INFO_KEY_MODEL);
+ @Nullable
+ public String getModel() throws CarNotConnectedException {
+ CarPropertyValue<String> carProp = getProperty(String.class, BASIC_INFO_KEY_MODEL, 0);
+ return carProp != null ? carProp.getValue() : null;
}
/**
* @return Model year of the car in AC. Null if not available.
*/
- public @Nullable String getModelYear() throws CarNotConnectedException {
- return getBasicInfo().getString(BASIC_INFO_KEY_MODEL_YEAR);
+ @Nullable
+ public String getModelYear() throws CarNotConnectedException {
+ CarPropertyValue<String> carProp = getProperty(String.class,
+ BASIC_INFO_KEY_MODEL_YEAR, 0);
+ return carProp != null ? carProp.getValue() : null;
}
/**
* @return Unique identifier for the car. This is not VIN, and vehicle id is
* persistent until user resets it. This ID is guaranteed to be always
* available.
+ * TODO: BASIC_INFO_KEY_VEHICLE_ID property?
*/
public String getVehicleId() throws CarNotConnectedException {
- return getBasicInfo().getString(BASIC_INFO_KEY_VEHICLE_ID);
+ return "";
}
/**
@@ -156,7 +163,9 @@
* fuel.
*/
public float getFuelCapacity() throws CarNotConnectedException {
- return getBasicInfo().getFloat(BASIC_INFO_FUEL_CAPACITY);
+ CarPropertyValue<Float> carProp = getProperty(Float.class,
+ BASIC_INFO_FUEL_CAPACITY, 0);
+ return carProp != null ? carProp.getValue() : 0f;
}
/**
@@ -164,7 +173,8 @@
* types available.
*/
public @FuelType.Enum int[] getFuelTypes() throws CarNotConnectedException {
- return getIntArray(BASIC_INFO_FUEL_TYPES);
+ CarPropertyValue<int[]> carProp = getProperty(int[].class, BASIC_INFO_FUEL_TYPES, 0);
+ return carProp != null ? carProp.getValue() : new int[0];
}
/**
@@ -172,7 +182,9 @@
* battery.
*/
public float getEvBatteryCapacity() throws CarNotConnectedException {
- return getBasicInfo().getFloat(BASIC_INFO_EV_BATTERY_CAPACITY);
+ CarPropertyValue<Float> carProp = getProperty(Float.class,
+ BASIC_INFO_EV_BATTERY_CAPACITY, 0);
+ return carProp != null ? carProp.getValue() : 0f;
}
/**
@@ -180,77 +192,42 @@
* no connector types available.
*/
public @EvConnectorType.Enum int[] getEvConnectorTypes() throws CarNotConnectedException {
- return getIntArray(BASIC_INFO_EV_CONNECTOR_TYPES);
- }
-
- /**
- * Get product configuration string. Contents of this string is product specific but it should
- * be composed of key-value pairs with the format of:
- * key1=value1;key2=value2;...
- * @return null if such information is not available in this car.
- * @throws CarNotConnectedException
- * @hide
- */
- @FutureFeature
- public @Nullable String getProductConfiguration() throws CarNotConnectedException {
- try {
- return mService.getStringInfo(INFO_KEY_PRODUCT_CONFIGURATION);
- } catch (IllegalStateException e) {
- CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
- } catch (RemoteException e) {
- throw new CarNotConnectedException(e);
- }
- return null;
- }
-
- /**
- * Get {@link android.os.Bundle} containing basic car information. Check
- * {@link #BASIC_INFO_KEY_MANUFACTURER}, {@link #BASIC_INFO_KEY_MODEL},
- * {@link #BASIC_INFO_KEY_MODEL_YEAR}, and {@link #BASIC_INFO_KEY_VEHICLE_ID} for supported
- * keys in the {@link android.os.Bundle}.
- * @return {@link android.os.Bundle} containing basic car info.
- * @throws CarNotConnectedException
- */
- private synchronized Bundle getBasicInfo() throws CarNotConnectedException {
- if (mBasicInfo != null) {
- return mBasicInfo;
- }
- try {
- mBasicInfo = mService.getBasicInfo();
- } catch (IllegalStateException e) {
- CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
- } catch (RemoteException e) {
- throw new CarNotConnectedException(e);
- }
- return mBasicInfo;
- }
-
- /**
- * Get int array from property ID.
- * @param id property ID to get
- * @return array of property values or empty array if the property isn't
- * available.
- * @throws CarNotConnectedException
- */
- private int[] getIntArray(String id) throws CarNotConnectedException {
- int[] retVal = getBasicInfo().getIntArray(id);
- if (retVal == null) {
- // Create an empty array
- retVal = new int[0];
- }
- return retVal;
+ CarPropertyValue<int[]> carProp = getProperty(int[].class,
+ BASIC_INFO_EV_CONNECTOR_TYPES, 0);
+ return carProp != null ? carProp.getValue() : new int[0];
}
/** @hide */
CarInfoManager(IBinder service) {
- mService = ICarInfo.Stub.asInterface(service);
+ mService = ICarProperty.Stub.asInterface(service);
}
/** @hide */
- @Override
public void onCarDisconnected() {
- synchronized (this) {
- mBasicInfo = null;
+ }
+
+ private <E> CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int area)
+ throws CarNotConnectedException {
+ if (DBG) {
+ Log.d(TAG, "getProperty, propId: 0x" + toHexString(propId)
+ + ", area: 0x" + toHexString(area) + ", class: " + clazz);
+ }
+ try {
+ CarPropertyValue<E> propVal = mService.getProperty(propId, area);
+ if (propVal != null && propVal.getValue() != null) {
+ Class<?> actualClass = propVal.getValue().getClass();
+ if (actualClass != clazz) {
+ throw new IllegalArgumentException("Invalid property type. " + "Expected: "
+ + clazz + ", but was: " + actualClass);
+ }
+ }
+ return propVal;
+ } catch (RemoteException e) {
+ Log.e(TAG, "getProperty failed with " + e.toString()
+ + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+ throw new CarNotConnectedException(e);
+ } catch (IllegalArgumentException e) {
+ return null;
}
}
}
diff --git a/car-lib/src/android/car/VehicleAreaType.java b/car-lib/src/android/car/VehicleAreaType.java
index f484487..971f000 100644
--- a/car-lib/src/android/car/VehicleAreaType.java
+++ b/car-lib/src/android/car/VehicleAreaType.java
@@ -31,7 +31,7 @@
@SystemApi
public final class VehicleAreaType {
/** Used for global properties */
- public static final int VEHICLE_AREA_TYPE_NONE = 0;
+ public static final int VEHICLE_AREA_TYPE_GLOBAL = 0;
public static final int VEHICLE_AREA_TYPE_WINDOW = 2;
public static final int VEHICLE_AREA_TYPE_SEAT = 3;
public static final int VEHICLE_AREA_TYPE_DOOR = 4;
@@ -41,7 +41,7 @@
/** @hide */
@IntDef({
- VEHICLE_AREA_TYPE_NONE,
+ VEHICLE_AREA_TYPE_GLOBAL,
VEHICLE_AREA_TYPE_WINDOW,
VEHICLE_AREA_TYPE_SEAT,
VEHICLE_AREA_TYPE_DOOR,
diff --git a/car-lib/src/android/car/VehiclePropertyType.java b/car-lib/src/android/car/VehiclePropertyType.java
new file mode 100644
index 0000000..b236d2d
--- /dev/null
+++ b/car-lib/src/android/car/VehiclePropertyType.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.car;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
+/**
+ * Value type of VehicleProperty
+ * @hide
+ */
+public class VehiclePropertyType {
+ public static final int STRING = 0x00100000;
+ public static final int BOOLEAN = 0x00200000;
+ public static final int INT32 = 0x00400000;
+ public static final int INT32_VEC = 0x00410000;
+ public static final int INT64 = 0x00500000;
+ public static final int INT64_VEC = 0x00510000;
+ public static final int FLOAT = 0x00600000;
+ public static final int FLOAT_VEC = 0x00610000;
+ public static final int BYTES = 0x00700000;
+ public static final int MIXED = 0x00e00000;
+ public static final int MASK = 0x00ff0000;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ STRING,
+ BOOLEAN,
+ INT32,
+ INT32_VEC,
+ INT64,
+ INT64_VEC,
+ FLOAT,
+ FLOAT_VEC,
+ BYTES,
+ /**
+ * Any combination of scalar or vector types. The exact format must be
+ * provided in the description of the property.
+ */
+ MIXED,
+ MASK
+ })
+ public @interface Enum {}
+ private VehiclePropertyType() {}
+}
diff --git a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
index 1c2c334..57e7d60 100644
--- a/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
+++ b/car-lib/src/android/car/drivingstate/CarUxRestrictionsManager.java
@@ -45,7 +45,7 @@
private final Context mContext;
private final ICarUxRestrictionsManager mUxRService;
private final EventCallbackHandler mEventCallbackHandler;
- private onUxRestrictionsChangedListener mUxRListener;
+ private OnUxRestrictionsChangedListener mUxRListener;
private CarUxRestrictionsChangeListenerToService mListenerToService;
@@ -67,7 +67,7 @@
* Listener Interface for clients to implement to get updated on driving state related
* changes.
*/
- public interface onUxRestrictionsChangedListener {
+ public interface OnUxRestrictionsChangedListener {
/**
* Called when the UX restrictions due to a car's driving state changes.
*
@@ -77,15 +77,15 @@
}
/**
- * Register a {@link onUxRestrictionsChangedListener} for listening to changes in the
+ * Register a {@link OnUxRestrictionsChangedListener} for listening to changes in the
* UX Restrictions to adhere to.
* <p>
* If a listener has already been registered, it has to be unregistered before registering
* the new one.
*
- * @param listener {@link onUxRestrictionsChangedListener}
+ * @param listener {@link OnUxRestrictionsChangedListener}
*/
- public synchronized void registerListener(@NonNull onUxRestrictionsChangedListener listener)
+ public synchronized void registerListener(@NonNull OnUxRestrictionsChangedListener listener)
throws CarNotConnectedException, IllegalArgumentException {
if (listener == null) {
if (VDBG) {
@@ -117,7 +117,7 @@
}
/**
- * Unregister the registered {@link onUxRestrictionsChangedListener}
+ * Unregister the registered {@link OnUxRestrictionsChangedListener}
*/
public synchronized void unregisterListener()
throws CarNotConnectedException {
@@ -218,7 +218,7 @@
if (restrictionInfo == null) {
return;
}
- onUxRestrictionsChangedListener listener;
+ OnUxRestrictionsChangedListener listener;
synchronized (this) {
listener = mUxRListener;
}
@@ -226,5 +226,4 @@
listener.onUxRestrictionsChanged(restrictionInfo);
}
}
-
}
diff --git a/car-lib/src/android/car/hardware/CarPropertyConfig.java b/car-lib/src/android/car/hardware/CarPropertyConfig.java
index 965253a..be2b86c 100644
--- a/car-lib/src/android/car/hardware/CarPropertyConfig.java
+++ b/car-lib/src/android/car/hardware/CarPropertyConfig.java
@@ -98,7 +98,7 @@
/** Returns true if this property doesn't hold car area-specific configuration */
public boolean isGlobalProperty() {
- return mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_NONE;
+ return mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
}
public int getAreaCount() {
diff --git a/car-lib/src/android/car/hardware/CarSensorEvent.java b/car-lib/src/android/car/hardware/CarSensorEvent.java
index abf2b2a..86af063 100644
--- a/car-lib/src/android/car/hardware/CarSensorEvent.java
+++ b/car-lib/src/android/car/hardware/CarSensorEvent.java
@@ -37,39 +37,39 @@
* sensor type.
* GEAR_NEUTRAL means transmission gear is in neutral state, and the car may be moving.
*/
- public static final int GEAR_NEUTRAL = 0;
+ public static final int GEAR_NEUTRAL = 0x0001;
/**
* intValues[0] from 1 to 99 represents transmission gear number for moving forward.
* GEAR_FIRST is for gear number 1.
*/
- public static final int GEAR_FIRST = 1;
+ public static final int GEAR_FIRST = 0x0010;
/** Gear number 2. */
- public static final int GEAR_SECOND = 2;
+ public static final int GEAR_SECOND = 0x0020;
/** Gear number 3. */
- public static final int GEAR_THIRD = 3;
+ public static final int GEAR_THIRD = 0x0040;
/** Gear number 4. */
- public static final int GEAR_FOURTH = 4;
+ public static final int GEAR_FOURTH = 0x0080;
/** Gear number 5. */
- public static final int GEAR_FIFTH = 5;
+ public static final int GEAR_FIFTH = 0x0100;
/** Gear number 6. */
- public static final int GEAR_SIXTH = 6;
+ public static final int GEAR_SIXTH = 0x0200;
/** Gear number 7. */
- public static final int GEAR_SEVENTH = 7;
+ public static final int GEAR_SEVENTH = 0x0400;
/** Gear number 8. */
- public static final int GEAR_EIGHTH = 8;
+ public static final int GEAR_EIGHTH = 0x0800;
/** Gear number 9. */
- public static final int GEAR_NINTH = 9;
+ public static final int GEAR_NINTH = 0x1000;
/** Gear number 10. */
- public static final int GEAR_TENTH = 10;
+ public static final int GEAR_TENTH = 0x2000;
/**
* This is for transmission without specific gear number for moving forward like CVT. It tells
* that car is in a transmission state to move it forward.
*/
- public static final int GEAR_DRIVE = 100;
+ public static final int GEAR_DRIVE = 0x0008;
/** Gear in parking state */
- public static final int GEAR_PARK = 101;
+ public static final int GEAR_PARK = 0x0004;
/** Gear in reverse */
- public static final int GEAR_REVERSE = 102;
+ public static final int GEAR_REVERSE = 0x0002;
/**
* Ignition state is unknown.
diff --git a/car-lib/src/android/car/hardware/CarSensorManager.java b/car-lib/src/android/car/hardware/CarSensorManager.java
index dd05bc8..2536604 100644
--- a/car-lib/src/android/car/hardware/CarSensorManager.java
+++ b/car-lib/src/android/car/hardware/CarSensorManager.java
@@ -24,28 +24,31 @@
import android.car.CarLibLog;
import android.car.CarManagerBase;
import android.car.CarNotConnectedException;
+import android.car.VehiclePropertyType;
+import android.car.hardware.property.CarPropertyManager;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.car.internal.CarRatedListeners;
-import com.android.car.internal.SingleMessageHandler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
-import java.util.function.Consumer;
+
/**
* API for monitoring car sensor data.
*/
public final class CarSensorManager implements CarManagerBase {
+ private static final boolean DBG = false;
+ private static final String TAG = "CarSensorManager";
+ private final CarPropertyManager mCarPropertyMgr;
/** @hide */
public static final int SENSOR_TYPE_RESERVED1 = 1;
/**
@@ -53,41 +56,41 @@
* Sensor data in {@link CarSensorEvent} is a float which will be >= 0.
* This requires {@link Car#PERMISSION_SPEED} permission.
*/
- public static final int SENSOR_TYPE_CAR_SPEED = 2;
+ public static final int SENSOR_TYPE_CAR_SPEED = 0x11600207;
/**
* Represents engine RPM of the car. Sensor data in {@link CarSensorEvent} is a float.
*/
- public static final int SENSOR_TYPE_RPM = 3;
+ public static final int SENSOR_TYPE_RPM = 0x11600305;
/**
* Total travel distance of the car in Kilometer. Sensor data is a float.
* This requires {@link Car#PERMISSION_MILEAGE} permission.
*/
- public static final int SENSOR_TYPE_ODOMETER = 4;
+ public static final int SENSOR_TYPE_ODOMETER = 0x11600204;
/**
* Indicates fuel level of the car.
* In {@link CarSensorEvent}, represents fuel level in milliliters.
* This requires {@link Car#PERMISSION_ENERGY} permission.
*/
- public static final int SENSOR_TYPE_FUEL_LEVEL = 5;
+ public static final int SENSOR_TYPE_FUEL_LEVEL = 0x11600307;
/**
* Represents the current status of parking brake. Sensor data in {@link CarSensorEvent} is an
* intValues[0]. Value of 1 represents parking brake applied while 0 means the other way
* around. For this sensor, rate in {@link #registerListener(OnSensorChangedListener, int, int)}
* will be ignored and all changes will be notified.
*/
- public static final int SENSOR_TYPE_PARKING_BRAKE = 6;
+ public static final int SENSOR_TYPE_PARKING_BRAKE = 0x11200402;
/**
* This represents the current position of transmission gear. Sensor data in
* {@link CarSensorEvent} is an intValues[0]. For the meaning of the value, check
* {@link CarSensorEvent#GEAR_NEUTRAL} and other GEAR_*.
*/
- public static final int SENSOR_TYPE_GEAR = 7;
+ public static final int SENSOR_TYPE_GEAR = 0x11400400;
/** @hide */
public static final int SENSOR_TYPE_RESERVED8 = 8;
/**
* Day/night sensor. Sensor data is intValues[0].
*/
- public static final int SENSOR_TYPE_NIGHT = 9;
+ public static final int SENSOR_TYPE_NIGHT = 0x11200407;
/** @hide */
public static final int SENSOR_TYPE_RESERVED10 = 10;
/** @hide */
@@ -118,7 +121,7 @@
* Represents ignition state. The value should be one of the constants that starts with
* IGNITION_STATE_* in {@link CarSensorEvent}.
*/
- public static final int SENSOR_TYPE_IGNITION_STATE = 22;
+ public static final int SENSOR_TYPE_IGNITION_STATE = 0x11400409;
/**
* Represents wheel distance in millimeters. Some cars may not have individual sensors on each
* wheel. If a value is not available, Long.MAX_VALUE will be reported. The wheel distance
@@ -126,23 +129,23 @@
* distance shall be reset to zero each time a vehicle is started by the user.
* This requires {@link Car#PERMISSION_SPEED} permission.
*/
- public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 23;
+ public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE = 0x11510306;
/**
* Set to true when ABS is active. This sensor is event driven.
* This requires {@link Car#PERMISSION_CAR_DYNAMICS_STATE} permission.
*/
- public static final int SENSOR_TYPE_ABS_ACTIVE = 24;
+ public static final int SENSOR_TYPE_ABS_ACTIVE = 0x1120040a;
/**
* Set to true when traction control is active. This sensor is event driven.
* This requires {@link Car#PERMISSION_CAR_DYNAMICS_STATE} permission.
*/
- public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 25;
+ public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE = 0x1120040b;
/** @hide */
public static final int SENSOR_TYPE_RESERVED26 = 26;
/**
* Set to true if the fuel door is open.
*/
- public static final int SENSOR_TYPE_FUEL_DOOR_OPEN = 27;
+ public static final int SENSOR_TYPE_FUEL_DOOR_OPEN = 0x11200308;
/**
* Indicates battery level of the car.
@@ -152,129 +155,154 @@
* of the vehicle.
* This requires {@link Car#PERMISSION_ENERGY} permission.
*/
- public static final int SENSOR_TYPE_EV_BATTERY_LEVEL = 28;
+ public static final int SENSOR_TYPE_EV_BATTERY_LEVEL = 0x11600309;
/**
* Set to true if EV charging port is open.
*/
- public static final int SENSOR_TYPE_EV_CHARGE_PORT_OPEN = 29;
+ public static final int SENSOR_TYPE_EV_CHARGE_PORT_OPEN = 0x1120030a;
/**
* Set to true if EV charging port is connected.
*/
- public static final int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED = 30;
+ public static final int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED = 0x1120030b;
/**
* Indicates the instantaneous battery charging rate in mW.
* This requires {@link Car#PERMISSION_ENERGY} permission.
*/
- public static final int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE = 31;
+ public static final int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE = 0x1160030c;
/**
* Oil level sensor.
* This requires {@link Car#PERMISSION_CAR_ENGINE_DETAILED} permission
* @hide
*/
- public static final int SENSOR_TYPE_ENGINE_OIL_LEVEL = 32;
+ public static final int SENSOR_TYPE_ENGINE_OIL_LEVEL = 0x11400303;
- /**
- * Sensor type bigger than this is invalid. Always update this after adding a new sensor.
- * @hide
- */
- private static final int SENSOR_TYPE_MAX = SENSOR_TYPE_ENGINE_OIL_LEVEL;
-
- /**
- * Sensors defined in this range [{@link #SENSOR_TYPE_VENDOR_EXTENSION_START},
- * {@link #SENSOR_TYPE_VENDOR_EXTENSION_END}] is for each car vendor's to use.
- * This should be only used for system app to access sensors not defined as standard types.
- * So the sensor supported in this range can vary depending on car models / manufacturers.
- * 3rd party apps should not use sensors in this range as they are not compatible across
- * different cars. Additionally 3rd party apps trying to access sensor in this range will get
- * security exception as their access is restricted to system apps.
- *
- * @hide
- */
- public static final int SENSOR_TYPE_VENDOR_EXTENSION_START = 0x60000000;
- public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 0x6fffffff;
/** @hide */
@IntDef({
- SENSOR_TYPE_CAR_SPEED,
- SENSOR_TYPE_RPM,
- SENSOR_TYPE_ODOMETER,
- SENSOR_TYPE_FUEL_LEVEL,
- SENSOR_TYPE_PARKING_BRAKE,
- SENSOR_TYPE_GEAR,
- SENSOR_TYPE_NIGHT,
- SENSOR_TYPE_ENVIRONMENT,
- SENSOR_TYPE_IGNITION_STATE,
- SENSOR_TYPE_WHEEL_TICK_DISTANCE,
- SENSOR_TYPE_ABS_ACTIVE,
- SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
- SENSOR_TYPE_FUEL_DOOR_OPEN,
- SENSOR_TYPE_EV_BATTERY_LEVEL,
- SENSOR_TYPE_EV_CHARGE_PORT_OPEN,
- SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
- SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
- SENSOR_TYPE_ENGINE_OIL_LEVEL,
+ SENSOR_TYPE_CAR_SPEED,
+ SENSOR_TYPE_RPM,
+ SENSOR_TYPE_ODOMETER,
+ SENSOR_TYPE_FUEL_LEVEL,
+ SENSOR_TYPE_PARKING_BRAKE,
+ SENSOR_TYPE_GEAR,
+ SENSOR_TYPE_NIGHT,
+ SENSOR_TYPE_ENVIRONMENT,
+ SENSOR_TYPE_IGNITION_STATE,
+ SENSOR_TYPE_WHEEL_TICK_DISTANCE,
+ SENSOR_TYPE_ABS_ACTIVE,
+ SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
+ SENSOR_TYPE_FUEL_DOOR_OPEN,
+ SENSOR_TYPE_EV_BATTERY_LEVEL,
+ SENSOR_TYPE_EV_CHARGE_PORT_OPEN,
+ SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
+ SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
+ SENSOR_TYPE_ENGINE_OIL_LEVEL,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SensorType {}
+ private final ArraySet<Integer> mSensorConfigIds = new ArraySet<>(Arrays.asList(new Integer[]{
+ SENSOR_TYPE_CAR_SPEED,
+ SENSOR_TYPE_RPM,
+ SENSOR_TYPE_ODOMETER,
+ SENSOR_TYPE_FUEL_LEVEL,
+ SENSOR_TYPE_PARKING_BRAKE,
+ SENSOR_TYPE_GEAR,
+ SENSOR_TYPE_NIGHT,
+ SENSOR_TYPE_ENVIRONMENT,
+ SENSOR_TYPE_IGNITION_STATE,
+ SENSOR_TYPE_WHEEL_TICK_DISTANCE,
+ SENSOR_TYPE_ABS_ACTIVE,
+ SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
+ SENSOR_TYPE_FUEL_DOOR_OPEN,
+ SENSOR_TYPE_EV_BATTERY_LEVEL,
+ SENSOR_TYPE_EV_CHARGE_PORT_OPEN,
+ SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
+ SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
+ SENSOR_TYPE_ENGINE_OIL_LEVEL,
+ }));
+
/** Read sensor in default normal rate set for each sensors. This is default rate. */
- public static final int SENSOR_RATE_NORMAL = 3;
- public static final int SENSOR_RATE_UI = 2;
- public static final int SENSOR_RATE_FAST = 1;
+ public static final int SENSOR_RATE_NORMAL = 1;
+ public static final int SENSOR_RATE_UI = 5;
+ public static final int SENSOR_RATE_FAST = 10;
/** Read sensor at the maximum rate. Actual rate will be different depending on the sensor. */
- public static final int SENSOR_RATE_FASTEST = 0;
+ public static final int SENSOR_RATE_FASTEST = 100;
/** @hide */
@IntDef({
- SENSOR_RATE_NORMAL,
- SENSOR_RATE_UI,
- SENSOR_RATE_FAST,
- SENSOR_RATE_FASTEST
+ SENSOR_RATE_NORMAL,
+ SENSOR_RATE_UI,
+ SENSOR_RATE_FAST,
+ SENSOR_RATE_FASTEST
})
@Retention(RetentionPolicy.SOURCE)
public @interface SensorRate {}
- private static final int MSG_SENSOR_EVENTS = 0;
-
- private final ICarSensor mService;
-
- private CarSensorEventListenerToService mCarSensorEventListenerToService;
+ private CarPropertyEventListenerToBase mCarPropertyEventListener = null;
/**
- * To keep record of locally active sensors. Key is sensor type. This is used as a basic lock
- * for all client accesses.
+ * To keep record of CarPropertyEventListenerToBase
*/
- private final SparseArray<CarSensorListeners> mActiveSensorListeners = new SparseArray<>();
+ private final HashMap<OnSensorChangedListener, CarPropertyEventListenerToBase> mListenerMap =
+ new HashMap<>();
+ /**
+ * Listener for car sensor data change.
+ * Callbacks are called in the Looper context.
+ */
+ public interface OnSensorChangedListener {
+ /**
+ * Called when there is a new sensor data from car.
+ * @param event Incoming sensor event for the given sensor type.
+ */
+ void onSensorChanged(CarSensorEvent event);
+ }
- /** Handles call back into clients. */
- private final SingleMessageHandler<CarSensorEvent> mHandlerCallback;
+ private static class CarPropertyEventListenerToBase implements
+ CarPropertyManager.CarPropertyEventListener{
+ private final WeakReference<CarSensorManager> mManager;
+ private final OnSensorChangedListener mListener;
+ CarPropertyEventListenerToBase(CarSensorManager manager, OnSensorChangedListener listener) {
+ mManager = new WeakReference<>(manager);
+ mListener = listener;
+ }
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ CarSensorManager manager = mManager.get();
+ if (manager != null) {
+ manager.handleOnChangeEvent(value, mListener);
+ }
+ }
+ @Override
+ public void onErrorEvent(int propertyId, int zone) {
+
+ }
+ }
+
+ private void handleOnChangeEvent(CarPropertyValue value, OnSensorChangedListener listener) {
+ synchronized (mListenerMap) {
+ CarSensorEvent event = createCarSensorEvent(value);
+ listener.onSensorChanged(event);
+ }
+ }
+
+ private void handleOnErrorEvent(int propertyId, int zone) {
+
+ }
/** @hide */
public CarSensorManager(IBinder service, Context context, Handler handler) {
- mService = ICarSensor.Stub.asInterface(service);
- mHandlerCallback = new SingleMessageHandler<CarSensorEvent>(handler.getLooper(),
- MSG_SENSOR_EVENTS) {
- @Override
- protected void handleEvent(CarSensorEvent event) {
- CarSensorListeners listeners;
- synchronized (mActiveSensorListeners) {
- listeners = mActiveSensorListeners.get(event.sensorType);
- }
- if (listeners != null) {
- listeners.onSensorChanged(event);
- }
- }
- };
+ mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
}
/** @hide */
@Override
public void onCarDisconnected() {
- synchronized(mActiveSensorListeners) {
- mActiveSensorListeners.clear();
- mCarSensorEventListenerToService = null;
+ synchronized (mListenerMap) {
+ mListenerMap.clear();
}
+ mCarPropertyMgr.onCarDisconnected();
}
/**
@@ -284,16 +312,28 @@
*/
public int[] getSupportedSensors() throws CarNotConnectedException {
try {
- return mService.getSupportedSensors();
+ List<CarPropertyConfig> carPropertyConfigList = getPropertyList();
+ int[] supportedSensors = new int[carPropertyConfigList.size()];
+ for (int i = 0; i < supportedSensors.length; i++) {
+ supportedSensors[i] = carPropertyConfigList.get(i).getPropertyId();
+ }
+ return supportedSensors;
} catch (IllegalStateException e) {
CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
- } catch (RemoteException e) {
- throw new CarNotConnectedException(e);
}
return new int[0];
}
/**
+ * Get list of properties represented by CarSensorManager for this car.
+ * @return List of CarPropertyConfig objects available via Car Cabin Manager.
+ * @throws CarNotConnectedException if the connection to the car service has been lost.
+ */
+ public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
+ return mCarPropertyMgr.getPropertyList(mSensorConfigIds);
+ }
+
+ /**
* Tells if given sensor is supported or not.
* @param sensorType
* @return true if the sensor is supported.
@@ -325,18 +365,6 @@
}
/**
- * Listener for car sensor data change.
- * Callbacks are called in the Looper context.
- */
- public interface OnSensorChangedListener {
- /**
- * Called when there is a new sensor data from car.
- * @param event Incoming sensor event for the given sensor type.
- */
- void onSensorChanged(final CarSensorEvent event);
- }
-
- /**
* Register {@link OnSensorChangedListener} to get repeated sensor updates. Multiple listeners
* can be registered for a single sensor or the same listener can be used for different sensors.
* If the same listener is registered again for the same sensor, it will be either ignored or
@@ -368,33 +396,21 @@
conditional=true)
public boolean registerListener(OnSensorChangedListener listener, @SensorType int sensorType,
@SensorRate int rate) throws CarNotConnectedException, IllegalArgumentException {
- assertSensorType(sensorType);
if (rate != SENSOR_RATE_FASTEST && rate != SENSOR_RATE_NORMAL
&& rate != SENSOR_RATE_UI && rate != SENSOR_RATE_FAST) {
throw new IllegalArgumentException("wrong rate " + rate);
}
- synchronized(mActiveSensorListeners) {
- if (mCarSensorEventListenerToService == null) {
- mCarSensorEventListenerToService = new CarSensorEventListenerToService(this);
- }
- boolean needsServerUpdate = false;
- CarSensorListeners listeners;
- listeners = mActiveSensorListeners.get(sensorType);
- if (listeners == null) {
- listeners = new CarSensorListeners(rate);
- mActiveSensorListeners.put(sensorType, listeners);
- needsServerUpdate = true;
- }
- if (listeners.addAndUpdateRate(listener, rate)) {
- needsServerUpdate = true;
- }
- if (needsServerUpdate) {
- if (!registerOrUpdateSensorListener(sensorType, rate)) {
- return false;
- }
- }
+ if (mListenerMap.get(listener) == null) {
+ mCarPropertyEventListener = new CarPropertyEventListenerToBase(this, listener);
+ } else {
+ mCarPropertyEventListener = mListenerMap.get(listener);
}
- return true;
+ if (mCarPropertyMgr.registerListener(mCarPropertyEventListener, sensorType, rate)) {
+ mListenerMap.put(listener, mCarPropertyEventListener);
+ return true;
+ } else {
+ return false;
+ }
}
/**
@@ -404,10 +420,10 @@
*/
public void unregisterListener(OnSensorChangedListener listener) {
//TODO: removing listener should reset update rate, bug: 32060307
- synchronized(mActiveSensorListeners) {
- for (int i = 0; i < mActiveSensorListeners.size(); i++) {
- doUnregisterListenerLocked(listener, mActiveSensorListeners.keyAt(i));
- }
+ synchronized (mListenerMap) {
+ mCarPropertyEventListener = mListenerMap.get(listener);
+ mCarPropertyMgr.unregisterListener(mCarPropertyEventListener);
+ mListenerMap.remove(listener);
}
}
@@ -418,49 +434,10 @@
* @param sensorType
*/
public void unregisterListener(OnSensorChangedListener listener, @SensorType int sensorType) {
- synchronized(mActiveSensorListeners) {
- doUnregisterListenerLocked(listener, sensorType);
+ synchronized (mListenerMap) {
+ mCarPropertyEventListener = mListenerMap.get(listener);
}
- }
-
- private void doUnregisterListenerLocked(OnSensorChangedListener listener, Integer sensor) {
- CarSensorListeners listeners = mActiveSensorListeners.get(sensor);
- if (listeners != null) {
- boolean needsServerUpdate = false;
- if (listeners.contains(listener)) {
- needsServerUpdate = listeners.remove(listener);
- }
- if (listeners.isEmpty()) {
- try {
- mService.unregisterSensorListener(sensor.intValue(),
- mCarSensorEventListenerToService);
- } catch (RemoteException e) {
- //ignore
- }
- mActiveSensorListeners.remove(sensor);
- } else if (needsServerUpdate) {
- try {
- registerOrUpdateSensorListener(sensor, listeners.getRate());
- } catch (CarNotConnectedException e) {
- // ignore
- }
- }
- }
- }
-
- private boolean registerOrUpdateSensorListener(int sensor, int rate)
- throws CarNotConnectedException {
- try {
- if (!mService.registerOrUpdateSensorListener(sensor, rate,
- mCarSensorEventListenerToService)) {
- return false;
- }
- } catch (IllegalStateException e) {
- CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
- } catch (RemoteException e) {
- throw new CarNotConnectedException(e);
- }
- return true;
+ mCarPropertyMgr.unregisterListener(mCarPropertyEventListener, sensorType);
}
/**
@@ -473,13 +450,11 @@
*/
public CarSensorEvent getLatestSensorEvent(@SensorType int type)
throws CarNotConnectedException {
- assertSensorType(type);
try {
- return mService.getLatestSensorEvent(type);
+ CarPropertyValue propertyValue = mCarPropertyMgr.getProperty(type, 0);
+ return createCarSensorEvent(propertyValue);
} catch (IllegalStateException e) {
CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
- } catch(RemoteException e) {
- handleCarServiceRemoteExceptionAndThrow(e);
}
return null;
}
@@ -492,58 +467,38 @@
throw new CarNotConnectedException();
}
- private void assertSensorType(int sensorType) {
- if (sensorType == 0 || !((sensorType <= SENSOR_TYPE_MAX) ||
- ((sensorType >= SENSOR_TYPE_VENDOR_EXTENSION_START) &&
- (sensorType <= SENSOR_TYPE_VENDOR_EXTENSION_END)))) {
- throw new IllegalArgumentException("invalid sensor type " + sensorType);
- }
- }
-
- private void handleOnSensorChanged(List<CarSensorEvent> events) {
- mHandlerCallback.sendEvents(events);
- }
-
- private static class CarSensorEventListenerToService extends ICarSensorEventListener.Stub {
- private final WeakReference<CarSensorManager> mManager;
-
- public CarSensorEventListenerToService(CarSensorManager manager) {
- mManager = new WeakReference<>(manager);
- }
-
- @Override
- public void onSensorChanged(List<CarSensorEvent> events) {
- CarSensorManager manager = mManager.get();
- if (manager != null) {
- manager.handleOnSensorChanged(events);
- }
- }
- }
-
- private class CarSensorListeners extends CarRatedListeners<OnSensorChangedListener> {
- CarSensorListeners(int rate) {
- super(rate);
- }
-
- void onSensorChanged(final CarSensorEvent event) {
- // throw away old sensor data as oneway binder call can change order.
- long updateTime = event.timestamp;
- if (updateTime < mLastUpdateTime) {
- Log.w(CarLibLog.TAG_SENSOR, "dropping old sensor data");
- return;
- }
- mLastUpdateTime = updateTime;
- List<OnSensorChangedListener> listeners;
- synchronized (mActiveSensorListeners) {
- listeners = new ArrayList<>(getListeners());
- }
- listeners.forEach(new Consumer<OnSensorChangedListener>() {
- @Override
- public void accept(OnSensorChangedListener listener) {
- listener.onSensorChanged(event);
+ private CarSensorEvent createCarSensorEvent(CarPropertyValue propertyValue) {
+ CarSensorEvent event = null;
+ switch (propertyValue.getPropertyId() & VehiclePropertyType.MASK) {
+ case VehiclePropertyType.FLOAT:
+ event = new CarSensorEvent(propertyValue.getPropertyId(),
+ propertyValue.getTimestamp(), 1, 0, 0);
+ event.floatValues[0] = (float) propertyValue.getValue();
+ break;
+ case VehiclePropertyType.INT32:
+ event = new CarSensorEvent(propertyValue.getPropertyId(),
+ propertyValue.getTimestamp(), 0, 1, 0);
+ event.intValues[0] = (int) propertyValue.getValue();
+ break;
+ case VehiclePropertyType.BOOLEAN:
+ event = new CarSensorEvent(propertyValue.getPropertyId(),
+ propertyValue.getTimestamp(), 0, 1, 0);
+ event.intValues[0] = (boolean) propertyValue.getValue() ? 1 : 0;
+ break;
+ case VehiclePropertyType.INT64_VEC:
+ Object[] value = (Object[]) propertyValue.getValue();
+ event = new CarSensorEvent(propertyValue.getPropertyId(),
+ propertyValue.getTimestamp(), 0, 0, value.length);
+ for (int i = 0; i < value.length; i++) {
+ event.longValues[i] = (Long) value[i];
}
- });
+ break;
+ default:
+ Log.e(TAG, "unhandled VehiclePropertyType for propId="
+ + propertyValue.getPropertyId());
+ break;
}
+ return event;
}
/**
@@ -558,15 +513,44 @@
* @hide
*/
public CarSensorConfig getSensorConfig(@SensorType int type)
- throws CarNotConnectedException {
- assertSensorType(type);
- try {
- return mService.getSensorConfig(type);
- } catch (IllegalStateException e) {
- CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
- } catch(RemoteException e) {
- handleCarServiceRemoteExceptionAndThrow(e);
+ throws CarNotConnectedException {
+ Bundle b = null;
+ switch (type) {
+ case SENSOR_TYPE_WHEEL_TICK_DISTANCE:
+ List<CarPropertyConfig> propertyConfigs = mCarPropertyMgr.getPropertyList();
+ for (CarPropertyConfig p : propertyConfigs) {
+ if (p.getPropertyId() == type) {
+ b = createWheelDistanceTickBundle(p.getConfigArray());
+ break;
+ }
+ }
+ break;
+ default:
+ b = Bundle.EMPTY;
+ break;
}
- return new CarSensorConfig(0, Bundle.EMPTY);
+ return new CarSensorConfig(type, b);
+ }
+
+ 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(List<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;
}
}
diff --git a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
index bdaa8cd..9f06764 100644
--- a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
+++ b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
@@ -20,14 +20,16 @@
import android.car.Car;
import android.car.CarManagerBase;
import android.car.CarNotConnectedException;
-import android.car.hardware.property.CarPropertyManagerBase;
-import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback;
+import android.car.hardware.property.CarPropertyManager;
import android.os.Handler;
import android.os.IBinder;
import android.util.ArraySet;
import com.android.internal.annotations.GuardedBy;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -42,12 +44,36 @@
private final static boolean DBG = false;
private final static String TAG = CarVendorExtensionManager.class.getSimpleName();
- private final CarPropertyManagerBase mPropertyManager;
+ private final CarPropertyManager mPropertyManager;
@GuardedBy("mLock")
- private ArraySet<CarVendorExtensionCallback> mCallbacks;
+ private final ArraySet<CarVendorExtensionCallback> mCallbacks = new ArraySet<>();
private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private CarPropertyEventListenerToBase mListenerToBase = null;
+
+ private void handleOnChangeEvent(CarPropertyValue value) {
+ Collection<CarVendorExtensionCallback> callbacks;
+ synchronized (mLock) {
+ callbacks = new ArrayList<>(mCallbacks);
+ }
+ for (CarVendorExtensionCallback l: callbacks) {
+ l.onChangeEvent(value);
+ }
+ }
+
+ private void handleOnErrorEvent(int propertyId, int zone) {
+ Collection<CarVendorExtensionCallback> listeners;
+ synchronized (mLock) {
+ listeners = new ArrayList<>(mCallbacks);
+ }
+ for (CarVendorExtensionCallback l: listeners) {
+ l.onErrorEvent(propertyId, zone);
+ }
+
+ }
+
/**
* Creates an instance of the {@link CarVendorExtensionManager}.
*
@@ -55,7 +81,7 @@
* @hide
*/
public CarVendorExtensionManager(IBinder service, Handler handler) {
- mPropertyManager = new CarPropertyManagerBase(service, handler, DBG, TAG);
+ mPropertyManager = new CarPropertyManager(service, handler, DBG, TAG);
}
/**
@@ -77,43 +103,32 @@
public void registerCallback(CarVendorExtensionCallback callback)
throws CarNotConnectedException {
synchronized (mLock) {
- if (mCallbacks == null) {
- mPropertyManager.registerCallback(new CarPropertyEventCallback() {
- @Override
- public void onChangeEvent(CarPropertyValue value) {
- for (CarVendorExtensionCallback listener: getCallbacks()) {
- listener.onChangeEvent(value);
- }
- }
+ if (mCallbacks.isEmpty()) {
+ mListenerToBase = new CarPropertyEventListenerToBase(this);
+ }
- @Override
- public void onErrorEvent(int propertyId, int zone) {
- for (CarVendorExtensionCallback listener: getCallbacks()) {
- listener.onErrorEvent(propertyId, zone);
- }
- }
- });
- mCallbacks = new ArraySet<>(1 /* We expect at least one element */);
+ List<CarPropertyConfig> configs = mPropertyManager.getPropertyList();
+ for (CarPropertyConfig c : configs) {
+ // Register each individual propertyId
+ mPropertyManager.registerListener(mListenerToBase, c.getPropertyId(), 0);
}
mCallbacks.add(callback);
}
}
/** Unregisters listener that was previously registered. */
- public void unregisterCallback(CarVendorExtensionCallback callback) {
+ public void unregisterCallback(CarVendorExtensionCallback callback)
+ throws CarNotConnectedException {
synchronized (mLock) {
mCallbacks.remove(callback);
- if (mCallbacks.isEmpty()) {
- mPropertyManager.unregisterCallback();
- mCallbacks = null;
+ List<CarPropertyConfig> configs = mPropertyManager.getPropertyList();
+ for (CarPropertyConfig c : configs) {
+ // Register each individual propertyId
+ mPropertyManager.unregisterListener(mListenerToBase, c.getPropertyId());
}
- }
- }
-
- /** Returns copy of listeners. Thread safe. */
- private CarVendorExtensionCallback[] getCallbacks() {
- synchronized (mLock) {
- return mCallbacks.toArray(new CarVendorExtensionCallback[mCallbacks.size()]);
+ if (mCallbacks.isEmpty()) {
+ mListenerToBase = null;
+ }
}
}
@@ -204,4 +219,28 @@
public void onCarDisconnected() {
mPropertyManager.onCarDisconnected();
}
+ private static class CarPropertyEventListenerToBase implements
+ CarPropertyManager.CarPropertyEventListener {
+ private final WeakReference<CarVendorExtensionManager> mManager;
+
+ CarPropertyEventListenerToBase(CarVendorExtensionManager manager) {
+ mManager = new WeakReference<>(manager);
+ }
+
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ CarVendorExtensionManager manager = mManager.get();
+ if (manager != null) {
+ manager.handleOnChangeEvent(value);
+ }
+ }
+
+ @Override
+ public void onErrorEvent(int propertyId, int zone) {
+ CarVendorExtensionManager manager = mManager.get();
+ if (manager != null) {
+ manager.handleOnErrorEvent(propertyId, zone);
+ }
+ }
+ }
}
diff --git a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
index c27b414..1dee2b0 100644
--- a/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
+++ b/car-lib/src/android/car/hardware/cabin/CarCabinManager.java
@@ -23,8 +23,7 @@
import android.car.CarNotConnectedException;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManagerBase;
-import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback;
+import android.car.hardware.property.CarPropertyManager;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
@@ -33,6 +32,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -57,7 +57,7 @@
public final class CarCabinManager implements CarManagerBase {
private final static boolean DBG = false;
private final static String TAG = "CarCabinManager";
- private final CarPropertyManagerBase mMgr;
+ private final CarPropertyManager mCarPropertyMgr;
private final ArraySet<CarCabinEventCallback> mCallbacks = new ArraySet<>();
private CarPropertyEventListenerToBase mListenerToBase = null;
@@ -69,45 +69,45 @@
* Some vehicles (minivans) can open the door electronically. Hence, the ability
* to write this property.
*/
- public static final int ID_DOOR_POS = 0x0001;
+ public static final int ID_DOOR_POS = 0x16400b00;
/** door move, int type
* Positive values open the door, negative values close it.
*/
- public static final int ID_DOOR_MOVE = 0x0002;
+ public static final int ID_DOOR_MOVE = 0x16400b01;
/** door lock, bool type
* 'true' indicates door is locked.
*/
- public static final int ID_DOOR_LOCK = 0x0003;
+ public static final int ID_DOOR_LOCK = 0x16200b02;
/** Mirror properties are zoned by VehicleAreaMirror */
/**
* mirror z position, int type
* Positive value indicates tilt upwards, negative value tilt downwards.
*/
- public static final int ID_MIRROR_Z_POS = 0x1001;
+ public static final int ID_MIRROR_Z_POS = 0x14400b40;
/** mirror z move, int type
* Positive value tilts the mirror upwards, negative value tilts downwards.
*/
- public static final int ID_MIRROR_Z_MOVE = 0x1002;
+ public static final int ID_MIRROR_Z_MOVE = 0x14400b41;
/**
* mirror y position, int type
* Positive value indicates tilt right, negative value tilt left
*/
- public static final int ID_MIRROR_Y_POS = 0x1003;
+ public static final int ID_MIRROR_Y_POS = 0x14400b42;
/** mirror y move, int type
* Positive value tilts the mirror right, negative value tilts left.
*/
- public static final int ID_MIRROR_Y_MOVE = 0x1004;
+ public static final int ID_MIRROR_Y_MOVE = 0x14400b43;
/**
* mirror lock, bool type
* True indicates mirror positions are locked and not changeable.
*/
- public static final int ID_MIRROR_LOCK = 0x1005;
+ public static final int ID_MIRROR_LOCK = 0x11200b44;
/**
* mirror fold, bool type
* True indicates mirrors are folded.
*/
- public static final int ID_MIRROR_FOLD = 0x1006;
+ public static final int ID_MIRROR_FOLD = 0x11200b45;
/** Seat properties are zoned by VehicleAreaSeat */
/**
@@ -120,173 +120,173 @@
* When the user wants to select a preset, the desired preset number (1, 2, or 3)
* is set.
*/
- public static final int ID_SEAT_MEMORY_SELECT = 0x2001;
+ public static final int ID_SEAT_MEMORY_SELECT = 0x15400b80;
/**
* seat memory set, int type
* This setting allows the user to save the current seat position settings into
* the selected preset slot. The maxValue for each seat position shall match
* the maxValue for VEHICLE_PROPERTY_SEAT_MEMORY_SELECT.
*/
- public static final int ID_SEAT_MEMORY_SET = 0x2002;
+ public static final int ID_SEAT_MEMORY_SET = 0x15400b81;
/**
* seat belt buckled, bool type
* True indicates belt is buckled.
*/
- public static final int ID_SEAT_BELT_BUCKLED = 0x2003;
+ public static final int ID_SEAT_BELT_BUCKLED = 0x15200b82;
/**
* seat belt height position, int type
* Adjusts the shoulder belt anchor point.
* Max value indicates highest position.
* Min value indicates lowest position.
*/
- public static final int ID_SEAT_BELT_HEIGHT_POS = 0x2004;
+ public static final int ID_SEAT_BELT_HEIGHT_POS = 0x15400b83;
/** seat belt height move, int type
* Adjusts the shoulder belt anchor point.
* Positive value moves towards highest point.
* Negative value moves towards lowest point.
*/
- public static final int ID_SEAT_BELT_HEIGHT_MOVE = 0x2005;
+ public static final int ID_SEAT_BELT_HEIGHT_MOVE = 0x15400b84;
/**
* seat fore/aft position, int type
* Sets the seat position forward (closer to steering wheel) and backwards.
* Max value indicates closest to wheel, min value indicates most rearward position.
*/
- public static final int ID_SEAT_FORE_AFT_POS = 0x2006;
+ public static final int ID_SEAT_FORE_AFT_POS = 0x15400b85;
/**
* seat fore/aft move, int type
* Positive value moves seat forward (closer to steering wheel).
* Negative value moves seat rearward.
*/
- public static final int ID_SEAT_FORE_AFT_MOVE = 0x2007;
+ public static final int ID_SEAT_FORE_AFT_MOVE = 0x15400b86;
/**
* seat backrest angle #1 position, int type
* Backrest angle 1 is the actuator closest to the bottom of the seat.
* Max value indicates angling forward towards the steering wheel.
* Min value indicates full recline.
*/
- public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 0x2008;
+ public static final int ID_SEAT_BACKREST_ANGLE_1_POS = 0x15400b87;
/** seat backrest angle #1 move, int type
* Backrest angle 1 is the actuator closest to the bottom of the seat.
* Positive value angles seat towards the steering wheel.
* Negatie value angles away from steering wheel.
*/
- public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 0x2009;
+ public static final int ID_SEAT_BACKREST_ANGLE_1_MOVE = 0x15400b88;
/**
* seat backrest angle #2 position, int type
* Backrest angle 2 is the next actuator up from the bottom of the seat.
* Max value indicates angling forward towards the steering wheel.
* Min value indicates full recline.
*/
- public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 0x200A;
+ public static final int ID_SEAT_BACKREST_ANGLE_2_POS = 0x15400b89;
/** seat backrest angle #2 move, int type
* Backrest angle 2 is the next actuator up from the bottom of the seat.
* Positive value tilts forward towards the steering wheel.
* Negative value tilts backwards.
*/
- public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 0x200B;
+ public static final int ID_SEAT_BACKREST_ANGLE_2_MOVE = 0x15400b8a;
/**
* seat height position, int type
* Sets the seat height.
* Max value indicates highest position.
* Min value indicates lowest position.
*/
- public static final int ID_SEAT_HEIGHT_POS = 0x200C;
+ public static final int ID_SEAT_HEIGHT_POS = 0x15400b8b;
/** seat height move, int type
* Sets the seat height.
* Positive value raises the seat.
* Negative value lowers the seat.
* */
- public static final int ID_SEAT_HEIGHT_MOVE = 0x200D;
+ public static final int ID_SEAT_HEIGHT_MOVE = 0x15400b8c;
/**
* seat depth position, int type
* Sets the seat depth, distance from back rest to front edge of seat.
* Max value indicates longest depth position.
* Min value indicates shortest position.
*/
- public static final int ID_SEAT_DEPTH_POS = 0x200E;
+ public static final int ID_SEAT_DEPTH_POS = 0x15400b8d;
/** seat depth move, int type
* Adjusts the seat depth, distance from back rest to front edge of seat.
* Positive value increases the distance from back rest to front edge of seat.
* Negative value decreases this distance.
*/
- public static final int ID_SEAT_DEPTH_MOVE = 0x200F;
+ public static final int ID_SEAT_DEPTH_MOVE = 0x15400b8e;
/**
* seat tilt position, int type
* Sets the seat tilt.
* Max value indicates front edge of seat higher than back edge.
* Min value indicates front edge of seat lower than back edge.
*/
- public static final int ID_SEAT_TILT_POS = 0x2010;
+ public static final int ID_SEAT_TILT_POS = 0x15400b8f;
/** seat tilt move, int type
* Adjusts the seat tilt.
* Positive value lifts front edge of seat higher than back edge.
* Negative value lowers front edge of seat in relation to back edge.
*/
- public static final int ID_SEAT_TILT_MOVE = 0x2011;
+ public static final int ID_SEAT_TILT_MOVE = 0x15400b90;
/**
* seat lumbar fore/aft position, int type
* Pushes the lumbar support forward and backwards.
* Max value indicates most forward position.
* Min value indicates most rearward position.
*/
- public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 0x2012;
+ public static final int ID_SEAT_LUMBAR_FORE_AFT_POS = 0x15400b91;
/** seat lumbar fore/aft move, int type
* Adjusts the lumbar support forwards and backwards.
* Positive value moves lumbar support forward.
* Negative value moves lumbar support rearward.
*/
- public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 0x2013;
+ public static final int ID_SEAT_LUMBAR_FORE_AFT_MOVE = 0x15400b92;
/**
* seat lumbar side support position, int type
* Sets the amount of lateral lumbar support.
* Max value indicates widest lumbar setting (i.e. least support)
* Min value indicates thinnest lumbar setting.
*/
- public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x2014;
+ public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x15400b93;
/** seat lumbar side support move, int type
* Adjusts the amount of lateral lumbar support.
* Positive value widens the lumbar area.
* Negative value makes the lumbar area thinner.
*/
- public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x2015;
+ public static final int ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x15400b94;
/**
* seat headrest height position, int type
* Sets the headrest height.
* Max value indicates tallest setting.
* Min value indicates shortest setting.
*/
- public static final int ID_SEAT_HEADREST_HEIGHT_POS = 0x2016;
+ public static final int ID_SEAT_HEADREST_HEIGHT_POS = 0x15400b95;
/** seat headrest height move, int type
* Postive value moves the headrest higher.
* Negative value moves the headrest lower.
*/
- public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 0x2017;
+ public static final int ID_SEAT_HEADREST_HEIGHT_MOVE = 0x15400b96;
/**
* seat headrest angle position, int type
* Sets the angle of the headrest.
* Max value indicates most upright angle.
* Min value indicates shallowest headrest angle.
*/
- public static final int ID_SEAT_HEADREST_ANGLE_POS = 0x2018;
+ public static final int ID_SEAT_HEADREST_ANGLE_POS = 0x15400b97;
/** seat headrest angle move, int type
* Adjusts the angle of the headrest.
* Positive value angles headrest towards most upright angle.
* Negative value angles headrest towards shallowest headrest angle.
*/
- public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 0x2019;
+ public static final int ID_SEAT_HEADREST_ANGLE_MOVE = 0x15400b98;
/**
* seat headrest fore/aft position, int type
* Sets the headrest forwards and backwards.
* Max value indicates position closest to front of car.
* Min value indicates position closest to rear of car.
*/
- public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 0x201A;
+ public static final int ID_SEAT_HEADREST_FORE_AFT_POS = 0x15400b99;
/** seat headrest fore/aft move, int type
* Adjsuts the headrest forwards and backwards.
* Positive value moves the headrest closer to front of car.
* Negative value moves the headrest closer to rear of car.
*/
- public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 0x201B;
+ public static final int ID_SEAT_HEADREST_FORE_AFT_MOVE = 0x15400b9a;
/** Window properties are zoned by VehicleAreaWindow */
/**
@@ -294,62 +294,103 @@
* Max = window down / open.
* Min = window up / closed.
*/
- public static final int ID_WINDOW_POS = 0x3001;
+ public static final int ID_WINDOW_POS = 0x13400bc0;
/** window move, int type
* Positive value moves window down / opens window.
* Negative value moves window up / closes window.
*/
- public static final int ID_WINDOW_MOVE = 0x3002;
+ public static final int ID_WINDOW_MOVE = 0x13400bc1;
/**
* window lock, bool type
* True indicates windows are locked and can't be moved.
*/
- public static final int ID_WINDOW_LOCK = 0x3003;
+ public static final int ID_WINDOW_LOCK = 0x13400bc4;
/** @hide */
@IntDef({
- ID_DOOR_POS,
- ID_DOOR_MOVE,
- ID_DOOR_LOCK,
- ID_MIRROR_Z_POS,
- ID_MIRROR_Z_MOVE,
- ID_MIRROR_Y_POS,
- ID_MIRROR_Y_MOVE,
- ID_MIRROR_LOCK,
- ID_MIRROR_FOLD,
- ID_SEAT_MEMORY_SELECT,
- ID_SEAT_MEMORY_SET,
- ID_SEAT_BELT_BUCKLED,
- ID_SEAT_BELT_HEIGHT_POS,
- ID_SEAT_BELT_HEIGHT_MOVE,
- ID_SEAT_FORE_AFT_POS,
- ID_SEAT_FORE_AFT_MOVE,
- ID_SEAT_BACKREST_ANGLE_1_POS,
- ID_SEAT_BACKREST_ANGLE_1_MOVE,
- ID_SEAT_BACKREST_ANGLE_2_POS,
- ID_SEAT_BACKREST_ANGLE_2_MOVE,
- ID_SEAT_HEIGHT_POS,
- ID_SEAT_HEIGHT_MOVE,
- ID_SEAT_DEPTH_POS,
- ID_SEAT_DEPTH_MOVE,
- ID_SEAT_TILT_POS,
- ID_SEAT_TILT_MOVE,
- ID_SEAT_LUMBAR_FORE_AFT_POS,
- ID_SEAT_LUMBAR_FORE_AFT_MOVE,
- ID_SEAT_LUMBAR_SIDE_SUPPORT_POS,
- ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
- ID_SEAT_HEADREST_HEIGHT_POS,
- ID_SEAT_HEADREST_HEIGHT_MOVE,
- ID_SEAT_HEADREST_ANGLE_POS,
- ID_SEAT_HEADREST_ANGLE_MOVE,
- ID_SEAT_HEADREST_FORE_AFT_POS,
- ID_SEAT_HEADREST_FORE_AFT_MOVE,
- ID_WINDOW_POS,
- ID_WINDOW_MOVE,
- ID_WINDOW_LOCK
+ ID_DOOR_POS,
+ ID_DOOR_MOVE,
+ ID_DOOR_LOCK,
+ ID_MIRROR_Z_POS,
+ ID_MIRROR_Z_MOVE,
+ ID_MIRROR_Y_POS,
+ ID_MIRROR_Y_MOVE,
+ ID_MIRROR_LOCK,
+ ID_MIRROR_FOLD,
+ ID_SEAT_MEMORY_SELECT,
+ ID_SEAT_MEMORY_SET,
+ ID_SEAT_BELT_BUCKLED,
+ ID_SEAT_BELT_HEIGHT_POS,
+ ID_SEAT_BELT_HEIGHT_MOVE,
+ ID_SEAT_FORE_AFT_POS,
+ ID_SEAT_FORE_AFT_MOVE,
+ ID_SEAT_BACKREST_ANGLE_1_POS,
+ ID_SEAT_BACKREST_ANGLE_1_MOVE,
+ ID_SEAT_BACKREST_ANGLE_2_POS,
+ ID_SEAT_BACKREST_ANGLE_2_MOVE,
+ ID_SEAT_HEIGHT_POS,
+ ID_SEAT_HEIGHT_MOVE,
+ ID_SEAT_DEPTH_POS,
+ ID_SEAT_DEPTH_MOVE,
+ ID_SEAT_TILT_POS,
+ ID_SEAT_TILT_MOVE,
+ ID_SEAT_LUMBAR_FORE_AFT_POS,
+ ID_SEAT_LUMBAR_FORE_AFT_MOVE,
+ ID_SEAT_LUMBAR_SIDE_SUPPORT_POS,
+ ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
+ ID_SEAT_HEADREST_HEIGHT_POS,
+ ID_SEAT_HEADREST_HEIGHT_MOVE,
+ ID_SEAT_HEADREST_ANGLE_POS,
+ ID_SEAT_HEADREST_ANGLE_MOVE,
+ ID_SEAT_HEADREST_FORE_AFT_POS,
+ ID_SEAT_HEADREST_FORE_AFT_MOVE,
+ ID_WINDOW_POS,
+ ID_WINDOW_MOVE,
+ ID_WINDOW_LOCK
})
@Retention(RetentionPolicy.SOURCE)
public @interface PropertyId {}
+ private final ArraySet<Integer> mCabinPropertyIds = new ArraySet<>(Arrays.asList(new Integer[]{
+ ID_DOOR_POS,
+ ID_DOOR_MOVE,
+ ID_DOOR_LOCK,
+ ID_MIRROR_Z_POS,
+ ID_MIRROR_Z_MOVE,
+ ID_MIRROR_Y_POS,
+ ID_MIRROR_Y_MOVE,
+ ID_MIRROR_LOCK,
+ ID_MIRROR_FOLD,
+ ID_SEAT_MEMORY_SELECT,
+ ID_SEAT_MEMORY_SET,
+ ID_SEAT_BELT_BUCKLED,
+ ID_SEAT_BELT_HEIGHT_POS,
+ ID_SEAT_BELT_HEIGHT_MOVE,
+ ID_SEAT_FORE_AFT_POS,
+ ID_SEAT_FORE_AFT_MOVE,
+ ID_SEAT_BACKREST_ANGLE_1_POS,
+ ID_SEAT_BACKREST_ANGLE_1_MOVE,
+ ID_SEAT_BACKREST_ANGLE_2_POS,
+ ID_SEAT_BACKREST_ANGLE_2_MOVE,
+ ID_SEAT_HEIGHT_POS,
+ ID_SEAT_HEIGHT_MOVE,
+ ID_SEAT_DEPTH_POS,
+ ID_SEAT_DEPTH_MOVE,
+ ID_SEAT_TILT_POS,
+ ID_SEAT_TILT_MOVE,
+ ID_SEAT_LUMBAR_FORE_AFT_POS,
+ ID_SEAT_LUMBAR_FORE_AFT_MOVE,
+ ID_SEAT_LUMBAR_SIDE_SUPPORT_POS,
+ ID_SEAT_LUMBAR_SIDE_SUPPORT_MOVE,
+ ID_SEAT_HEADREST_HEIGHT_POS,
+ ID_SEAT_HEADREST_HEIGHT_MOVE,
+ ID_SEAT_HEADREST_ANGLE_POS,
+ ID_SEAT_HEADREST_ANGLE_MOVE,
+ ID_SEAT_HEADREST_FORE_AFT_POS,
+ ID_SEAT_HEADREST_FORE_AFT_MOVE,
+ ID_WINDOW_POS,
+ ID_WINDOW_MOVE,
+ ID_WINDOW_LOCK
+ }));
/**
* Application registers CarCabinEventCallback object to receive updates and changes to
@@ -370,7 +411,8 @@
void onErrorEvent(@PropertyId int propertyId, int zone);
}
- private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
+ private static class CarPropertyEventListenerToBase implements
+ CarPropertyManager.CarPropertyEventListener{
private final WeakReference<CarCabinManager> mManager;
public CarPropertyEventListenerToBase(CarCabinManager manager) {
@@ -426,7 +468,7 @@
* @hide
*/
public CarCabinManager(IBinder service, Context context, Handler handler) {
- mMgr = new CarPropertyManagerBase(service, handler, DBG, TAG);
+ mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
}
/**
@@ -447,9 +489,15 @@
CarNotConnectedException {
if (mCallbacks.isEmpty()) {
mListenerToBase = new CarPropertyEventListenerToBase(this);
- mMgr.registerCallback(mListenerToBase);
+ }
+ List<CarPropertyConfig> configs = getPropertyList();
+ for (CarPropertyConfig c : configs) {
+ // Register each individual propertyId
+ mCarPropertyMgr.registerListener(mListenerToBase, c.getPropertyId(), 0);
}
mCallbacks.add(callback);
+
+
}
/**
@@ -457,10 +505,15 @@
* this listener, all listening will be stopped.
* @param callback
*/
- public synchronized void unregisterCallback(CarCabinEventCallback callback) {
+ public synchronized void unregisterCallback(CarCabinEventCallback callback)
+ throws CarNotConnectedException {
mCallbacks.remove(callback);
+ List<CarPropertyConfig> configs = getPropertyList();
+ for (CarPropertyConfig c : configs) {
+ // Register each individual propertyId
+ mCarPropertyMgr.unregisterListener(mListenerToBase, c.getPropertyId());
+ }
if (mCallbacks.isEmpty()) {
- mMgr.unregisterCallback();
mListenerToBase = null;
}
}
@@ -471,7 +524,7 @@
* @throws CarNotConnectedException if the connection to the car service has been lost.
*/
public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
- return mMgr.getPropertyList();
+ return mCarPropertyMgr.getPropertyList(mCabinPropertyIds);
}
/**
@@ -483,7 +536,7 @@
*/
public boolean getBooleanProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
- return mMgr.getBooleanProperty(propertyId, area);
+ return mCarPropertyMgr.getBooleanProperty(propertyId, area);
}
/**
@@ -495,7 +548,7 @@
*/
public float getFloatProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
- return mMgr.getFloatProperty(propertyId, area);
+ return mCarPropertyMgr.getFloatProperty(propertyId, area);
}
/**
@@ -507,7 +560,7 @@
*/
public int getIntProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
- return mMgr.getIntProperty(propertyId, area);
+ return mCarPropertyMgr.getIntProperty(propertyId, area);
}
/**
@@ -519,7 +572,9 @@
*/
public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val)
throws CarNotConnectedException {
- mMgr.setBooleanProperty(propertyId, area, val);
+ if (mCabinPropertyIds.contains(propertyId)) {
+ mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
+ }
}
/**
@@ -531,7 +586,9 @@
*/
public void setFloatProperty(@PropertyId int propertyId, int area, float val)
throws CarNotConnectedException {
- mMgr.setFloatProperty(propertyId, area, val);
+ if (mCabinPropertyIds.contains(propertyId)) {
+ mCarPropertyMgr.setFloatProperty(propertyId, area, val);
+ }
}
/**
@@ -543,12 +600,14 @@
*/
public void setIntProperty(@PropertyId int propertyId, int area, int val)
throws CarNotConnectedException {
- mMgr.setIntProperty(propertyId, area, val);
+ if (mCabinPropertyIds.contains(propertyId)) {
+ mCarPropertyMgr.setIntProperty(propertyId, area, val);
+ }
}
/** @hide */
@Override
public void onCarDisconnected() {
- mMgr.onCarDisconnected();
+ mCarPropertyMgr.onCarDisconnected();
}
}
diff --git a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
index af4e190..c953d6f 100644
--- a/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
+++ b/car-lib/src/android/car/hardware/hvac/CarHvacManager.java
@@ -23,16 +23,17 @@
import android.car.CarNotConnectedException;
import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManagerBase;
-import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback;
+import android.car.hardware.property.CarPropertyManager;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.util.ArraySet;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -44,10 +45,11 @@
public final class CarHvacManager implements CarManagerBase {
private final static boolean DBG = false;
private final static String TAG = "CarHvacManager";
- private final CarPropertyManagerBase mMgr;
+ private final CarPropertyManager mCarPropertyMgr;
private final ArraySet<CarHvacEventCallback> mCallbacks = new ArraySet<>();
private CarPropertyEventListenerToBase mListenerToBase = null;
+
/**
* HVAC property IDs for get/set methods
*/
@@ -59,31 +61,24 @@
* Mirror defrosters state, bool type
* true indicates mirror defroster is on
*/
- public static final int ID_MIRROR_DEFROSTER_ON = 0x0001;
+ public static final int ID_MIRROR_DEFROSTER_ON = 0x1440050c;
/**
* Steering wheel temp, int type
* Positive values indicate heating.
* Negative values indicate cooling
*/
- public static final int ID_STEERING_WHEEL_HEAT = 0x0002;
+ public static final int ID_STEERING_WHEEL_HEAT = 0x1140050d;
/**
* Outside air temperature, float type
* Value is in degrees Celsius
*/
- public static final int ID_OUTSIDE_AIR_TEMP = 0x0003;
+ public static final int ID_OUTSIDE_AIR_TEMP = 0x11600703;
/**
* Temperature units being used, int type
* 0x30 = Celsius
* 0x31 = Fahrenheit
*/
- public static final int ID_TEMPERATURE_DISPLAY_UNITS = 0x0004;
-
-
- /**
- * The maximum id that can be assigned to global (non-zoned) property.
- * @hide
- */
- public static final int ID_MAX_GLOBAL_PROPERTY_ID = 0x3fff;
+ public static final int ID_TEMPERATURE_DISPLAY_UNITS = 0x1140050e;
/**
* ID_ZONED_* represents properties available on a per-zone basis. All zones in a car are
@@ -93,85 +88,85 @@
* Temperature setpoint, float type
* Temperature set by the user, units are in degrees Celsius.
*/
- public static final int ID_ZONED_TEMP_SETPOINT = 0x4001;
+ public static final int ID_ZONED_TEMP_SETPOINT = 0x15600503;
/**
* Actual temperature, float type
* Actual zone temperature is read only value, in terms of F or C.
*/
- public static final int ID_ZONED_TEMP_ACTUAL = 0x4002;
+ public static final int ID_ZONED_TEMP_ACTUAL = 0x15600502;
/**
* HVAC system powered on / off, bool type
* In many vehicles, if the HVAC system is powered off, the SET and GET command will
* throw an IllegalStateException. To correct this, need to turn on the HVAC module first
* before manipulating a parameter.
*/
- public static final int ID_ZONED_HVAC_POWER_ON = 0x4003;
+ public static final int ID_ZONED_HVAC_POWER_ON = 0x15200510;
/**
* Fan speed setpoint, int type
* Fan speed is an integer from 0-n, depending on number of fan speeds available.
*/
- public static final int ID_ZONED_FAN_SPEED_SETPOINT = 0x4004;
+ public static final int ID_ZONED_FAN_SPEED_SETPOINT = 0x15400500;
/**
* Actual fan speed, int type
* Actual fan speed is a read-only value, expressed in RPM.
*/
- public static final int ID_ZONED_FAN_SPEED_RPM = 0x4005;
+ public static final int ID_ZONED_FAN_SPEED_RPM = 0x1540050f;
/**
* Fan direction available, int vector type
* Fan direction is a bitmask of directions available for each zone.
*/
- public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 0x4006;
+ public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 0x15410511;
/**
* Current fan direction setting, int type. The value must be one of the FAN_DIRECTION_AVAILABLE
* values declared above.
*/
- public static final int ID_ZONED_FAN_DIRECTION = 0x4007;
+ public static final int ID_ZONED_FAN_DIRECTION = 0x15400501;
/**
* Seat temperature, int type
* Seat temperature is negative for cooling, positive for heating. Temperature is a
* setting, i.e. -3 to 3 for 3 levels of cooling and 3 levels of heating.
*/
- public static final int ID_ZONED_SEAT_TEMP = 0x4008;
+ public static final int ID_ZONED_SEAT_TEMP = 0x1540050b;
/**
* Air ON, bool type
* true indicates AC is ON.
*/
- public static final int ID_ZONED_AC_ON = 0x4009;
+ public static final int ID_ZONED_AC_ON = 0x15200505;
/**
* Automatic Mode ON, bool type
* true indicates HVAC is in automatic mode
*/
- public static final int ID_ZONED_AUTOMATIC_MODE_ON = 0x400A;
+ public static final int ID_ZONED_AUTOMATIC_MODE_ON = 0x1520050A;
/**
* Air recirculation ON, bool type
* true indicates recirculation is active.
*/
- public static final int ID_ZONED_AIR_RECIRCULATION_ON = 0x400B;
+ public static final int ID_ZONED_AIR_RECIRCULATION_ON = 0x15200508;
/**
* Max AC ON, bool type
* true indicates MAX AC is ON
*/
- public static final int ID_ZONED_MAX_AC_ON = 0x400C;
+ public static final int ID_ZONED_MAX_AC_ON = 0x15200506;
/** Dual zone ON, bool type
* true indicates dual zone mode is ON
*/
- public static final int ID_ZONED_DUAL_ZONE_ON = 0x400D;
+ public static final int ID_ZONED_DUAL_ZONE_ON = 0x15200509;
/**
* Max Defrost ON, bool type
* true indicates max defrost is active.
*/
- public static final int ID_ZONED_MAX_DEFROST_ON = 0x400E;
+ public static final int ID_ZONED_MAX_DEFROST_ON = 0x15200507;
/**
* Automatic recirculation mode ON
* true indicates recirculation is in automatic mode
*/
- public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 0x400F;
+ public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 0x15200512;
/**
* Defroster ON, bool type
* Defroster controls are based on window position.
* True indicates the defroster is ON.
*/
- public static final int ID_WINDOW_DEFROSTER_ON = 0x5001;
+ public static final int ID_WINDOW_DEFROSTER_ON = 0x13200504;
/** @hide */
@IntDef({
@@ -194,10 +189,33 @@
ID_ZONED_MAX_DEFROST_ON,
ID_ZONED_HVAC_POWER_ON,
ID_ZONED_HVAC_AUTO_RECIRC_ON,
- ID_WINDOW_DEFROSTER_ON,
+ ID_WINDOW_DEFROSTER_ON
})
@Retention(RetentionPolicy.SOURCE)
public @interface PropertyId {}
+ private final ArraySet<Integer> mHvacPropertyIds = new ArraySet<>(Arrays.asList(new Integer [] {
+ ID_MIRROR_DEFROSTER_ON,
+ ID_STEERING_WHEEL_HEAT,
+ ID_OUTSIDE_AIR_TEMP,
+ ID_TEMPERATURE_DISPLAY_UNITS,
+ ID_ZONED_TEMP_SETPOINT,
+ ID_ZONED_TEMP_ACTUAL,
+ ID_ZONED_FAN_SPEED_SETPOINT,
+ ID_ZONED_FAN_SPEED_RPM,
+ ID_ZONED_FAN_DIRECTION_AVAILABLE,
+ ID_ZONED_FAN_DIRECTION,
+ ID_ZONED_SEAT_TEMP,
+ ID_ZONED_AC_ON,
+ ID_ZONED_AUTOMATIC_MODE_ON,
+ ID_ZONED_AIR_RECIRCULATION_ON,
+ ID_ZONED_MAX_AC_ON,
+ ID_ZONED_DUAL_ZONE_ON,
+ ID_ZONED_MAX_DEFROST_ON,
+ ID_ZONED_HVAC_POWER_ON,
+ ID_ZONED_HVAC_AUTO_RECIRC_ON,
+ ID_WINDOW_DEFROSTER_ON
+ }));
+
/**
* Represents fan direction when air flows through face directed vents.
@@ -234,7 +252,8 @@
void onErrorEvent(@PropertyId int propertyId, int zone);
}
- private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
+ private static class CarPropertyEventListenerToBase implements
+ CarPropertyManager.CarPropertyEventListener {
private final WeakReference<CarHvacManager> mManager;
public CarPropertyEventListenerToBase(CarHvacManager manager) {
@@ -292,28 +311,22 @@
* @hide
*/
public CarHvacManager(IBinder service, Context context, Handler handler) {
- mMgr = new CarPropertyManagerBase(service, handler, DBG, TAG);
+ mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
}
-
/**
- * Determine if a property is zoned or not.
- * @param propertyId
- * @return true if property is a zoned type.
- */
- public static boolean isZonedProperty(@PropertyId int propertyId) {
- return propertyId > ID_MAX_GLOBAL_PROPERTY_ID;
- }
-
- /**
- * Implement wrappers for contained CarPropertyManagerBase object
+ * Implement wrappers for contained CarPropertyManager object
* @param callback
* @throws CarNotConnectedException
*/
- public synchronized void registerCallback(CarHvacEventCallback callback) throws
- CarNotConnectedException {
+ public synchronized void registerCallback(CarHvacEventCallback callback)
+ throws CarNotConnectedException {
if (mCallbacks.isEmpty()) {
mListenerToBase = new CarPropertyEventListenerToBase(this);
- mMgr.registerCallback(mListenerToBase);
+ }
+ List<CarPropertyConfig> configs = getPropertyList();
+ for (CarPropertyConfig c : configs) {
+ // Register each individual propertyId
+ mCarPropertyMgr.registerListener(mListenerToBase, c.getPropertyId(), 0);
}
mCallbacks.add(callback);
}
@@ -325,8 +338,17 @@
*/
public synchronized void unregisterCallback(CarHvacEventCallback callback) {
mCallbacks.remove(callback);
+ try {
+ List<CarPropertyConfig> configs = getPropertyList();
+ for (CarPropertyConfig c : configs) {
+ // Register each individual propertyId
+ mCarPropertyMgr.unregisterListener(mListenerToBase, c.getPropertyId());
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "getPropertyList exception ", e);
+ }
if (mCallbacks.isEmpty()) {
- mMgr.unregisterCallback();
+ mCarPropertyMgr.unregisterListener(mListenerToBase);
mListenerToBase = null;
}
}
@@ -337,7 +359,7 @@
* @throws CarNotConnectedException if the connection to the car service has been lost.
*/
public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
- return mMgr.getPropertyList();
+ return mCarPropertyMgr.getPropertyList(mHvacPropertyIds);
}
/**
@@ -346,7 +368,7 @@
*/
public boolean isPropertyAvailable(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
- return mMgr.isPropertyAvailable(propertyId, area);
+ return mCarPropertyMgr.isPropertyAvailable(propertyId, area);
}
/**
@@ -358,7 +380,7 @@
*/
public boolean getBooleanProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
- return mMgr.getBooleanProperty(propertyId, area);
+ return mCarPropertyMgr.getBooleanProperty(propertyId, area);
}
/**
@@ -370,7 +392,7 @@
*/
public float getFloatProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
- return mMgr.getFloatProperty(propertyId, area);
+ return mCarPropertyMgr.getFloatProperty(propertyId, area);
}
/**
@@ -382,7 +404,7 @@
*/
public int getIntProperty(@PropertyId int propertyId, int area)
throws CarNotConnectedException {
- return mMgr.getIntProperty(propertyId, area);
+ return mCarPropertyMgr.getIntProperty(propertyId, area);
}
/**
@@ -394,7 +416,9 @@
*/
public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val)
throws CarNotConnectedException {
- mMgr.setBooleanProperty(propertyId, area, val);
+ if (mHvacPropertyIds.contains(propertyId)) {
+ mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
+ }
}
/**
@@ -406,7 +430,9 @@
*/
public void setFloatProperty(@PropertyId int propertyId, int area, float val)
throws CarNotConnectedException {
- mMgr.setFloatProperty(propertyId, area, val);
+ if (mHvacPropertyIds.contains(propertyId)) {
+ mCarPropertyMgr.setFloatProperty(propertyId, area, val);
+ }
}
/**
@@ -418,12 +444,13 @@
*/
public void setIntProperty(@PropertyId int propertyId, int area, int val)
throws CarNotConnectedException {
- mMgr.setIntProperty(propertyId, area, val);
+ if (mHvacPropertyIds.contains(propertyId)) {
+ mCarPropertyMgr.setIntProperty(propertyId, area, val);
+ }
}
/** @hide */
- @Override
public void onCarDisconnected() {
- mMgr.onCarDisconnected();
+ mCarPropertyMgr.onCarDisconnected();
}
}
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
new file mode 100644
index 0000000..5c094e7
--- /dev/null
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -0,0 +1,420 @@
+/*
+ * 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 android.car.hardware.property;
+
+import static java.lang.Integer.toHexString;
+
+import android.car.CarApiUtil;
+import android.car.CarManagerBase;
+import android.car.CarNotConnectedException;
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.car.internal.CarRatedFloatListeners;
+import com.android.car.internal.SingleMessageHandler;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+
+/**
+ * API for creating Car*Manager
+ * @hide
+ */
+public class CarPropertyManager implements CarManagerBase {
+ private final boolean mDbg;
+ private final SingleMessageHandler<CarPropertyEvent> mHandler;
+ private final ICarProperty mService;
+ private final String mTag;
+ private static final int MSG_GENERIC_EVENT = 0;
+
+ private CarPropertyEventListenerToService mCarPropertyEventToService;
+
+
+ /** Record of locally active properties. Key is propertyId */
+ private final SparseArray<CarPropertyListeners> mActivePropertyListener =
+ new SparseArray<>();
+
+ /** Callback functions for property events */
+ public interface CarPropertyEventListener {
+ /** Called when a property is updated */
+ void onChangeEvent(CarPropertyValue value);
+
+ /** Called when an error is detected with a property */
+ void onErrorEvent(int propId, int zone);
+ }
+
+ /**
+ * Get an instance of the CarPropertyManager.
+ */
+ public CarPropertyManager(IBinder service, Handler handler, boolean dbg, String tag) {
+ mDbg = dbg;
+ mTag = tag;
+ mService = ICarProperty.Stub.asInterface(service);
+ mHandler = new SingleMessageHandler<CarPropertyEvent>(handler.getLooper(),
+ MSG_GENERIC_EVENT) {
+ @Override
+ protected void handleEvent(CarPropertyEvent event) {
+ CarPropertyListeners listeners;
+ synchronized (mActivePropertyListener) {
+ listeners = mActivePropertyListener.get(
+ event.getCarPropertyValue().getPropertyId());
+ }
+ if (listeners != null) {
+ switch (event.getEventType()) {
+ case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
+ listeners.onPropertyChanged(event);
+ break;
+ case CarPropertyEvent.PROPERTY_EVENT_ERROR:
+ listeners.onErrorEvent(event);
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+ }
+ };
+ }
+
+ /** Use to register or update Callback for properties */
+ public boolean registerListener(CarPropertyEventListener listener, int propertyId, float rate)
+ throws CarNotConnectedException {
+ synchronized (mActivePropertyListener) {
+ if (mCarPropertyEventToService == null) {
+ mCarPropertyEventToService = new CarPropertyEventListenerToService(this);
+ }
+ boolean needsServerUpdate = false;
+ CarPropertyListeners listeners;
+ listeners = mActivePropertyListener.get(propertyId);
+ if (listeners == null) {
+ listeners = new CarPropertyListeners(rate);
+ mActivePropertyListener.put(propertyId, listeners);
+ needsServerUpdate = true;
+ }
+ if (listeners.addAndUpdateRate(listener, rate)) {
+ needsServerUpdate = true;
+ }
+ if (needsServerUpdate) {
+ if (!registerOrUpdatePropertyListener(propertyId, rate)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private boolean registerOrUpdatePropertyListener(int propertyId, float rate)
+ throws CarNotConnectedException {
+ try {
+ mService.registerListener(propertyId, rate, mCarPropertyEventToService);
+ } catch (IllegalStateException e) {
+ CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
+ } catch (RemoteException e) {
+ throw new CarNotConnectedException(e);
+ }
+ return true;
+ }
+
+ private class CarPropertyEventListenerToService extends ICarPropertyEventListener.Stub{
+ private final WeakReference<CarPropertyManager> mMgr;
+
+ CarPropertyEventListenerToService(CarPropertyManager mgr) {
+ mMgr = new WeakReference<>(mgr);
+ }
+
+ @Override
+ public void onEvent(List<CarPropertyEvent> events) throws RemoteException {
+ CarPropertyManager manager = mMgr.get();
+ if (manager != null) {
+ manager.handleEvent(events);
+ }
+ }
+ }
+
+ private void handleEvent(List<CarPropertyEvent> events) {
+ mHandler.sendEvents(events);
+ }
+
+ /**
+ * Stop getting sensor update for the given listener. If there are multiple registrations for
+ * this listener, all listening will be stopped.
+ * @param listener
+ */
+ public void unregisterListener(CarPropertyEventListener listener) {
+ synchronized (mActivePropertyListener) {
+ for (int i = 0; i < mActivePropertyListener.size(); i++) {
+ doUnregisterListenerLocked(listener, mActivePropertyListener.keyAt(i));
+ }
+ }
+ }
+
+ /**
+ * Stop getting sensor update for the given listener and sensor. If the same listener is used
+ * for other sensors, those subscriptions will not be affected.
+ * @param listener
+ * @param propertyId
+ */
+ public void unregisterListener(CarPropertyEventListener listener, int propertyId) {
+ synchronized (mActivePropertyListener) {
+ doUnregisterListenerLocked(listener, propertyId);
+ }
+ }
+
+ private void doUnregisterListenerLocked(CarPropertyEventListener listener, int propertyId) {
+ CarPropertyListeners listeners = mActivePropertyListener.get(propertyId);
+ if (listeners != null) {
+ boolean needsServerUpdate = false;
+ if (listeners.contains(listener)) {
+ needsServerUpdate = listeners.remove(listener);
+ }
+ if (listeners.isEmpty()) {
+ try {
+ mService.unregisterListener(propertyId, mCarPropertyEventToService);
+ } catch (RemoteException e) {
+ //ignore
+ }
+ mActivePropertyListener.remove(propertyId);
+ } else if (needsServerUpdate) {
+ try {
+ registerOrUpdatePropertyListener(propertyId, listeners.getRate());
+ } catch (CarNotConnectedException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the list of properties implemented by this car.
+ *
+ * @return Caller must check the property type and typecast to the appropriate subclass
+ * (CarPropertyBooleanProperty, CarPropertyFloatProperty, CarrPropertyIntProperty)
+ */
+ public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
+ try {
+ return mService.getPropertyList();
+ } catch (RemoteException e) {
+ Log.e(mTag, "getPropertyList exception ", e);
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Returns the list of properties implemented by this car in given property id list.
+ *
+ * @return Caller must check the property type and typecast to the appropriate subclass
+ * (CarPropertyBooleanProperty, CarPropertyFloatProperty, CarrPropertyIntProperty)
+ */
+ public List<CarPropertyConfig> getPropertyList(ArraySet<Integer> propertyIds)
+ throws CarNotConnectedException {
+ try {
+ List<CarPropertyConfig> configs = new ArrayList<>();
+ for (CarPropertyConfig c : mService.getPropertyList()) {
+ if (propertyIds.contains(c.getPropertyId())) {
+ configs.add(c);
+ }
+ }
+ return configs;
+ } catch (RemoteException e) {
+ Log.e(mTag, "getPropertyList exception ", e);
+ throw new CarNotConnectedException(e);
+ }
+
+ }
+
+ /**
+ * Check whether a given property is available or disabled based on the car's current state.
+ * @return true if STATUS_AVAILABLE, false otherwise (eg STATUS_UNAVAILABLE)
+ * @throws CarNotConnectedException
+ */
+ public boolean isPropertyAvailable(int propId, int area) throws CarNotConnectedException {
+ try {
+ CarPropertyValue propValue = mService.getProperty(propId, area);
+ return (propValue != null)
+ && (propValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE);
+ } catch (RemoteException e) {
+ Log.e(mTag, "isPropertyAvailable failed with " + e.toString()
+ + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Returns value of a bool property
+ *
+ * @param prop Property ID to get
+ * @param area Area of the property to get
+ */
+ public boolean getBooleanProperty(int prop, int area) throws CarNotConnectedException {
+ CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
+ return carProp != null ? carProp.getValue() : false;
+ }
+
+ /**
+ * Returns value of a float property
+ *
+ * @param prop Property ID to get
+ * @param area Area of the property to get
+ */
+ public float getFloatProperty(int prop, int area) throws CarNotConnectedException {
+ CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
+ return carProp != null ? carProp.getValue() : 0f;
+ }
+
+ /**
+ * Returns value of a integer property
+ *
+ * @param prop Property ID to get
+ * @param area Zone of the property to get
+ */
+ public int getIntProperty(int prop, int area) throws CarNotConnectedException {
+ CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
+ return carProp != null ? carProp.getValue() : 0;
+ }
+
+ /** Return CarPropertyValue */
+ @SuppressWarnings("unchecked")
+ public <E> CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int area)
+ throws CarNotConnectedException {
+ if (mDbg) {
+ Log.d(mTag, "getProperty, propId: 0x" + toHexString(propId)
+ + ", area: 0x" + toHexString(area) + ", class: " + clazz);
+ }
+ try {
+ CarPropertyValue<E> propVal = mService.getProperty(propId, area);
+ if (propVal != null && propVal.getValue() != null) {
+ Class<?> actualClass = propVal.getValue().getClass();
+ if (actualClass != clazz) {
+ throw new IllegalArgumentException("Invalid property type. " + "Expected: "
+ + clazz + ", but was: " + actualClass);
+ }
+ }
+ return propVal;
+ } catch (RemoteException e) {
+ Log.e(mTag, "getProperty failed with " + e.toString()
+ + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /** Return raw CarPropertyValue */
+ public <E> CarPropertyValue<E> getProperty(int propId, int area)
+ throws CarNotConnectedException {
+ try {
+ CarPropertyValue<E> propVal = mService.getProperty(propId, area);
+ return propVal;
+ } catch (RemoteException e) {
+ Log.e(mTag, "getProperty failed with " + e.toString()
+ + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /** Set CarPropertyValue */
+ public <E> void setProperty(Class<E> clazz, int propId, int area, E val)
+ throws CarNotConnectedException {
+ if (mDbg) {
+ Log.d(mTag, "setProperty, propId: 0x" + toHexString(propId)
+ + ", area: 0x" + toHexString(area) + ", class: " + clazz + ", val: " + val);
+ }
+ try {
+ mService.setProperty(new CarPropertyValue<>(propId, area, val));
+ } catch (RemoteException e) {
+ Log.e(mTag, "setProperty failed with " + e.toString(), e);
+ throw new CarNotConnectedException(e);
+ }
+ }
+
+ /**
+ * Modifies a property. If the property modification doesn't occur, an error event shall be
+ * generated and propagated back to the application.
+ *
+ * @param prop Property ID to modify
+ * @param area Area to apply the modification.
+ * @param val Value to set
+ */
+ public void setBooleanProperty(int prop, int area, boolean val)
+ throws CarNotConnectedException {
+ setProperty(Boolean.class, prop, area, val);
+ }
+
+ /** Set float value of property*/
+ public void setFloatProperty(int prop, int area, float val) throws CarNotConnectedException {
+ setProperty(Float.class, prop, area, val);
+ }
+ /** Set int value of property*/
+ public void setIntProperty(int prop, int area, int val) throws CarNotConnectedException {
+ setProperty(Integer.class, prop, area, val);
+ }
+
+
+ private class CarPropertyListeners extends CarRatedFloatListeners<CarPropertyEventListener> {
+ CarPropertyListeners(float rate) {
+ super(rate);
+ }
+ void onPropertyChanged(final CarPropertyEvent event) {
+ // throw away old sensor data as oneway binder call can change order.
+ long updateTime = event.getCarPropertyValue().getTimestamp();
+ if (updateTime < mLastUpdateTime) {
+ Log.w(mTag, "dropping old property data");
+ return;
+ }
+ mLastUpdateTime = updateTime;
+ List<CarPropertyEventListener> listeners;
+ synchronized (mActivePropertyListener) {
+ listeners = new ArrayList<>(getListeners());
+ }
+ listeners.forEach(new Consumer<CarPropertyEventListener>() {
+ @Override
+ public void accept(CarPropertyEventListener listener) {
+ listener.onChangeEvent(event.getCarPropertyValue());
+ }
+ });
+ }
+
+ void onErrorEvent(final CarPropertyEvent event) {
+ List<CarPropertyEventListener> listeners;
+ CarPropertyValue value = event.getCarPropertyValue();
+ synchronized (mActivePropertyListener) {
+ listeners = new ArrayList<>(getListeners());
+ }
+ listeners.forEach(new Consumer<CarPropertyEventListener>() {
+ @Override
+ public void accept(CarPropertyEventListener listener) {
+ listener.onErrorEvent(value.getPropertyId(), value.getAreaId());
+ }
+ });
+ }
+ }
+
+ /** @hide */
+ @Override
+ public void onCarDisconnected() {
+ synchronized (mActivePropertyListener) {
+ mActivePropertyListener.clear();
+ mCarPropertyEventToService = null;
+ }
+ }
+}
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManagerBase.java b/car-lib/src/android/car/hardware/property/CarPropertyManagerBase.java
deleted file mode 100644
index 002284d..0000000
--- a/car-lib/src/android/car/hardware/property/CarPropertyManagerBase.java
+++ /dev/null
@@ -1,316 +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 android.car.hardware.property;
-
-import static java.lang.Integer.toHexString;
-
-import android.annotation.Nullable;
-import android.car.Car;
-import android.car.CarNotConnectedException;
-import android.car.hardware.CarPropertyConfig;
-import android.car.hardware.CarPropertyValue;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.ref.WeakReference;
-import java.util.List;
-
-/**
- * API for creating Car*Manager
- * @hide
- */
-public class CarPropertyManagerBase {
- private final boolean mDbg;
- private final Handler mHandler;
- private final ICarProperty mService;
- private final String mTag;
-
- @GuardedBy("mLock")
- private ICarPropertyEventListener mListenerToService;
- @GuardedBy("mLock")
- private CarPropertyEventCallback mCallback;
-
- private final Object mLock = new Object();
-
- /** Callback functions for property events */
- public interface CarPropertyEventCallback {
- /** Called when a property is updated */
- void onChangeEvent(CarPropertyValue value);
-
- /** Called when an error is detected with a property */
- void onErrorEvent(int propertyId, int zone);
- }
-
- private final static class EventCallbackHandler extends Handler {
- /** Constants handled in the handler */
- private static final int MSG_GENERIC_EVENT = 0;
-
- private final WeakReference<CarPropertyManagerBase> mMgr;
-
- EventCallbackHandler(CarPropertyManagerBase mgr, Looper looper) {
- super(looper);
- mMgr = new WeakReference<>(mgr);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_GENERIC_EVENT:
- CarPropertyManagerBase mgr = mMgr.get();
- if (mgr != null) {
- mgr.dispatchEventToClient((CarPropertyEvent) msg.obj);
- }
- break;
- default:
- Log.e("EventtCallbackHandler", "Event type not handled: " + msg);
- break;
- }
- }
- }
-
- /**
- * Get an instance of the CarPropertyManagerBase.
- */
- public CarPropertyManagerBase(IBinder service, Handler handler, boolean dbg,
- String tag) {
- mDbg = dbg;
- mTag = tag;
- mService = ICarProperty.Stub.asInterface(service);
- mHandler = new EventCallbackHandler(this, handler.getLooper());
- }
-
- public void registerCallback(CarPropertyEventCallback callback)
- throws CarNotConnectedException {
- synchronized (mLock) {
- if (mCallback != null) {
- throw new IllegalStateException("Callback is already registered.");
- }
-
- mCallback = callback;
- mListenerToService = new ICarPropertyEventListener.Stub() {
- @Override
- public void onEvent(CarPropertyEvent event) throws RemoteException {
- handleEvent(event);
- }
- };
- }
-
- try {
- mService.registerListener(mListenerToService);
- } catch (RemoteException ex) {
- Log.e(mTag, "Could not connect: ", ex);
- throw new CarNotConnectedException(ex);
- } catch (IllegalStateException ex) {
- Car.checkCarNotConnectedExceptionFromCarService(ex);
- }
- }
-
- public void unregisterCallback() {
- ICarPropertyEventListener listenerToService;
- synchronized (mLock) {
- listenerToService = mListenerToService;
- mCallback = null;
- mListenerToService = null;
- }
-
- if (listenerToService == null) {
- Log.w(mTag, "unregisterListener: listener was not registered");
- return;
- }
-
- try {
- mService.unregisterListener(listenerToService);
- } catch (RemoteException ex) {
- Log.e(mTag, "Failed to unregister listener", ex);
- //ignore
- } catch (IllegalStateException ex) {
- Car.hideCarNotConnectedExceptionFromCarService(ex);
- }
- }
-
- /**
- * Returns the list of properties implemented by this car.
- *
- * @return Caller must check the property type and typecast to the appropriate subclass
- * (CarPropertyBooleanProperty, CarPropertyFloatProperty, CarrPropertyIntProperty)
- */
- public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
- try {
- return mService.getPropertyList();
- } catch (RemoteException e) {
- Log.e(mTag, "Exception in getPropertyList", e);
- throw new CarNotConnectedException(e);
- }
- }
-
- /**
- * Check whether a given property is available or disabled based on the car's current state.
- * @return true if STATUS_AVAILABLE, false otherwise (eg STATUS_UNAVAILABLE)
- * @throws CarNotConnectedException
- */
- public boolean isPropertyAvailable(int propId, int area) throws CarNotConnectedException {
- try {
- CarPropertyValue propValue = mService.getProperty(propId, area);
- return (propValue != null) &&
- (propValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE);
- } catch (RemoteException e) {
- Log.e(mTag, "isPropertyAvailable failed with " + e.toString()
- + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
- throw new CarNotConnectedException(e);
- }
- }
-
- /**
- * Returns value of a bool property
- *
- * @param prop Property ID to get
- * @param area Area of the property to get
- */
- public boolean getBooleanProperty(int prop, int area) throws CarNotConnectedException {
- CarPropertyValue<Boolean> carProp = getProperty(Boolean.class, prop, area);
- return carProp != null ? carProp.getValue() : false;
- }
-
- /**
- * Returns value of a float property
- *
- * @param prop Property ID to get
- * @param area Area of the property to get
- */
- public float getFloatProperty(int prop, int area) throws CarNotConnectedException {
- CarPropertyValue<Float> carProp = getProperty(Float.class, prop, area);
- return carProp != null ? carProp.getValue() : 0f;
- }
-
- /**
- * Returns value of a integer property
- *
- * @param prop Property ID to get
- * @param area Zone of the property to get
- */
- public int getIntProperty(int prop, int area) throws CarNotConnectedException {
- CarPropertyValue<Integer> carProp = getProperty(Integer.class, prop, area);
- return carProp != null ? carProp.getValue() : 0;
- }
-
- @Nullable
- @SuppressWarnings("unchecked")
- public <E> CarPropertyValue<E> getProperty(Class<E> clazz, int propId, int area)
- throws CarNotConnectedException {
- if (mDbg) {
- Log.d(mTag, "getProperty, propId: 0x" + toHexString(propId)
- + ", area: 0x" + toHexString(area) + ", class: " + clazz);
- }
- try {
- CarPropertyValue<E> propVal = mService.getProperty(propId, area);
- if (propVal != null && propVal.getValue() != null) {
- Class<?> actualClass = propVal.getValue().getClass();
- if (actualClass != clazz) {
- throw new IllegalArgumentException("Invalid property type. " + "Expected: "
- + clazz + ", but was: " + actualClass);
- }
- }
- return propVal;
- } catch (RemoteException e) {
- Log.e(mTag, "getProperty failed with " + e.toString()
- + ", propId: 0x" + toHexString(propId) + ", area: 0x" + toHexString(area), e);
- throw new CarNotConnectedException(e);
- }
- }
-
- public <E> void setProperty(Class<E> clazz, int propId, int area, E val)
- throws CarNotConnectedException {
- if (mDbg) {
- Log.d(mTag, "setProperty, propId: 0x" + toHexString(propId)
- + ", area: 0x" + toHexString(area) + ", class: " + clazz + ", val: " + val);
- }
- try {
- mService.setProperty(new CarPropertyValue<>(propId, area, val));
- } catch (RemoteException e) {
- Log.e(mTag, "setProperty failed with " + e.toString(), e);
- throw new CarNotConnectedException(e);
- }
- }
-
- /**
- * Modifies a property. If the property modification doesn't occur, an error event shall be
- * generated and propagated back to the application.
- *
- * @param prop Property ID to modify
- * @param area Area to apply the modification.
- * @param val Value to set
- */
- public void setBooleanProperty(int prop, int area, boolean val)
- throws CarNotConnectedException {
- setProperty(Boolean.class, prop, area, val);
- }
-
- public void setFloatProperty(int prop, int area, float val) throws CarNotConnectedException {
- setProperty(Float.class, prop, area, val);
- }
-
- public void setIntProperty(int prop, int area, int val) throws CarNotConnectedException {
- setProperty(Integer.class, prop, area, val);
- }
-
- private void dispatchEventToClient(CarPropertyEvent event) {
- CarPropertyEventCallback listener;
- synchronized (mLock) {
- listener = mCallback;
- }
-
- if (listener == null) {
- Log.e(mTag, "Listener died, not dispatching event.");
- return;
- }
-
- CarPropertyValue propVal = event.getCarPropertyValue();
- switch(event.getEventType()) {
- case CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE:
- listener.onChangeEvent(propVal);
- break;
- case CarPropertyEvent.PROPERTY_EVENT_ERROR:
- listener.onErrorEvent(propVal.getPropertyId(), propVal.getAreaId());
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- private void handleEvent(CarPropertyEvent event) {
- mHandler.sendMessage(mHandler.obtainMessage(EventCallbackHandler.MSG_GENERIC_EVENT, event));
- }
-
- /** @hide */
- public void onCarDisconnected() {
-
- ICarPropertyEventListener listenerToService;
- synchronized (mLock) {
- listenerToService = mListenerToService;
- }
-
- if (listenerToService != null) {
- unregisterCallback();
- }
- }
-}
diff --git a/car-lib/src/android/car/hardware/property/ICarProperty.aidl b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
index 2121ebb..3e7e5c9 100644
--- a/car-lib/src/android/car/hardware/property/ICarProperty.aidl
+++ b/car-lib/src/android/car/hardware/property/ICarProperty.aidl
@@ -25,9 +25,9 @@
*/
interface ICarProperty {
- void registerListener(in ICarPropertyEventListener callback) = 0;
+ void registerListener(int propId, float rate, in ICarPropertyEventListener callback) = 0;
- void unregisterListener(in ICarPropertyEventListener callback) = 1;
+ void unregisterListener(int propId, in ICarPropertyEventListener callback) = 1;
List<CarPropertyConfig> getPropertyList() = 2;
diff --git a/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl b/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl
index b0d57fc..ebda47c 100644
--- a/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl
+++ b/car-lib/src/android/car/hardware/property/ICarPropertyEventListener.aidl
@@ -28,6 +28,6 @@
* Called when an event is triggered in response to one of the calls (such as on tune) or
* asynchronously (such as on announcement).
*/
- void onEvent(in CarPropertyEvent event) = 0;
+ void onEvent(in List<CarPropertyEvent> events) = 0;
}
diff --git a/car-lib/src/android/car/media/ICarVolumeCallback.aidl b/car-lib/src/android/car/media/ICarVolumeCallback.aidl
index 10a5ddc..8540680 100644
--- a/car-lib/src/android/car/media/ICarVolumeCallback.aidl
+++ b/car-lib/src/android/car/media/ICarVolumeCallback.aidl
@@ -27,12 +27,12 @@
* The changed-to volume index is not included, the caller is encouraged to
* get the current group volume index via CarAudioManager.
*/
- void onGroupVolumeChanged(int groupId);
+ void onGroupVolumeChanged(int groupId, int flags);
/**
* This is called whenever the master mute state is changed.
* The changed-to master mute state is not included, the caller is encouraged to
* get the current master mute state via AudioManager.
*/
- void onMasterMuteChanged();
+ void onMasterMuteChanged(int flags);
}
diff --git a/car-lib/src/android/car/user/CarUserManagerHelper.java b/car-lib/src/android/car/user/CarUserManagerHelper.java
index 45d2c7f..4a69f0b 100644
--- a/car-lib/src/android/car/user/CarUserManagerHelper.java
+++ b/car-lib/src/android/car/user/CarUserManagerHelper.java
@@ -17,6 +17,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.car.settings.CarSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -177,15 +178,6 @@
}
/**
- * Temporary method: Gets all the users that includes system user.
- *
- * @return List of {@code UserInfo} for users that associated with a real person.
- */
- public List<UserInfo> getAllUsersIncludingSystemUser() {
- return mUserManager.getUsers(/* excludeDying= */true);
- }
-
- /**
* Get all the users except the one with userId passed in.
*
* @param userId of the user not to be returned.
@@ -236,6 +228,16 @@
}
/**
+ * Checks whether the user is default user.
+ *
+ * @param userInfo User to check against system user.
+ * @return {@code true} if is default user, {@code false} otherwise.
+ */
+ public boolean isDefaultUser(UserInfo userInfo) {
+ return userInfo.id == CarSettings.DEFAULT_USER_ID_TO_BOOT_INTO;
+ }
+
+ /**
* Checks whether passed in user is the foreground user.
*
* @param userInfo User to check.
@@ -315,6 +317,14 @@
return mUserManager.isGuestUser();
}
+ /**
+ * Check is the calling app is running as a restricted profile user (ie. a LinkedUser).
+ * Restricted profiles are only available when {@link #isHeadlessSystemUser()} is false.
+ */
+ public boolean isCurrentProcessRestrictedProfileUser() {
+ return mUserManager.isRestrictedProfile();
+ }
+
// Current process user restriction accessors
/**
@@ -410,6 +420,13 @@
return false;
}
+ // Not allow to delete the default user for now. Since default user is the one to
+ // boot into.
+ if (isHeadlessSystemUser() && isDefaultUser(userInfo)) {
+ Log.w(TAG, "User " + userInfo.id + " is the default user, could not be removed.");
+ return false;
+ }
+
if (userInfo.id == getCurrentForegroundUserId()) {
startNewGuestSession(guestUserName);
}
diff --git a/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java b/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
new file mode 100644
index 0000000..c59a2fa
--- /dev/null
+++ b/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
@@ -0,0 +1,96 @@
+/*
+ * 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.internal;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represent listeners for a property grouped by their rate.
+ * T is a type of EventListener such as CarPropertyEventListener
+ * in {@link android.car.hardware.property.CarPropertyManager}
+ * @param <T>
+ * @hide
+ */
+public class CarRatedFloatListeners<T> {
+ private final Map<T, Float> mListenersToRate = new HashMap<>(4);
+
+ private float mUpdateRate;
+
+ protected long mLastUpdateTime = -1;
+
+ protected CarRatedFloatListeners(float rate) {
+ mUpdateRate = rate;
+ }
+
+ /** Check listener */
+ public boolean contains(T listener) {
+ return mListenersToRate.containsKey(listener);
+ }
+ /** Return current rate after updating */
+ public float getRate() {
+ return mUpdateRate;
+ }
+
+ /**
+ * Remove given listener from the list and update rate if necessary.
+ *
+ * @param listener
+ * @return true if rate was updated. Otherwise, returns false.
+ */
+ public boolean remove(T listener) {
+ mListenersToRate.remove(listener);
+ if (mListenersToRate.isEmpty()) {
+ return false;
+ }
+ Float updateRate = Collections.max(mListenersToRate.values());
+ if (updateRate != mUpdateRate) {
+ mUpdateRate = updateRate;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isEmpty() {
+ return mListenersToRate.isEmpty();
+ }
+
+ /**
+ * Add given listener to the list and update rate if necessary.
+ *
+ * @param listener if null, add part is skipped.
+ * @param updateRate
+ * @return true if rate was updated. Otherwise, returns false.
+ */
+ public boolean addAndUpdateRate(T listener, float updateRate) {
+ Float oldUpdateRate = mListenersToRate.put(listener, updateRate);
+ if (mUpdateRate < updateRate) {
+ mUpdateRate = updateRate;
+ return true;
+ } else if (oldUpdateRate != null && oldUpdateRate == mUpdateRate) {
+ mUpdateRate = Collections.max(mListenersToRate.values());
+ }
+ return false;
+ }
+
+ public Collection<T> getListeners() {
+ return mListenersToRate.keySet();
+ }
+}
+
diff --git a/car-lib/src/com/android/car/internal/SingleMessageHandler.java b/car-lib/src/com/android/car/internal/SingleMessageHandler.java
index f61309c..57788a7 100644
--- a/car-lib/src/com/android/car/internal/SingleMessageHandler.java
+++ b/car-lib/src/com/android/car/internal/SingleMessageHandler.java
@@ -20,6 +20,7 @@
import android.os.Handler.Callback;
import android.os.Looper;
import android.os.Message;
+
import java.util.List;
import java.util.function.Consumer;
@@ -60,4 +61,5 @@
public void sendEvents(List<EventType> events) {
mHandler.sendMessage(mHandler.obtainMessage(mHandledMessageWhat, events));
}
+
}
diff --git a/car-support-lib/api/current.txt b/car-support-lib/api/current.txt
index 347c25d..7ee1246 100644
--- a/car-support-lib/api/current.txt
+++ b/car-support-lib/api/current.txt
@@ -152,8 +152,8 @@
method public abstract boolean isSensorSupported(int) throws android.support.car.CarNotConnectedException;
method public abstract void removeListener(android.support.car.hardware.CarSensorManager.OnSensorChangedListener);
method public abstract void removeListener(android.support.car.hardware.CarSensorManager.OnSensorChangedListener, int);
- field public static final int SENSOR_RATE_FASTEST = 0; // 0x0
- field public static final int SENSOR_RATE_NORMAL = 3; // 0x3
+ field public static final int SENSOR_RATE_FASTEST = 100; // 0x64
+ field public static final int SENSOR_RATE_NORMAL = 1; // 0x1
field public static final int SENSOR_TYPE_ABS_ACTIVE = 24; // 0x18
field public static final int SENSOR_TYPE_COMPASS = 1; // 0x1
field public static final int SENSOR_TYPE_DRIVING_STATUS = 11; // 0xb
diff --git a/car-support-lib/proguard-release.flags b/car-support-lib/proguard-release.flags
index c6cdd2b..91cab7e 100644
--- a/car-support-lib/proguard-release.flags
+++ b/car-support-lib/proguard-release.flags
@@ -2067,6 +2067,7 @@
-keep class android.app.AppOpsManager$OpEntry {
<init>(int, int, long, long, int, int, java.lang.String);
+ <init>(int, int, long[], long[], int, boolean, int, java.lang.String);
<init>(int, int, long[], long[], int, int, java.lang.String);
public int describeContents();
@@ -5133,9 +5134,9 @@
public static int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
public static int SYNC_ERROR_TOO_MANY_DELETIONS;
public static int SYNC_ERROR_TOO_MANY_RETRIES;
- public static int SYNC_EXEMPTION_ACTIVE;
- public static int SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
public static int SYNC_EXEMPTION_NONE;
+ public static int SYNC_EXEMPTION_PROMOTE_BUCKET;
+ public static int SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
public static java.lang.String SYNC_EXTRAS_ACCOUNT;
public static java.lang.String SYNC_EXTRAS_DISALLOW_METERED;
public static java.lang.String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS;
@@ -13403,28 +13404,29 @@
-keep class android.media.session.ISessionCallback {
- public abstract void onAdjustVolume(java.lang.String, int, int, int);
- public abstract void onCommand(java.lang.String, int, int, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- public abstract void onCustomAction(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public abstract void onFastForward(java.lang.String, int, int);
+ public abstract void onAdjustVolume(java.lang.String, int, int, android.media.session.ISessionControllerCallback, int);
+ public abstract void onCommand(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ public abstract void onCustomAction(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void onFastForward(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
public abstract void onMediaButton(java.lang.String, int, int, android.content.Intent, int, android.os.ResultReceiver);
- public abstract void onNext(java.lang.String, int, int);
- public abstract void onPause(java.lang.String, int, int);
- public abstract void onPlay(java.lang.String, int, int);
- public abstract void onPlayFromMediaId(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public abstract void onPlayFromSearch(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public abstract void onPlayFromUri(java.lang.String, int, int, android.net.Uri, android.os.Bundle);
- public abstract void onPrepare(java.lang.String, int, int);
- public abstract void onPrepareFromMediaId(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public abstract void onPrepareFromSearch(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public abstract void onPrepareFromUri(java.lang.String, int, int, android.net.Uri, android.os.Bundle);
- public abstract void onPrevious(java.lang.String, int, int);
- public abstract void onRate(java.lang.String, int, int, android.media.Rating);
- public abstract void onRewind(java.lang.String, int, int);
- public abstract void onSeekTo(java.lang.String, int, int, long);
- public abstract void onSetVolumeTo(java.lang.String, int, int, int);
- public abstract void onSkipToTrack(java.lang.String, int, int, long);
- public abstract void onStop(java.lang.String, int, int);
+ public abstract void onMediaButtonFromController(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.content.Intent);
+ public abstract void onNext(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public abstract void onPause(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public abstract void onPlay(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public abstract void onPlayFromMediaId(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void onPlayFromSearch(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void onPlayFromUri(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.net.Uri, android.os.Bundle);
+ public abstract void onPrepare(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public abstract void onPrepareFromMediaId(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void onPrepareFromSearch(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void onPrepareFromUri(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.net.Uri, android.os.Bundle);
+ public abstract void onPrevious(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public abstract void onRate(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.media.Rating);
+ public abstract void onRewind(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public abstract void onSeekTo(java.lang.String, int, int, android.media.session.ISessionControllerCallback, long);
+ public abstract void onSetVolumeTo(java.lang.String, int, int, android.media.session.ISessionControllerCallback, int);
+ public abstract void onSkipToTrack(java.lang.String, int, int, android.media.session.ISessionControllerCallback, long);
+ public abstract void onStop(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
}
@@ -13441,8 +13443,8 @@
-keep class android.media.session.ISessionController {
- public abstract void adjustVolume(java.lang.String, boolean, int, int);
- public abstract void fastForward(java.lang.String);
+ public abstract void adjustVolume(java.lang.String, android.media.session.ISessionControllerCallback, boolean, int, int);
+ public abstract void fastForward(java.lang.String, android.media.session.ISessionControllerCallback);
public abstract android.os.Bundle getExtras();
public abstract long getFlags();
public abstract android.app.PendingIntent getLaunchPendingIntent();
@@ -13455,27 +13457,27 @@
public abstract java.lang.String getTag();
public abstract android.media.session.ParcelableVolumeInfo getVolumeAttributes();
public abstract boolean isTransportControlEnabled();
- public abstract void next(java.lang.String);
- public abstract void pause(java.lang.String);
- public abstract void play(java.lang.String);
- public abstract void playFromMediaId(java.lang.String, java.lang.String, android.os.Bundle);
- public abstract void playFromSearch(java.lang.String, java.lang.String, android.os.Bundle);
- public abstract void playFromUri(java.lang.String, android.net.Uri, android.os.Bundle);
- public abstract void prepare(java.lang.String);
- public abstract void prepareFromMediaId(java.lang.String, java.lang.String, android.os.Bundle);
- public abstract void prepareFromSearch(java.lang.String, java.lang.String, android.os.Bundle);
- public abstract void prepareFromUri(java.lang.String, android.net.Uri, android.os.Bundle);
- public abstract void previous(java.lang.String);
- public abstract void rate(java.lang.String, android.media.Rating);
- public abstract void registerCallbackListener(android.media.session.ISessionControllerCallback);
- public abstract void rewind(java.lang.String);
- public abstract void seekTo(java.lang.String, long);
- public abstract void sendCommand(java.lang.String, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- public abstract void sendCustomAction(java.lang.String, java.lang.String, android.os.Bundle);
- public abstract boolean sendMediaButton(java.lang.String, boolean, android.view.KeyEvent);
- public abstract void setVolumeTo(java.lang.String, int, int);
- public abstract void skipToQueueItem(java.lang.String, long);
- public abstract void stop(java.lang.String);
+ public abstract void next(java.lang.String, android.media.session.ISessionControllerCallback);
+ public abstract void pause(java.lang.String, android.media.session.ISessionControllerCallback);
+ public abstract void play(java.lang.String, android.media.session.ISessionControllerCallback);
+ public abstract void playFromMediaId(java.lang.String, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void playFromSearch(java.lang.String, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void playFromUri(java.lang.String, android.media.session.ISessionControllerCallback, android.net.Uri, android.os.Bundle);
+ public abstract void prepare(java.lang.String, android.media.session.ISessionControllerCallback);
+ public abstract void prepareFromMediaId(java.lang.String, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void prepareFromSearch(java.lang.String, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract void prepareFromUri(java.lang.String, android.media.session.ISessionControllerCallback, android.net.Uri, android.os.Bundle);
+ public abstract void previous(java.lang.String, android.media.session.ISessionControllerCallback);
+ public abstract void rate(java.lang.String, android.media.session.ISessionControllerCallback, android.media.Rating);
+ public abstract void registerCallbackListener(java.lang.String, android.media.session.ISessionControllerCallback);
+ public abstract void rewind(java.lang.String, android.media.session.ISessionControllerCallback);
+ public abstract void seekTo(java.lang.String, android.media.session.ISessionControllerCallback, long);
+ public abstract void sendCommand(java.lang.String, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ public abstract void sendCustomAction(java.lang.String, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public abstract boolean sendMediaButton(java.lang.String, android.media.session.ISessionControllerCallback, boolean, android.view.KeyEvent);
+ public abstract void setVolumeTo(java.lang.String, android.media.session.ISessionControllerCallback, int, int);
+ public abstract void skipToQueueItem(java.lang.String, android.media.session.ISessionControllerCallback, long);
+ public abstract void stop(java.lang.String, android.media.session.ISessionControllerCallback);
public abstract void unregisterCallbackListener(android.media.session.ISessionControllerCallback);
@@ -13646,28 +13648,29 @@
-keep class android.media.session.MediaSession$CallbackStub {
<init>(android.media.session.MediaSession);
- public void onAdjustVolume(java.lang.String, int, int, int);
- public void onCommand(java.lang.String, int, int, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
- public void onCustomAction(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public void onFastForward(java.lang.String, int, int);
+ public void onAdjustVolume(java.lang.String, int, int, android.media.session.ISessionControllerCallback, int);
+ public void onCommand(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle, android.os.ResultReceiver);
+ public void onCustomAction(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public void onFastForward(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
public void onMediaButton(java.lang.String, int, int, android.content.Intent, int, android.os.ResultReceiver);
- public void onNext(java.lang.String, int, int);
- public void onPause(java.lang.String, int, int);
- public void onPlay(java.lang.String, int, int);
- public void onPlayFromMediaId(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public void onPlayFromSearch(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public void onPlayFromUri(java.lang.String, int, int, android.net.Uri, android.os.Bundle);
- public void onPrepare(java.lang.String, int, int);
- public void onPrepareFromMediaId(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public void onPrepareFromSearch(java.lang.String, int, int, java.lang.String, android.os.Bundle);
- public void onPrepareFromUri(java.lang.String, int, int, android.net.Uri, android.os.Bundle);
- public void onPrevious(java.lang.String, int, int);
- public void onRate(java.lang.String, int, int, android.media.Rating);
- public void onRewind(java.lang.String, int, int);
- public void onSeekTo(java.lang.String, int, int, long);
- public void onSetVolumeTo(java.lang.String, int, int, int);
- public void onSkipToTrack(java.lang.String, int, int, long);
- public void onStop(java.lang.String, int, int);
+ public void onMediaButtonFromController(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.content.Intent);
+ public void onNext(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public void onPause(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public void onPlay(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public void onPlayFromMediaId(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public void onPlayFromSearch(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public void onPlayFromUri(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.net.Uri, android.os.Bundle);
+ public void onPrepare(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public void onPrepareFromMediaId(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public void onPrepareFromSearch(java.lang.String, int, int, android.media.session.ISessionControllerCallback, java.lang.String, android.os.Bundle);
+ public void onPrepareFromUri(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.net.Uri, android.os.Bundle);
+ public void onPrevious(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public void onRate(java.lang.String, int, int, android.media.session.ISessionControllerCallback, android.media.Rating);
+ public void onRewind(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
+ public void onSeekTo(java.lang.String, int, int, android.media.session.ISessionControllerCallback, long);
+ public void onSetVolumeTo(java.lang.String, int, int, android.media.session.ISessionControllerCallback, int);
+ public void onSkipToTrack(java.lang.String, int, int, android.media.session.ISessionControllerCallback, long);
+ public void onStop(java.lang.String, int, int, android.media.session.ISessionControllerCallback);
}
@@ -13776,6 +13779,7 @@
-keep class android.media.session.MediaSessionManager$RemoteUserInfo {
<init>(java.lang.String, int, int);
+ <init>(java.lang.String, int, int, android.os.IBinder);
public boolean equals(java.lang.Object);
public java.lang.String getPackageName();
@@ -15459,6 +15463,7 @@
<init>(android.os.Parcel);
public android.content.Intent buildBrowseIntent();
+ public android.content.Intent buildBrowseIntentForUser(int);
public static int buildStableMtpStorageId(java.lang.String);
public android.os.storage.StorageVolume buildStorageVolume(android.content.Context, int, boolean);
public android.os.storage.VolumeInfo clone();
@@ -20804,7 +20809,6 @@
public void dispatchInvalidateOnAnimation(android.view.View);
public void dispatchInvalidateRectDelayed(android.view.View$AttachInfo$InvalidateInfo, long);
public void dispatchInvalidateRectOnAnimation(android.view.View$AttachInfo$InvalidateInfo);
- public boolean dispatchKeyFallbackEvent(android.view.KeyEvent);
public void dispatchKeyFromAutofill(android.view.KeyEvent);
public void dispatchKeyFromIme(android.view.KeyEvent);
public void dispatchMoved(int, int);
@@ -20812,6 +20816,7 @@
public void dispatchRequestKeyboardShortcuts(com.android.internal.os.IResultReceiver, int);
public void dispatchSystemUiVisibilityChanged(int, int, int, int);
public void dispatchUnhandledInputEvent(android.view.InputEvent);
+ public boolean dispatchUnhandledKeyEvent(android.view.KeyEvent);
public void dispatchWindowShown();
public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
public void dumpGfxInfo(int[]);
@@ -21481,6 +21486,7 @@
public android.view.WindowInsets consumeSystemWindowInsets(boolean, boolean, boolean, boolean);
public android.view.WindowInsets consumeWindowDecorInsets();
public android.view.WindowInsets consumeWindowDecorInsets(boolean, boolean, boolean, boolean);
+ public boolean equals(java.lang.Object);
public android.view.DisplayCutout getDisplayCutout();
public int getStableInsetBottom();
public int getStableInsetLeft();
@@ -21499,6 +21505,9 @@
public boolean hasStableInsets();
public boolean hasSystemWindowInsets();
public boolean hasWindowDecorInsets();
+ public int hashCode();
+ public android.view.WindowInsets inset(android.graphics.Rect);
+ public android.view.WindowInsets inset(int, int, int, int);
public boolean isConsumed();
public boolean isRound();
public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
diff --git a/car-support-lib/src/android/support/car/CarServiceLoaderEmbedded.java b/car-support-lib/src/android/support/car/CarServiceLoaderEmbedded.java
index 3a21b1e..cfd598a 100644
--- a/car-support-lib/src/android/support/car/CarServiceLoaderEmbedded.java
+++ b/car-support-lib/src/android/support/car/CarServiceLoaderEmbedded.java
@@ -22,7 +22,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.support.car.content.pm.CarPackageManagerEmbedded;
-import android.support.car.hardware.CarSensorManagerEmbedded;
import android.support.car.media.CarAudioManagerEmbedded;
import android.support.car.navigation.CarNavigationStatusManagerEmbedded;
@@ -92,8 +91,6 @@
switch (serviceName) {
case Car.AUDIO_SERVICE:
return new CarAudioManagerEmbedded(manager);
- case Car.SENSOR_SERVICE:
- return new CarSensorManagerEmbedded(manager, getContext());
case Car.INFO_SERVICE:
return new CarInfoManagerEmbedded(manager);
case Car.APP_FOCUS_SERVICE:
diff --git a/car-support-lib/src/android/support/car/hardware/CarSensorManager.java b/car-support-lib/src/android/support/car/hardware/CarSensorManager.java
index 9c13478..29d6f40 100644
--- a/car-support-lib/src/android/support/car/hardware/CarSensorManager.java
+++ b/car-support-lib/src/android/support/car/hardware/CarSensorManager.java
@@ -215,13 +215,13 @@
public @interface SensorType {}
/** Read sensor at the default normal rate set for each sensors. This is default rate. */
- public static final int SENSOR_RATE_NORMAL = 3;
+ public static final int SENSOR_RATE_NORMAL = 1;
/**@hide*/
- public static final int SENSOR_RATE_UI = 2;
+ public static final int SENSOR_RATE_UI = 5;
/**@hide*/
- public static final int SENSOR_RATE_FAST = 1;
+ public static final int SENSOR_RATE_FAST = 10;
/** Read sensor at the maximum rate. Actual rate will be different depending on the sensor. */
- public static final int SENSOR_RATE_FASTEST = 0;
+ public static final int SENSOR_RATE_FASTEST = 100;
/** @hide */
@IntDef({
diff --git a/car_product/overlay/frameworks/base/core/res/res/values/dimens.xml b/car_product/overlay/frameworks/base/core/res/res/values/dimens.xml
index ac98448..2adc535 100644
--- a/car_product/overlay/frameworks/base/core/res/res/values/dimens.xml
+++ b/car_product/overlay/frameworks/base/core/res/res/values/dimens.xml
@@ -140,5 +140,5 @@
<dimen name="car_keyline_4">182dp</dimen>
<!-- Make the dots in lock pattern thicker in Car -->
- <dimen name="lock_pattern_dot_size">16dp</dimen>
+ <dimen name="lock_pattern_dot_size">20dp</dimen>
</resources>
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/CarAudioService.java b/service/src/com/android/car/CarAudioService.java
index 77f0f09..1b7ee67 100644
--- a/service/src/com/android/car/CarAudioService.java
+++ b/service/src/com/android/car/CarAudioService.java
@@ -138,7 +138,7 @@
+ " suggested usage: " + AudioAttributes.usageToString(usage));
final int groupId = getVolumeGroupIdForUsage(usage);
final int currentVolume = getGroupVolume(groupId);
- final int flags = AudioManager.FLAG_FROM_KEY;
+ final int flags = AudioManager.FLAG_FROM_KEY | AudioManager.FLAG_SHOW_UI;
switch (adjustment) {
case AudioManager.ADJUST_LOWER:
if (currentVolume > getGroupMinVolume(groupId)) {
@@ -152,15 +152,15 @@
break;
case AudioManager.ADJUST_MUTE:
mAudioManager.setMasterMute(true, flags);
- callbackMasterMuteChange();
+ callbackMasterMuteChange(flags);
break;
case AudioManager.ADJUST_UNMUTE:
mAudioManager.setMasterMute(false, flags);
- callbackMasterMuteChange();
+ callbackMasterMuteChange(flags);
break;
case AudioManager.ADJUST_TOGGLE_MUTE:
mAudioManager.setMasterMute(!mAudioManager.isMasterMute(), flags);
- callbackMasterMuteChange();
+ callbackMasterMuteChange(flags);
break;
case AudioManager.ADJUST_SAME:
default:
@@ -185,11 +185,11 @@
if (groupId == -1) {
Log.w(CarLog.TAG_AUDIO, "Unknown stream type: " + streamType);
} else {
- callbackGroupVolumeChange(groupId);
+ callbackGroupVolumeChange(groupId, 0);
}
break;
case AudioManager.MASTER_MUTE_CHANGED_ACTION:
- callbackMasterMuteChange();
+ callbackMasterMuteChange(0);
break;
}
}
@@ -260,7 +260,7 @@
synchronized (mImplLock) {
enforcePermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
- callbackGroupVolumeChange(groupId);
+ callbackGroupVolumeChange(groupId, flags);
// For legacy stream type based volume control
if (!mUseDynamicRouting) {
mAudioManager.setStreamVolume(STREAM_TYPES[groupId], index, flags);
@@ -272,22 +272,22 @@
}
}
- private void callbackGroupVolumeChange(int groupId) {
+ private void callbackGroupVolumeChange(int groupId, int flags) {
for (BinderInterfaceContainer.BinderInterface<ICarVolumeCallback> callback :
mVolumeCallbackContainer.getInterfaces()) {
try {
- callback.binderInterface.onGroupVolumeChanged(groupId);
+ callback.binderInterface.onGroupVolumeChanged(groupId, flags);
} catch (RemoteException e) {
Log.e(CarLog.TAG_AUDIO, "Failed to callback onGroupVolumeChanged", e);
}
}
}
- private void callbackMasterMuteChange() {
+ private void callbackMasterMuteChange(int flags) {
for (BinderInterfaceContainer.BinderInterface<ICarVolumeCallback> callback :
mVolumeCallbackContainer.getInterfaces()) {
try {
- callback.binderInterface.onMasterMuteChanged();
+ callback.binderInterface.onMasterMuteChanged(flags);
} catch (RemoteException e) {
Log.e(CarLog.TAG_AUDIO, "Failed to callback onMasterMuteChanged", e);
}
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..bc0fbc1 100644
--- a/service/src/com/android/car/CarDrivingStateService.java
+++ b/service/src/com/android/car/CarDrivingStateService.java
@@ -17,14 +17,18 @@
package com.android.car;
import android.annotation.Nullable;
+import android.car.VehicleAreaType;
import android.car.drivingstate.CarDrivingStateEvent;
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 +40,83 @@
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
- // 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 final List<DrivingStateClient> mDrivingStateClients = new ArrayList<>();
+ // Array of properties that the service needs to listen to from CarPropertyService for deriving
+ // the driving state.
+ private static final int[] REQUIRED_PROPERTIES = {
+ VehicleProperty.PERF_VEHICLE_SPEED,
+ VehicleProperty.GEAR_SELECTION,
+ VehicleProperty.PARKING_BRAKE_ON};
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;
+ private boolean mLastParkingBrakeState;
+ private long mLastParkingBrakeTimestamp = NOT_RECEIVED;
+ private List<Integer> mSupportedGears;
- 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()) {
+ public synchronized void init() {
+ if (!checkPropertySupport()) {
Log.e(TAG, "init failure. Driving state will always be fully restrictive");
return;
}
- subscribeToSensors();
+ subscribeToProperties();
+ mCurrentDrivingState = createDrivingStateEvent(inferDrivingStateLocked());
+ addTransitionLog(TAG + " Boot", CarDrivingStateEvent.DRIVING_STATE_UNKNOWN,
+ mCurrentDrivingState.eventValue, mCurrentDrivingState.timeStamp);
}
@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 +124,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 +162,7 @@
Log.e(TAG, "Cannot link death recipient to binder " + e);
return;
}
- mDivingStateClients.add(client);
+ mDrivingStateClients.add(client);
}
}
@@ -158,7 +178,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 +206,7 @@
return;
}
listener.asBinder().unlinkToDeath(client, 0);
- mDivingStateClients.remove(client);
+ mDrivingStateClients.remove(client);
}
/**
@@ -222,7 +242,7 @@
}
listenerBinder.unlinkToDeath(this, 0);
synchronized (CarDrivingStateService.this) {
- mDivingStateClients.remove(this);
+ mDrivingStateClients.remove(this);
}
}
@@ -257,37 +277,90 @@
@Override
public void dump(PrintWriter writer) {
- writer.println("Driving state chane log:");
+ writer.println("Driving state change log:");
for (Utils.TransitionLog tLog : mTransitionLogs) {
writer.println(tLog);
}
writer.println("Current Driving State: " + mCurrentDrivingState.eventValue);
+ if (mSupportedGears != null) {
+ writer.println("Supported gears:");
+ for (Integer gear : mSupportedGears) {
+ writer.print("Gear:" + gear);
+ }
+ }
}
/**
- * {@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:
+ if (mSupportedGears == null) {
+ mSupportedGears = getSupportedGears();
+ }
+ 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;
+ case VehicleProperty.PARKING_BRAKE_ON:
+ boolean curParkingBrake = (boolean) value.getValue();
+ if (DBG) {
+ Log.d(TAG, "Parking Brake: " + curParkingBrake + "@" + curTimestamp);
+ }
+ if (curTimestamp > mLastParkingBrakeTimestamp) {
+ mLastParkingBrakeTimestamp = curTimestamp;
+ mLastParkingBrakeState = curParkingBrake;
+ } else if (DBG) {
+ Log.d(TAG, "Ignoring Parking Brake status with an 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,26 +368,35 @@
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;
}
}
+ private List<Integer> getSupportedGears() {
+ List<CarPropertyConfig> properyList = mPropertyService.getPropertyList();
+ for (CarPropertyConfig p : properyList) {
+ if (p.getPropertyId() == VehicleProperty.GEAR_SELECTION) {
+ return p.getConfigArray();
+ }
+ }
+ return null;
+ }
+
private void addTransitionLog(String name, int from, int to, long timestamp) {
if (mTransitionLogs.size() >= MAX_TRANSITION_LOG_SIZE) {
mTransitionLogs.remove();
@@ -327,80 +409,124 @@
/**
* Infers the current driving state of the car from the other Car Sensor properties like
* Current Gear, Speed etc.
- * ToDo (ramperry@) - Fine tune this - b/69859926
*
* @return Current driving state
*/
@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;
- }
+ updateVehiclePropertiesIfNeeded();
+ if (DBG) {
+ Log.d(TAG, "Last known Gear:" + mLastGear + " Last known speed:" + mLastSpeed);
}
- 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:
+ Logic to start off deriving driving state:
1. If gear == parked, then Driving State is parked.
2. If gear != parked,
- 2a. if speed == 0, then driving state is idling
- 2b. if speed != 0, then driving state is moving
- 2c. if speed unavailable, then driving state is unknown
- This logic needs to be tested and iterated on. Tracked in b/69859926
+ 2a. if parking brake is applied, then Driving state is parked.
+ 2b. if parking brake is not applied or unknown/unavailable, then driving state
+ is still unknown.
+ 3. If driving state is unknown at the end of step 2,
+ 3a. if speed == 0, then driving state is idling
+ 3b. if speed != 0, then driving state is moving
+ 3c. if speed unavailable, then driving state is unknown
*/
- 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 (isVehicleKnownToBeParked()) {
+ return CarDrivingStateEvent.DRIVING_STATE_PARKED;
+ }
+
+ // We don't know if the vehicle is parked, let's look at the speed.
+ if (mLastSpeedTimestamp == NOT_RECEIVED || mLastSpeed < 0) {
+ return CarDrivingStateEvent.DRIVING_STATE_UNKNOWN;
+ } else if (mLastSpeed == 0f) {
+ return CarDrivingStateEvent.DRIVING_STATE_IDLING;
+ } else {
+ return CarDrivingStateEvent.DRIVING_STATE_MOVING;
+ }
+ }
+
+ /**
+ * Find if we have signals to know if the vehicle is parked
+ *
+ * @return true if we have enough information to say the vehicle is parked.
+ * false, if the vehicle is either not parked or if we don't have any information.
+ */
+ private boolean isVehicleKnownToBeParked() {
+ // If we know the gear is in park, return true
+ if (mLastGearTimestamp != NOT_RECEIVED && mLastGear == VehicleGear.GEAR_PARK) {
+ return true;
+ } else if (mLastParkingBrakeTimestamp != NOT_RECEIVED) {
+ // if gear is not in park or unknown, look for status of parking brake if transmission
+ // type is manual.
+ if (isCarManualTransmissionType()) {
+ return mLastParkingBrakeState;
+ }
+ }
+ // if neither information is available, return false to indicate we can't determine
+ // if the vehicle is parked.
+ return false;
+ }
+
+ /**
+ * If Supported gears information is available and GEAR_PARK is not one of the supported gears,
+ * transmission type is considered to be Manual. Automatic transmission is assumed otherwise.
+ */
+ private boolean isCarManualTransmissionType() {
+ if (mSupportedGears != null
+ && !mSupportedGears.isEmpty()
+ && !mSupportedGears.contains(VehicleGear.GEAR_PARK)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Try querying the gear selection and parking brake if we haven't received the event yet.
+ * This could happen if the gear change occurred before car service booted up like in the
+ * case of a HU restart in the middle of a drive. Since gear and parking brake are
+ * on-change only properties, we could be in this situation where we will have to query
+ * VHAL.
+ */
+ private void updateVehiclePropertiesIfNeeded() {
+ if (mLastGearTimestamp == NOT_RECEIVED) {
+ CarPropertyValue propertyValue = mPropertyService.getProperty(
+ VehicleProperty.GEAR_SELECTION,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+ if (propertyValue != null) {
+ mLastGear = (Integer) propertyValue.getValue();
+ mLastGearTimestamp = propertyValue.getTimestamp();
+ if (DBG) {
+ Log.d(TAG, "updateVehiclePropertiesIfNeeded: gear:" + mLastGear);
}
}
}
- return drivingState;
- }
- private boolean isSpeedZero(CarSensorEvent event) {
- return event.floatValues[0] == 0f;
- }
+ if (mLastParkingBrakeTimestamp == NOT_RECEIVED) {
+ CarPropertyValue propertyValue = mPropertyService.getProperty(
+ VehicleProperty.PARKING_BRAKE_ON,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+ if (propertyValue != null) {
+ mLastParkingBrakeState = (boolean) propertyValue.getValue();
+ mLastParkingBrakeTimestamp = propertyValue.getTimestamp();
+ if (DBG) {
+ Log.d(TAG, "updateVehiclePropertiesIfNeeded: brake:" + mLastParkingBrakeState);
+ }
+ }
+ }
- private boolean isGearInParking(CarSensorEvent event) {
- int gear = event.intValues[0];
- return gear == CarSensorEvent.GEAR_PARK;
+ if (mLastSpeedTimestamp == NOT_RECEIVED) {
+ CarPropertyValue propertyValue = mPropertyService.getProperty(
+ VehicleProperty.PERF_VEHICLE_SPEED,
+ VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL);
+ if (propertyValue != null) {
+ mLastSpeed = (float) propertyValue.getValue();
+ mLastSpeedTimestamp = propertyValue.getTimestamp();
+ if (DBG) {
+ Log.d(TAG, "updateVehiclePropertiesIfNeeded: speed:" + mLastSpeed);
+ }
+ }
+ }
}
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..23c4d32 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,11 @@
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 static final float SPEED_NOT_AVAILABLE = -1.0F;
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,20 +65,20 @@
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);
}
@Override
- public void init() {
+ public synchronized void init() {
try {
if (!mHelper.loadUxRestrictionsFromXml()) {
Log.e(TAG, "Error reading Ux Restrictions Mapping. Falling back to defaults");
@@ -88,9 +91,41 @@
// 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);
+ initializeUxRestrictions();
+ }
+
+ // Update current restrictions by getting the current driving state and speed.
+ private void initializeUxRestrictions() {
+ CarDrivingStateEvent currentDrivingStateEvent =
+ mDrivingStateService.getCurrentDrivingState();
+ // if we don't have enough information from the CarPropertyService to compute the UX
+ // restrictions, then leave the UX restrictions unchanged from what it was initialized to
+ // in the constructor.
+ if (currentDrivingStateEvent == null || currentDrivingStateEvent.eventValue
+ == CarDrivingStateEvent.DRIVING_STATE_UNKNOWN) {
+ return;
+ }
+ int currentDrivingState = currentDrivingStateEvent.eventValue;
+ Float currentSpeed = getCurrentSpeed();
+ if (currentSpeed == SPEED_NOT_AVAILABLE) {
+ return;
+ }
+ // At this point the underlying CarPropertyService has provided us enough information to
+ // compute the UX restrictions that could be potentially different from the initial UX
+ // restrictions.
+ handleDispatchUxRestrictions(currentDrivingState, currentSpeed);
+ }
+
+ private Float getCurrentSpeed() {
+ CarPropertyValue value = mCarPropertyService.getProperty(VehicleProperty.PERF_VEHICLE_SPEED,
+ 0);
+ if (value != null) {
+ return (Float) value.getValue();
+ }
+ return SPEED_NOT_AVAILABLE;
}
@Override
@@ -154,7 +189,6 @@
return null;
}
-
/**
* Unregister the given UX Restrictions listener
*
@@ -280,10 +314,10 @@
return;
}
int drivingState = event.eventValue;
- CarSensorEvent speed = mCarSensorService.getLatestSensorEvent(
- CarSensorManager.SENSOR_TYPE_CAR_SPEED);
- if (speed != null) {
- mCurrentMovingSpeed = speed.floatValues[0];
+ Float speed = getCurrentSpeed();
+
+ if (speed != SPEED_NOT_AVAILABLE) {
+ mCurrentMovingSpeed = speed;
} 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 +337,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());
}
}
}
@@ -348,7 +384,6 @@
uxRestrictions = getDefaultRestrictions(currentDrivingState);
} else {
uxRestrictions = mHelper.getUxRestrictions(currentDrivingState, speed);
-
}
if (DBG) {
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 c192202..ce5ea75 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -65,21 +65,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;
@@ -116,10 +112,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);
@@ -127,22 +123,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());
@@ -156,23 +147,19 @@
List<CarServiceBase> allServices = new ArrayList<>();
allServices.add(mSystemActivityMonitoringService);
allServices.add(mCarPowerManagementService);
- allServices.add(mCarSensorService);
+ allServices.add(mCarPropertyService);
allServices.add(mCarDrivingStateService);
allServices.add(mCarUXRestrictionsService);
allServices.add(mCarPackageManagerService);
allServices.add(mCarInputService);
allServices.add(mCarLocationService);
allServices.add(mGarageModeService);
- allServices.add(mCarInfoService);
allServices.add(mAppFocusService);
allServices.add(mCarAudioService);
- allServices.add(mCarCabinService);
- allServices.add(mCarHvacService);
allServices.add(mCarNightService);
allServices.add(mInstrumentClusterService);
allServices.add(mCarProjectionService);
allServices.add(mSystemStateControllerService);
- allServices.add(mCarVendorExtensionService);
allServices.add(mCarBluetoothService);
allServices.add(mCarDiagnosticService);
allServices.add(mPerUserCarServiceHelper);
@@ -233,26 +220,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 =
@@ -264,9 +248,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;
@@ -319,10 +300,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);
}
@@ -331,10 +308,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);
}
@@ -343,10 +316,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,
@@ -371,6 +340,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..d9151e2 100644
--- a/service/src/com/android/car/hal/CarPropertyUtils.java
+++ b/service/src/com/android/car/hal/CarPropertyUtils.java
@@ -51,14 +51,23 @@
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()];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = v.int32Values.get(i) == 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);
+ } else if (Long[].class == clazz) {
+ Long[] values = new Long[v.int64Values.size()];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = v.int64Values.get(i);
+ }
+ return new CarPropertyValue<>(propertyId, areaId, status, timestamp, values);
} else /* All list properties */ {
Object[] values = getRawValueList(clazz, v).toArray();
return new CarPropertyValue<>(propertyId, areaId, status, timestamp,
@@ -76,15 +85,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[]) {
@@ -159,7 +176,7 @@
private static @VehicleAreaType.VehicleAreaTypeValue int getVehicleAreaType(int halArea) {
switch (halArea) {
case VehicleArea.GLOBAL:
- return VehicleAreaType.VEHICLE_AREA_TYPE_NONE;
+ return VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
case VehicleArea.SEAT:
return VehicleAreaType.VEHICLE_AREA_TYPE_SEAT;
case VehicleArea.DOOR:
@@ -203,10 +220,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
diff --git a/service/src/com/android/car/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index bea3e2c..fd84e2b 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -802,7 +802,7 @@
private static VehiclePropValue toTypedVmsVehiclePropValue(int messageType) {
VehiclePropValue vehicleProp = new VehiclePropValue();
vehicleProp.prop = HAL_PROPERTY_ID;
- vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_NONE;
+ vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
VehiclePropValue.RawValue v = vehicleProp.value;
v.int32Values.add(messageType);
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/car_assistant.xml b/tests/EmbeddedKitchenSinkApp/res/layout/car_assistant.xml
index 759a73e..89d67be 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/car_assistant.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/car_assistant.xml
@@ -17,8 +17,13 @@
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
- android:id="@+id/voice_button"
+ android:id="@+id/voice_button_intent"
android:layout_gravity="center"
android:src="@drawable/ic_voice_assistant_mic"
style="@style/OverviewButton"/>
-</LinearLayout>
\ No newline at end of file
+ <ImageView
+ android:id="@+id/voice_button_service"
+ android:layout_gravity="center"
+ android:src="@drawable/ic_voice_assistant_mic"
+ style="@style/OverviewButton"/>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/property.xml b/tests/EmbeddedKitchenSinkApp/res/layout/property.xml
new file mode 100644
index 0000000..f8f6f79
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/property.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal" >
+ <ListView
+ android:id="@+id/lvPropertyList"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:scrollbars="vertical">
+ </ListView>
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:orientation="vertical" >
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="0dp"
+ android:layout_weight="2"
+ android:layout_width="match_parent"
+ android:orientation="horizontal" >
+ <Spinner
+ android:id="@+id/sPropertyId"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_width="0dp" />
+ <Button
+ android:id="@+id/bGetProperty"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:text="@string/property_get"
+ android:textSize="@dimen/propertyTextSize"/>
+ <TextView
+ android:id="@+id/tvGetPropertyValue"
+ android:gravity="center"
+ android:layout_height="wrap_content"
+ android:layout_weight="2"
+ android:layout_width="0dp"
+ android:textSize="@dimen/propertyValueTextSize"/>
+ </LinearLayout>
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:orientation="horizontal" >
+ <Spinner
+ android:id="@+id/sAreaId"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_width="0dp" />
+ <EditText
+ android:id="@+id/etSetPropertyValue"
+ android:layout_height="wrap_content"
+ android:layout_weight="2"
+ android:layout_width="0dp"
+ android:inputType="phone" />
+ <Button
+ android:id="@+id/bSetProperty"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:text="@string/property_set"
+ android:textSize="@dimen/propertyTextSize"/>
+ </LinearLayout>
+
+ <!-- Event Log -->
+ <ScrollView
+ android:id="@+id/svEventLog"
+ android:layout_height="0dp"
+ android:layout_weight="6"
+ android:layout_width="match_parent"
+ android:scrollbars="vertical">
+ <TextView
+ android:id="@+id/tvEventLog"
+ android:gravity="left"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:textSize="@dimen/propertyValueTextSize"/>
+ </ScrollView>
+ <Button
+ android:id="@+id/bClearLog"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:text="@string/property_clear"
+ android:textSize="@dimen/propertyTextSize"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/property_list_item.xml b/tests/EmbeddedKitchenSinkApp/res/layout/property_list_item.xml
new file mode 100644
index 0000000..f8051ee
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/property_list_item.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <TextView
+ android:id="@+id/tvPropertyName"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentLeft="true"
+ android:paddingLeft="8dp"
+ android:textSize="@dimen/propertyTextSize" />
+
+ <ToggleButton
+ android:id="@+id/tbRegisterPropertyBtn"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:text="@string/property_register" />
+
+</RelativeLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml b/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml
index a9e3457..c8806bc 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/dimens.xml
@@ -20,6 +20,8 @@
<dimen name="powerBtnHeight">80dp</dimen>
<dimen name="powerBtnWidth">300dp</dimen>
<dimen name="powerTextSize">24sp</dimen>
+ <dimen name="propertyTextSize">24sp</dimen>
+ <dimen name="propertyValueTextSize">14sp</dimen>
<dimen name="rvcBtnHeight">40dp</dimen>
<dimen name="rvcBtnWidth">150dp</dimen>
<dimen name="rvcTextSize">10dp</dimen>
diff --git a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
index 36854c1..74c7c26 100644
--- a/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/values/strings.xml
@@ -180,6 +180,13 @@
<string name="power_shutdown">Shutdown</string>
<string name="power_sleep">Sleep</string>
+ <!-- property test -->
+ <string name="property_clear">Clear Log</string>
+ <string name="property_get">Get</string>
+ <string name="property_register">Register</string>
+ <string name="property_set">Set</string>
+ <string name="property_unregister">Unregister</string>
+
<!-- radio test -->
<string name="radio_open">Open</string>
<string name="radio_close">Close</string>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index aa6202a..7837f2e 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -17,8 +17,10 @@
package com.google.android.car.kitchensink;
+import android.car.hardware.CarSensorManager;
import android.car.hardware.hvac.CarHvacManager;
import android.car.hardware.power.CarPowerManager;
+import android.car.hardware.property.CarPropertyManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
@@ -26,7 +28,6 @@
import android.support.car.CarAppFocusManager;
import android.support.car.CarConnectionCallback;
import android.support.car.CarNotConnectedException;
-import android.support.car.hardware.CarSensorManager;
import android.support.v4.app.Fragment;
import android.util.Log;
@@ -50,6 +51,7 @@
import com.google.android.car.kitchensink.notification.NotificationFragment;
import com.google.android.car.kitchensink.orientation.OrientationTestFragment;
import com.google.android.car.kitchensink.power.PowerTestFragment;
+import com.google.android.car.kitchensink.property.PropertyTestFragment;
import com.google.android.car.kitchensink.sensor.SensorsTestFragment;
import com.google.android.car.kitchensink.setting.CarServiceSettingsActivity;
import com.google.android.car.kitchensink.storagelifetime.StorageLifetimeFragment;
@@ -153,6 +155,7 @@
add("notification", NotificationFragment.class);
add("orientation test", OrientationTestFragment.class);
add("power test", PowerTestFragment.class);
+ add("property test", PropertyTestFragment.class);
add("sensors", SensorsTestFragment.class);
add("storage lifetime", StorageLifetimeFragment.class);
add("touch test", TouchTestFragment.class);
@@ -177,17 +180,10 @@
private Car mCarApi;
private CarHvacManager mHvacManager;
private CarPowerManager mPowerManager;
- private CarSensorManager mCarSensorManager;
+ private CarPropertyManager mPropertyManager;
+ private CarSensorManager mSensorManager;
private CarAppFocusManager mCarAppFocusManager;
- private final CarSensorManager.OnSensorChangedListener mListener = (manager, event) -> {
- switch (event.sensorType) {
- case CarSensorManager.SENSOR_TYPE_DRIVING_STATUS:
- Log.d(TAG, "driving status:" + event.intValues[0]);
- break;
- }
- };
-
public CarHvacManager getHvacManager() {
return mHvacManager;
}
@@ -196,11 +192,19 @@
return mPowerManager;
}
+ public CarPropertyManager getPropertyManager() {
+ return mPropertyManager;
+ }
+
@Override
protected CarDrawerAdapter getRootAdapter() {
return new DrawerAdapter();
}
+ public CarSensorManager getSensorManager() {
+ return mSensorManager;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -247,9 +251,6 @@
@Override
protected void onDestroy() {
super.onDestroy();
- if (mCarSensorManager != null) {
- mCarSensorManager.removeListener(mListener);
- }
if (mCarApi != null) {
mCarApi.disconnect();
}
@@ -271,10 +272,10 @@
mHvacManager = (CarHvacManager) mCarApi.getCarManager(android.car.Car.HVAC_SERVICE);
mPowerManager = (CarPowerManager) mCarApi.getCarManager(
android.car.Car.POWER_SERVICE);
- mCarSensorManager = (CarSensorManager) mCarApi.getCarManager(Car.SENSOR_SERVICE);
- mCarSensorManager.addListener(mListener,
- CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
- CarSensorManager.SENSOR_RATE_NORMAL);
+ mPropertyManager = (CarPropertyManager) mCarApi.getCarManager(
+ android.car.Car.PROPERTY_SERVICE);
+ mSensorManager = (CarSensorManager) mCarApi.getCarManager(
+ android.car.Car.SENSOR_SERVICE);
mCarAppFocusManager =
(CarAppFocusManager) mCarApi.getCarManager(Car.APP_FOCUS_SERVICE);
} catch (CarNotConnectedException e) {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/assistant/CarAssistantFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/assistant/CarAssistantFragment.java
index 147b017..4bee453 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/assistant/CarAssistantFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/assistant/CarAssistantFragment.java
@@ -31,15 +31,18 @@
public class CarAssistantFragment extends Fragment {
- private ImageView mMic;
+ private ImageView mMicIntent;
+ private ImageView mMicService;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.car_assistant, container, false);
- mMic = (ImageView) v.findViewById(R.id.voice_button);
+ mMicIntent = (ImageView) v.findViewById(R.id.voice_button_intent);
+ mMicService = (ImageView) v.findViewById(R.id.voice_button_service);
Context context = getContext();
- mMic.setOnClickListener(new View.OnClickListener() {
+
+ mMicIntent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
@@ -54,6 +57,14 @@
}
}
});
+ mMicService.setOnClickListener(v1 -> {
+ v1.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ boolean success = getActivity().showAssist(null);
+ if (!success) {
+ Toast.makeText(context,
+ "Assistant app is not available.", Toast.LENGTH_SHORT).show();
+ }
+ });
return v;
}
}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyInfo.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyInfo.java
new file mode 100644
index 0000000..0f0b5d4
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyInfo.java
@@ -0,0 +1,55 @@
+/*
+ * 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.google.android.car.kitchensink.property;
+
+import android.car.hardware.CarPropertyConfig;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+
+class PropertyInfo implements Comparable<PropertyInfo> {
+ public final CarPropertyConfig mConfig;
+ public final String mName;
+ public final int mPropId;
+
+ PropertyInfo(CarPropertyConfig config) {
+ mConfig = config;
+ mPropId = config.getPropertyId();
+ mName = VehicleProperty.toString(mPropId);
+ }
+
+ @Override
+ public String toString() {
+ return mName;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof PropertyInfo) {
+ return ((PropertyInfo) other).mPropId == mPropId;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mPropId;
+ }
+
+ @Override
+ public int compareTo(PropertyInfo propertyInfo) {
+ return mName.compareTo(propertyInfo.mName);
+ }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
new file mode 100644
index 0000000..06ea4ee
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
@@ -0,0 +1,149 @@
+/*
+ * 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.google.android.car.kitchensink.property;
+
+import static java.lang.Integer.toHexString;
+
+import android.car.hardware.CarPropertyConfig;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyManager;
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListAdapter;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+
+import com.google.android.car.kitchensink.R;
+
+import java.util.List;
+
+class PropertyListAdapter extends BaseAdapter implements ListAdapter {
+ private static final int DEFAULT_RATE = 1;
+ private static final String TAG = "PropertyListAdapter";
+ private final Context mContext;
+ private final PropertyListEventListener mListener;
+ private final CarPropertyManager mMgr;
+ private final List<PropertyInfo> mPropInfo;
+ private final TextView mTvEventLog;
+
+ PropertyListAdapter(List<PropertyInfo> propInfo, CarPropertyManager mgr, TextView eventLog,
+ ScrollView svEventLog, Context context) {
+ mContext = context;
+ mListener = new PropertyListEventListener(eventLog, svEventLog);
+ mMgr = mgr;
+ mPropInfo = propInfo;
+ mTvEventLog = eventLog;
+ }
+
+ @Override
+ public int getCount() {
+ return mPropInfo.size();
+ }
+
+ @Override
+ public Object getItem(int pos) {
+ return mPropInfo.get(pos);
+ }
+
+ @Override
+ public long getItemId(int pos) {
+ return mPropInfo.get(pos).mPropId;
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ View view = convertView;
+ if (view == null) {
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ view = inflater.inflate(R.layout.property_list_item, null);
+ }
+
+ //Handle TextView and display string from your list
+ TextView listItemText = (TextView) view.findViewById(R.id.tvPropertyName);
+ listItemText.setText(mPropInfo.get(position).toString());
+
+ //Handle buttons and add onClickListeners
+ ToggleButton btn = (ToggleButton) view.findViewById(R.id.tbRegisterPropertyBtn);
+
+ btn.setOnClickListener(new View.OnClickListener(){
+ @Override
+ public void onClick(View v) {
+ CarPropertyConfig c = mPropInfo.get(position).mConfig;
+ int propId = c.getPropertyId();
+ try {
+ if (btn.isChecked()) {
+ mMgr.registerListener(mListener, propId, DEFAULT_RATE);
+ } else {
+ mMgr.unregisterListener(mListener, propId);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unhandled exception: ", e);
+ }
+ }
+ });
+ return view;
+ }
+
+
+ private static class PropertyListEventListener implements
+ CarPropertyManager.CarPropertyEventListener {
+ private int mNumEvents;
+ private ScrollView mScrollView;
+ private TextView mTvLogEvent;
+
+ PropertyListEventListener(TextView logEvent, ScrollView scrollView) {
+ mScrollView = scrollView;
+ mTvLogEvent = logEvent;
+ }
+
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ mNumEvents++;
+ mTvLogEvent.append("Event " + mNumEvents + ":"
+ + " time=" + value.getTimestamp()
+ + " propId=0x" + toHexString(value.getPropertyId())
+ + " areaId=0x" + toHexString(value.getAreaId())
+ + " status=" + value.getStatus()
+ + " value=" + value.getValue()
+ + "\n");
+ scrollToBottom();
+ }
+
+ @Override
+ public void onErrorEvent(int propId, int areaId) {
+ mTvLogEvent.append("Received error event propId=0x" + toHexString(propId)
+ + ", areaId=0x" + toHexString(areaId));
+ scrollToBottom();
+ }
+
+ private void scrollToBottom() {
+ mScrollView.post(new Runnable() {
+ public void run() {
+ mScrollView.fullScroll(View.FOCUS_DOWN);
+ //mScrollView.smoothScrollTo(0, mTextStatus.getBottom());
+ }
+ });
+ }
+
+ }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
new file mode 100644
index 0000000..fc6621a
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
@@ -0,0 +1,205 @@
+/*
+ * 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.google.android.car.kitchensink.property;
+
+import static java.lang.Integer.toHexString;
+
+import android.annotation.Nullable;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.property.CarPropertyManager;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
+import android.hardware.automotive.vehicle.V2_0.VehiclePropertyType;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.ScrollView;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.google.android.car.kitchensink.KitchenSinkActivity;
+import com.google.android.car.kitchensink.R;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class PropertyTestFragment extends Fragment implements OnItemSelectedListener{
+ private static final String TAG = "PropertyTestFragment";
+
+ private KitchenSinkActivity mActivity;
+ private CarPropertyManager mMgr;
+ private List<PropertyInfo> mPropInfo = null;
+ private Spinner mAreaId;
+ private TextView mEventLog;
+ private TextView mGetValue;
+ private ListView mListView;
+ private Spinner mPropertyId;
+ private ScrollView mScrollView;
+ private EditText mSetValue;
+
+ private final OnClickListener mNopOnClickListener = new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) { }
+ };
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.property, container, false);
+ mActivity = (KitchenSinkActivity) getHost();
+ mMgr = mActivity.getPropertyManager();
+
+ // Get resource IDs
+ mAreaId = view.findViewById(R.id.sAreaId);
+ mEventLog = view.findViewById(R.id.tvEventLog);
+ mGetValue = view.findViewById(R.id.tvGetPropertyValue);
+ mListView = view.findViewById(R.id.lvPropertyList);
+ mPropertyId = view.findViewById(R.id.sPropertyId);
+ mScrollView = view.findViewById(R.id.svEventLog);
+ mSetValue = view.findViewById(R.id.etSetPropertyValue);
+
+ populateConfigList();
+ mListView.setAdapter(new PropertyListAdapter(mPropInfo, mMgr, mEventLog, mScrollView,
+ mActivity));
+
+ // Configure dropdown menu for propertyId spinner
+ ArrayAdapter<PropertyInfo> adapter =
+ new ArrayAdapter<PropertyInfo>(mActivity, android.R.layout.simple_spinner_item,
+ mPropInfo);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mPropertyId.setAdapter(adapter);
+ mPropertyId.setOnItemSelectedListener(this);
+
+
+
+ // Configure listeners for buttons
+ Button b = view.findViewById(R.id.bGetProperty);
+ b.setOnClickListener(v -> {
+ try {
+ PropertyInfo info = (PropertyInfo) mPropertyId.getSelectedItem();
+ int propId = info.mConfig.getPropertyId();
+ int areaId = Integer.decode(mAreaId.getSelectedItem().toString());
+ CarPropertyValue value = mMgr.getProperty(propId, areaId);
+ if (propId == VehicleProperty.WHEEL_TICK) {
+ Object[] ticks = (Object[]) value.getValue();
+ mGetValue.setText("Timestamp=" + value.getTimestamp()
+ + "\nstatus=" + value.getStatus()
+ + "\n[0]=" + (Long) ticks[0]
+ + "\n[1]=" + (Long) ticks[1] + " [2]=" + (Long) ticks[2]
+ + "\n[3]=" + (Long) ticks[3] + " [4]=" + (Long) ticks[4]);
+ } else {
+ mGetValue.setText("Timestamp=" + value.getTimestamp()
+ + "\nstatus=" + value.getStatus()
+ + "\nvalue=" + value.getValue());
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to get property", e);
+ }
+ });
+
+ b = view.findViewById(R.id.bSetProperty);
+ b.setOnClickListener(v -> {
+ try {
+ PropertyInfo info = (PropertyInfo) mPropertyId.getSelectedItem();
+ int propId = info.mConfig.getPropertyId();
+ int areaId = Integer.decode(mAreaId.getSelectedItem().toString());
+ String valueString = mSetValue.getText().toString();
+
+ switch (propId & VehiclePropertyType.MASK) {
+ case VehiclePropertyType.BOOLEAN:
+ Boolean boolVal = Boolean.parseBoolean(valueString);
+ mMgr.setBooleanProperty(propId, areaId, boolVal);
+ break;
+ case VehiclePropertyType.FLOAT:
+ Float floatVal = Float.parseFloat(valueString);
+ mMgr.setFloatProperty(propId, areaId, floatVal);
+ break;
+ case VehiclePropertyType.INT32:
+ Integer intVal = Integer.parseInt(valueString);
+ mMgr.setIntProperty(propId, areaId, intVal);
+ break;
+ default:
+ Toast.makeText(mActivity, "PropertyType=0x" + toHexString(propId
+ & VehiclePropertyType.MASK) + " is not handled!",
+ Toast.LENGTH_LONG).show();
+ break;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to set HVAC boolean property", e);
+ }
+ });
+
+ b = view.findViewById(R.id.bClearLog);
+ b.setOnClickListener(v -> {
+ mEventLog.setText("");
+ });
+
+ return view;
+ }
+
+ private void populateConfigList() {
+ try {
+ mPropInfo = mMgr.getPropertyList()
+ .stream()
+ .map(PropertyInfo::new)
+ .sorted()
+ .collect(Collectors.toList());
+ } catch (Exception e) {
+ Log.e(TAG, "Unhandled exception in populateConfigList: ", e);
+ }
+ }
+
+ // Spinner callbacks
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ // An item was selected. You can retrieve the selected item using
+ PropertyInfo info = (PropertyInfo) parent.getItemAtPosition(pos);
+ int[] areaIds = info.mConfig.getAreaIds();
+ List<String> areaString = new LinkedList<String>();
+ if (areaIds.length == 0) {
+ areaString.add("0x0");
+ } else {
+ for (int areaId : areaIds) {
+ areaString.add("0x" + toHexString(areaId));
+ }
+ }
+
+ // Configure dropdown menu for propertyId spinner
+ ArrayAdapter<String> adapter =
+ new ArrayAdapter<String>(mActivity, android.R.layout.simple_spinner_item,
+ areaString);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ mAreaId.setAdapter(adapter);
+ }
+
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Another interface callback
+ }
+}
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
index 9c84f6e..abc2c10 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
@@ -16,17 +16,18 @@
package com.google.android.car.kitchensink.sensor;
+import static java.lang.Integer.toHexString;
+
import android.Manifest;
import android.annotation.Nullable;
import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.hardware.CarSensorConfig;
+import android.car.hardware.CarSensorEvent;
+import android.car.hardware.CarSensorManager;
import android.content.pm.PackageManager;
-import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
-import android.support.car.CarNotConnectedException;
-import android.support.car.hardware.CarSensorConfig;
-import android.support.car.hardware.CarSensorEvent;
-import android.support.car.hardware.CarSensorManager;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;
@@ -51,7 +52,7 @@
public class SensorsTestFragment extends Fragment {
private static final String TAG = "CAR.SENSOR.KS";
private static final boolean DBG = true;
- private static final boolean DBG_VERBOSE = false;
+ private static final boolean DBG_VERBOSE = true;
private static final int KS_PERMISSIONS_REQUEST = 1;
private final static String[] REQUIRED_PERMISSIONS = new String[]{
@@ -66,7 +67,7 @@
private final CarSensorManager.OnSensorChangedListener mOnSensorChangedListener =
new CarSensorManager.OnSensorChangedListener() {
@Override
- public void onSensorChanged(CarSensorManager manager, CarSensorEvent event) {
+ public void onSensorChanged(CarSensorEvent event) {
if (DBG_VERBOSE) {
Log.v(TAG, "New car sensor event: " + event);
}
@@ -115,26 +116,23 @@
public void onPause() {
super.onPause();
if (mSensorManager != null) {
- mSensorManager.removeListener(mOnSensorChangedListener);
+ mSensorManager.unregisterListener(mOnSensorChangedListener);
}
}
private void initSensors() {
try {
- mSensorManager = (CarSensorManager)
- mActivity.getCar().getCarManager(Car.SENSOR_SERVICE);
+ mSensorManager =
+ (CarSensorManager) ((KitchenSinkActivity) getActivity()).getSensorManager();
supportedSensors = mSensorManager.getSupportedSensors();
for (Integer sensor : supportedSensors) {
- if ((sensor == CarSensorManager.SENSOR_TYPE_LOCATION
- || sensor == CarSensorManager.SENSOR_TYPE_GPS_SATELLITE)
- && !mActivePermissions.contains(Manifest.permission.ACCESS_FINE_LOCATION)) {
- continue;
- }
- mSensorManager.addListener(mOnSensorChangedListener, sensor,
+ mSensorManager.registerListener(mOnSensorChangedListener, sensor,
CarSensorManager.SENSOR_RATE_NORMAL);
}
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car not connected or not supported", e);
+ } catch (Exception e) {
+ Log.e(TAG, "initSensors() exception caught: ", e);
}
}
@@ -188,23 +186,20 @@
for (Integer i : supportedSensors) {
CarSensorEvent event = mEventMap.get(i);
switch (i) {
- case CarSensorManager.SENSOR_TYPE_COMPASS:
- summary.add(getCompassString(event));
- break;
case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
summary.add(getContext().getString(R.string.sensor_speed,
getTimestamp(event),
- event == null ? mNaString : event.getCarSpeedData().carSpeed));
+ event == null ? mNaString : event.getCarSpeedData(null).carSpeed));
break;
case CarSensorManager.SENSOR_TYPE_RPM:
summary.add(getContext().getString(R.string.sensor_rpm,
getTimestamp(event),
- event == null ? mNaString : event.getRpmData().rpm));
+ event == null ? mNaString : event.getRpmData(null).rpm));
break;
case CarSensorManager.SENSOR_TYPE_ODOMETER:
summary.add(getContext().getString(R.string.sensor_odometer,
getTimestamp(event),
- event == null ? mNaString : event.getOdometerData().kms));
+ event == null ? mNaString : event.getOdometerData(null).kms));
break;
case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
summary.add(getFuelLevel(event));
@@ -216,38 +211,23 @@
summary.add(getContext().getString(R.string.sensor_parking_brake,
getTimestamp(event),
event == null ? mNaString :
- event.getParkingBrakeData().isEngaged));
+ event.getParkingBrakeData(null).isEngaged));
break;
case CarSensorManager.SENSOR_TYPE_GEAR:
summary.add(getContext().getString(R.string.sensor_gear,
getTimestamp(event),
- event == null ? mNaString : event.getGearData().gear));
+ event == null ? mNaString : event.getGearData(null).gear));
break;
case CarSensorManager.SENSOR_TYPE_NIGHT:
summary.add(getContext().getString(R.string.sensor_night,
getTimestamp(event),
- event == null ? mNaString : event.getNightData().isNightMode));
- break;
- case CarSensorManager.SENSOR_TYPE_LOCATION:
- summary.add(getLocationString(event));
- break;
- case CarSensorManager.SENSOR_TYPE_DRIVING_STATUS:
- String drivingStatus = mNaString;
- String binDrivingStatus = mNaString;
- if (event != null) {
- CarSensorEvent.DrivingStatusData drivingStatusData =
- event.getDrivingStatusData();
- drivingStatus = String.valueOf(drivingStatusData.status);
- binDrivingStatus = Integer.toBinaryString(drivingStatusData.status);
- }
- summary.add(getContext().getString(R.string.sensor_driving_status,
- getTimestamp(event), drivingStatus, binDrivingStatus));
+ event == null ? mNaString : event.getNightData(null).isNightMode));
break;
case CarSensorManager.SENSOR_TYPE_ENVIRONMENT:
String temperature = mNaString;
String pressure = mNaString;
if (event != null) {
- CarSensorEvent.EnvironmentData env = event.getEnvironmentData();
+ CarSensorEvent.EnvironmentData env = event.getEnvironmentData(null);
temperature = Float.isNaN(env.temperature) ? temperature :
String.valueOf(env.temperature);
pressure = Float.isNaN(env.pressure) ? pressure :
@@ -256,19 +236,10 @@
summary.add(getContext().getString(R.string.sensor_environment,
getTimestamp(event), temperature, pressure));
break;
- case CarSensorManager.SENSOR_TYPE_ACCELEROMETER:
- summary.add(getAccelerometerString(event));
- break;
- case CarSensorManager.SENSOR_TYPE_GPS_SATELLITE:
- summary.add(getGpsSatelliteString(event));
- break;
- case CarSensorManager.SENSOR_TYPE_GYROSCOPE:
- summary.add(getGyroscopeString(event));
- break;
case CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE:
if(event != null) {
CarSensorEvent.CarWheelTickDistanceData d =
- event.getCarWheelTickDistanceData();
+ event.getCarWheelTickDistanceData(null);
summary.add(getContext().getString(R.string.sensor_wheel_ticks,
getTimestamp(event), d.sensorResetCount, d.frontLeftWheelDistanceMm,
d.frontRightWheelDistanceMm, d.rearLeftWheelDistanceMm,
@@ -295,14 +266,15 @@
case CarSensorManager.SENSOR_TYPE_ABS_ACTIVE:
summary.add(getContext().getString(R.string.sensor_abs_is_active,
getTimestamp(event), event == null ? mNaString :
- event.getCarAbsActiveData().absIsActive));
+ event.getCarAbsActiveData(null).absIsActive));
break;
case CarSensorManager.SENSOR_TYPE_TRACTION_CONTROL_ACTIVE:
summary.add(
getContext().getString(R.string.sensor_traction_control_is_active,
getTimestamp(event), event == null ? mNaString :
- event.getCarTractionControlActiveData().tractionControlIsActive));
+ event.getCarTractionControlActiveData(null)
+ .tractionControlIsActive));
break;
case CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL:
summary.add(getEvBatteryLevel(event));
@@ -318,7 +290,7 @@
break;
default:
// Should never happen.
- Log.w(TAG, "Unrecognized event type: " + i);
+ Log.w(TAG, "Unrecognized event type: " + toHexString(i));
}
}
summaryString = TextUtils.join("\n", summary);
@@ -338,93 +310,10 @@
return mDateFormat.format(new Date(event.timestamp / (1000L * 1000L)));
}
- private String getCompassString(CarSensorEvent event) {
- String bear = mNaString;
- String pitch = mNaString;
- String roll = mNaString;
- if (event != null) {
- CarSensorEvent.CompassData compass = event.getCompassData();
- bear = Float.isNaN(compass.bearing) ? bear : String.valueOf(compass.bearing);
- pitch = Float.isNaN(compass.pitch) ? pitch : String.valueOf(compass.pitch);
- roll = Float.isNaN(compass.roll) ? roll : String.valueOf(compass.roll);
- }
- return getContext().getString(R.string.sensor_compass,
- getTimestamp(event), bear, pitch, roll);
- }
-
- private String getGyroscopeString(CarSensorEvent event) {
- String x = mNaString;
- String y = mNaString;
- String z = mNaString;
- if (event != null) {
- CarSensorEvent.GyroscopeData gyro = event.getGyroscopeData();
- x = Float.isNaN(gyro.x) ? x : String.valueOf(gyro.x);
- y = Float.isNaN(gyro.y) ? y : String.valueOf(gyro.y);
- z = Float.isNaN(gyro.z) ? z : String.valueOf(gyro.z);
- }
- return getContext().getString(R.string.sensor_gyroscope,
- getTimestamp(event), x, y, z);
- }
-
- private String getAccelerometerString(CarSensorEvent event) {
- String x = mNaString;
- String y = mNaString;
- String z = mNaString;
- if (event != null) {
- CarSensorEvent.AccelerometerData gyro = event.getAccelerometerData();
- x = Float.isNaN(gyro.x) ? x : String.valueOf(gyro.x);
- y = Float.isNaN(gyro.y) ? y : String.valueOf(gyro.y);
- z = Float.isNaN(gyro.z) ? z : String.valueOf(gyro.z);
- }
- return getContext().getString(R.string.sensor_accelerometer,
- getTimestamp(event), x, y, z);
- }
-
- private String getLocationString(CarSensorEvent event) {
- String lat = mNaString;
- String lon = mNaString;
- String accuracy = mNaString;
- String alt = mNaString;
- String speed = mNaString;
- String bearing = mNaString;
- if (event != null) {
- Location location = event.getLocation(null);
- lat = String.valueOf(location.getLatitude());
- lon = String.valueOf(location.getLongitude());
- accuracy = location.hasAccuracy() ? String.valueOf(location.getAccuracy()) : accuracy;
- alt = location.hasAltitude() ? String.valueOf(location.getAltitude()) : alt;
- speed = location.hasSpeed() ? String.valueOf(location.getSpeed()) : speed;
- bearing = location.hasBearing() ? String.valueOf(location.getBearing()) : bearing;
- }
- return getContext().getString(R.string.sensor_location,
- getTimestamp(event), lat, lon, accuracy, alt, speed, bearing);
- }
-
- private String getGpsSatelliteString(CarSensorEvent event) {
- String inUse = mNaString;
- String inView = mNaString;
- String perSattelite = "";
- if (event != null) {
- CarSensorEvent.GpsSatelliteData gpsData = event.getGpsSatelliteData(true);
- inUse = gpsData.numberInUse != -1 ? String.valueOf(gpsData.numberInUse) : inUse;
- inView = gpsData.numberInView != -1 ? String.valueOf(gpsData.numberInView) : inView;
- List<String> perSatteliteList = new ArrayList<>();
- int num = gpsData.usedInFix.length;
- for (int i=0; i<num; i++) {
- perSatteliteList.add(getContext().getString(R.string.sensor_single_gps_satellite,
- i+1, gpsData.usedInFix[i], gpsData.prn[i], gpsData.snr[i],
- gpsData.azimuth[i], gpsData.elevation[i]));
- }
- perSattelite = TextUtils.join(", ", perSatteliteList);
- }
- return getContext().getString(R.string.sensor_gps,
- getTimestamp(event), inView, inUse, perSattelite);
- }
-
private String getFuelLevel(CarSensorEvent event) {
String fuelLevel = mNaString;
if(event != null) {
- fuelLevel = String.valueOf(event.getFuelLevelData().level);
+ fuelLevel = String.valueOf(event.getFuelLevelData(null).level);
}
return getContext().getString(R.string.sensor_fuel_level, getTimestamp(event), fuelLevel);
}
@@ -432,7 +321,7 @@
private String getFuelDoorOpen(CarSensorEvent event) {
String fuelDoorOpen = mNaString;
if(event != null) {
- fuelDoorOpen = String.valueOf(event.getCarFuelDoorOpenData().fuelDoorIsOpen);
+ fuelDoorOpen = String.valueOf(event.getCarFuelDoorOpenData(null).fuelDoorIsOpen);
}
return getContext().getString(R.string.sensor_fuel_door_open, getTimestamp(event),
fuelDoorOpen);
@@ -441,7 +330,7 @@
private String getEvBatteryLevel(CarSensorEvent event) {
String evBatteryLevel = mNaString;
if(event != null) {
- evBatteryLevel = String.valueOf(event.getCarEvBatteryLevelData().evBatteryLevel);
+ evBatteryLevel = String.valueOf(event.getCarEvBatteryLevelData(null).evBatteryLevel);
}
return getContext().getString(R.string.sensor_ev_battery_level, getTimestamp(event),
evBatteryLevel);
@@ -451,7 +340,7 @@
String evChargePortOpen = mNaString;
if(event != null) {
evChargePortOpen = String.valueOf(
- event.getCarEvChargePortOpenData().evChargePortIsOpen);
+ event.getCarEvChargePortOpenData(null).evChargePortIsOpen);
}
return getContext().getString(R.string.sensor_ev_charge_port_is_open, getTimestamp(event),
evChargePortOpen);
@@ -461,7 +350,7 @@
String evChargePortConnected = mNaString;
if(event != null) {
evChargePortConnected = String.valueOf(
- event.getCarEvChargePortConnectedData().evChargePortIsConnected);
+ event.getCarEvChargePortConnectedData(null).evChargePortIsConnected);
}
return getContext().getString(R.string.sensor_ev_charge_port_is_connected,
getTimestamp(event), evChargePortConnected);
@@ -470,7 +359,7 @@
private String getEvChargeRate(CarSensorEvent event) {
String evChargeRate = mNaString;
if(event != null) {
- evChargeRate = String.valueOf(event.getCarEvBatteryChargeRateData().evChargeRate);
+ evChargeRate = String.valueOf(event.getCarEvBatteryChargeRateData(null).evChargeRate);
}
return getContext().getString(R.string.sensor_ev_charge_rate, getTimestamp(event),
evChargeRate);
diff --git a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
index e91abb7..ba82e6f 100644
--- a/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
+++ b/tests/UxRestrictionsSample/src/com/google/android/car/uxr/sample/MainActivity.java
@@ -147,7 +147,7 @@
mDrvStatus.requestLayout();
}
- private CarUxRestrictionsManager.onUxRestrictionsChangedListener mUxRChangeListener =
+ private CarUxRestrictionsManager.OnUxRestrictionsChangedListener mUxRChangeListener =
this::updateUxRText;
diff --git a/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java b/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
index 8e86b60..67725b9 100644
--- a/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarCabinManagerTest.java
@@ -142,7 +142,9 @@
@Test
public void testEvent() throws Exception {
mCarCabinManager.registerCallback(new EventListener());
-
+ // Wait for two events generated on registration
+ assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+ assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
// Inject a boolean event and wait for its callback in onPropertySet.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.DOOR_LOCK)
.setAreaId(VehicleAreaDoor.ROW_1_LEFT)
@@ -163,7 +165,6 @@
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.addIntValue(75)
.build();
-
assertEquals(0, mAvailable.availablePermits());
getMockedVehicleHal().injectEvent(v);
@@ -191,6 +192,15 @@
@Override
public synchronized void onPropertySubscribe(int property, float sampleRate) {
Log.d(TAG, "onPropertySubscribe property " + property + " sampleRate " + sampleRate);
+ if (mMap.get(property) == null) {
+ Log.d(TAG, "onPropertySubscribe add dummy property: " + property);
+ VehiclePropValue dummyValue = VehiclePropValueBuilder.newBuilder(property)
+ .setAreaId(VehicleAreaDoor.ROW_1_LEFT)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .addIntValue(1)
+ .build();
+ mMap.put(property, dummyValue);
+ }
}
@Override
diff --git a/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java b/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
index 38fd4b1..31ed4b2 100644
--- a/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
+++ b/tests/carservice_test/src/com/android/car/CarDrivingRestrictionsTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.car.Car;
@@ -82,13 +83,8 @@
mCarUxRManager.registerListener(listener);
// With no gear value available, driving state should be unknown
listener.reset();
- getMockedVehicleHal().injectEvent(
- VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
- .addFloatValue(0.0f)
- .setTimestamp(SystemClock.elapsedRealtimeNanos())
- .build());
-
// Test Parked state and corresponding restrictions based on car_ux_restrictions_map.xml
+ Log.d(TAG, "Injecting gear park");
getMockedVehicleHal().injectEvent(
VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
.addIntValue(VehicleGear.GEAR_PARK)
@@ -98,9 +94,17 @@
assertNotNull(drivingEvent);
assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_PARKED);
+ Log.d(TAG, "Injecting speed 0");
+ getMockedVehicleHal().injectEvent(
+ VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
+ .addFloatValue(0.0f)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build());
+
// Switch gear to drive. Driving state changes to Idling but the UX restrictions don't
// change between parked and idling.
listener.reset();
+ Log.d(TAG, "Injecting gear drive");
getMockedVehicleHal().injectEvent(
VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
.addIntValue(VehicleGear.GEAR_DRIVE)
@@ -112,6 +116,7 @@
// Test Moving state and corresponding restrictions based on car_ux_restrictions_map.xml
listener.reset();
+ Log.d(TAG, "Injecting speed 30");
getMockedVehicleHal().injectEvent(
VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
.addFloatValue(30.0f)
@@ -128,6 +133,7 @@
// Test Idling state and corresponding restrictions based on car_ux_restrictions_map.xml
listener.reset();
+ Log.d(TAG, "Injecting speed 0");
getMockedVehicleHal().injectEvent(
VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
.addFloatValue(0.0f)
@@ -142,6 +148,83 @@
assertThat(restrictions.getActiveRestrictions())
.isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_BASELINE);
+ // Apply Parking brake. Supported gears is not provided in this test and hence
+ // Automatic transmission should be assumed and hence parking brake state should not
+ // make a difference to the driving state.
+ listener.reset();
+ Log.d(TAG, "Injecting parking brake on");
+ getMockedVehicleHal().injectEvent(
+ VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
+ .setBooleanValue(true)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build());
+ drivingEvent = listener.waitForDrivingStateChange();
+ assertNull(drivingEvent);
+
+ mCarDrivingStateManager.unregisterListener();
+ mCarUxRManager.unregisterListener();
+ }
+
+ @Test
+ public void testDrivingStateChangeForMalformedInputs()
+ throws CarNotConnectedException, InterruptedException {
+ CarDrivingStateEvent drivingEvent;
+ CarUxRestrictions restrictions;
+ DrivingStateListener listener = new DrivingStateListener();
+ mCarDrivingStateManager.registerListener(listener);
+ mCarUxRManager.registerListener(listener);
+
+ // Start with gear = park and speed = 0 to begin with a known state.
+ listener.reset();
+ Log.d(TAG, "Injecting gear park");
+ getMockedVehicleHal().injectEvent(
+ VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
+ .addIntValue(VehicleGear.GEAR_PARK)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build());
+ drivingEvent = listener.waitForDrivingStateChange();
+ assertNotNull(drivingEvent);
+ assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_PARKED);
+
+ Log.d(TAG, "Injecting speed 0");
+ getMockedVehicleHal().injectEvent(
+ VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
+ .addFloatValue(0.0f)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build());
+
+ // Inject an invalid gear. Since speed is still valid, idling will be the expected
+ // driving state
+ listener.reset();
+ Log.d(TAG, "Injecting gear -1");
+ getMockedVehicleHal().injectEvent(
+ VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
+ .addIntValue(-1)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build());
+ drivingEvent = listener.waitForDrivingStateChange();
+ assertNotNull(drivingEvent);
+ assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_IDLING);
+
+ // Now, send in an invalid speed value as well, now the driving state will be unknown and
+ // the UX restrictions will change to fully restricted.
+ listener.reset();
+ Log.d(TAG, "Injecting speed -1");
+ getMockedVehicleHal().injectEvent(
+ VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
+ .addFloatValue(-1.0f)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build());
+ drivingEvent = listener.waitForDrivingStateChange();
+ assertNotNull(drivingEvent);
+ assertThat(drivingEvent.eventValue).isEqualTo(CarDrivingStateEvent.DRIVING_STATE_UNKNOWN);
+ restrictions = listener.waitForUxRestrictionsChange();
+ assertNotNull(restrictions);
+ assertTrue(restrictions.isRequiresDistractionOptimization());
+ assertThat(restrictions.getActiveRestrictions())
+ .isEqualTo(CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED);
+ mCarDrivingStateManager.unregisterListener();
+ mCarUxRManager.unregisterListener();
}
/**
@@ -149,7 +232,7 @@
*/
private class DrivingStateListener implements
CarDrivingStateManager.CarDrivingStateEventListener,
- CarUxRestrictionsManager.onUxRestrictionsChangedListener {
+ CarUxRestrictionsManager.OnUxRestrictionsChangedListener {
private final Object mDrivingStateLock = new Object();
@GuardedBy("mDrivingStateLock")
private CarDrivingStateEvent mLastEvent = null;
diff --git a/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java b/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
index 6029637..1493fe9 100644
--- a/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarHvacManagerTest.java
@@ -142,7 +142,7 @@
MutableInt propertyIdReceived = new MutableInt(0);
MutableInt areaIdReceived = new MutableInt(0);
- mCarHvacManager.registerCallback(new CarHvacEventCallback() {
+ mCarHvacManager.registerCallback(new CarHvacEventCallback() {
@Override
public void onChangeEvent(CarPropertyValue value) {
@@ -166,6 +166,11 @@
@Test
public void testEvent() throws Exception {
mCarHvacManager.registerCallback(new EventListener());
+ // Wait for events generated on registration
+ assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+ assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+ assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
+ assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
// Inject a boolean event and wait for its callback in onPropertySet.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_DEFROSTER)
@@ -225,6 +230,16 @@
@Override
public synchronized void onPropertySubscribe(int property, float sampleRate) {
Log.d(TAG, "onPropertySubscribe property " + property + " sampleRate " + sampleRate);
+ if (mMap.get(property) == null) {
+ Log.d(TAG, "onPropertySubscribe add dummy property: " + property);
+ VehiclePropValue dummyValue = VehiclePropValueBuilder.newBuilder(property)
+ .setAreaId(0)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .addIntValue(1)
+ .addFloatValue(1)
+ .build();
+ mMap.put(property, dummyValue);
+ }
}
@Override
diff --git a/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java b/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
index 7f58063..e5b3566 100644
--- a/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/CarSensorManagerTest.java
@@ -154,6 +154,8 @@
CarSensorEvent event;
CarSensorEvent.NightData data = null;
+ // Clear event generated by registerListener()
+ listener.waitForSensorChange();
listener.reset();
// Set the value TRUE and wait for the event to arrive
@@ -161,7 +163,7 @@
VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
.setBooleanValue(true)
.setTimestamp(1L)
- .build());
+ .build(), true);
assertTrue(listener.waitForSensorChange(1L));
// Ensure we got the expected event
@@ -185,7 +187,7 @@
VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
.setTimestamp(1001)
.setBooleanValue(false)
- .build());
+ .build(), true);
assertTrue(listener.waitForSensorChange(1001));
// Ensure we got the expected event
@@ -211,7 +213,7 @@
.setTimestamp(2001)
.setBooleanValue(true)
.build();
- getMockedVehicleHal().injectEvent(value);
+ getMockedVehicleHal().injectEvent(value, true);
// Ensure we did not get a callback (should timeout)
Log.i(TAG, "waiting for unexpected callback -- should timeout.");
@@ -238,7 +240,8 @@
SensorListener listener = new SensorListener();
mCarSensorManager.registerListener(listener, CarSensorManager.SENSOR_TYPE_IGNITION_STATE,
CarSensorManager.SENSOR_RATE_NORMAL);
-
+ // Clear event generated by registerListener()
+ listener.waitForSensorChange();
// Mapping of HAL -> Manager ignition states.
int[] ignitionStates = new int[] {
@@ -265,7 +268,7 @@
VehiclePropValueBuilder.newBuilder(VehicleProperty.IGNITION_STATE)
.addIntValue(halIgnitionState)
.setTimestamp(time)
- .build());
+ .build(), true);
assertTrue(listener.waitForSensorChange(time));
CarSensorEvent eventReceived = listener.getLastEvent();
@@ -274,29 +277,15 @@
}
@Test
- public void testIgnitionEvents_Bad() throws Exception {
- SensorListener listener = new SensorListener();
- mCarSensorManager.registerListener(listener, CarSensorManager.SENSOR_TYPE_IGNITION_STATE,
- CarSensorManager.SENSOR_RATE_NORMAL);
-
- listener.reset();
- long time = SystemClock.elapsedRealtimeNanos();
- getMockedVehicleHal().injectEvent(
- VehiclePropValueBuilder.newBuilder(VehicleProperty.IGNITION_STATE)
- .addIntValue(0xdeadbeef)
- .setTimestamp(time)
- .build());
-
- // Make sure invalid events are never propagated to clients.
- assertFalse(listener.waitForSensorChange(time));
- }
-
- @Test
public void testGear() throws Exception {
SensorListener listener = new SensorListener();
+
mCarSensorManager.registerListener(listener, CarSensorManager.SENSOR_TYPE_GEAR,
CarSensorManager.SENSOR_RATE_NORMAL);
+ // Clear event generated by registerListener()
+ listener.waitForSensorChange();
+
// Mapping of HAL -> Manager gear selection states.
int[] gears = new int[] {
VehicleGear.GEAR_PARK, CarSensorEvent.GEAR_PARK,
@@ -317,19 +306,6 @@
for (int i = 0; i < gears.length; i += 2) {
injectGearEventAndAssert(listener, gears[i], gears[i + 1]);
}
-
- // invalid input should not be forwarded
- long time = SystemClock.elapsedRealtimeNanos();
- getMockedVehicleHal().injectEvent(
- VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
- .addIntValue(0xdeadbeef)
- .setTimestamp(time)
- .build());
- assertFalse(listener.waitForSensorChange(time));
- CarSensorEvent event = mCarSensorManager.getLatestSensorEvent(
- CarSensorManager.SENSOR_TYPE_GEAR);
- assertNotNull(event); // Still holds an old event.
- assertEquals(CarSensorEvent.GEAR_NINTH, event.intValues[0]);
}
private void injectGearEventAndAssert(SensorListener listener, int halValue,
@@ -340,7 +316,7 @@
VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
.addIntValue(halValue)
.setTimestamp(time)
- .build());
+ .build(), true);
assertTrue(listener.waitForSensorChange(time));
CarSensorEvent event = mCarSensorManager.getLatestSensorEvent(
CarSensorManager.SENSOR_TYPE_GEAR);
@@ -375,17 +351,20 @@
VehiclePropValue value;
CarSensorEvent event;
+ // Clear event generated by registerListener()
+ listener1.waitForSensorChange();
+ listener2.waitForSensorChange();
+ listener3.waitForSensorChange();
listener1.reset();
listener2.reset();
listener3.reset();
// Set the value TRUE and wait for the event to arrive
value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
- .setTimestamp(42L)
- .setBooleanValue(true)
- .build();
-
- getMockedVehicleHal().injectEvent(value);
+ .setTimestamp(42L)
+ .setBooleanValue(true)
+ .build();
+ getMockedVehicleHal().injectEvent(value, true);
assertTrue(listener1.waitForSensorChange(42L));
assertTrue(listener2.waitForSensorChange(42L));
@@ -423,7 +402,7 @@
.setTimestamp(1001)
.setBooleanValue(false)
.build();
- getMockedVehicleHal().injectEvent(value);
+ getMockedVehicleHal().injectEvent(value, true);
assertTrue(listener1.waitForSensorChange(1001));
assertTrue(listener2.waitForSensorChange(1001));
assertTrue(listener3.waitForSensorChange(1001));
@@ -443,7 +422,6 @@
assertFalse("Unexpected value", data.isNightMode);
data = listener3.getLastEvent().getNightData(data);
- listener3.reset();
assertEquals("Unexpected event timestamp", 1001, data.timestamp);
assertFalse("Unexpected value", data.isNightMode);
@@ -453,13 +431,19 @@
assertFalse(data.isNightMode);
Log.d(TAG, "Unregistering listener3");
+ listener1.reset();
+ listener2.reset();
+ listener3.reset();
mCarSensorManager.unregisterListener(listener3);
-
Log.d(TAG, "Rate changed - expect sensor restart and change event sent.");
+ value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
+ .setTimestamp(1002)
+ .setBooleanValue(false)
+ .build();
+ getMockedVehicleHal().injectEvent(value, true);
assertTrue(listener1.waitForSensorChange());
assertTrue(listener2.waitForSensorChange());
assertFalse(listener3.waitForSensorChange());
-
listener1.reset();
listener2.reset();
listener3.reset();
@@ -468,11 +452,10 @@
.setTimestamp()
.setBooleanValue(true)
.build();
- getMockedVehicleHal().injectEvent(value);
+ getMockedVehicleHal().injectEvent(value, true);
assertTrue(listener1.waitForSensorChange());
assertTrue(listener2.waitForSensorChange());
-
listener1.reset();
listener2.reset();
@@ -481,7 +464,7 @@
assertFalse(listener3.waitForSensorChange());
Log.d(TAG, "Unregistering listener2");
- mCarSensorManager.unregisterListener(listener3);
+ mCarSensorManager.unregisterListener(listener2);
Log.d(TAG, "Rate did nor change - dont expect sensor restart and change event sent.");
assertFalse(listener1.waitForSensorChange());
diff --git a/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java b/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java
index 9f46ffe..82c9361 100644
--- a/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsHalServiceSubscriptionEventTest.java
@@ -61,7 +61,7 @@
addProperty(VehicleProperty.VEHICLE_MAP_SERVICE, mHalHandler)
.setChangeMode(VehiclePropertyChangeMode.ON_CHANGE)
.setAccess(VehiclePropertyAccess.READ_WRITE)
- .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_NONE, 0, 0);
+ .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 0, 0);
}
@Override
diff --git a/tests/carservice_test/src/com/android/car/VmsPublisherClientServiceTest.java b/tests/carservice_test/src/com/android/car/VmsPublisherClientServiceTest.java
index a9f9bef..d8cbe7b 100644
--- a/tests/carservice_test/src/com/android/car/VmsPublisherClientServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsPublisherClientServiceTest.java
@@ -68,7 +68,7 @@
addProperty(VehicleProperty.VEHICLE_MAP_SERVICE, mHalHandler)
.setChangeMode(VehiclePropertyChangeMode.ON_CHANGE)
.setAccess(VehiclePropertyAccess.READ_WRITE)
- .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_NONE, 0, 0);
+ .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 0, 0);
}
@Override
diff --git a/tests/carservice_test/src/com/android/car/VmsPublisherPermissionsTest.java b/tests/carservice_test/src/com/android/car/VmsPublisherPermissionsTest.java
index 1650f48..a4d094a 100644
--- a/tests/carservice_test/src/com/android/car/VmsPublisherPermissionsTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsPublisherPermissionsTest.java
@@ -16,7 +16,6 @@
package com.android.car;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.car.VehicleAreaType;
@@ -59,7 +58,7 @@
addProperty(VehicleProperty.VEHICLE_MAP_SERVICE, mHalHandler)
.setChangeMode(VehiclePropertyChangeMode.ON_CHANGE)
.setAccess(VehiclePropertyAccess.READ_WRITE)
- .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_NONE, 0, 0);
+ .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 0, 0);
}
@Override
diff --git a/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java b/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
index 30035b1..1ef35f7 100644
--- a/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsPublisherSubscriberTest.java
@@ -100,7 +100,7 @@
addProperty(VehicleProperty.VEHICLE_MAP_SERVICE, mHalHandler)
.setChangeMode(VehiclePropertyChangeMode.ON_CHANGE)
.setAccess(VehiclePropertyAccess.READ_WRITE)
- .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_NONE, 0, 0);
+ .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 0, 0);
}
@Override
diff --git a/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java b/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java
index 5fe153b..643ffff 100644
--- a/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/VmsSubscriberManagerTest.java
@@ -37,8 +37,13 @@
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
+
import com.android.car.vehiclehal.VehiclePropValueBuilder;
import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -46,8 +51,6 @@
import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-import org.junit.Test;
-import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@MediumTest
@@ -110,7 +113,7 @@
addProperty(VehicleProperty.VEHICLE_MAP_SERVICE, mHalHandler)
.setChangeMode(VehiclePropertyChangeMode.ON_CHANGE)
.setAccess(VehiclePropertyAccess.READ_WRITE)
- .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_NONE, 0, 0);
+ .addAreaConfig(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 0, 0);
}
@Override
@@ -132,7 +135,7 @@
// Inject a value and wait for its callback in TestClientCallback.onVmsMessageReceived.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
v.value.int32Values.add(VmsMessageType.DATA); // MessageType
@@ -162,7 +165,7 @@
// Inject a value and wait for its callback in TestClientCallback.onVmsMessageReceived.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
v.value.int32Values.add(VmsMessageType.DATA); // MessageType
@@ -190,7 +193,7 @@
// Inject a value and wait for its callback in TestClientCallback.onVmsMessageReceived.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
v.value.int32Values.add(VmsMessageType.DATA); // MessageType
@@ -221,7 +224,7 @@
// Inject a value and wait for its callback in TestClientCallback.onVmsMessageReceived.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
v.value.int32Values.add(VmsMessageType.DATA); // MessageType
@@ -248,7 +251,7 @@
// Inject a value and wait for its callback in TestClientCallback.onVmsMessageReceived.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
v.value.int32Values.add(VmsMessageType.DATA); // MessageType
@@ -276,7 +279,7 @@
// Inject a value and wait for its callback in TestClientCallback.onVmsMessageReceived.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
v.value.int32Values.add(VmsMessageType.DATA); // MessageType
@@ -303,7 +306,7 @@
// Inject a value and wait for its callback in TestClientCallback.onVmsMessageReceived.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
v.value.int32Values.add(VmsMessageType.DATA); // MessageType
@@ -332,7 +335,7 @@
// Inject a value and wait for its callback in TestClientCallback.onLayersAvailabilityChanged.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
//
@@ -378,7 +381,7 @@
// Inject a value and wait for its callback in TestClientCallback.onLayersAvailabilityChanged.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
//
@@ -425,7 +428,7 @@
// Inject a value and wait for its callback in TestClientCallback.onLayersAvailabilityChanged.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
//
@@ -465,7 +468,7 @@
// Inject a value and wait for its callback in TestClientCallback.onLayersAvailabilityChanged.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
//
@@ -559,7 +562,7 @@
// Inject a value and wait for its callback in TestClientCallback.onLayersAvailabilityChanged.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
//
@@ -637,7 +640,7 @@
// Inject a value and wait for its callback in TestClientCallback.onLayersAvailabilityChanged.
VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
- .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)
.setTimestamp(SystemClock.elapsedRealtimeNanos())
.build();
//
diff --git a/tests/carservice_unit_test/src/com/android/car/BluetoothAutoConnectPolicyTest.java b/tests/carservice_unit_test/src/com/android/car/BluetoothAutoConnectPolicyTest.java
index 591b610..a180886 100644
--- a/tests/carservice_unit_test/src/com/android/car/BluetoothAutoConnectPolicyTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/BluetoothAutoConnectPolicyTest.java
@@ -50,6 +50,7 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -72,8 +73,7 @@
private Handler mMainHandler;
private Context mMockContext;
// Mock of Services that the policy interacts with
- private CarCabinService mMockCarCabinService;
- private CarSensorService mMockCarSensorService;
+ private CarPropertyService mMockCarPropertyService;
private CarUxRestrictionsManagerService mMockCarUxRService;
private CarBluetoothUserService mMockBluetoothUserService;
private PerUserCarServiceHelper mMockPerUserCarServiceHelper;
@@ -223,7 +223,9 @@
0, false);
CarPropertyEvent event = new CarPropertyEvent(
CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, value);
- mCabinEventListener.onEvent(event);
+ List<CarPropertyEvent> events = new ArrayList<>();
+ events.add(event);
+ mCabinEventListener.onEvent(events);
}
/**
@@ -231,8 +233,7 @@
*/
private void makeMockServices() {
mMockContext = mock(Context.class);
- mMockCarCabinService = mock(CarCabinService.class);
- mMockCarSensorService = mock(CarSensorService.class);
+ mMockCarPropertyService = mock(CarPropertyService.class);
mMockCarUxRService = mock(CarUxRestrictionsManagerService.class);
mMockPerUserCarServiceHelper = mock(PerUserCarServiceHelper.class);
mMockPerUserCarService = mock(ICarUserService.class);
@@ -296,7 +297,7 @@
.thenReturn(mMockBluetoothUserService);
mBluetoothDeviceConnectionPolicyTest = BluetoothDeviceConnectionPolicy.create(mMockContext,
- mMockCarCabinService, mMockCarSensorService, mMockPerUserCarServiceHelper,
+ mMockCarPropertyService, mMockPerUserCarServiceHelper,
mMockCarUxRService, mMockCarBluetoothService);
mBluetoothDeviceConnectionPolicyTest.setAllowReadWriteToSettings(false);
mBluetoothDeviceConnectionPolicyTest.init();
diff --git a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
index 11b3c5c..8ac7d9b 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarLocationServiceTest.java
@@ -26,9 +26,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.car.hardware.CarPropertyValue;
import android.car.hardware.CarSensorEvent;
import android.car.hardware.CarSensorManager;
-import android.car.hardware.ICarSensorEventListener;
+import android.car.hardware.property.CarPropertyEvent;
+import android.car.hardware.property.ICarPropertyEventListener;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -81,7 +83,7 @@
private CountDownLatch mLatch;
@Mock private Context mMockContext;
@Mock private LocationManager mMockLocationManager;
- @Mock private CarSensorService mMockCarSensorService;
+ @Mock private CarPropertyService mMockCarPropertyService;
@Mock private CarPowerManagementService mMockCarPowerManagementService;
/**
@@ -93,7 +95,7 @@
mContext = InstrumentationRegistry.getTargetContext();
mLatch = new CountDownLatch(1);
mCarLocationService = new CarLocationService(mMockContext, mMockCarPowerManagementService,
- mMockCarSensorService) {
+ mMockCarPropertyService) {
@Override
void asyncOperation(Runnable operation) {
super.asyncOperation(() -> {
@@ -147,8 +149,8 @@
assertTrue(ArrayUtils.contains(actions, Intent.ACTION_LOCKED_BOOT_COMPLETED));
assertTrue(ArrayUtils.contains(actions, LocationManager.MODE_CHANGED_ACTION));
assertTrue(ArrayUtils.contains(actions, LocationManager.GPS_ENABLED_CHANGE_ACTION));
- verify(mMockCarSensorService).registerOrUpdateSensorListener(
- eq(CarSensorManager.SENSOR_TYPE_IGNITION_STATE), eq(0), any());
+ verify(mMockCarPropertyService).registerListener(
+ eq(CarSensorManager.SENSOR_TYPE_IGNITION_STATE), eq(0.0f), any());
}
/**
@@ -158,7 +160,7 @@
public void testUnregistersEventReceivers() {
mCarLocationService.release();
verify(mMockContext).unregisterReceiver(mCarLocationService);
- verify(mMockCarSensorService).unregisterSensorListener(
+ verify(mMockCarPropertyService).unregisterListener(
eq(CarSensorManager.SENSOR_TYPE_IGNITION_STATE), any());
}
@@ -423,15 +425,17 @@
private void sendIgnitionOffEvent() throws RemoteException {
mCarLocationService.init();
- ArgumentCaptor<ICarSensorEventListener> argument =
- ArgumentCaptor.forClass(ICarSensorEventListener.class);
- verify(mMockCarSensorService).registerOrUpdateSensorListener(
- eq(CarSensorManager.SENSOR_TYPE_IGNITION_STATE), eq(0), argument.capture());
- ICarSensorEventListener carSensorEventListener = argument.getValue();
- CarSensorEvent ignitionOff = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_IGNITION_STATE,
- System.currentTimeMillis(), 0, 1, 0);
- ignitionOff.intValues[0] = CarSensorEvent.IGNITION_STATE_OFF;
- List<CarSensorEvent> events = new ArrayList<>(Arrays.asList(ignitionOff));
- carSensorEventListener.onSensorChanged(events);
+ ArgumentCaptor<ICarPropertyEventListener> argument =
+ ArgumentCaptor.forClass(ICarPropertyEventListener.class);
+ verify(mMockCarPropertyService).registerListener(
+ eq(CarSensorManager.SENSOR_TYPE_IGNITION_STATE), eq(0.0f), argument.capture());
+ ICarPropertyEventListener carPropertyEventListener = argument.getValue();
+ int intValues = CarSensorEvent.IGNITION_STATE_OFF;
+ CarPropertyValue ignitionOff = new CarPropertyValue(
+ CarSensorManager.SENSOR_TYPE_IGNITION_STATE, 0, 0,
+ System.currentTimeMillis(), intValues);
+ CarPropertyEvent event = new CarPropertyEvent(0, ignitionOff);
+ List<CarPropertyEvent> events = new ArrayList<>(Arrays.asList(event));
+ carPropertyEventListener.onEvent(events);
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java b/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java
index 3f556d5..405c014 100644
--- a/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java
+++ b/tests/carservice_unit_test/src/com/android/car/MockedPowerHalService.java
@@ -35,7 +35,7 @@
public MockedPowerHalService(boolean isPowerStateSupported, boolean isDeepSleepAllowed,
boolean isTimedWakeupAllowed) {
- super(new VehicleHal(null, null, null, null, null, null, null));
+ super(new VehicleHal(null, null, null, null));
mIsPowerStateSupported = isPowerStateSupported;
mIsDeepSleepAllowed = isDeepSleepAllowed;
mIsTimedWakeupAllowed = isTimedWakeupAllowed;
diff --git a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarHvacTest.java b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarHvacTest.java
index 3b12d87..08544bd 100644
--- a/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarHvacTest.java
+++ b/tests/vehiclehal_test/src/com/android/car/vehiclehal/test/CarHvacTest.java
@@ -20,6 +20,7 @@
import static java.lang.Integer.toHexString;
import android.car.Car;
+import android.car.hardware.CarPropertyConfig;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.hvac.CarHvacManager;
import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
@@ -58,6 +59,8 @@
// are in CONTINUOUS mode. They should be omitted when testing ON_CHANGE properties.
private static final Set<Integer> CONTINUOUS_HVAC_PROPS;
+ private Integer mNumPropEventsToSkip;
+
static {
CONTINUOUS_HVAC_PROPS = new ArraySet<>();
CONTINUOUS_HVAC_PROPS.add(VehicleProperty.ENV_OUTSIDE_TEMPERATURE);
@@ -75,7 +78,13 @@
public void onChangeEvent(CarPropertyValue carPropertyValue) {
VehiclePropValue event = Utils.fromHvacPropertyValue(carPropertyValue);
if (!CONTINUOUS_HVAC_PROPS.contains(event.prop)) {
- mVerifier.verify(Utils.fromHvacPropertyValue(carPropertyValue));
+ synchronized (mNumPropEventsToSkip) {
+ if (mNumPropEventsToSkip == 0) {
+ mVerifier.verify(Utils.fromHvacPropertyValue(carPropertyValue));
+ } else {
+ mNumPropEventsToSkip--;
+ }
+ }
}
}
@@ -85,6 +94,19 @@
}
}
+ private Integer calculateNumPropEventsToSkip(CarHvacManager hvacMgr) {
+ int numToSkip = 0;
+ try {
+ for (CarPropertyConfig c: hvacMgr.getPropertyList()) {
+ if (!CONTINUOUS_HVAC_PROPS.contains(c.getPropertyId())) {
+ numToSkip += c.getAreaCount();
+ }
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "Unhandled exception thrown: ", e);
+ }
+ return Integer.valueOf(numToSkip);
+ }
@Test
public void testHvacOperations() throws Exception {
Log.d(TAG, "Prepare HVAC test data");
@@ -93,6 +115,8 @@
Log.d(TAG, "Start listening to the HAL");
CarHvacManager hvacMgr = (CarHvacManager) mCar.getCarManager(Car.HVAC_SERVICE);
+ // Calculate number of properties to skip due to registration event
+ mNumPropEventsToSkip = calculateNumPropEventsToSkip(hvacMgr);
CarHvacEventCallback callback = new CarHvacOnChangeEventListener(verifier);
hvacMgr.registerCallback(callback);
@@ -106,7 +130,6 @@
Log.d(TAG, "Send command to VHAL to stop generation");
hvacGenerator.stop();
-
hvacMgr.unregisterCallback(callback);
assertTrue("Detected mismatched events: " + verifier.getResultString(),
diff --git a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/MockedVehicleHal.java b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/MockedVehicleHal.java
index a248269..477c2c5 100644
--- a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/MockedVehicleHal.java
+++ b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/MockedVehicleHal.java
@@ -16,11 +16,12 @@
package com.android.car.vehiclehal.test;
-import static java.lang.Integer.toHexString;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.fail;
+import static java.lang.Integer.toHexString;
+
import android.hardware.automotive.vehicle.V2_0.IVehicle;
import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
import android.hardware.automotive.vehicle.V2_0.StatusCode;
@@ -92,11 +93,20 @@
}
}
- public synchronized void injectEvent(VehiclePropValue value) {
+ public synchronized void injectEvent(VehiclePropValue value, boolean setProperty) {
List<IVehicleCallback> callbacks = mSubscribers.get(value.prop);
assertNotNull("Injecting event failed for property: " + value.prop
+ ". No listeners found", callbacks);
- for (IVehicleCallback callback : callbacks) {
+
+ if (setProperty) {
+ // Update property if requested
+ VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(value.prop);
+ if (handler != null) {
+ handler.onPropertySet(value);
+ }
+ }
+
+ for (IVehicleCallback callback: callbacks) {
try {
callback.onPropertyEvent(Lists.newArrayList(value));
} catch (RemoteException e) {
@@ -106,6 +116,10 @@
}
}
+ public synchronized void injectEvent(VehiclePropValue value) {
+ injectEvent(value, false);
+ }
+
public synchronized void injectError(int errorCode, int propertyId, int areaId) {
List<IVehicleCallback> callbacks = mSubscribers.get(propertyId);
assertNotNull("Injecting error failed for property: " + propertyId
@@ -175,6 +189,14 @@
subscribers = new ArrayList<>();
mSubscribers.put(opt.propId, subscribers);
notifyAll();
+ } else {
+ for (IVehicleCallback s : subscribers) {
+ if (callback.asBinder() == s.asBinder()) {
+ // Remove callback that was registered previously for this property
+ subscribers.remove(callback);
+ break;
+ }
+ }
}
subscribers.add(callback);
}