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