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