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