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