CarSensorManagerTest.java revision 0d07c76bbc788fba8c77d8e932330ab22ec6ba27
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.hardware.CarSensorEvent;
21import android.car.hardware.CarSensorManager;
22import android.hardware.vehicle.V2_0.VehiclePropValue;
23import android.hardware.vehicle.V2_0.VehicleProperty;
24import android.os.SystemClock;
25import android.test.suitebuilder.annotation.MediumTest;
26import android.util.Log;
27
28import com.android.car.vehiclehal.VehiclePropValueBuilder;
29
30/**
31 * Test the public entry points for the CarSensorManager
32 */
33@MediumTest
34public class CarSensorManagerTest extends MockedCarTestBase {
35    private static final String TAG = CarSensorManagerTest.class.getSimpleName();
36
37    private CarSensorManager mCarSensorManager;
38
39    @Override
40    protected synchronized void configureMockedHal() {
41        addProperty(VehicleProperty.NIGHT_MODE,
42                VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
43                        .addIntValue(0)
44                        .build());
45        addProperty(VehicleProperty.PERF_VEHICLE_SPEED,
46                VehiclePropValueBuilder.newBuilder(VehicleProperty.PERF_VEHICLE_SPEED)
47                        .addFloatValue(0f)
48                        .build());
49        addProperty(VehicleProperty.FUEL_LEVEL_LOW,
50                VehiclePropValueBuilder.newBuilder(VehicleProperty.FUEL_LEVEL_LOW)
51                        .setBooleanValue(false)
52                        .build());
53        addProperty(VehicleProperty.PARKING_BRAKE_ON,
54                VehiclePropValueBuilder.newBuilder(VehicleProperty.PARKING_BRAKE_ON)
55                        .setBooleanValue(true)
56                        .build());
57        addProperty(VehicleProperty.CURRENT_GEAR,
58                VehiclePropValueBuilder.newBuilder(VehicleProperty.CURRENT_GEAR)
59                        .addIntValue(0)
60                        .build());
61        addProperty(VehicleProperty.GEAR_SELECTION,
62                VehiclePropValueBuilder.newBuilder(VehicleProperty.GEAR_SELECTION)
63                        .addIntValue(0)
64                        .build());
65        addProperty(VehicleProperty.DRIVING_STATUS,
66                VehiclePropValueBuilder.newBuilder(VehicleProperty.DRIVING_STATUS)
67                        .addIntValue(0)
68                        .build());
69    }
70
71    @Override
72    protected void setUp() throws Exception {
73        super.setUp();
74        // Start the HAL layer and set up the sensor manager service
75        mCarSensorManager = (CarSensorManager) getCar().getCarManager(Car.SENSOR_SERVICE);
76    }
77
78    /**
79     * Test single sensor availability entry point
80     * @throws Exception
81     */
82    public void testSensorAvailability() throws Exception {
83        // NOTE:  Update this test if/when the reserved values put into use.  For now, we
84        //        expect them to never be supported.
85        assertFalse(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_RESERVED1));
86        assertFalse(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_RESERVED13));
87        assertFalse(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_RESERVED21));
88
89        // We expect these sensors to always be available
90        assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_CAR_SPEED));
91        assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_FUEL_LEVEL));
92        assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_PARKING_BRAKE));
93        assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_GEAR));
94        assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_NIGHT));
95        assertTrue(mCarSensorManager.isSensorSupported(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS));
96    }
97
98    /**
99     * Test sensor enumeration entry point
100     * @throws Exception
101     */
102    public void testSensorEnumeration() throws Exception {
103        int[] supportedSensors = mCarSensorManager.getSupportedSensors();
104        assertNotNull(supportedSensors);
105
106        Log.i(TAG, "Found " + supportedSensors.length + " supported sensors.");
107
108        // Unfortunately, we don't have a definitive range for legal sensor values,
109        // so we have set a "reasonable" range here.  The ending value, in particular,
110        // will need to be updated if/when new sensor types are allowed.
111        // Here we are ensuring that all the enumerated sensors also return supported.
112        for (int candidate = 0; candidate <= CarSensorManager.SENSOR_TYPE_RESERVED21; ++candidate) {
113            boolean supported = mCarSensorManager.isSensorSupported(candidate);
114            boolean found = false;
115            for (int sensor : supportedSensors) {
116                if (candidate == sensor) {
117                    found = true;
118                    Log.i(TAG, "Sensor type " + sensor + " is supported.");
119                    break;
120                }
121            }
122
123            // Make sure the individual query on a sensor type is consistent
124            assertEquals(found, supported);
125        }
126
127        // Here we simply ensure that one specific expected sensor is always available to help
128        // ensure we don't have a trivially broken test finding nothing.
129        boolean found = false;
130        for (int sensor : supportedSensors) {
131            if (sensor == CarSensorManager.SENSOR_TYPE_DRIVING_STATUS) {
132                found = true;
133                break;
134            }
135        }
136        assertTrue("We expect at least DRIVING_STATUS to be available", found);
137    }
138
139    /**
140     * Test senor notification registration, delivery, and unregistration
141     * @throws Exception
142     */
143    public void testEvents() throws Exception {
144        // Set up our listener callback
145        SensorListener listener = new SensorListener();
146        mCarSensorManager.registerListener(listener,
147                CarSensorManager.SENSOR_TYPE_NIGHT,
148                CarSensorManager.SENSOR_RATE_NORMAL);
149
150        VehiclePropValue value;
151        CarSensorEvent event;
152        CarSensorEvent.NightData data = null;
153
154        listener.reset();
155
156        // Set the value TRUE and wait for the event to arrive
157        getMockedVehicleHal().injectEvent(
158                VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
159                        .setBooleanValue(true)
160                        .setTimestamp(1L)
161                        .build());
162        assertTrue(listener.waitForSensorChange(1L));
163
164        // Ensure we got the expected event
165        assertEquals(listener.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
166
167        // Ensure we got the expected value in our callback
168        data = listener.getLastEvent().getNightData(data);
169        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
170        assertTrue(data.isNightMode);
171
172        // Ensure we have the expected value in the sensor manager's cache
173        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
174        assertNotNull(event);
175        data = event.getNightData(data);
176        assertEquals("Unexpected event timestamp", data.timestamp, 1);
177        assertTrue("Unexpected value", data.isNightMode);
178
179        listener.reset();
180        // Set the value FALSE
181        getMockedVehicleHal().injectEvent(
182                VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
183                        .setTimestamp(1001)
184                        .setBooleanValue(false)
185                        .build());
186        assertTrue(listener.waitForSensorChange(1001));
187
188        // Ensure we got the expected event
189        assertEquals(listener.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
190
191        // Ensure we got the expected value in our callback
192        data = listener.getLastEvent().getNightData(data);
193        assertEquals("Unexpected event timestamp", 1001, data.timestamp);
194        assertFalse("Unexpected value", data.isNightMode);
195
196        // Ensure we have the expected value in the sensor manager's cache
197        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
198        assertNotNull(event);
199        data = event.getNightData(data);
200        assertFalse(data.isNightMode);
201
202        // Unregister our handler (from all sensor types)
203        mCarSensorManager.unregisterListener(listener);
204
205        listener.reset();
206        // Set the value TRUE again
207        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
208                .setTimestamp(2001)
209                .setBooleanValue(true)
210                .build();
211        getMockedVehicleHal().injectEvent(value);
212
213        // Ensure we did not get a callback (should timeout)
214        Log.i(TAG, "waiting for unexpected callback -- should timeout.");
215        assertFalse(listener.waitForSensorChange(2001));
216
217        // Despite us not having a callback registered, the Sensor Manager should see the update
218        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
219        assertNotNull(event);
220        data = event.getNightData(data);
221        assertEquals("Unexpected event timestamp", data.timestamp, 2001);
222        assertTrue("Unexpected value", data.isNightMode);
223    }
224
225
226    /**
227     * Test senor multiple liseners notification registration, delivery and unregistration.
228     * @throws Exception
229     */
230    public void testEventsWithMultipleListeners() throws Exception {
231        // Set up our listeners callback
232        SensorListener listener1 = new SensorListener();
233        SensorListener listener2 = new SensorListener();
234        SensorListener listener3 = new SensorListener();
235
236        mCarSensorManager.registerListener(listener1,
237                CarSensorManager.SENSOR_TYPE_NIGHT,
238                CarSensorManager.SENSOR_RATE_NORMAL);
239
240        mCarSensorManager.registerListener(listener2,
241                CarSensorManager.SENSOR_TYPE_NIGHT,
242                CarSensorManager.SENSOR_RATE_NORMAL);
243
244        mCarSensorManager.registerListener(listener3,
245                CarSensorManager.SENSOR_TYPE_NIGHT,
246                CarSensorManager.SENSOR_RATE_FASTEST);
247
248        CarSensorEvent.NightData data = null;
249        VehiclePropValue value;
250        CarSensorEvent event;
251
252        listener1.reset();
253        listener2.reset();
254        listener3.reset();
255
256        // Set the value TRUE and wait for the event to arrive
257        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
258                    .setTimestamp(42L)
259                    .setBooleanValue(true)
260                    .build();
261
262        getMockedVehicleHal().injectEvent(value);
263
264        assertTrue(listener1.waitForSensorChange(42L));
265        assertTrue(listener2.waitForSensorChange(42L));
266        assertTrue(listener3.waitForSensorChange(42L));
267
268        // Ensure we got the expected event
269        assertEquals(listener1.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
270        assertEquals(listener2.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
271        assertEquals(listener3.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
272
273        // Ensure we got the expected value in our callback
274        data = listener1.getLastEvent().getNightData(data);
275        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
276        assertTrue(data.isNightMode);
277
278        data = listener2.getLastEvent().getNightData(data);
279        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
280        assertTrue(data.isNightMode);
281
282        data = listener3.getLastEvent().getNightData(data);
283        Log.d(TAG, "NightMode " + data.isNightMode + " at " + data.timestamp);
284        assertTrue(data.isNightMode);
285
286        // Ensure we have the expected value in the sensor manager's cache
287        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
288        data = event.getNightData(data);
289        assertEquals("Unexpected event timestamp", 42, data.timestamp);
290        assertTrue("Unexpected value", data.isNightMode);
291
292        listener1.reset();
293        listener2.reset();
294        listener3.reset();
295        // Set the value FALSE
296        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
297                .setTimestamp(1001)
298                .setBooleanValue(false)
299                .build();
300        getMockedVehicleHal().injectEvent(value);
301        assertTrue(listener1.waitForSensorChange(1001));
302        assertTrue(listener2.waitForSensorChange(1001));
303        assertTrue(listener3.waitForSensorChange(1001));
304
305        // Ensure we got the expected event
306        assertEquals(listener1.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
307        assertEquals(listener2.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
308        assertEquals(listener3.getLastEvent().sensorType, CarSensorManager.SENSOR_TYPE_NIGHT);
309
310        // Ensure we got the expected value in our callback
311        data = listener1.getLastEvent().getNightData(data);
312        assertEquals("Unexpected event timestamp", 1001, data.timestamp);
313        assertFalse("Unexpected value", data.isNightMode);
314
315        data = listener2.getLastEvent().getNightData(data);
316        assertEquals("Unexpected event timestamp", 1001, data.timestamp);
317        assertFalse("Unexpected value", data.isNightMode);
318
319        data = listener3.getLastEvent().getNightData(data);
320        listener3.reset();
321        assertEquals("Unexpected event timestamp", 1001, data.timestamp);
322        assertFalse("Unexpected value", data.isNightMode);
323
324        // Ensure we have the expected value in the sensor manager's cache
325        event = mCarSensorManager.getLatestSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT);
326        data = event.getNightData(data);
327        assertFalse(data.isNightMode);
328
329        Log.d(TAG, "Unregistering listener3");
330        mCarSensorManager.unregisterListener(listener3);
331
332        Log.d(TAG, "Rate changed - expect sensor restart and change event sent.");
333        assertTrue(listener1.waitForSensorChange());
334        assertTrue(listener2.waitForSensorChange());
335        assertFalse(listener3.waitForSensorChange());
336
337        listener1.reset();
338        listener2.reset();
339        listener3.reset();
340        // Set the value TRUE again
341        value = VehiclePropValueBuilder.newBuilder(VehicleProperty.NIGHT_MODE)
342                .setTimestamp()
343                .setBooleanValue(true)
344                .build();
345        getMockedVehicleHal().injectEvent(value);
346
347        assertTrue(listener1.waitForSensorChange());
348        assertTrue(listener2.waitForSensorChange());
349
350        listener1.reset();
351        listener2.reset();
352
353        // Ensure we did not get a callback (should timeout)
354        Log.i(TAG, "waiting for unexpected callback -- should timeout.");
355        assertFalse(listener3.waitForSensorChange());
356
357        Log.d(TAG, "Unregistering listener2");
358        mCarSensorManager.unregisterListener(listener3);
359
360        Log.d(TAG, "Rate did nor change - dont expect sensor restart and change event sent.");
361        assertFalse(listener1.waitForSensorChange());
362        assertFalse(listener2.waitForSensorChange());
363        assertFalse(listener3.waitForSensorChange());
364    }
365
366
367    /**
368     * Callback function we register for sensor update notifications.
369     * This tracks the number of times it has been called via the mAvailable semaphore,
370     * and keeps a reference to the most recent event delivered.
371     */
372    class SensorListener implements CarSensorManager.OnSensorChangedListener {
373        private final Object mSync = new Object();
374
375        private CarSensorEvent mLastEvent = null;
376
377        CarSensorEvent getLastEvent() {
378            return mLastEvent;
379        }
380
381        void reset() {
382            synchronized (mSync) {
383                mLastEvent = null;
384            }
385        }
386
387        boolean waitForSensorChange() throws InterruptedException {
388            return waitForSensorChange(0);
389        }
390
391        // Returns True to indicate receipt of a sensor event.  False indicates a timeout.
392        boolean waitForSensorChange(long eventTimeStamp) throws InterruptedException {
393            long start = SystemClock.elapsedRealtime();
394            boolean matchTimeStamp = eventTimeStamp != 0;
395            synchronized (mSync) {
396                Log.d(TAG, "waitForSensorChange, mLastEvent: " + mLastEvent);
397                while ((mLastEvent == null
398                        || (matchTimeStamp && mLastEvent.timestamp != eventTimeStamp))
399                        && (start + SHORT_WAIT_TIMEOUT_MS > SystemClock.elapsedRealtime())) {
400                    mSync.wait(10L);
401                }
402                return mLastEvent != null &&
403                        (!matchTimeStamp || mLastEvent.timestamp == eventTimeStamp);
404            }
405        }
406
407        @Override
408        public void onSensorChanged(CarSensorEvent event) {
409            Log.d(TAG, "onSensorChanged, event: " + event);
410            synchronized (mSync) {
411                // We're going to hold a reference to this object
412                mLastEvent = event;
413                mSync.notify();
414            }
415        }
416    }
417
418}
419