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.test; 18 19 import android.car.Car; 20 import android.car.hardware.CarPropertyValue; 21 import android.car.hardware.cabin.CarCabinManager; 22 import android.car.hardware.cabin.CarCabinManager.CarCabinEventCallback; 23 import android.car.hardware.cabin.CarCabinManager.PropertyId; 24 import android.hardware.automotive.vehicle.V2_0.VehicleAreaDoor; 25 import android.hardware.automotive.vehicle.V2_0.VehicleAreaWindow; 26 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 27 import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 28 import android.os.SystemClock; 29 import android.test.suitebuilder.annotation.MediumTest; 30 import android.util.Log; 31 import android.util.MutableInt; 32 33 import com.android.car.vehiclehal.VehiclePropValueBuilder; 34 import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; 35 36 import java.util.HashMap; 37 import java.util.concurrent.CountDownLatch; 38 import java.util.concurrent.Semaphore; 39 import java.util.concurrent.TimeUnit; 40 41 @MediumTest 42 public 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