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