CarSensorManager.java revision 0d07c76bbc788fba8c77d8e932330ab22ec6ba27
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 17package android.car.hardware; 18 19import android.Manifest; 20import android.annotation.IntDef; 21import android.annotation.RequiresPermission; 22import android.car.Car; 23import android.car.CarApiUtil; 24import android.car.CarLibLog; 25import android.car.CarManagerBase; 26import android.car.CarNotConnectedException; 27import android.content.Context; 28import android.os.Binder; 29import android.os.Handler; 30import android.os.Handler.Callback; 31import android.os.IBinder; 32import android.os.Message; 33import android.os.RemoteException; 34import android.util.Log; 35 36import com.google.android.collect.Lists; 37 38import java.lang.annotation.Retention; 39import java.lang.annotation.RetentionPolicy; 40import java.lang.ref.WeakReference; 41import java.util.ArrayList; 42import java.util.Arrays; 43import java.util.Collections; 44import java.util.HashMap; 45import java.util.Iterator; 46import java.util.List; 47import java.util.Map; 48 49/** 50 * API for monitoring car sensor data. 51 */ 52public final class CarSensorManager implements CarManagerBase { 53 /** @hide */ 54 public static final int SENSOR_TYPE_RESERVED1 = 1; 55 /** 56 * This sensor represents vehicle speed in m/s. 57 * Sensor data in {@link CarSensorEvent} is a float which will be >= 0. 58 * This requires {@link Car#PERMISSION_SPEED} permission. 59 */ 60 public static final int SENSOR_TYPE_CAR_SPEED = 2; 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 = 3; 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 = 4; 70 /** 71 * Indicates fuel level of the car. 72 * In {@link CarSensorEvent}, floatValues[{@link CarSensorEvent#INDEX_FUEL_LEVEL_IN_PERCENTILE}] 73 * represents fuel level in percentile (0 to 100) while 74 * floatValues[{@link CarSensorEvent#INDEX_FUEL_LEVEL_IN_DISTANCE}] represents estimated range 75 * in Kilometer with the remaining fuel. 76 * Note that the gas mileage used for the estimation may not represent the current driving 77 * condition. 78 * This requires {@link Car#PERMISSION_FUEL} permission. 79 */ 80 public static final int SENSOR_TYPE_FUEL_LEVEL = 5; 81 /** 82 * Represents the current status of parking brake. Sensor data in {@link CarSensorEvent} is an 83 * intValues[0]. Value of 1 represents parking brake applied while 0 means the other way 84 * around. For this sensor, rate in {@link #registerListener(OnSensorChangedListener, int, int)} 85 * will be ignored and all changes will be notified. 86 */ 87 public static final int SENSOR_TYPE_PARKING_BRAKE = 6; 88 /** 89 * This represents the current position of transmission gear. Sensor data in 90 * {@link CarSensorEvent} is an intValues[0]. For the meaning of the value, check 91 * {@link CarSensorEvent#GEAR_NEUTRAL} and other GEAR_*. 92 */ 93 public static final int SENSOR_TYPE_GEAR = 7; 94 /** @hide */ 95 public static final int SENSOR_TYPE_RESERVED8 = 8; 96 /** 97 * Day/night sensor. Sensor data is intValues[0]. 98 */ 99 public static final int SENSOR_TYPE_NIGHT = 9; 100 /** @hide */ 101 public static final int SENSOR_TYPE_RESERVED10 = 10; 102 /** 103 * Represents the current driving status of car. Different user interaction should be used 104 * depending on the current driving status. Driving status is intValues[0]. 105 */ 106 public static final int SENSOR_TYPE_DRIVING_STATUS = 11; 107 /** 108 * Environment like temperature and pressure. 109 */ 110 public static final int SENSOR_TYPE_ENVIRONMENT = 12; 111 /** @hide */ 112 public static final int SENSOR_TYPE_RESERVED13 = 13; 113 /** @hide */ 114 public static final int SENSOR_TYPE_RESERVED14 = 14; 115 /** @hide */ 116 public static final int SENSOR_TYPE_RESERVED15 = 15; 117 /** @hide */ 118 public static final int SENSOR_TYPE_RESERVED16 = 16; 119 /** @hide */ 120 public static final int SENSOR_TYPE_RESERVED17 = 17; 121 /** @hide */ 122 public static final int SENSOR_TYPE_RESERVED18 = 18; 123 /** @hide */ 124 public static final int SENSOR_TYPE_RESERVED19 = 19; 125 /** @hide */ 126 public static final int SENSOR_TYPE_RESERVED20 = 20; 127 /** @hide */ 128 public static final int SENSOR_TYPE_RESERVED21 = 21; 129 130 /** 131 * Sensor type bigger than this is invalid. Always update this after adding a new sensor. 132 * @hide 133 */ 134 private static final int SENSOR_TYPE_MAX = SENSOR_TYPE_ENVIRONMENT; 135 136 /** 137 * Sensors defined in this range [{@link #SENSOR_TYPE_VENDOR_EXTENSION_START}, 138 * {@link #SENSOR_TYPE_VENDOR_EXTENSION_END}] is for each car vendor's to use. 139 * This should be only used for system app to access sensors not defined as standard types. 140 * So the sensor supported in this range can vary depending on car models / manufacturers. 141 * 3rd party apps should not use sensors in this range as they are not compatible across 142 * different cars. Additionally 3rd party apps trying to access sensor in this range will get 143 * security exception as their access is restricted to system apps. 144 * 145 * @hide 146 */ 147 public static final int SENSOR_TYPE_VENDOR_EXTENSION_START = 0x60000000; 148 public static final int SENSOR_TYPE_VENDOR_EXTENSION_END = 0x6fffffff; 149 150 /** @hide */ 151 @IntDef({ 152 SENSOR_TYPE_CAR_SPEED, 153 SENSOR_TYPE_RPM, 154 SENSOR_TYPE_ODOMETER, 155 SENSOR_TYPE_FUEL_LEVEL, 156 SENSOR_TYPE_PARKING_BRAKE, 157 SENSOR_TYPE_GEAR, 158 SENSOR_TYPE_NIGHT, 159 SENSOR_TYPE_DRIVING_STATUS, 160 SENSOR_TYPE_ENVIRONMENT 161 }) 162 @Retention(RetentionPolicy.SOURCE) 163 public @interface SensorType {} 164 165 /** Read sensor in default normal rate set for each sensors. This is default rate. */ 166 public static final int SENSOR_RATE_NORMAL = 3; 167 public static final int SENSOR_RATE_UI = 2; 168 public static final int SENSOR_RATE_FAST = 1; 169 /** Read sensor at the maximum rate. Actual rate will be different depending on the sensor. */ 170 public static final int SENSOR_RATE_FASTEST = 0; 171 172 /** @hide */ 173 @IntDef({ 174 SENSOR_RATE_NORMAL, 175 SENSOR_RATE_UI, 176 SENSOR_RATE_FAST, 177 SENSOR_RATE_FASTEST 178 }) 179 @Retention(RetentionPolicy.SOURCE) 180 public @interface SensorRate {} 181 182 private static final int MSG_SENSOR_EVENTS = 0; 183 184 private final ICarSensor mService; 185 186 private CarSensorEventListenerToService mCarSensorEventListenerToService; 187 188 /** 189 * To keep record of locally active sensors. Key is sensor type. This is used as a basic lock 190 * for all client accesses. 191 */ 192 private final HashMap<Integer, CarSensorListeners> mActiveSensorListeners = 193 new HashMap<Integer, CarSensorListeners>(); 194 195 /** Handles call back into projected apps. */ 196 private final Handler mHandler; 197 private final Callback mHandlerCallback = new Callback() { 198 @Override 199 public boolean handleMessage(Message msg) { 200 switch (msg.what) { 201 case MSG_SENSOR_EVENTS: 202 synchronized(mActiveSensorListeners) { 203 List<CarSensorEvent> events = (List<CarSensorEvent>) msg.obj; 204 for (CarSensorEvent event: events) { 205 CarSensorListeners listeners = 206 mActiveSensorListeners.get(event.sensorType); 207 if (listeners != null) { 208 listeners.onSensorChanged(event); 209 } 210 } 211 } 212 break; 213 default: 214 break; 215 } 216 return true; 217 } 218 }; 219 220 221 /** @hide */ 222 public CarSensorManager(IBinder service, Context context, Handler handler) { 223 mService = ICarSensor.Stub.asInterface(service); 224 mHandler = new Handler(handler.getLooper(), mHandlerCallback); 225 } 226 227 /** @hide */ 228 @Override 229 public void onCarDisconnected() { 230 synchronized(mActiveSensorListeners) { 231 mActiveSensorListeners.clear(); 232 mCarSensorEventListenerToService = null; 233 } 234 } 235 236 /** 237 * Give the list of CarSensors available in the connected car. 238 * @return array of all sensor types supported. 239 * @throws CarNotConnectedException if the connection to the car service has been lost. 240 */ 241 public int[] getSupportedSensors() throws CarNotConnectedException { 242 try { 243 return mService.getSupportedSensors(); 244 } catch (IllegalStateException e) { 245 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 246 } catch (RemoteException e) { 247 throw new CarNotConnectedException(e); 248 } 249 return new int[0]; 250 } 251 252 /** 253 * Tells if given sensor is supported or not. 254 * @param sensorType 255 * @return true if the sensor is supported. 256 * @throws CarNotConnectedException if the connection to the car service has been lost. 257 */ 258 public boolean isSensorSupported(@SensorType int sensorType) throws CarNotConnectedException { 259 int[] sensors = getSupportedSensors(); 260 for (int sensorSupported: sensors) { 261 if (sensorType == sensorSupported) { 262 return true; 263 } 264 } 265 return false; 266 } 267 268 /** 269 * Check if given sensorList is including the sensorType. 270 * @param sensorList 271 * @param sensorType 272 * @return 273 */ 274 public static boolean isSensorSupported(int[] sensorList, @SensorType int sensorType) { 275 for (int sensorSupported: sensorList) { 276 if (sensorType == sensorSupported) { 277 return true; 278 } 279 } 280 return false; 281 } 282 283 /** 284 * Listener for car sensor data change. 285 * Callbacks are called in the Looper context. 286 */ 287 public interface OnSensorChangedListener { 288 /** 289 * Called when there is a new sensor data from car. 290 * @param event Incoming sensor event for the given sensor type. 291 */ 292 void onSensorChanged(final CarSensorEvent event); 293 } 294 295 /** 296 * Register {@link OnSensorChangedListener} to get repeated sensor updates. Multiple listeners 297 * can be registered for a single sensor or the same listener can be used for different sensors. 298 * If the same listener is registered again for the same sensor, it will be either ignored or 299 * updated depending on the rate. 300 * <p> 301 * Requires {@link Car#PERMISSION_SPEED} for {@link #SENSOR_TYPE_CAR_SPEED}, 302 * {@link Car#PERMISSION_MILEAGE} for {@link #SENSOR_TYPE_ODOMETER}, 303 * or {@link Car#PERMISSION_FUEL} for {@link #SENSOR_TYPE_FUEL_LEVEL}. 304 * 305 * @param listener 306 * @param sensorType sensor type to subscribe. 307 * @param rate how fast the sensor events are delivered. It should be one of 308 * {@link #SENSOR_RATE_FASTEST} or {@link #SENSOR_RATE_NORMAL}. Rate may not be respected 309 * especially when the same sensor is registered with different listener with different 310 * rates. 311 * @return if the sensor was successfully enabled. 312 * @throws CarNotConnectedException if the connection to the car service has been lost. 313 * @throws IllegalArgumentException for wrong argument like wrong rate 314 * @throws SecurityException if missing the appropriate permission 315 */ 316 @RequiresPermission(anyOf={Manifest.permission.ACCESS_FINE_LOCATION, Car.PERMISSION_SPEED, 317 Car.PERMISSION_MILEAGE, Car.PERMISSION_FUEL}, conditional=true) 318 public boolean registerListener(OnSensorChangedListener listener, @SensorType int sensorType, 319 @SensorRate int rate) throws CarNotConnectedException, IllegalArgumentException { 320 assertSensorType(sensorType); 321 if (rate != SENSOR_RATE_FASTEST && rate != SENSOR_RATE_NORMAL) { 322 throw new IllegalArgumentException("wrong rate " + rate); 323 } 324 synchronized(mActiveSensorListeners) { 325 if (mCarSensorEventListenerToService == null) { 326 mCarSensorEventListenerToService = new CarSensorEventListenerToService(this); 327 } 328 boolean needsServerUpdate = false; 329 CarSensorListeners listeners; 330 listeners = mActiveSensorListeners.get(sensorType); 331 if (listeners == null) { 332 listeners = new CarSensorListeners(rate); 333 mActiveSensorListeners.put(sensorType, listeners); 334 needsServerUpdate = true; 335 } 336 if (listeners.addAndUpdateRate(listener, rate)) { 337 needsServerUpdate = true; 338 } 339 if (needsServerUpdate) { 340 if (!registerOrUpdateSensorListener(sensorType, rate)) { 341 return false; 342 } 343 } 344 } 345 return true; 346 } 347 348 /** 349 * Stop getting sensor update for the given listener. If there are multiple registrations for 350 * this listener, all listening will be stopped. 351 * @param listener 352 */ 353 public void unregisterListener(OnSensorChangedListener listener) { 354 //TODO: removing listener should reset update rate, bug: 32060307 355 synchronized(mActiveSensorListeners) { 356 Iterator<Integer> sensorIterator = mActiveSensorListeners.keySet().iterator(); 357 while (sensorIterator.hasNext()) { 358 Integer sensor = sensorIterator.next(); 359 doUnregisterListenerLocked(listener, sensor, sensorIterator); 360 } 361 } 362 } 363 364 /** 365 * Stop getting sensor update for the given listener and sensor. If the same listener is used 366 * for other sensors, those subscriptions will not be affected. 367 * @param listener 368 * @param sensorType 369 */ 370 public void unregisterListener(OnSensorChangedListener listener, @SensorType int sensorType) { 371 synchronized(mActiveSensorListeners) { 372 doUnregisterListenerLocked(listener, sensorType, null); 373 } 374 } 375 376 private void doUnregisterListenerLocked(OnSensorChangedListener listener, Integer sensor, 377 Iterator<Integer> sensorIterator) { 378 CarSensorListeners listeners = mActiveSensorListeners.get(sensor); 379 if (listeners != null) { 380 boolean needsServerUpdate = false; 381 if (listeners.contains(listener)) { 382 needsServerUpdate = listeners.remove(listener); 383 } 384 if (listeners.isEmpty()) { 385 try { 386 mService.unregisterSensorListener(sensor.intValue(), 387 mCarSensorEventListenerToService); 388 } catch (RemoteException e) { 389 //ignore 390 } 391 if (sensorIterator == null) { 392 mActiveSensorListeners.remove(sensor); 393 } else { 394 sensorIterator.remove(); 395 } 396 } else if (needsServerUpdate) { 397 try { 398 registerOrUpdateSensorListener(sensor, listeners.getRate()); 399 } catch (CarNotConnectedException e) { 400 // ignore 401 } 402 } 403 } 404 } 405 406 private boolean registerOrUpdateSensorListener(int sensor, int rate) 407 throws CarNotConnectedException { 408 try { 409 if (!mService.registerOrUpdateSensorListener(sensor, rate, 410 mCarSensorEventListenerToService)) { 411 return false; 412 } 413 } catch (IllegalStateException e) { 414 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 415 } catch (RemoteException e) { 416 throw new CarNotConnectedException(e); 417 } 418 return true; 419 } 420 421 /** 422 * Get the most recent CarSensorEvent for the given type. Note that latest sensor data from car 423 * will not be available if it was never subscribed before. This call will return immediately 424 * with null if there is no data available. 425 * @param type A sensor to request 426 * @return null if there was no sensor update since connected to the car. 427 * @throws CarNotConnectedException if the connection to the car service has been lost. 428 */ 429 public CarSensorEvent getLatestSensorEvent(@SensorType int type) 430 throws CarNotConnectedException { 431 assertSensorType(type); 432 try { 433 return mService.getLatestSensorEvent(type); 434 } catch (IllegalStateException e) { 435 CarApiUtil.checkCarNotConnectedExceptionFromCarService(e); 436 } catch(RemoteException e) { 437 handleCarServiceRemoteExceptionAndThrow(e); 438 } 439 return null; 440 } 441 442 private void handleCarServiceRemoteExceptionAndThrow(RemoteException e) 443 throws CarNotConnectedException { 444 if (Log.isLoggable(CarLibLog.TAG_SENSOR, Log.INFO)) { 445 Log.i(CarLibLog.TAG_SENSOR, "RemoteException from car service:" + e.getMessage()); 446 } 447 throw new CarNotConnectedException(); 448 } 449 450 private void assertSensorType(int sensorType) { 451 if (sensorType == 0 || !((sensorType <= SENSOR_TYPE_MAX) || 452 ((sensorType >= SENSOR_TYPE_VENDOR_EXTENSION_START) && 453 (sensorType <= SENSOR_TYPE_VENDOR_EXTENSION_END)))) { 454 throw new IllegalArgumentException("invalid sensor type " + sensorType); 455 } 456 } 457 458 private void handleOnSensorChanged(List<CarSensorEvent> events) { 459 mHandler.sendMessage(mHandler.obtainMessage(MSG_SENSOR_EVENTS, events)); 460 } 461 462 private static class CarSensorEventListenerToService extends ICarSensorEventListener.Stub { 463 private final WeakReference<CarSensorManager> mManager; 464 465 public CarSensorEventListenerToService(CarSensorManager manager) { 466 mManager = new WeakReference<>(manager); 467 } 468 469 @Override 470 public void onSensorChanged(List<CarSensorEvent> events) { 471 CarSensorManager manager = mManager.get(); 472 if (manager != null) { 473 manager.handleOnSensorChanged(events); 474 } 475 } 476 } 477 478 /** 479 * Represent listeners for a sensor. 480 */ 481 private class CarSensorListeners { 482 private final Map<OnSensorChangedListener, Integer> mListenersToRate = 483 new HashMap<>(); 484 485 private int mUpdateRate; 486 private long mLastUpdateTime = -1; 487 488 CarSensorListeners(int rate) { 489 mUpdateRate = rate; 490 } 491 492 boolean contains(OnSensorChangedListener listener) { 493 return mListenersToRate.containsKey(listener); 494 } 495 496 int getRate() { 497 return mUpdateRate; 498 } 499 500 /** 501 * Remove given listener from the list and update rate if necessary. 502 * @param listener. 503 * @return true if rate was updated. Otherwise, returns false. 504 */ 505 boolean remove(OnSensorChangedListener listener) { 506 mListenersToRate.remove(listener); 507 if (mListenersToRate.isEmpty()) { 508 return false; 509 } 510 Integer updateRate = Collections.min(mListenersToRate.values()); 511 if (updateRate != mUpdateRate) { 512 mUpdateRate = updateRate; 513 return true; 514 } 515 return false; 516 } 517 518 boolean isEmpty() { 519 return mListenersToRate.isEmpty(); 520 } 521 522 /** 523 * Add given listener to the list and update rate if necessary. 524 * @param listener if null, add part is skipped. 525 * @param updateRate 526 * @return true if rate was updated. Otherwise, returns false. 527 */ 528 boolean addAndUpdateRate(OnSensorChangedListener listener, int updateRate) { 529 Integer oldUpdateRate = mListenersToRate.put(listener, updateRate); 530 if (mUpdateRate > updateRate) { 531 mUpdateRate = updateRate; 532 return true; 533 } else if (oldUpdateRate != null && oldUpdateRate == mUpdateRate) { 534 mUpdateRate = Collections.min(mListenersToRate.values()); 535 } 536 return false; 537 } 538 539 void onSensorChanged(CarSensorEvent event) { 540 // throw away old sensor data as oneway binder call can change order. 541 long updateTime = event.timestamp; 542 if (updateTime < mLastUpdateTime) { 543 Log.w(CarLibLog.TAG_SENSOR, "dropping old sensor data"); 544 return; 545 } 546 mLastUpdateTime = updateTime; 547 for (OnSensorChangedListener listener: mListenersToRate.keySet()) { 548 listener.onSensorChanged(event); 549 } 550 } 551 } 552} 553