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