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.CarPropertyValue;
21import android.car.hardware.cabin.CarCabinManager;
22import android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback;
23import android.car.hardware.cabin.CarCabinManager.PropertyId;
24import android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor;
25import android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow;
26import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
27import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
28import android.os.SystemClock;
29import android.test.suitebuilder.annotation.MediumTest;
30import android.util.Log;
31import android.util.MutableInt;
32
33import com.android.car.vehiclehal.VehiclePropValueBuilder;
34import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
35
36import java.util.HashMap;
37import java.util.concurrent.CountDownLatch;
38import java.util.concurrent.Semaphore;
39import java.util.concurrent.TimeUnit;
40
41@MediumTest
42public class CarCabinManagerTest extends MockedCarTestBase {
43    private static final String TAG = CarCabinManagerTest.class.getSimpleName();
44
45    // Use this semaphore to block until the callback is heard of.
46    private Semaphore mAvailable;
47
48    private CarCabinManager mCarCabinManager;
49    private boolean mEventBoolVal;
50    private int mEventIntVal;
51    private int mEventZoneVal;
52
53    @Override
54    protected synchronized void configureMockedHal() {
55        CabinPropertyHandler handler = new CabinPropertyHandler();
56        addProperty(VehicleProperty.DOOR_LOCK, handler)
57                .setSupportedAreas(VehicleAreaDoor.ROW_1_LEFT);
58        addProperty(VehicleProperty.WINDOW_POS, handler)
59                .setSupportedAreas(VehicleAreaWindow.ROW_1_LEFT);
60    }
61
62    @Override
63    protected void setUp() throws Exception {
64        super.setUp();
65        mAvailable = new Semaphore(0);
66        mCarCabinManager = (CarCabinManager) getCar().getCarManager(Car.CABIN_SERVICE);
67    }
68
69    // Test a boolean property
70    public void testCabinDoorLockOn() throws Exception {
71        mCarCabinManager.setBooleanProperty(CarCabinManager.ID_DOOR_LOCK,
72                VehicleAreaDoor.ROW_1_LEFT, true);
73        boolean lock = mCarCabinManager.getBooleanProperty(CarCabinManager.ID_DOOR_LOCK,
74                VehicleAreaDoor.ROW_1_LEFT);
75        assertTrue(lock);
76
77        mCarCabinManager.setBooleanProperty(CarCabinManager.ID_DOOR_LOCK,
78                VehicleAreaDoor.ROW_1_LEFT, false);
79        lock = mCarCabinManager.getBooleanProperty(CarCabinManager.ID_DOOR_LOCK,
80                VehicleAreaDoor.ROW_1_LEFT);
81        assertFalse(lock);
82    }
83
84    // Test an integer property
85    public void testCabinWindowPos() throws Exception {
86        mCarCabinManager.setIntProperty(CarCabinManager.ID_WINDOW_POS,
87                VehicleAreaWindow.ROW_1_LEFT, 50);
88        int windowPos = mCarCabinManager.getIntProperty(CarCabinManager.ID_WINDOW_POS,
89                VehicleAreaWindow.ROW_1_LEFT);
90        assertEquals(50, windowPos);
91
92        mCarCabinManager.setIntProperty(CarCabinManager.ID_WINDOW_POS,
93                VehicleAreaWindow.ROW_1_LEFT, 25);
94        windowPos = mCarCabinManager.getIntProperty(CarCabinManager.ID_WINDOW_POS,
95                VehicleAreaWindow.ROW_1_LEFT);
96        assertEquals(25, windowPos);
97    }
98
99    public void testError() throws Exception {
100        final int PROP = VehicleProperty.DOOR_LOCK;
101        final int AREA = VehicleAreaWindow.ROW_1_LEFT;
102        final int ERR_CODE = 42;
103
104        CountDownLatch errorLatch = new CountDownLatch(1);
105        MutableInt propertyIdReceived = new MutableInt(0);
106        MutableInt areaIdReceived = new MutableInt(0);
107
108        mCarCabinManager.registerCallback(new CarCabinEventCallback() {
109            @Override
110            public void onChangeEvent(CarPropertyValue value) {
111
112            }
113
114            @Override
115            public void onErrorEvent(@PropertyId int propertyId, int area) {
116                propertyIdReceived.value = propertyId;
117                areaIdReceived.value = area;
118                errorLatch.countDown();
119            }
120        });
121
122        getMockedVehicleHal().injectError(ERR_CODE, PROP, AREA);
123        assertTrue(errorLatch.await(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
124        assertEquals(PROP, propertyIdReceived.value);
125        assertEquals(AREA, areaIdReceived.value);
126    }
127
128
129    // Test an event
130    public void testEvent() throws Exception {
131        mCarCabinManager.registerCallback(new EventListener());
132
133        // Inject a boolean event and wait for its callback in onPropertySet.
134        VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.DOOR_LOCK)
135                .setAreaId(VehicleAreaDoor.ROW_1_LEFT)
136                .setTimestamp(SystemClock.elapsedRealtimeNanos())
137                .addIntValue(1)
138                .build();
139
140        assertEquals(0, mAvailable.availablePermits());
141        getMockedVehicleHal().injectEvent(v);
142
143        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
144        assertTrue(mEventBoolVal);
145        assertEquals(VehicleAreaDoor.ROW_1_LEFT, mEventZoneVal);
146
147        // Inject an integer event and wait for its callback in onPropertySet.
148        v = VehiclePropValueBuilder.newBuilder(VehicleProperty.WINDOW_POS)
149                .setAreaId(VehicleAreaWindow.ROW_1_LEFT)
150                .setTimestamp(SystemClock.elapsedRealtimeNanos())
151                .addIntValue(75)
152                .build();
153
154        assertEquals(0, mAvailable.availablePermits());
155        getMockedVehicleHal().injectEvent(v);
156
157        assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
158        assertEquals(mEventIntVal, 75);
159        assertEquals(VehicleAreaWindow.ROW_1_LEFT, mEventZoneVal);
160    }
161
162
163    private class CabinPropertyHandler implements VehicleHalPropertyHandler {
164        HashMap<Integer, VehiclePropValue> mMap = new HashMap<>();
165
166        @Override
167        public synchronized void onPropertySet(VehiclePropValue value) {
168            mMap.put(value.prop, value);
169        }
170
171        @Override
172        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
173            VehiclePropValue currentValue = mMap.get(value.prop);
174            // VNS will call get method when subscribe is called, just return empty value.
175            return currentValue != null ? currentValue : value;
176        }
177
178        @Override
179        public synchronized void onPropertySubscribe(int property, int zones, float sampleRate) {
180            Log.d(TAG, "onPropertySubscribe property " + property + " sampleRate " + sampleRate);
181        }
182
183        @Override
184        public synchronized void onPropertyUnsubscribe(int property) {
185            Log.d(TAG, "onPropertyUnSubscribe property " + property);
186        }
187    }
188
189    private class EventListener implements CarCabinEventCallback {
190        EventListener() { }
191
192        @Override
193        public void onChangeEvent(final CarPropertyValue value) {
194            Log.d(TAG, "onChangeEvent: "  + value);
195            Object o = value.getValue();
196            mEventZoneVal = value.getAreaId();
197
198            if (o instanceof Integer) {
199                mEventIntVal = (Integer) o;
200            } else if (o instanceof Boolean) {
201                mEventBoolVal = (Boolean) o;
202            } else {
203                Log.e(TAG, "onChangeEvent:  Unknown instance type = " + o.getClass().getName());
204            }
205            mAvailable.release();
206        }
207
208        @Override
209        public void onErrorEvent(final int propertyId, final int zone) {
210            Log.d(TAG, "Error:  propertyId=" + propertyId + "  zone=" + zone);
211        }
212    }
213}
214