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