Home | History | Annotate | Download | only in hardware
      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          */
    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;
    265         CarPropertyEventListenerToBase(CarSensorManager manager, OnSensorChangedListener listener) {
    266             mManager = new WeakReference<>(manager);
    267             mListener = listener;
    268         }
    269 
    270         @Override
    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
    279         public void onErrorEvent(int propertyId, int zone) {
    280 
    281         }
    282     }
    283 
    284     private void handleOnChangeEvent(CarPropertyValue value, OnSensorChangedListener listener) {
    285         synchronized (mListenerMap) {
    286             CarSensorEvent event = createCarSensorEvent(value);
    287             listener.onSensorChanged(event);
    288         }
    289     }
    290 
    291     private void handleOnErrorEvent(int propertyId, int zone) {
    292 
    293     }
    294     /** @hide */
    295     public CarSensorManager(IBinder service, Context context, Handler handler) {
    296         mCarPropertyMgr = new CarPropertyManager(service, handler, DBG, TAG);
    297     }
    298 
    299     /** @hide */
    300     @Override
    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      */
    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      */
    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      */
    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      */
    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)
    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      */
    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      */
    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      */
    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 
    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 
    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      */
    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 
    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