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 com.android.car; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 24 import android.car.Car; 25 import android.car.hardware.CarSensorEvent; 26 import android.car.hardware.CarSensorManager; 27 import android.hardware.automotive.vehicle.V2_0.VehicleGear; 28 import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState; 29 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 30 import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 31 import android.os.SystemClock; 32 import android.test.suitebuilder.annotation.MediumTest; 33 import android.util.Log; 34 35 import com.android.car.vehiclehal.VehiclePropValueBuilder; 36 37 import org.junit.Test; 38 39 /** 40 * Test the public entry points for the CarSensorManager 41 */ 42 @MediumTest 43 public class CarSensorManagerTest extends MockedCarTestBase { 44 private static final String TAG = CarSensorManagerTest.class.getSimpleName(); 45 46 private CarSensorManager mCarSensorManager; 47 48 @Override configureMockedHal()49 protected synchronized void configureMockedHal() { 50 addProperty(VehicleProperty.NIGHT_MODE, 51 VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 52 .addIntValue(0) 53 .build()); 54 addProperty(VehicleProperty.PERF_VEHICLE_SPEED, 55 VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED) 56 .addFloatValue(0f) 57 .build()); 58 addProperty(VehicleProperty.FUEL_LEVEL, 59 VehiclePropValueBuilder.newBuilder(VehicleProperty.FUEL_LEVEL) 60 .addFloatValue(20000) // ml 61 .build()); 62 addProperty(VehicleProperty.PARKING_BRAKE_ON, 63 VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON) 64 .setBooleanValue(true) 65 .build()); 66 addProperty(VehicleProperty.CURRENT_GEAR, 67 VehiclePropValueBuilder.newBuilder(VehicleProperty.CURRENT_GEAR) 68 .addIntValue(0) 69 .build()); 70 addProperty(VehicleProperty.GEAR_SELECTION, 71 VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION) 72 .addIntValue(0) 73 .build()); 74 addProperty(VehicleProperty.IGNITION_STATE, 75 VehiclePropValueBuilder.newBuilder(VehicleProperty.IGNITION_STATE) 76 .addIntValue(CarSensorEvent.IGNITION_STATE_ACC) 77 .build()); 78 } 79 80 @Override setUp()81 public void setUp() throws Exception { 82 super.setUp(); 83 // Start the HAL layer and set up the sensor manager service 84 mCarSensorManager = (CarSensorManager) getCar().getCarManager(Car.SENSOR_SERVICE); 85 } 86 87 /** 88 * Test single sensor availability entry point 89 * @throws Exception 90 */ 91 @Test testSensorAvailability()92 public void testSensorAvailability() throws Exception { 93 // NOTE: Update this test if/when the reserved values put into use. For now, we 94 // expect them to never be supported. 95 assertFalse(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_RESERVED1)); 96 assertFalse(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_RESERVED13)); 97 assertFalse(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_RESERVED21)); 98 99 // We expect these sensors to always be available 100 assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_CAR_SPEED)); 101 assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_FUEL_LEVEL)); 102 assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE)); 103 assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_GEAR)); 104 assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_NIGHT)); 105 assertTrue(mCarSensorManager.isSensorSupported( 106 CarSensorManager.SENSOR_TYPE_IGNITION_STATE)); 107 } 108 109 /** 110 * Test sensor enumeration entry point 111 * @throws Exception 112 */ 113 @Test testSensorEnumeration()114 public void testSensorEnumeration() throws Exception { 115 int[] supportedSensors = mCarSensorManager.getSupportedSensors(); 116 assertNotNull(supportedSensors); 117 118 Log.i(TAG, "Found " + supportedSensors.length + " supported sensors."); 119 120 // Unfortunately, we don't have a definitive range for legal sensor values, 121 // so we have set a "reasonable" range here. The ending value, in particular, 122 // will need to be updated if/when new sensor types are allowed. 123 // Here we are ensuring that all the enumerated sensors also return supported. 124 for (int candidate = 0; candidate <= CarSensorManager.SENSOR_TYPE_RESERVED21; ++candidate) { 125 boolean supported = mCarSensorManager.isSensorSupported(candidate); 126 boolean found = false; 127 for (int sensor : supportedSensors) { 128 if (candidate == sensor) { 129 found = true; 130 Log.i(TAG, "Sensor type " + sensor + " is supported."); 131 break; 132 } 133 } 134 135 // Make sure the individual query on a sensor type is consistent 136 assertEquals(found, supported); 137 } 138 } 139 140 /** 141 * Test sensor notification registration, delivery, and unregistration 142 * @throws Exception 143 */ 144 @Test testEvents()145 public void testEvents() throws Exception { 146 // Set up our listener callback 147 SensorListener listener = new SensorListener(); 148 mCarSensorManager.registerListener(listener, 149 CarSensorManager.SENSOR_TYPE_NIGHT, 150 CarSensorManager.SENSOR_RATE_FASTEST); 151 152 VehiclePropValue value; 153 CarSensorEvent event; 154 CarSensorEvent.NightData data = null; 155 156 // Clear event generated by registerCallback() 157 listener.waitForSensorChange(); 158 listener.reset(); 159 160 // Set the value TRUE and wait for the event to arrive 161 getMockedVehicleHal().injectEvent( 162 VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 163 .setBooleanValue(true) 164 .setTimestamp(51L) 165 .build(), true); 166 assertTrue(listener.waitForSensorChange(51L)); 167 168 // Ensure we got the expected event 169 assertEquals(listener.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 170 171 // Ensure we got the expected value in our callback 172 data = listener.getLastEvent().getNightData(data); 173 Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp); 174 assertTrue(data.isNightMode); 175 176 // Ensure we have the expected value in the sensor manager's cache 177 event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT); 178 assertNotNull(event); 179 data = event.getNightData(data); 180 assertEquals("Unexpected event timestamp", data.timestamp, 51); 181 assertTrue("Unexpected value", data.isNightMode); 182 183 listener.reset(); 184 // Set the value FALSE 185 getMockedVehicleHal().injectEvent( 186 VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 187 .setTimestamp(1001) 188 .setBooleanValue(false) 189 .build(), true); 190 assertTrue(listener.waitForSensorChange(1001)); 191 192 // Ensure we got the expected event 193 assertEquals(listener.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 194 195 // Ensure we got the expected value in our callback 196 data = listener.getLastEvent().getNightData(data); 197 assertEquals("Unexpected event timestamp", 1001, data.timestamp); 198 assertFalse("Unexpected value", data.isNightMode); 199 200 // Ensure we have the expected value in the sensor manager's cache 201 event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT); 202 assertNotNull(event); 203 data = event.getNightData(data); 204 assertFalse(data.isNightMode); 205 206 // Unregister our handler (from all sensor types) 207 mCarSensorManager.unregisterListener(listener); 208 209 listener.reset(); 210 // Set the value TRUE again 211 value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 212 .setTimestamp(2001) 213 .setBooleanValue(true) 214 .build(); 215 getMockedVehicleHal().injectEvent(value, true); 216 217 // Ensure we did not get a callback (should timeout) 218 Log.i(TAG, "waiting for unexpected callback -- should timeout."); 219 assertFalse(listener.waitForSensorChange(2001)); 220 221 // Despite us not having a callback registered, the Sensor Manager should see the update 222 event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT); 223 assertNotNull(event); 224 data = event.getNightData(data); 225 assertEquals("Unexpected event timestamp", data.timestamp, 2001); 226 assertTrue("Unexpected value", data.isNightMode); 227 } 228 229 @Test testIgnitionState()230 public void testIgnitionState() { 231 CarSensorEvent event = mCarSensorManager.getLatestSensorEvent( 232 CarSensorManager.SENSOR_TYPE_IGNITION_STATE); 233 assertNotNull(event); 234 assertEquals(CarSensorEvent.IGNITION_STATE_ACC, event.intValues[0]); 235 } 236 237 @Test testIgnitionEvents()238 public void testIgnitionEvents() throws Exception { 239 SensorListener listener = new SensorListener(); 240 mCarSensorManager.registerListener(listener, CarSensorManager.SENSOR_TYPE_IGNITION_STATE, 241 CarSensorManager.SENSOR_RATE_NORMAL); 242 // Clear event generated by registerCallback() 243 listener.waitForSensorChange(); 244 245 // Mapping of HAL -> Manager ignition states. 246 int[] ignitionStates = new int[] { 247 VehicleIgnitionState.UNDEFINED, CarSensorEvent.IGNITION_STATE_UNDEFINED, 248 VehicleIgnitionState.LOCK, CarSensorEvent.IGNITION_STATE_LOCK, 249 VehicleIgnitionState.OFF, CarSensorEvent.IGNITION_STATE_OFF, 250 VehicleIgnitionState.ACC, CarSensorEvent.IGNITION_STATE_ACC, 251 VehicleIgnitionState.ON, CarSensorEvent.IGNITION_STATE_ON, 252 VehicleIgnitionState.START, CarSensorEvent.IGNITION_STATE_START, 253 VehicleIgnitionState.ON, CarSensorEvent.IGNITION_STATE_ON, 254 VehicleIgnitionState.LOCK, CarSensorEvent.IGNITION_STATE_LOCK, 255 }; 256 257 for (int i = 0; i < ignitionStates.length; i += 2) { 258 injectIgnitionStateAndAssert(listener, ignitionStates[i], ignitionStates[i + 1]); 259 } 260 } 261 injectIgnitionStateAndAssert(SensorListener listener, int halIgnitionState, int mgrIgnitionState)262 private void injectIgnitionStateAndAssert(SensorListener listener, int halIgnitionState, 263 int mgrIgnitionState) throws Exception{ 264 listener.reset(); 265 long time = SystemClock.elapsedRealtimeNanos(); 266 getMockedVehicleHal().injectEvent( 267 VehiclePropValueBuilder.newBuilder(VehicleProperty.IGNITION_STATE) 268 .addIntValue(halIgnitionState) 269 .setTimestamp(time) 270 .build(), true); 271 assertTrue(listener.waitForSensorChange(time)); 272 273 CarSensorEvent eventReceived = listener.getLastEvent(); 274 assertEquals(CarSensorManager.SENSOR_TYPE_IGNITION_STATE, eventReceived.sensorType); 275 assertEquals(mgrIgnitionState, eventReceived.intValues[0]); 276 } 277 278 @Test testGear()279 public void testGear() throws Exception { 280 SensorListener listener = new SensorListener(); 281 282 mCarSensorManager.registerListener(listener, CarSensorManager.SENSOR_TYPE_GEAR, 283 CarSensorManager.SENSOR_RATE_NORMAL); 284 285 // Clear event generated by registerCallback() 286 listener.waitForSensorChange(); 287 288 // Mapping of HAL -> Manager gear selection states. 289 int[] gears = new int[] { 290 VehicleGear.GEAR_PARK, CarSensorEvent.GEAR_PARK, 291 VehicleGear.GEAR_DRIVE, CarSensorEvent.GEAR_DRIVE, 292 VehicleGear.GEAR_NEUTRAL, CarSensorEvent.GEAR_NEUTRAL, 293 VehicleGear.GEAR_REVERSE, CarSensorEvent.GEAR_REVERSE, 294 VehicleGear.GEAR_1, CarSensorEvent.GEAR_FIRST, 295 VehicleGear.GEAR_2, CarSensorEvent.GEAR_SECOND, 296 VehicleGear.GEAR_3, CarSensorEvent.GEAR_THIRD, 297 VehicleGear.GEAR_4, CarSensorEvent.GEAR_FOURTH, 298 VehicleGear.GEAR_5, CarSensorEvent.GEAR_FIFTH, 299 VehicleGear.GEAR_6, CarSensorEvent.GEAR_SIXTH, 300 VehicleGear.GEAR_7, CarSensorEvent.GEAR_SEVENTH, 301 VehicleGear.GEAR_8, CarSensorEvent.GEAR_EIGHTH, 302 VehicleGear.GEAR_9, CarSensorEvent.GEAR_NINTH, 303 }; 304 305 for (int i = 0; i < gears.length; i += 2) { 306 injectGearEventAndAssert(listener, gears[i], gears[i + 1]); 307 } 308 } 309 injectGearEventAndAssert(SensorListener listener, int halValue, int carSensorValue)310 private void injectGearEventAndAssert(SensorListener listener, int halValue, 311 int carSensorValue) throws Exception { 312 listener.reset(); 313 long time = SystemClock.elapsedRealtimeNanos(); 314 getMockedVehicleHal().injectEvent( 315 VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION) 316 .addIntValue(halValue) 317 .setTimestamp(time) 318 .build(), true); 319 assertTrue(listener.waitForSensorChange(time)); 320 CarSensorEvent event = mCarSensorManager.getLatestSensorEvent( 321 CarSensorManager.SENSOR_TYPE_GEAR); 322 assertNotNull(event); 323 assertEquals(carSensorValue, event.intValues[0]); 324 } 325 326 /** 327 * Test sensor multiple liseners notification registration, delivery and unregistration. 328 * @throws Exception 329 */ 330 @Test testEventsWithMultipleListeners()331 public void testEventsWithMultipleListeners() throws Exception { 332 // Set up our listeners callback 333 SensorListener listener1 = new SensorListener(); 334 SensorListener listener2 = new SensorListener(); 335 SensorListener listener3 = new SensorListener(); 336 337 mCarSensorManager.registerListener(listener1, 338 CarSensorManager.SENSOR_TYPE_NIGHT, 339 CarSensorManager.SENSOR_RATE_NORMAL); 340 341 mCarSensorManager.registerListener(listener2, 342 CarSensorManager.SENSOR_TYPE_NIGHT, 343 CarSensorManager.SENSOR_RATE_NORMAL); 344 345 mCarSensorManager.registerListener(listener3, 346 CarSensorManager.SENSOR_TYPE_NIGHT, 347 CarSensorManager.SENSOR_RATE_FASTEST); 348 349 CarSensorEvent.NightData data = null; 350 VehiclePropValue value; 351 CarSensorEvent event; 352 353 // Clear event generated by registerCallback() 354 listener1.waitForSensorChange(); 355 listener2.waitForSensorChange(); 356 listener3.waitForSensorChange(); 357 listener1.reset(); 358 listener2.reset(); 359 listener3.reset(); 360 361 // Set the value TRUE and wait for the event to arrive 362 value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 363 .setTimestamp(1001L) 364 .setBooleanValue(true) 365 .build(); 366 getMockedVehicleHal().injectEvent(value, true); 367 368 assertTrue(listener1.waitForSensorChange(1001L)); 369 assertTrue(listener2.waitForSensorChange(1001L)); 370 assertTrue(listener3.waitForSensorChange(1001L)); 371 372 // Ensure we got the expected event 373 assertEquals(listener1.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 374 assertEquals(listener2.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 375 assertEquals(listener3.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 376 377 // Ensure we got the expected value in our callback 378 data = listener1.getLastEvent().getNightData(data); 379 Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp); 380 assertTrue(data.isNightMode); 381 382 data = listener2.getLastEvent().getNightData(data); 383 Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp); 384 assertTrue(data.isNightMode); 385 386 data = listener3.getLastEvent().getNightData(data); 387 Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp); 388 assertTrue(data.isNightMode); 389 390 // Ensure we have the expected value in the sensor manager's cache 391 event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT); 392 data = event.getNightData(data); 393 assertEquals("Unexpected event timestamp", 1001, data.timestamp); 394 assertTrue("Unexpected value", data.isNightMode); 395 396 listener1.reset(); 397 listener2.reset(); 398 listener3.reset(); 399 // Set the value FALSE 400 value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 401 .setTimestamp(2001) 402 .setBooleanValue(false) 403 .build(); 404 getMockedVehicleHal().injectEvent(value, true); 405 assertTrue(listener1.waitForSensorChange(2001)); 406 assertTrue(listener2.waitForSensorChange(2001)); 407 assertTrue(listener3.waitForSensorChange(2001)); 408 409 // Ensure we got the expected event 410 assertEquals(listener1.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 411 assertEquals(listener2.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 412 assertEquals(listener3.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT); 413 414 // Ensure we got the expected value in our callback 415 data = listener1.getLastEvent().getNightData(data); 416 assertEquals("Unexpected event timestamp", 2001, data.timestamp); 417 assertFalse("Unexpected value", data.isNightMode); 418 419 data = listener2.getLastEvent().getNightData(data); 420 assertEquals("Unexpected event timestamp", 2001, data.timestamp); 421 assertFalse("Unexpected value", data.isNightMode); 422 423 data = listener3.getLastEvent().getNightData(data); 424 assertEquals("Unexpected event timestamp", 2001, data.timestamp); 425 assertFalse("Unexpected value", data.isNightMode); 426 427 // Ensure we have the expected value in the sensor manager's cache 428 event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT); 429 data = event.getNightData(data); 430 assertFalse(data.isNightMode); 431 432 Log.d(TAG, "Unregistering listener3"); 433 listener1.reset(); 434 listener2.reset(); 435 listener3.reset(); 436 mCarSensorManager.unregisterListener(listener3); 437 Log.d(TAG, "Rate changed - expect sensor restart and change event sent."); 438 value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 439 .setTimestamp(3002) 440 .setBooleanValue(false) 441 .build(); 442 getMockedVehicleHal().injectEvent(value, true); 443 assertTrue(listener1.waitForSensorChange()); 444 assertTrue(listener2.waitForSensorChange()); 445 assertFalse(listener3.waitForSensorChange()); 446 listener1.reset(); 447 listener2.reset(); 448 listener3.reset(); 449 // Set the value TRUE again 450 value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE) 451 .setTimestamp() 452 .setBooleanValue(true) 453 .build(); 454 getMockedVehicleHal().injectEvent(value, true); 455 456 assertTrue(listener1.waitForSensorChange()); 457 assertTrue(listener2.waitForSensorChange()); 458 listener1.reset(); 459 listener2.reset(); 460 461 // Ensure we did not get a callback (should timeout) 462 Log.i(TAG, "waiting for unexpected callback -- should timeout."); 463 assertFalse(listener3.waitForSensorChange()); 464 465 Log.d(TAG, "Unregistering listener2"); 466 mCarSensorManager.unregisterListener(listener2); 467 468 Log.d(TAG, "Rate did nor change - dont expect sensor restart and change event sent."); 469 assertFalse(listener1.waitForSensorChange()); 470 assertFalse(listener2.waitForSensorChange()); 471 assertFalse(listener3.waitForSensorChange()); 472 } 473 474 475 /** 476 * Callback function we register for sensor update notifications. 477 * This tracks the number of times it has been called via the mAvailable semaphore, 478 * and keeps a reference to the most recent event delivered. 479 */ 480 class SensorListener implements CarSensorManager.OnSensorChangedListener { 481 private final Object mSync = new Object(); 482 483 private CarSensorEvent mLastEvent = null; 484 getLastEvent()485 CarSensorEvent getLastEvent() { 486 return mLastEvent; 487 } 488 reset()489 void reset() { 490 synchronized (mSync) { 491 mLastEvent = null; 492 } 493 } 494 waitForSensorChange()495 boolean waitForSensorChange() throws InterruptedException { 496 return waitForSensorChange(0); 497 } 498 499 // Returns True to indicate receipt of a sensor event. False indicates a timeout. waitForSensorChange(long eventTimeStamp)500 boolean waitForSensorChange(long eventTimeStamp) throws InterruptedException { 501 long start = SystemClock.elapsedRealtime(); 502 boolean matchTimeStamp = eventTimeStamp != 0; 503 synchronized (mSync) { 504 Log.d(TAG, "waitForSensorChange, mLastEvent: " + mLastEvent); 505 while ((mLastEvent == null 506 || (matchTimeStamp && mLastEvent.timestamp != eventTimeStamp)) 507 && (start + SHORT_WAIT_TIMEOUT_MS > SystemClock.elapsedRealtime())) { 508 mSync.wait(10L); 509 } 510 return mLastEvent != null && 511 (!matchTimeStamp || mLastEvent.timestamp == eventTimeStamp); 512 } 513 } 514 515 @Override onSensorChanged(CarSensorEvent event)516 public void onSensorChanged(CarSensorEvent event) { 517 Log.d(TAG, "onSensorChanged, event: " + event); 518 synchronized (mSync) { 519 // We're going to hold a reference to this object 520 mLastEvent = event; 521 mSync.notify(); 522 } 523 } 524 } 525 526 } 527