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