Merge "Add maximum and average sample rates in KitchenSyn app." into sc-dev
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/custom_spinner_dropdown_item.xml b/tests/EmbeddedKitchenSinkApp/res/layout/custom_spinner_dropdown_item.xml
new file mode 100644
index 0000000..4bc954d
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/custom_spinner_dropdown_item.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:id="@android:id/text1"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:gravity="right" />
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/property_list_item.xml b/tests/EmbeddedKitchenSinkApp/res/layout/property_list_item.xml
index f8051ee..e550d45 100644
--- a/tests/EmbeddedKitchenSinkApp/res/layout/property_list_item.xml
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/property_list_item.xml
@@ -15,8 +15,8 @@
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
 
     <TextView
         android:id="@+id/tvPropertyName"
@@ -25,14 +25,13 @@
         android:layout_centerVertical="true"
         android:layout_alignParentLeft="true"
         android:paddingLeft="8dp"
-        android:textSize="@dimen/propertyTextSize" />
+        android:textSize="@dimen/propertyTextSize"/>
 
-    <ToggleButton
-        android:id="@+id/tbRegisterPropertyBtn"
+    <Spinner
+        android:id="@+id/tbRegisterPropertySpinner"
+        android:layout_alignParentRight="true"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignParentRight="true"
-        android:layout_centerVertical="true"
-        android:text="@string/property_register" />
+        android:gravity="right"/>
 
 </RelativeLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
index 92ed8c5..d81ea8c 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyListAdapter.java
@@ -18,36 +18,50 @@
 
 import static java.lang.Integer.toHexString;
 
+import android.car.VehiclePropertyIds;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.property.CarPropertyManager;
 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
 import android.content.Context;
 import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.SparseLongArray;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
 import android.widget.BaseAdapter;
 import android.widget.ListAdapter;
 import android.widget.ScrollView;
+import android.widget.Spinner;
 import android.widget.TextView;
-import android.widget.ToggleButton;
 
 import com.google.android.car.kitchensink.R;
 
 import java.util.List;
 
 class PropertyListAdapter extends BaseAdapter implements ListAdapter {
-    private static final int DEFAULT_RATE = 1;
+    private static final float DEFAULT_RATE = 1f;
     private static final String TAG = "PropertyListAdapter";
+    private static final String OFF = "Off";
+    private static final String ON = "On";
+    private static final String MAX_SAMPLE_RATE = "Maximum sample rate";
+    private static final String AVG_SAMPLE_RATE = "Average sample rate";
+    private static final String[] DROP_MENU_FOR_CONTINUOUS =
+            new String[]{OFF, MAX_SAMPLE_RATE, AVG_SAMPLE_RATE};
+    private static final String[] DROP_MENU_FOR_ON_CHANGE = new String[]{OFF, ON};
     private final Context mContext;
     private final PropertyListEventListener mListener;
     private final CarPropertyManager mMgr;
     private final List<PropertyInfo> mPropInfo;
     private final TextView mTvEventLog;
+    private String[] mItems;
 
     PropertyListAdapter(List<PropertyInfo> propInfo, CarPropertyManager mgr, TextView eventLog,
-                        ScrollView svEventLog, Context context) {
+            ScrollView svEventLog, Context context) {
         mContext = context;
         mListener = new PropertyListEventListener(eventLog, svEventLog);
         mMgr = mgr;
@@ -83,56 +97,111 @@
         TextView listItemText = (TextView) view.findViewById(R.id.tvPropertyName);
         listItemText.setText(mPropInfo.get(position).toString());
 
-        //Handle buttons and add onClickListeners
-        ToggleButton btn = (ToggleButton) view.findViewById(R.id.tbRegisterPropertyBtn);
+        Spinner dropdown = view.findViewById(R.id.tbRegisterPropertySpinner);
 
-        btn.setOnClickListener(new View.OnClickListener(){
+        CarPropertyConfig c = mPropInfo.get(position).mConfig;
+        if (c.getChangeMode() == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) {
+            mItems = DROP_MENU_FOR_CONTINUOUS;
+        } else {
+            mItems = DROP_MENU_FOR_ON_CHANGE;
+        }
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext,
+                R.layout.custom_spinner_dropdown_item, mItems);
+
+        adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown_item);
+        dropdown.setAdapter(adapter);
+        dropdown.setSelection(0);
+        dropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
-            public void onClick(View v) {
+            public void onItemSelected(AdapterView<?> adapterView, View view, int pos, long id) {
+                String item = (String) adapterView.getItemAtPosition(pos);
                 CarPropertyConfig c = mPropInfo.get(position).mConfig;
                 int propId = c.getPropertyId();
                 try {
-                    if (btn.isChecked()) {
-                        mMgr.registerCallback(mListener, propId, DEFAULT_RATE);
-                    } else {
+                    if (OFF.equals(item)) {
                         mMgr.unregisterCallback(mListener, propId);
+                    } else if (MAX_SAMPLE_RATE.equals(item)) {
+                        mListener.addPropertySelectedSampleRate(propId, c.getMaxSampleRate());
+                        mListener.updatePropertyStartTime(propId);
+                        mListener.resetEventCountForProperty(propId);
+                        mMgr.registerCallback(mListener, propId, c.getMaxSampleRate());
+                    } else if (AVG_SAMPLE_RATE.equals(item)) {
+                        mListener.addPropertySelectedSampleRate(propId,
+                                (c.getMaxSampleRate() + c.getMinSampleRate()) / 2);
+                        mListener.updatePropertyStartTime(propId);
+                        mListener.resetEventCountForProperty(propId);
+                        mMgr.registerCallback(mListener, propId,
+                                (c.getMaxSampleRate() + c.getMinSampleRate()) / 2);
+                    } else if (ON.equals(item)) {
+                        mListener.addPropertySelectedSampleRate(propId,
+                                DEFAULT_RATE);
+                        mListener.updatePropertyStartTime(propId);
+                        mListener.resetEventCountForProperty(propId);
+                        mMgr.registerCallback(mListener, propId, DEFAULT_RATE);
                     }
                 } catch (Exception e) {
                     Log.e(TAG, "Unhandled exception: ", e);
                 }
             }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> adapterView) {
+                // do nothing.
+            }
         });
         return view;
     }
 
 
     private static class PropertyListEventListener implements CarPropertyEventCallback {
-        private int mNumEvents;
-        private ScrollView mScrollView;
-        private TextView mTvLogEvent;
+        private final ScrollView mScrollView;
+        private final TextView mTvLogEvent;
+        private final SparseArray<Float> mPropSampleRate = new SparseArray<>();
+        private final SparseLongArray mStartTime = new SparseLongArray();
+        private final SparseIntArray mNumEvents = new SparseIntArray();
 
         PropertyListEventListener(TextView logEvent, ScrollView scrollView) {
             mScrollView = scrollView;
             mTvLogEvent = logEvent;
         }
 
+        void addPropertySelectedSampleRate(Integer propId, Float sampleRate) {
+            mPropSampleRate.put(propId, sampleRate);
+        }
+
+        void updatePropertyStartTime(Integer propId) {
+            mStartTime.put(propId, System.currentTimeMillis());
+        }
+
+        void resetEventCountForProperty(Integer propId) {
+            mNumEvents.put(propId, 0);
+        }
+
         @Override
         public void onChangeEvent(CarPropertyValue value) {
-            mNumEvents++;
-            mTvLogEvent.append("Event " + mNumEvents + ":"
-                               + " time=" + value.getTimestamp()
-                               + " propId=0x" + toHexString(value.getPropertyId())
-                               + " areaId=0x" + toHexString(value.getAreaId())
-                               + " status=" + value.getStatus()
-                               + " value=" + value.getValue()
-                               + "\n");
+            int propId = value.getPropertyId();
+
+            mNumEvents.put(propId, mNumEvents.get(propId) + 1);
+            mTvLogEvent.append(String.format("Event %1$s: time=%2$s propId=0x%3$s areaId=0x%3$s "
+                            + "name=%4$s status=%5$s value=%6$s", mNumEvents.get(propId),
+                    value.getTimestamp(), toHexString(propId), VehiclePropertyIds.toString(propId),
+                    value.getStatus(), value.getValue()));
+            if (mPropSampleRate.contains(propId)) {
+                mTvLogEvent.append(
+                        String.format(" selected sample rate=%1$s actual sample rate=%2$s\n",
+                                mPropSampleRate.get(propId),
+                                mNumEvents.get(propId) / (System.currentTimeMillis()
+                                        - mStartTime.get(propId))));
+            } else {
+                mTvLogEvent.append("\n");
+            }
             scrollToBottom();
         }
 
         @Override
         public void onErrorEvent(int propId, int areaId) {
             mTvLogEvent.append("Received error event propId=0x" + toHexString(propId)
-                               + ", areaId=0x" + toHexString(areaId));
+                    + ", areaId=0x" + toHexString(areaId));
             scrollToBottom();
         }
 
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
index 6122330..c65b6df 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/property/PropertyTestFragment.java
@@ -188,7 +188,6 @@
 
     // Spinner callbacks
     public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-        // An item was selected. You can retrieve the selected item using
         PropertyInfo info = (PropertyInfo) parent.getItemAtPosition(pos);
         int[] areaIds = info.mConfig.getAreaIds();
         List<String> areaString = new LinkedList<String>();