CarSensorManagerTest.java revision cfe93105f637c2822da113308f113ed418d0b319
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
17package com.android.car.test;
18
19import android.car.Car;
20import android.car.CarNotConnectedException;
21import android.car.hardware.CarSensorEvent;
22import android.car.hardware.CarSensorManager;
23import android.hardware.automotive.vehicle.V2_0.VehicleGear;
24import android.hardware.automotive.vehicle.V2_0.VehicleIgnitionState;
25import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
26import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
27import android.os.SystemClock;
28import android.test.suitebuilder.annotation.MediumTest;
29import android.util.Log;
30
31import com.android.car.vehiclehal.VehiclePropValueBuilder;
32
33/**
34 * Test the public entry points for the CarSensorManager
35 */
36@MediumTest
37public 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