Merge "Change CarPropertyListeners to be notified by rate."
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index ac151b8..74c5bc0 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -66,6 +66,12 @@
         void onErrorEvent(int propId, int zone);
     }
 
+    /** Read sensor in default normal rate set for each sensors. */
+    public static final float SENSOR_RATE_NORMAL = 1; // 1 hertz
+    public static final float SENSOR_RATE_UI = 5;
+    public static final float SENSOR_RATE_FAST = 10;
+    public static final float SENSOR_RATE_FASTEST = 100;
+
     /**
      * Get an instance of the CarPropertyManager.
      */
@@ -424,7 +430,9 @@
             listeners.forEach(new Consumer<CarPropertyEventListener>() {
                 @Override
                 public void accept(CarPropertyEventListener listener) {
-                    listener.onChangeEvent(event.getCarPropertyValue());
+                    if (needUpdate(listener, updateTime)) {
+                        listener.onChangeEvent(event.getCarPropertyValue());
+                    }
                 }
             });
         }
diff --git a/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java b/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
index c59a2fa..3cc4aed 100644
--- a/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
+++ b/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
@@ -31,6 +31,8 @@
 public class CarRatedFloatListeners<T> {
     private final Map<T, Float> mListenersToRate = new HashMap<>(4);
 
+    private final Map<T, Long> mListenersUpdateTime = new HashMap<>(4);
+
     private float mUpdateRate;
 
     protected long mLastUpdateTime = -1;
@@ -56,6 +58,7 @@
      */
     public boolean remove(T listener) {
         mListenersToRate.remove(listener);
+        mListenersUpdateTime.remove(listener);
         if (mListenersToRate.isEmpty()) {
             return false;
         }
@@ -80,11 +83,39 @@
      */
     public boolean addAndUpdateRate(T listener, float updateRate) {
         Float oldUpdateRate = mListenersToRate.put(listener, updateRate);
+        mListenersUpdateTime.put(listener, 0L);
         if (mUpdateRate < updateRate) {
             mUpdateRate = updateRate;
             return true;
         } else if (oldUpdateRate != null && oldUpdateRate == mUpdateRate) {
-            mUpdateRate = Collections.max(mListenersToRate.values());
+            Float newUpdateRate = Collections.max(mListenersToRate.values());
+            if (newUpdateRate != mUpdateRate) {
+                mUpdateRate = newUpdateRate;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check whether listener should be notified by events.
+     *
+     * @param listener
+     * @param eventTimeStamp
+     * @return true if listener need to be notified.
+     */
+    public boolean needUpdate(T listener, long eventTimeStamp) {
+        Long nextUpdateTime = mListenersUpdateTime.get(listener);
+        Float updateRate = mListenersToRate.get(listener);
+        /** Update ON_CHANGE property. */
+        if (updateRate == 0) {
+            return true;
+        }
+        if (nextUpdateTime <= eventTimeStamp) {
+            Float cycle = 1000 / updateRate;
+            nextUpdateTime = eventTimeStamp + cycle.longValue();
+            mListenersUpdateTime.put(listener, nextUpdateTime);
+            return true;
         }
         return false;
     }