1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.android.car.kitchensink.property; 18 19 import static java.lang.Integer.toHexString; 20 21 import android.car.VehiclePropertyIds; 22 import android.car.hardware.CarPropertyConfig; 23 import android.car.hardware.CarPropertyValue; 24 import android.car.hardware.property.CarPropertyManager; 25 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback; 26 import android.content.Context; 27 import android.util.Log; 28 import android.util.SparseArray; 29 import android.util.SparseIntArray; 30 import android.util.SparseLongArray; 31 import android.view.LayoutInflater; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.widget.AdapterView; 35 import android.widget.ArrayAdapter; 36 import android.widget.BaseAdapter; 37 import android.widget.ListAdapter; 38 import android.widget.ScrollView; 39 import android.widget.Spinner; 40 import android.widget.TextView; 41 42 import com.google.android.car.kitchensink.R; 43 44 import java.util.List; 45 46 class PropertyListAdapter extends BaseAdapter implements ListAdapter { 47 private static final float DEFAULT_RATE = 1f; 48 private static final String TAG = "PropertyListAdapter"; 49 private static final String OFF = "Off"; 50 private static final String ON = "On"; 51 private static final String MAX_SAMPLE_RATE = "Maximum sample rate"; 52 private static final String AVG_SAMPLE_RATE = "Average sample rate"; 53 private static final String[] DROP_MENU_FOR_CONTINUOUS = 54 new String[]{OFF, MAX_SAMPLE_RATE, AVG_SAMPLE_RATE}; 55 private static final String[] DROP_MENU_FOR_ON_CHANGE = new String[]{OFF, ON}; 56 private final Context mContext; 57 private final PropertyListEventListener mListener; 58 private final CarPropertyManager mMgr; 59 private final List<PropertyInfo> mPropInfo; 60 private final TextView mTvEventLog; 61 private String[] mItems; 62 PropertyListAdapter(List<PropertyInfo> propInfo, CarPropertyManager mgr, TextView eventLog, ScrollView svEventLog, Context context)63 PropertyListAdapter(List<PropertyInfo> propInfo, CarPropertyManager mgr, TextView eventLog, 64 ScrollView svEventLog, Context context) { 65 mContext = context; 66 mListener = new PropertyListEventListener(eventLog, svEventLog); 67 mMgr = mgr; 68 mPropInfo = propInfo; 69 mTvEventLog = eventLog; 70 } 71 72 @Override getCount()73 public int getCount() { 74 return mPropInfo.size(); 75 } 76 77 @Override getItem(int pos)78 public Object getItem(int pos) { 79 return mPropInfo.get(pos); 80 } 81 82 @Override getItemId(int pos)83 public long getItemId(int pos) { 84 return mPropInfo.get(pos).mPropId; 85 } 86 87 @Override getView(final int position, View convertView, ViewGroup parent)88 public View getView(final int position, View convertView, ViewGroup parent) { 89 View view = convertView; 90 if (view == null) { 91 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( 92 Context.LAYOUT_INFLATER_SERVICE); 93 view = inflater.inflate(R.layout.property_list_item, null); 94 } 95 96 //Handle TextView and display string from your list 97 TextView listItemText = (TextView) view.findViewById(R.id.tvPropertyName); 98 listItemText.setText(mPropInfo.get(position).toString()); 99 100 Spinner dropdown = view.findViewById(R.id.tbRegisterPropertySpinner); 101 102 CarPropertyConfig c = mPropInfo.get(position).mConfig; 103 if (c.getChangeMode() == CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) { 104 mItems = DROP_MENU_FOR_CONTINUOUS; 105 } else { 106 mItems = DROP_MENU_FOR_ON_CHANGE; 107 } 108 ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, 109 R.layout.custom_spinner_dropdown_item, mItems); 110 111 adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown_item); 112 dropdown.setAdapter(adapter); 113 dropdown.setSelection(0); 114 dropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 115 @Override 116 public void onItemSelected(AdapterView<?> adapterView, View view, int pos, long id) { 117 String item = (String) adapterView.getItemAtPosition(pos); 118 CarPropertyConfig c = mPropInfo.get(position).mConfig; 119 int propId = c.getPropertyId(); 120 try { 121 if (OFF.equals(item)) { 122 mMgr.unregisterCallback(mListener, propId); 123 } else if (MAX_SAMPLE_RATE.equals(item)) { 124 mListener.addPropertySelectedSampleRate(propId, c.getMaxSampleRate()); 125 mListener.updatePropertyStartTime(propId); 126 mListener.resetEventCountForProperty(propId); 127 mMgr.registerCallback(mListener, propId, c.getMaxSampleRate()); 128 } else if (AVG_SAMPLE_RATE.equals(item)) { 129 mListener.addPropertySelectedSampleRate(propId, 130 (c.getMaxSampleRate() + c.getMinSampleRate()) / 2); 131 mListener.updatePropertyStartTime(propId); 132 mListener.resetEventCountForProperty(propId); 133 mMgr.registerCallback(mListener, propId, 134 (c.getMaxSampleRate() + c.getMinSampleRate()) / 2); 135 } else if (ON.equals(item)) { 136 mListener.addPropertySelectedSampleRate(propId, 137 DEFAULT_RATE); 138 mListener.updatePropertyStartTime(propId); 139 mListener.resetEventCountForProperty(propId); 140 mMgr.registerCallback(mListener, propId, DEFAULT_RATE); 141 } 142 } catch (Exception e) { 143 Log.e(TAG, "Unhandled exception: ", e); 144 } 145 } 146 147 @Override 148 public void onNothingSelected(AdapterView<?> adapterView) { 149 // do nothing. 150 } 151 }); 152 return view; 153 } 154 155 156 private static class PropertyListEventListener implements CarPropertyEventCallback { 157 private final ScrollView mScrollView; 158 private final TextView mTvLogEvent; 159 private final SparseArray<Float> mPropSampleRate = new SparseArray<>(); 160 private final SparseLongArray mStartTime = new SparseLongArray(); 161 private final SparseIntArray mNumEvents = new SparseIntArray(); 162 PropertyListEventListener(TextView logEvent, ScrollView scrollView)163 PropertyListEventListener(TextView logEvent, ScrollView scrollView) { 164 mScrollView = scrollView; 165 mTvLogEvent = logEvent; 166 } 167 addPropertySelectedSampleRate(Integer propId, Float sampleRate)168 void addPropertySelectedSampleRate(Integer propId, Float sampleRate) { 169 mPropSampleRate.put(propId, sampleRate); 170 } 171 updatePropertyStartTime(Integer propId)172 void updatePropertyStartTime(Integer propId) { 173 mStartTime.put(propId, System.currentTimeMillis()); 174 } 175 resetEventCountForProperty(Integer propId)176 void resetEventCountForProperty(Integer propId) { 177 mNumEvents.put(propId, 0); 178 } 179 180 @Override onChangeEvent(CarPropertyValue value)181 public void onChangeEvent(CarPropertyValue value) { 182 int propId = value.getPropertyId(); 183 184 mNumEvents.put(propId, mNumEvents.get(propId) + 1); 185 mTvLogEvent.append(String.format("Event %1$s: time=%2$s propId=0x%3$s areaId=0x%3$s " 186 + "name=%4$s status=%5$s value=%6$s", mNumEvents.get(propId), 187 value.getTimestamp(), toHexString(propId), VehiclePropertyIds.toString(propId), 188 value.getStatus(), value.getValue())); 189 if (mPropSampleRate.contains(propId)) { 190 mTvLogEvent.append( 191 String.format(" selected sample rate=%1$s actual sample rate=%2$s\n", 192 mPropSampleRate.get(propId), 193 mNumEvents.get(propId) / (System.currentTimeMillis() 194 - mStartTime.get(propId)))); 195 } else { 196 mTvLogEvent.append("\n"); 197 } 198 scrollToBottom(); 199 } 200 201 @Override onErrorEvent(int propId, int areaId)202 public void onErrorEvent(int propId, int areaId) { 203 mTvLogEvent.append("Received error event propId=0x" + toHexString(propId) 204 + ", areaId=0x" + toHexString(areaId)); 205 scrollToBottom(); 206 } 207 scrollToBottom()208 private void scrollToBottom() { 209 mScrollView.post(new Runnable() { 210 public void run() { 211 mScrollView.fullScroll(View.FOCUS_DOWN); 212 //mScrollView.smoothScrollTo(0, mTextStatus.getBottom()); 213 } 214 }); 215 } 216 217 } 218 } 219