• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertTrue;
24 import static org.testng.Assert.assertThrows;
25 
26 import android.car.Car;
27 import android.car.hardware.CarPropertyValue;
28 import android.car.hardware.hvac.CarHvacManager;
29 import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
30 import android.car.hardware.hvac.CarHvacManager.PropertyId;
31 import android.hardware.automotive.vehicle.VehicleAreaSeat;
32 import android.hardware.automotive.vehicle.VehicleAreaWindow;
33 import android.hardware.automotive.vehicle.VehiclePropValue;
34 import android.hardware.automotive.vehicle.VehicleProperty;
35 import android.hardware.automotive.vehicle.VehiclePropertyAccess;
36 import android.hardware.automotive.vehicle.VehiclePropertyChangeMode;
37 import android.os.SystemClock;
38 import android.util.Log;
39 import android.util.MutableInt;
40 
41 import androidx.test.ext.junit.runners.AndroidJUnit4;
42 import androidx.test.filters.MediumTest;
43 
44 import com.android.car.hal.test.AidlMockedVehicleHal.VehicleHalPropertyHandler;
45 import com.android.car.hal.test.AidlVehiclePropValueBuilder;
46 
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 
50 import java.util.HashMap;
51 import java.util.concurrent.CountDownLatch;
52 import java.util.concurrent.Semaphore;
53 import java.util.concurrent.TimeUnit;
54 
55 @RunWith(AndroidJUnit4.class)
56 @MediumTest
57 public class CarHvacManagerTest extends MockedCarTestBase {
58     private static final String TAG = CarHvacManagerTest.class.getSimpleName();
59 
60     // Use this semaphore to block until the callback is heard of.
61     private Semaphore mAvailable;
62 
63     private CarHvacManager mCarHvacManager;
64     private boolean mEventBoolVal;
65     private float mEventFloatVal;
66     private int mEventIntVal;
67     private int mEventZoneVal;
68 
69     @Override
configureMockedHal()70     protected void configureMockedHal() {
71         HvacPropertyHandler handler = new HvacPropertyHandler();
72         addAidlProperty(VehicleProperty.HVAC_DEFROSTER, handler)
73                 .addAreaConfig(VehicleAreaWindow.FRONT_WINDSHIELD, 0, 0);
74         addAidlProperty(VehicleProperty.HVAC_FAN_SPEED, handler)
75                 .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT, 0, 0);
76         addAidlProperty(VehicleProperty.HVAC_TEMPERATURE_SET, handler)
77                 .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT, 0, 0);
78         addAidlProperty(VehicleProperty.HVAC_TEMPERATURE_CURRENT, handler)
79                 .setChangeMode(VehiclePropertyChangeMode.CONTINUOUS)
80                 .setAccess(VehiclePropertyAccess.READ)
81                 .addAreaConfig(VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT, 0, 0);
82     }
83 
84     @Override
setUp()85     public void setUp() throws Exception {
86         super.setUp();
87         mAvailable = new Semaphore(0);
88         mCarHvacManager = (CarHvacManager) getCar().getCarManager(Car.HVAC_SERVICE);
89         mCarHvacManager.setIntProperty(VehicleProperty.HVAC_FAN_SPEED,
90                 VehicleAreaSeat.ROW_1_LEFT, 0);
91     }
92 
93     // Test a boolean property
94     @Test
testHvacRearDefrosterOn()95     public void testHvacRearDefrosterOn() throws Exception {
96         mCarHvacManager.setBooleanProperty(CarHvacManager.ID_WINDOW_DEFROSTER_ON,
97                 VehicleAreaWindow.FRONT_WINDSHIELD, true);
98         boolean defrost = mCarHvacManager.getBooleanProperty(CarHvacManager.ID_WINDOW_DEFROSTER_ON,
99                 VehicleAreaWindow.FRONT_WINDSHIELD);
100         assertTrue(defrost);
101 
102         mCarHvacManager.setBooleanProperty(CarHvacManager.ID_WINDOW_DEFROSTER_ON,
103                 VehicleAreaWindow.FRONT_WINDSHIELD, false);
104         defrost = mCarHvacManager.getBooleanProperty(CarHvacManager.ID_WINDOW_DEFROSTER_ON,
105                 VehicleAreaWindow.FRONT_WINDSHIELD);
106         assertFalse(defrost);
107     }
108 
109     /**
110      * Test {@link CarHvacManager#isPropertyAvailable(int, int)}
111      */
112     @Test
testHvacPropertyAvailable()113     public void testHvacPropertyAvailable() {
114         assertThat(mCarHvacManager.isPropertyAvailable(VehicleProperty.HVAC_AC_ON,
115                 VehicleAreaSeat.ROW_1_CENTER)).isFalse();
116         assertThat(mCarHvacManager.isPropertyAvailable(VehicleProperty.HVAC_FAN_SPEED,
117                 VehicleAreaSeat.ROW_1_LEFT)).isTrue();
118     }
119 
120     // Test an integer property
121     @Test
testHvacFanSpeed()122     public void testHvacFanSpeed() throws Exception {
123         mCarHvacManager.setIntProperty(CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT,
124                 VehicleAreaSeat.ROW_1_LEFT, 15);
125         int speed = mCarHvacManager.getIntProperty(CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT,
126                 VehicleAreaSeat.ROW_1_LEFT);
127         assertEquals(15, speed);
128 
129         mCarHvacManager.setIntProperty(CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT,
130                 VehicleAreaSeat.ROW_1_LEFT, 23);
131         speed = mCarHvacManager.getIntProperty(CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT,
132                 VehicleAreaSeat.ROW_1_LEFT);
133         assertEquals(23, speed);
134     }
135 
136     // Test an float property
137     @Test
testHvacTempSetpoint()138     public void testHvacTempSetpoint() throws Exception {
139         mCarHvacManager.setFloatProperty(CarHvacManager.ID_ZONED_TEMP_SETPOINT,
140                 VehicleAreaSeat.ROW_1_LEFT, 70);
141         float temp = mCarHvacManager.getFloatProperty(CarHvacManager.ID_ZONED_TEMP_SETPOINT,
142                 VehicleAreaSeat.ROW_1_LEFT);
143         assertEquals(70.0, temp, 0);
144 
145         mCarHvacManager.setFloatProperty(CarHvacManager.ID_ZONED_TEMP_SETPOINT,
146                 VehicleAreaSeat.ROW_1_LEFT, (float) 65.5);
147         temp = mCarHvacManager.getFloatProperty(CarHvacManager.ID_ZONED_TEMP_SETPOINT,
148                 VehicleAreaSeat.ROW_1_LEFT);
149         assertEquals(65.5, temp, 0);
150     }
151 
152     @Test
testError()153     public void testError() throws Exception {
154         final int PROP = VehicleProperty.HVAC_DEFROSTER;
155         final int AREA = VehicleAreaWindow.FRONT_WINDSHIELD;
156         final int ERR_CODE = 42;
157 
158         CountDownLatch errorLatch = new CountDownLatch(1);
159         MutableInt propertyIdReceived = new MutableInt(0);
160         MutableInt areaIdReceived = new MutableInt(0);
161 
162         mCarHvacManager.registerCallback(new CarHvacEventCallback()  {
163             @Override
164             public void onChangeEvent(CarPropertyValue value) {
165 
166             }
167 
168             @Override
169             public void onErrorEvent(@PropertyId int propertyId, int area) {
170                 propertyIdReceived.value = propertyId;
171                 areaIdReceived.value = area;
172                 errorLatch.countDown();
173             }
174         });
175         mCarHvacManager.setBooleanProperty(PROP, AREA, true);
176         getAidlMockedVehicleHal().injectError(ERR_CODE, PROP, AREA);
177         assertTrue(errorLatch.await(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
178         assertEquals(PROP, propertyIdReceived.value);
179         assertEquals(AREA, areaIdReceived.value);
180     }
181 
182     // Test an event
183     @Test
testEvent()184     public void testEvent() throws Exception {
185         mCarHvacManager.registerCallback(new EventListener());
186         // Wait for events generated on registration
187         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
188         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
189         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
190         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
191 
192         // Inject a boolean event and wait for its callback in onPropertySet.
193         VehiclePropValue v = AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_DEFROSTER)
194                 .setAreaId(VehicleAreaWindow.FRONT_WINDSHIELD)
195                 .setTimestamp(SystemClock.elapsedRealtimeNanos())
196                 .addIntValues(1)
197                 .build();
198         assertEquals(0, mAvailable.availablePermits());
199         getAidlMockedVehicleHal().injectEvent(v);
200 
201         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
202         assertTrue(mEventBoolVal);
203         assertEquals(mEventZoneVal, VehicleAreaWindow.FRONT_WINDSHIELD);
204 
205         // Inject a float event and wait for its callback in onPropertySet.
206         v = AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_TEMPERATURE_CURRENT)
207                 .setAreaId(VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT)
208                 .setTimestamp(SystemClock.elapsedRealtimeNanos())
209                 .addFloatValues(67f)
210                 .build();
211         assertEquals(0, mAvailable.availablePermits());
212         getAidlMockedVehicleHal().injectEvent(v);
213 
214         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
215         assertEquals(67, mEventFloatVal, 0);
216         assertEquals(VehicleAreaSeat.ROW_1_LEFT | VehicleAreaSeat.ROW_1_RIGHT, mEventZoneVal);
217 
218         // Inject an integer event and wait for its callback in onPropertySet.
219         v = AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_FAN_SPEED)
220                 .setAreaId(VehicleAreaSeat.ROW_1_LEFT)
221                 .setTimestamp(SystemClock.elapsedRealtimeNanos())
222                 .addIntValues(4)
223                 .build();
224         assertEquals(0, mAvailable.availablePermits());
225         getAidlMockedVehicleHal().injectEvent(v);
226 
227         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
228         assertEquals(4, mEventIntVal);
229         assertEquals(VehicleAreaSeat.ROW_1_LEFT, mEventZoneVal);
230     }
231 
232     /**
233      * Test {@link CarHvacManager#unregisterCallback(CarHvacEventCallback)}
234      */
235     @Test
testUnregisterCallback()236     public void testUnregisterCallback() throws Exception {
237         EventListener listener = new EventListener();
238         mCarHvacManager.registerCallback(listener);
239         // Wait for events generated on registration
240         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
241         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
242         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
243         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
244 
245         // Inject a boolean event and wait for its callback in onPropertySet.
246         VehiclePropValue v = AidlVehiclePropValueBuilder.newBuilder(VehicleProperty.HVAC_DEFROSTER)
247                 .setAreaId(VehicleAreaWindow.FRONT_WINDSHIELD)
248                 .setTimestamp(SystemClock.elapsedRealtimeNanos())
249                 .addIntValues(1)
250                 .build();
251         assertEquals(0, mAvailable.availablePermits());
252         getAidlMockedVehicleHal().injectEvent(v);
253 
254         // Verify client get the callback.
255         assertTrue(mAvailable.tryAcquire(2L, TimeUnit.SECONDS));
256         assertTrue(mEventBoolVal);
257         assertEquals(mEventZoneVal, VehicleAreaWindow.FRONT_WINDSHIELD);
258 
259         // test unregister callback
260         mCarHvacManager.unregisterCallback(listener);
261         assertThrows(AssertionError.class, () -> getAidlMockedVehicleHal().injectEvent(v));
262     }
263 
264     private class HvacPropertyHandler implements VehicleHalPropertyHandler {
265         HashMap<Integer, VehiclePropValue> mMap = new HashMap<>();
266 
267         @Override
onPropertySet(VehiclePropValue value)268         public synchronized void onPropertySet(VehiclePropValue value) {
269             mMap.put(value.prop, value);
270         }
271 
272         @Override
onPropertyGet(VehiclePropValue value)273         public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
274             VehiclePropValue currentValue = mMap.get(value.prop);
275             // VNS will call get method when subscribe is called, just return empty value.
276             return currentValue != null ? currentValue : value;
277         }
278 
279         @Override
onPropertySubscribe(int property, float sampleRate)280         public synchronized void onPropertySubscribe(int property, float sampleRate) {
281             Log.d(TAG, "onPropertySubscribe property " + property + " sampleRate " + sampleRate);
282             if (mMap.get(property) == null) {
283                 Log.d(TAG, "onPropertySubscribe add placeholder property: " + property);
284                 VehiclePropValue placeholderValue = AidlVehiclePropValueBuilder.newBuilder(property)
285                         .setAreaId(0)
286                         .setTimestamp(SystemClock.elapsedRealtimeNanos())
287                         .addIntValues(1)
288                         .addFloatValues(1)
289                         .build();
290                 mMap.put(property, placeholderValue);
291             }
292         }
293 
294         @Override
onPropertyUnsubscribe(int property)295         public synchronized void onPropertyUnsubscribe(int property) {
296             Log.d(TAG, "onPropertyUnSubscribe property " + property);
297         }
298     }
299 
300     private class EventListener implements CarHvacEventCallback {
EventListener()301         EventListener() { }
302 
303         @Override
onChangeEvent(final CarPropertyValue value)304         public void onChangeEvent(final CarPropertyValue value) {
305             Log.d(TAG, "onChangeEvent: "  + value);
306             Object o = value.getValue();
307             mEventZoneVal = value.getAreaId();
308 
309             if (o instanceof Integer) {
310                 mEventIntVal = (Integer) o;
311             } else if (o instanceof Float) {
312                 mEventFloatVal = (Float) o;
313             } else if (o instanceof Boolean) {
314                 mEventBoolVal = (Boolean) o;
315             }
316             mAvailable.release();
317         }
318 
319         @Override
onErrorEvent(final int propertyId, final int zone)320         public void onErrorEvent(final int propertyId, final int zone) {
321             Log.d(TAG, "Error:  propertyId=" + propertyId + "  zone=" + zone);
322         }
323     }
324 }
325