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