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