• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 android.car.hardware;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.car.Car;
24 import android.car.CarManagerBase;
25 import android.car.VehiclePropertyType;
26 import android.car.hardware.property.CarPropertyManager;
27 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
28 import android.car.hardware.property.ICarProperty;
29 import android.os.Bundle;
30 import android.os.IBinder;
31 import android.util.ArraySet;
32 import android.util.Slog;
33 
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.lang.ref.WeakReference;
37 import java.util.Arrays;
38 import java.util.HashMap;
39 import java.util.List;
40 
41 /**
42  *  @deprecated Use {@link CarPropertyManager} instead.
43  *  API for monitoring car sensor data.
44  */
45 @Deprecated
46 public final class CarSensorManager extends CarManagerBase {
47     private static final String TAG = "CarSensorManager";
48     private final CarPropertyManager mCarPropertyMgr;
49     /** @hide */
50     public static final int SENSOR_TYPE_RESERVED1                   = 1;
51     /**
52      * This sensor represents vehicle speed in m/s.
53      *
54      * <p>Sensor data in {@link CarSensorEvent} is a float. When the vehicle is moving forward,
55      * SENSOR_TYPE_CAR_SPEED is positive and negative when the vehicle is moving backward. Also,
56      * this value is independent of SENSOR_TYPE_GEAR. For example, if SENSOR_TYPE_GEAR is {@link
57      * CarSensorEvent#GEAR_NEUTRAL}, SENSOR_TYPE_CAR_SPEED is positive when the vehicle is moving
58      * forward, negative when moving backward, and zero when not moving.
59      */
60     public static final int SENSOR_TYPE_CAR_SPEED                   = 0x11600207;
61     /**
62      * Represents engine RPM of the car. Sensor data in {@link CarSensorEvent} is a float.
63      */
64     public static final int SENSOR_TYPE_RPM                         = 0x11600305;
65     /**
66      * Total travel distance of the car in Kilometer. Sensor data is a float.
67      */
68     public static final int SENSOR_TYPE_ODOMETER                    = 0x11600204;
69     /**
70      * Indicates fuel level of the car.
71      * In {@link CarSensorEvent}, represents fuel level in milliliters.
72      * This requires {@link Car#PERMISSION_ENERGY} permission.
73      */
74     public static final int SENSOR_TYPE_FUEL_LEVEL                  = 0x11600307;
75     /**
76      * Represents the current status of parking brake. Sensor data in {@link CarSensorEvent} is an
77      * intValues[0]. Value of 1 represents parking brake applied while 0 means the other way
78      * around. For this sensor, rate in {@link #registerListener(OnSensorChangedListener, int, int)}
79      * will be ignored and all changes will be notified.
80      * This requires {@link Car#PERMISSION_POWERTRAIN} permission.
81      */
82     public static final int SENSOR_TYPE_PARKING_BRAKE               = 0x11200402;
83     /**
84      * This represents the current position of transmission gear. Sensor data in
85      * {@link CarSensorEvent} is an intValues[0]. For the meaning of the value, check
86      * {@link CarSensorEvent#GEAR_NEUTRAL} and other GEAR_*.
87      * This requires {@link Car#PERMISSION_POWERTRAIN} permission.
88      */
89     public static final int SENSOR_TYPE_GEAR                        = 0x11400400;
90     /** @hide */
91     public static final int SENSOR_TYPE_RESERVED8                   = 8;
92     /**
93      * Day/night sensor. Sensor data is intValues[0].
94      * This requires {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT} permission.
95      */
96     public static final int SENSOR_TYPE_NIGHT                       = 0x11200407;
97     /**
98      * Outside Environment like temperature.
99      * This requires {@link Car#PERMISSION_EXTERIOR_ENVIRONMENT} permission.
100      */
101     public static final int SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE     = 0x11600703;
102     /** @hide */
103     public static final int SENSOR_TYPE_RESERVED10                  = 10;
104     /** @hide */
105     public static final int SENSOR_TYPE_RESERVED11                  = 11;
106     /** @hide */
107     public static final int SENSOR_TYPE_RESERVED12                  = 12;
108     /** @hide */
109     public static final int SENSOR_TYPE_RESERVED13                  = 13;
110     /** @hide */
111     public static final int SENSOR_TYPE_RESERVED14                  = 14;
112     /** @hide */
113     public static final int SENSOR_TYPE_RESERVED15                  = 15;
114     /** @hide */
115     public static final int SENSOR_TYPE_RESERVED16                  = 16;
116     /** @hide */
117     public static final int SENSOR_TYPE_RESERVED17                  = 17;
118     /** @hide */
119     public static final int SENSOR_TYPE_RESERVED18                  = 18;
120     /** @hide */
121     public static final int SENSOR_TYPE_RESERVED19                  = 19;
122     /** @hide */
123     public static final int SENSOR_TYPE_RESERVED20                  = 20;
124     /** @hide */
125     public static final int SENSOR_TYPE_RESERVED21                  = 21;
126     /**
127      * Represents ignition state. The value should be one of the constants that starts with
128      * IGNITION_STATE_* in {@link CarSensorEvent}.
129      * This requires {@link Car#PERMISSION_POWERTRAIN} permission.
130      */
131     public static final int SENSOR_TYPE_IGNITION_STATE              = 0x11400409;
132     /**
133      * Represents wheel distance in millimeters.  Some cars may not have individual sensors on each
134      * wheel.  If a value is not available, Long.MAX_VALUE will be reported.  The wheel distance
135      * accumulates over time.  It increments on forward movement, and decrements on reverse.  Wheel
136      * distance shall be reset to zero each time a vehicle is started by the user.
137      * This requires {@link Car#PERMISSION_SPEED} permission.
138      */
139     public static final int SENSOR_TYPE_WHEEL_TICK_DISTANCE         = 0x11510306;
140     /**
141      * Set to true when ABS is active.  This sensor is event driven.
142      */
143     public static final int SENSOR_TYPE_ABS_ACTIVE                  = 0x1120040a;
144     /**
145      * Set to true when traction control is active.  This sensor is event driven.
146      */
147     public static final int SENSOR_TYPE_TRACTION_CONTROL_ACTIVE     = 0x1120040b;
148     /** @hide */
149     public static final int SENSOR_TYPE_RESERVED26                  = 26;
150     /**
151      * Set to true if the fuel door is open.
152      * This requires {@link Car#PERMISSION_ENERGY_PORTS} permission.
153      */
154     public static final int SENSOR_TYPE_FUEL_DOOR_OPEN              = 0x11200308;
155 
156     /**
157      * Indicates battery level of the car.
158      * In {@link CarSensorEvent}, represents battery level in WH.  floatValues of
159      * INDEX_EV_BATTERY_CAPACITY_ACTUAL property represents the actual battery capacity in
160      * WH.  The battery degrades over time, so this value is expected to drop slowly over the life
161      * of the vehicle.
162      * This requires {@link Car#PERMISSION_ENERGY} permission.
163      */
164     public static final int SENSOR_TYPE_EV_BATTERY_LEVEL            = 0x11600309;
165     /**
166      * Set to true if EV charging port is open.
167      * This requires {@link Car#PERMISSION_ENERGY_PORTS} permission.
168      */
169     public static final int SENSOR_TYPE_EV_CHARGE_PORT_OPEN         = 0x1120030a;
170     /**
171      * Set to true if EV charging port is connected.
172      * This requires {@link Car#PERMISSION_ENERGY_PORTS} permission.
173      */
174     public static final int SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED    = 0x1120030b;
175     /**
176      *  Indicates the instantaneous battery charging rate in mW.
177      *  This requires {@link Car#PERMISSION_ENERGY} permission.
178      */
179     public static final int SENSOR_TYPE_EV_BATTERY_CHARGE_RATE      = 0x1160030c;
180     /**
181      * Oil level sensor.
182      */
183     public static final int SENSOR_TYPE_ENGINE_OIL_LEVEL            = 0x11400303;
184 
185 
186     /** @hide */
187     @IntDef({
188             SENSOR_TYPE_CAR_SPEED,
189             SENSOR_TYPE_RPM,
190             SENSOR_TYPE_ODOMETER,
191             SENSOR_TYPE_FUEL_LEVEL,
192             SENSOR_TYPE_PARKING_BRAKE,
193             SENSOR_TYPE_GEAR,
194             SENSOR_TYPE_NIGHT,
195             SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE,
196             SENSOR_TYPE_IGNITION_STATE,
197             SENSOR_TYPE_WHEEL_TICK_DISTANCE,
198             SENSOR_TYPE_ABS_ACTIVE,
199             SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
200             SENSOR_TYPE_FUEL_DOOR_OPEN,
201             SENSOR_TYPE_EV_BATTERY_LEVEL,
202             SENSOR_TYPE_EV_CHARGE_PORT_OPEN,
203             SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
204             SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
205             SENSOR_TYPE_ENGINE_OIL_LEVEL,
206     })
207     @Retention(RetentionPolicy.SOURCE)
208     public @interface SensorType {}
209 
210     private final ArraySet<Integer> mSensorConfigIds = new ArraySet<>(Arrays.asList(new Integer[]{
211             SENSOR_TYPE_CAR_SPEED,
212             SENSOR_TYPE_RPM,
213             SENSOR_TYPE_ODOMETER,
214             SENSOR_TYPE_FUEL_LEVEL,
215             SENSOR_TYPE_PARKING_BRAKE,
216             SENSOR_TYPE_GEAR,
217             SENSOR_TYPE_NIGHT,
218             SENSOR_TYPE_ENV_OUTSIDE_TEMPERATURE,
219             SENSOR_TYPE_IGNITION_STATE,
220             SENSOR_TYPE_WHEEL_TICK_DISTANCE,
221             SENSOR_TYPE_ABS_ACTIVE,
222             SENSOR_TYPE_TRACTION_CONTROL_ACTIVE,
223             SENSOR_TYPE_FUEL_DOOR_OPEN,
224             SENSOR_TYPE_EV_BATTERY_LEVEL,
225             SENSOR_TYPE_EV_CHARGE_PORT_OPEN,
226             SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED,
227             SENSOR_TYPE_EV_BATTERY_CHARGE_RATE,
228             SENSOR_TYPE_ENGINE_OIL_LEVEL,
229     }));
230 
231     /** Read on_change type sensors */
232     public static final int SENSOR_RATE_ONCHANGE = 0;
233     /** Read sensor in default normal rate set for each sensors. This is default rate. */
234     public static final int SENSOR_RATE_NORMAL  = 1;
235     public static final int SENSOR_RATE_UI = 5;
236     public static final int SENSOR_RATE_FAST = 10;
237     /** Read sensor at the maximum rate. Actual rate will be different depending on the sensor. */
238     public static final int SENSOR_RATE_FASTEST = 100;
239 
240     /** @hide */
241     @IntDef({
242             SENSOR_RATE_ONCHANGE,
243             SENSOR_RATE_NORMAL,
244             SENSOR_RATE_UI,
245             SENSOR_RATE_FAST,
246             SENSOR_RATE_FASTEST
247     })
248     @Retention(RetentionPolicy.SOURCE)
249     public @interface SensorRate {}
250 
251     private CarPropertyEventListenerToBase mCarPropertyEventListener = null;
252 
253     /**
254      * To keep record of CarPropertyEventListenerToBase
255      */
256     private final HashMap<OnSensorChangedListener, CarPropertyEventListenerToBase> mListenerMap =
257             new HashMap<>();
258     /**
259      * Listener for car sensor data change.
260      * Callbacks are called in the Looper context.
261      */
262     public interface OnSensorChangedListener {
263         /**
264          * Called when there is a new sensor data from car.
265          * @param event Incoming sensor event for the given sensor type.
266          */
onSensorChanged(CarSensorEvent event)267         void onSensorChanged(CarSensorEvent event);
268     }
269 
270     private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
271         private final WeakReference<CarSensorManager> mManager;
272         private final OnSensorChangedListener mListener;
CarPropertyEventListenerToBase(CarSensorManager manager, OnSensorChangedListener listener)273         CarPropertyEventListenerToBase(CarSensorManager manager, OnSensorChangedListener listener) {
274             mManager = new WeakReference<>(manager);
275             mListener = listener;
276         }
277 
278         @Override
onChangeEvent(CarPropertyValue value)279         public void onChangeEvent(CarPropertyValue value) {
280             CarSensorManager manager = mManager.get();
281             if (manager != null) {
282                 manager.handleOnChangeEvent(value, mListener);
283             }
284         }
285 
286         @Override
onErrorEvent(int propertyId, int zone)287         public void onErrorEvent(int propertyId, int zone) {
288 
289         }
290     }
291 
handleOnChangeEvent(CarPropertyValue value, OnSensorChangedListener listener)292     private void handleOnChangeEvent(CarPropertyValue value, OnSensorChangedListener listener) {
293         synchronized (mListenerMap) {
294             CarSensorEvent event = createCarSensorEvent(value);
295             listener.onSensorChanged(event);
296         }
297     }
298 
299     /** @hide */
CarSensorManager(Car car, IBinder service)300     public CarSensorManager(Car car, IBinder service) {
301         super(car);
302         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
303         mCarPropertyMgr = new CarPropertyManager(car, mCarPropertyService);
304     }
305 
306     /** @hide */
307     @Override
onCarDisconnected()308     public void onCarDisconnected() {
309         synchronized (mListenerMap) {
310             mListenerMap.clear();
311         }
312         mCarPropertyMgr.onCarDisconnected();
313     }
314 
315     /**
316      * Give the list of CarSensors available in the connected car.
317      * @return array of all sensor types supported. Sensor types is the same as
318      * property id.
319      */
320     @NonNull
getSupportedSensors()321     public int[] getSupportedSensors() {
322         List<CarPropertyConfig> carPropertyConfigList = getPropertyList();
323         int[] supportedSensors = new int[carPropertyConfigList.size()];
324         for (int i = 0; i < supportedSensors.length; i++) {
325             supportedSensors[i] = carPropertyConfigList.get(i).getPropertyId();
326         }
327         return supportedSensors;
328     }
329 
330     /**
331      * Get list of properties represented by CarSensorManager for this car.
332      * @return List of CarPropertyConfig objects available via Car Sensor Manager.
333      */
334     @NonNull
getPropertyList()335     public List<CarPropertyConfig> getPropertyList() {
336         return mCarPropertyMgr.getPropertyList(mSensorConfigIds);
337     }
338 
339     /**
340      * Tells if given sensor is supported or not.
341      * @param sensorType
342      * @return true if the sensor is supported.
343      */
isSensorSupported(@ensorType int sensorType)344     public boolean isSensorSupported(@SensorType int sensorType) {
345         int[] sensors = getSupportedSensors();
346         for (int sensorSupported: sensors) {
347             if (sensorType == sensorSupported) {
348                 return true;
349             }
350         }
351         return false;
352     }
353 
354     /**
355      * Check if given sensorList is including the sensorType.
356      * @param sensorList
357      * @param sensorType
358      * @return true if sensor is supported.
359      * @hide
360      */
isSensorSupported(int[] sensorList, @SensorType int sensorType)361     public static boolean isSensorSupported(int[] sensorList, @SensorType int sensorType) {
362         for (int sensorSupported: sensorList) {
363             if (sensorType == sensorSupported) {
364                 return true;
365             }
366         }
367         return false;
368     }
369 
370     /**
371      * Register {@link OnSensorChangedListener} to get repeated sensor updates. Multiple listeners
372      * can be registered for a single sensor or the same listener can be used for different sensors.
373      * If the same listener is registered again for the same sensor, it will be either ignored or
374      * updated depending on the rate.
375      * <p>
376      *
377      * @param listener
378      * @param sensorType sensor type to subscribe.
379      * @param rate how fast the sensor events are delivered. It should be one of
380      *        {@link #SENSOR_RATE_FASTEST}, {@link #SENSOR_RATE_FAST}, {@link #SENSOR_RATE_UI},
381      *        {@link #SENSOR_RATE_NORMAL}. Rate may not be respected especially when the same sensor
382      *        is registered with different listener with different rates. Also, rate might be
383      *        ignored when vehicle property raises events only when the value is actually changed,
384      *        for example {@link #SENSOR_TYPE_PARKING_BRAKE} will raise an event only when parking
385      *        brake was engaged or disengaged.
386      * @return if the sensor was successfully enabled.
387      * @throws IllegalArgumentException for wrong argument like wrong rate
388      * @throws SecurityException if missing the appropriate permission
389      */
390     @RequiresPermission(anyOf = {Car.PERMISSION_SPEED, Car.PERMISSION_CAR_ENGINE_DETAILED,
391             Car.PERMISSION_MILEAGE, Car.PERMISSION_ENERGY, Car.PERMISSION_POWERTRAIN,
392             Car.PERMISSION_EXTERIOR_ENVIRONMENT, Car.PERMISSION_CAR_DYNAMICS_STATE,
393             Car.PERMISSION_ENERGY_PORTS}, conditional = true)
registerListener(@onNull OnSensorChangedListener listener, @SensorType int sensorType, @SensorRate int rate)394     public boolean registerListener(@NonNull OnSensorChangedListener listener,
395             @SensorType int sensorType, @SensorRate int rate) {
396         if (rate != SENSOR_RATE_FASTEST && rate != SENSOR_RATE_NORMAL
397                 && rate != SENSOR_RATE_UI && rate != SENSOR_RATE_FAST
398                 && rate != SENSOR_RATE_ONCHANGE) {
399             throw new IllegalArgumentException("wrong rate " + rate);
400         }
401         if (mListenerMap.get(listener) == null) {
402             mCarPropertyEventListener = new CarPropertyEventListenerToBase(this, listener);
403         } else {
404             mCarPropertyEventListener = mListenerMap.get(listener);
405         }
406         if (mCarPropertyMgr.registerCallback(mCarPropertyEventListener, sensorType, rate)) {
407             mListenerMap.put(listener, mCarPropertyEventListener);
408             return true;
409         } else {
410             return false;
411         }
412     }
413 
414     /**
415      * Stop getting sensor update for the given listener.
416      * If there are multiple registrations for this listener, all listening will be stopped.
417      * @param listener Listener for car sensor data change.
418      */
unregisterListener(@onNull OnSensorChangedListener listener)419     public void unregisterListener(@NonNull OnSensorChangedListener listener) {
420         synchronized (mListenerMap) {
421             mCarPropertyEventListener = mListenerMap.get(listener);
422             mCarPropertyMgr.unregisterCallback(mCarPropertyEventListener);
423             mListenerMap.remove(listener);
424         }
425     }
426 
427     /**
428      * Stop getting sensor update for the given listener and sensor.
429      * If the same listener is used for other sensors, those subscriptions will not be affected.
430      * @param listener Listener for car sensor data change.
431      * @param sensorType Property Id
432      */
unregisterListener(@onNull OnSensorChangedListener listener, @SensorType int sensorType)433     public void unregisterListener(@NonNull OnSensorChangedListener listener,
434             @SensorType int sensorType) {
435         synchronized (mListenerMap) {
436             mCarPropertyEventListener = mListenerMap.get(listener);
437         }
438         mCarPropertyMgr.unregisterCallback(mCarPropertyEventListener, sensorType);
439     }
440 
441     /**
442      * Get the most recent CarSensorEvent for the given type. Note that latest sensor data from car
443      * will not be available if it was never subscribed before. This call will return immediately
444      * with null if there is no data available.
445      * @param type A sensor to request
446      * @return null if there was no sensor update since connected to the car.
447      */
448     @Nullable
getLatestSensorEvent(@ensorType int type)449     public CarSensorEvent getLatestSensorEvent(@SensorType int type) {
450         CarPropertyValue propertyValue = mCarPropertyMgr.getProperty(type, 0);
451         return createCarSensorEvent(propertyValue);
452     }
453 
createCarSensorEvent(CarPropertyValue propertyValue)454     private CarSensorEvent createCarSensorEvent(CarPropertyValue propertyValue) {
455         CarSensorEvent event = null;
456         switch (propertyValue.getPropertyId() & VehiclePropertyType.MASK) {
457             case VehiclePropertyType.FLOAT:
458                 event = new CarSensorEvent(propertyValue.getPropertyId(),
459                         propertyValue.getTimestamp(), 1, 0, 0);
460                 event.floatValues[0] = (float) propertyValue.getValue();
461                 break;
462             case VehiclePropertyType.INT32:
463                 event = new CarSensorEvent(propertyValue.getPropertyId(),
464                         propertyValue.getTimestamp(), 0, 1, 0);
465                 event.intValues[0] = (int) propertyValue.getValue();
466                 break;
467             case VehiclePropertyType.BOOLEAN:
468                 event = new CarSensorEvent(propertyValue.getPropertyId(),
469                         propertyValue.getTimestamp(), 0, 1, 0);
470                 event.intValues[0] = (boolean) propertyValue.getValue() ? 1 : 0;
471                 break;
472             case VehiclePropertyType.INT64_VEC:
473                 Object[] value = (Object[]) propertyValue.getValue();
474                 event = new CarSensorEvent(propertyValue.getPropertyId(),
475                         propertyValue.getTimestamp(), 0, 0, value.length);
476                 for (int i = 0; i < value.length; i++) {
477                     event.longValues[i] = (Long) value[i];
478                 }
479                 break;
480             default:
481                 Slog.e(TAG, "unhandled VehiclePropertyType for propId="
482                         + propertyValue.getPropertyId());
483                 break;
484         }
485         return event;
486     }
487 
488     /**
489      * Get the config data for the given type.
490      *
491      * A CarSensorConfig object is returned for every sensor type.  However, if there is no
492      * config, the data will be empty.
493      *
494      * @param type sensor type to request
495      * @return CarSensorConfig object
496      * @hide
497      */
getSensorConfig(@ensorType int type)498     public CarSensorConfig getSensorConfig(@SensorType int type) {
499         Bundle b = null;
500         switch (type) {
501             case SENSOR_TYPE_WHEEL_TICK_DISTANCE:
502                 List<CarPropertyConfig> propertyConfigs = mCarPropertyMgr.getPropertyList();
503                 for (CarPropertyConfig p : propertyConfigs) {
504                     if (p.getPropertyId() == type) {
505                         b = createWheelDistanceTickBundle(p.getConfigArray());
506                         break;
507                     }
508                 }
509                 break;
510             default:
511                 b = Bundle.EMPTY;
512                 break;
513         }
514         return new CarSensorConfig(type, b);
515     }
516 
517     private static final int INDEX_WHEEL_DISTANCE_ENABLE_FLAG = 0;
518     private static final int INDEX_WHEEL_DISTANCE_FRONT_LEFT = 1;
519     private static final int INDEX_WHEEL_DISTANCE_FRONT_RIGHT = 2;
520     private static final int INDEX_WHEEL_DISTANCE_REAR_RIGHT = 3;
521     private static final int INDEX_WHEEL_DISTANCE_REAR_LEFT = 4;
522     private static final int WHEEL_TICK_DISTANCE_BUNDLE_SIZE = 6;
523 
createWheelDistanceTickBundle(List<Integer> configArray)524     private Bundle createWheelDistanceTickBundle(List<Integer> configArray) {
525         Bundle b = new Bundle(WHEEL_TICK_DISTANCE_BUNDLE_SIZE);
526         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS,
527                 configArray.get(INDEX_WHEEL_DISTANCE_ENABLE_FLAG));
528         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK,
529                 configArray.get(INDEX_WHEEL_DISTANCE_FRONT_LEFT));
530         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK,
531                 configArray.get(INDEX_WHEEL_DISTANCE_FRONT_RIGHT));
532         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK,
533                 configArray.get(INDEX_WHEEL_DISTANCE_REAR_RIGHT));
534         b.putInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK,
535                 configArray.get(INDEX_WHEEL_DISTANCE_REAR_LEFT));
536         return b;
537     }
538 }
539