Create CarPropertyService and CarPropertyManager

CarPropertyService replaces Cabin, Hvac, Info, Sensor,
and VendorExtension services.

Bug: 78782959
Bug: 36649684
Bug: 68056035
Test: runtest -x packages/services/Car/tests/android_car_api_test
      runtest -x packages/services/Car/tests/carservice_unit_test
Change-Id: I69756654473fe66ef95e9e2cd4f3c1045e3ac938
Merged-In: Ic0a94805f83cc0222fb2bcf9674b6031bc050986

(cherry picked from commit fc0257133967edcb217e07e9ab942690eeaae3de)
(cherry picked from commit 0265d8348716b2971f76e697f410f4cf7128371c)
diff --git a/car-lib/api/current.txt b/car-lib/api/current.txt
index 71eb12c..8bbc15b 100644
--- a/car-lib/api/current.txt
+++ b/car-lib/api/current.txt
@@ -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
@@ -293,28 +293,27 @@
     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..38cddf7 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";
@@ -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/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..fc97c9d 100644
--- a/car-lib/src/android/car/hardware/CarSensorManager.java
+++ b/car-lib/src/android/car/hardware/CarSensorManager.java
@@ -24,28 +24,30 @@
 import android.car.CarLibLog;
 import android.car.CarManagerBase;
 import android.car.CarNotConnectedException;
+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 +55,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 +120,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 +128,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 +154,156 @@
      * 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;
+        }
 
-
-    /** @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);
+        @Override
+        public void onChangeEvent(CarPropertyValue value) {
+            synchronized (this) {
+                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) {
+        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,15 +313,21 @@
      */
     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];
     }
 
+    private List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException {
+        return mCarPropertyMgr.getPropertyList(mSensorConfigIds);
+    }
     /**
      * Tells if given sensor is supported or not.
      * @param sensorType
@@ -325,18 +360,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 +391,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 +415,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 +429,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 +445,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 +462,25 @@
         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 CarSensorEvent createCarSensorEvent(CarPropertyValue propertyValue) {
+        Class<?> actualClass = propertyValue.getValue().getClass();
+        CarSensorEvent event = null;
+        if (actualClass == Float.class) {
+            event = new CarSensorEvent(propertyValue.getPropertyId(),
+                    propertyValue.getTimestamp(), 1, 0, 0);
+            event.floatValues[0] = (float) propertyValue.getValue();
+        } else if (actualClass == Integer.class) {
+            event = new CarSensorEvent(propertyValue.getPropertyId(),
+                    propertyValue.getTimestamp(), 0, 1, 0);
+            event.intValues[0] = (int) propertyValue.getValue();
+        } else if (actualClass == Boolean.class) {
+            event = new CarSensorEvent(propertyValue.getPropertyId(),
+                    propertyValue.getTimestamp(), 0, 1, 0);
+            event.intValues[0] = (boolean) propertyValue.getValue() ? 1 : 0;
+        } else {
+            // TODO: handle int64_vec and mixed type
         }
-    }
-
-    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);
-                }
-            });
-        }
+        return event;
     }
 
     /**
@@ -558,15 +495,43 @@
      * @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;
+            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..ce2831c 100644
--- a/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
+++ b/car-lib/src/android/car/hardware/CarVendorExtensionManager.java
@@ -20,14 +20,15 @@
 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.Collection;
 import java.util.List;
 
 /**
@@ -42,12 +43,60 @@
 
     private final static boolean DBG = false;
     private final static String TAG = CarVendorExtensionManager.class.getSimpleName();
-    private final CarPropertyManagerBase mPropertyManager;
+    private final CarPropertyManager mPropertyManager;
+    private CarPropertyEventListenerToBase mListenerToBase = null;
 
     @GuardedBy("mLock")
-    private ArraySet<CarVendorExtensionCallback> mCallbacks;
+    private final ArraySet<CarVendorExtensionCallback> mCallbacks = new ArraySet<>();
     private final Object mLock = new Object();
 
+    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);
+            }
+        }
+    }
+
+    private void handleOnChangeEvent(CarPropertyValue value) {
+        Collection<CarVendorExtensionCallback> callbacks;
+        synchronized (this) {
+            callbacks = new ArraySet<>(mCallbacks);
+        }
+        for (CarVendorExtensionCallback l: callbacks) {
+            l.onChangeEvent(value);
+        }
+    }
+
+    private void handleOnErrorEvent(int propertyId, int zone) {
+        Collection<CarVendorExtensionCallback> listeners;
+        synchronized (this) {
+            listeners = new ArraySet<>(mCallbacks);
+        }
+        if (!listeners.isEmpty()) {
+            for (CarVendorExtensionCallback l: listeners) {
+                l.onErrorEvent(propertyId, zone);
+            }
+        }
+    }
+
     /**
      * Creates an instance of the {@link CarVendorExtensionManager}.
      *
@@ -55,7 +104,7 @@
      * @hide
      */
     public CarVendorExtensionManager(IBinder service, Handler handler) {
-        mPropertyManager = new CarPropertyManagerBase(service, handler, DBG, TAG);
+        mPropertyManager = new CarPropertyManager(service, handler, DBG, TAG);
     }
 
     /**
@@ -77,43 +126,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;
+            }
         }
     }
 
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..d59ce58
--- /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.CarRatedListeners2;
+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 CarRatedListeners2<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/com/android/car/internal/CarRatedListeners2.java b/car-lib/src/com/android/car/internal/CarRatedListeners2.java
new file mode 100644
index 0000000..8708cd4
--- /dev/null
+++ b/car-lib/src/com/android/car/internal/CarRatedListeners2.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ * @param <EventListenerType>
+ * @hide
+ */
+public class CarRatedListeners2<EventListenerType> {
+    private final Map<EventListenerType, Float> mListenersToRate = new HashMap<>(4);
+
+    private float mUpdateRate;
+
+    protected long mLastUpdateTime = -1;
+
+    protected CarRatedListeners2(float rate) {
+        mUpdateRate = rate;
+    }
+
+    /** Check listener */
+    public boolean contains(EventListenerType 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(EventListenerType 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(EventListenerType 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<EventListenerType> 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));
     }
+
 }