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