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