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