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