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