• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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