Home | History | Annotate | Download | only in hardware
      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.RequiresPermission;
     21 import android.car.Car;
     22 import android.car.CarApiUtil;
     23 import android.car.CarLibLog;
     24 import android.car.CarManagerBase;
     25 import android.car.CarNotConnectedException;
     26 import android.content.Context;
     27 import android.os.Handler;
     28 import android.os.Handler.Callback;
     29 import android.os.IBinder;
     30 import android.os.Looper;
     31 import android.os.Message;
     32 import android.os.RemoteException;
     33 import android.util.Log;
     34 
     35 import java.lang.ref.WeakReference;
     36 import java.util.HashMap;
     37 import java.util.Iterator;
     38 import java.util.LinkedList;
     39 import java.util.List;
     40 
     41 /**
     42  *  API for monitoring car sensor data.
     43  */
     44 public 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