1 /* 2 * Copyright (C) 2019 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 package android.car.cts; 17 18 import static java.lang.Integer.toHexString; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertNotEquals; 23 import static org.junit.Assert.assertNotNull; 24 25 import android.car.Car; 26 import android.car.VehicleAreaType; 27 import android.car.VehiclePropertyIds; 28 import android.car.hardware.CarPropertyConfig; 29 import android.car.hardware.CarPropertyValue; 30 import android.car.hardware.property.CarPropertyManager; 31 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback; 32 import android.platform.test.annotations.RequiresDevice; 33 34 import androidx.test.runner.AndroidJUnit4; 35 36 import static com.google.common.truth.Truth.assertThat; 37 import static org.junit.Assert.assertTrue; 38 39 import android.test.suitebuilder.annotation.SmallTest; 40 import android.util.ArraySet; 41 import android.util.Log; 42 import android.util.SparseArray; 43 import com.android.internal.annotations.GuardedBy; 44 import java.util.List; 45 import org.junit.Assert; 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 50 @SmallTest 51 @RequiresDevice 52 @RunWith(AndroidJUnit4.class) 53 public class CarPropertyManagerTest extends CarApiTestBase { 54 55 private static final String TAG = CarPropertyManagerTest.class.getSimpleName(); 56 private static final long WAIT_CALLBACK = 1500L; 57 private CarPropertyManager mCarPropertyManager; 58 /** contains property Ids for the properties required by CDD*/ 59 private ArraySet<Integer> mPropertyIds = new ArraySet<>(); 60 61 62 private static class CarPropertyEventCounter implements CarPropertyEventCallback { 63 private final Object mLock = new Object(); 64 65 @GuardedBy("mLock") 66 private SparseArray<Integer> mEventCounter = new SparseArray<>(); 67 68 @GuardedBy("mLock") 69 private SparseArray<Integer> mErrorCounter = new SparseArray<>(); 70 71 public int receivedEvent(int propId) { 72 int val; 73 synchronized (mLock) { 74 val = mEventCounter.get(propId, 0); 75 } 76 return val; 77 } 78 79 public int receivedError(int propId) { 80 int val; 81 synchronized (mLock) { 82 val = mErrorCounter.get(propId, 0); 83 } 84 return val; 85 } 86 87 @Override 88 public void onChangeEvent(CarPropertyValue value) { 89 synchronized (mLock) { 90 int val = mEventCounter.get(value.getPropertyId(), 0) + 1; 91 mEventCounter.put(value.getPropertyId(), val); 92 } 93 } 94 95 @Override 96 public void onErrorEvent(int propId, int zone) { 97 synchronized (mLock) { 98 int val = mErrorCounter.get(propId, 0) + 1; 99 mErrorCounter.put(propId, val); 100 } 101 } 102 } 103 104 @Before 105 public void setUp() throws Exception { 106 super.setUp(); 107 mCarPropertyManager = (CarPropertyManager) getCar().getCarManager(Car.PROPERTY_SERVICE); 108 mPropertyIds.add(VehiclePropertyIds.PERF_VEHICLE_SPEED); 109 mPropertyIds.add(VehiclePropertyIds.GEAR_SELECTION); 110 mPropertyIds.add(VehiclePropertyIds.NIGHT_MODE); 111 } 112 113 @Test 114 public void testGetPropertyList() { 115 List<CarPropertyConfig> allConfigs = mCarPropertyManager.getPropertyList(); 116 assertNotNull(allConfigs); 117 List<CarPropertyConfig> requiredConfigs = mCarPropertyManager.getPropertyList(mPropertyIds); 118 // Vehicles need to implement all of those properties 119 assertEquals(mPropertyIds.size(), requiredConfigs.size()); 120 121 } 122 123 @SuppressWarnings("unchecked") 124 @Test 125 public void testGetProperty() { 126 List<CarPropertyConfig> configs = mCarPropertyManager.getPropertyList(mPropertyIds); 127 for (CarPropertyConfig cfg : configs) { 128 if (cfg.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ) { 129 int[] areaIds = getAreaIdsHelper(cfg); 130 int propId = cfg.getPropertyId(); 131 // no guarantee if we can get values, just call and check if it throws exception. 132 if (cfg.getPropertyType() == Boolean.class) { 133 for (int areaId : areaIds) { 134 mCarPropertyManager.getBooleanProperty(propId, areaId); 135 } 136 } else if (cfg.getPropertyType() == Integer.class) { 137 for (int areaId : areaIds) { 138 mCarPropertyManager.getIntProperty(propId, areaId); 139 } 140 } else if (cfg.getPropertyType() == Float.class) { 141 for (int areaId : areaIds) { 142 mCarPropertyManager.getFloatProperty(propId, areaId); 143 } 144 } else if (cfg.getPropertyType() == Integer[].class) { 145 for (int areId : areaIds) { 146 mCarPropertyManager.getIntArrayProperty(propId, areId); 147 } 148 } else { 149 for (int areaId : areaIds) { 150 mCarPropertyManager.getProperty( 151 cfg.getPropertyType(), propId, areaId);; 152 } 153 } 154 } 155 } 156 } 157 158 @Test 159 public void testIsPropertyAvailable() { 160 List<CarPropertyConfig> configs = mCarPropertyManager.getPropertyList(mPropertyIds); 161 162 for (CarPropertyConfig cfg : configs) { 163 int[] areaIds = getAreaIdsHelper(cfg); 164 for (int areaId : areaIds) { 165 assertTrue(mCarPropertyManager.isPropertyAvailable(cfg.getPropertyId(), areaId)); 166 } 167 } 168 } 169 170 @Test 171 public void testSetProperty() { 172 List<CarPropertyConfig> configs = mCarPropertyManager.getPropertyList(); 173 for (CarPropertyConfig cfg : configs) { 174 if (cfg.getAccess() == CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE 175 && cfg.getPropertyType() == Boolean.class) { 176 // Get the current value, and set a different value to the property and verify it. 177 for (int areaId : getAreaIdsHelper(cfg)) { 178 assertTrue(setBooleanPropertyHelper(cfg.getPropertyId(), areaId)); 179 } 180 } 181 } 182 } 183 184 185 @Test 186 public void testRegisterCallback() throws Exception { 187 //Test on registering a invalid property 188 int invalidPropertyId = -1; 189 boolean isRegistered = mCarPropertyManager.registerCallback( 190 new CarPropertyEventCounter(), invalidPropertyId, 0); 191 assertFalse(isRegistered); 192 193 // Test for continuous properties 194 int vehicleSpeed = VehiclePropertyIds.PERF_VEHICLE_SPEED; 195 CarPropertyEventCounter speedListenerNormal = new CarPropertyEventCounter(); 196 CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter(); 197 198 assertEquals(0, speedListenerNormal.receivedEvent(vehicleSpeed)); 199 assertEquals(0, speedListenerNormal.receivedError(vehicleSpeed)); 200 assertEquals(0, speedListenerUI.receivedEvent(vehicleSpeed)); 201 assertEquals(0, speedListenerUI.receivedError(vehicleSpeed)); 202 203 mCarPropertyManager.registerCallback(speedListenerNormal, vehicleSpeed, 204 CarPropertyManager.SENSOR_RATE_NORMAL); 205 mCarPropertyManager.registerCallback(speedListenerUI, vehicleSpeed, 206 CarPropertyManager.SENSOR_RATE_FASTEST); 207 208 Thread.sleep(WAIT_CALLBACK); 209 assertNotEquals(0, speedListenerNormal.receivedEvent(vehicleSpeed)); 210 assertNotEquals(0, speedListenerUI.receivedEvent(vehicleSpeed)); 211 assertTrue(speedListenerUI.receivedEvent(vehicleSpeed) > 212 speedListenerNormal.receivedEvent(vehicleSpeed)); 213 214 mCarPropertyManager.unregisterCallback(speedListenerUI); 215 mCarPropertyManager.unregisterCallback(speedListenerNormal); 216 217 // Test for on_change properties 218 int nightMode = VehiclePropertyIds.NIGHT_MODE; 219 CarPropertyEventCounter nightModeListener = new CarPropertyEventCounter(); 220 mCarPropertyManager.registerCallback(nightModeListener, nightMode, 0); 221 Thread.sleep(WAIT_CALLBACK); 222 assertEquals(1, nightModeListener.receivedEvent(nightMode)); 223 224 mCarPropertyManager.unregisterCallback(nightModeListener); 225 226 } 227 228 @Test 229 public void testUnregisterCallback() throws Exception { 230 231 int vehicleSpeed = VehiclePropertyIds.PERF_VEHICLE_SPEED; 232 CarPropertyEventCounter speedListenerNormal = new CarPropertyEventCounter(); 233 CarPropertyEventCounter speedListenerUI = new CarPropertyEventCounter(); 234 235 mCarPropertyManager.registerCallback(speedListenerNormal, vehicleSpeed, 236 CarPropertyManager.SENSOR_RATE_NORMAL); 237 238 // test on unregistering a callback that was never registered 239 try { 240 mCarPropertyManager.unregisterCallback(speedListenerUI); 241 } catch (Exception e) { 242 Assert.fail(); 243 } 244 245 mCarPropertyManager.registerCallback(speedListenerUI, vehicleSpeed, 246 CarPropertyManager.SENSOR_RATE_UI); 247 Thread.sleep(WAIT_CALLBACK); 248 249 mCarPropertyManager.unregisterCallback(speedListenerNormal, vehicleSpeed); 250 Thread.sleep(WAIT_CALLBACK); 251 252 int currentEventNormal = speedListenerNormal.receivedEvent(vehicleSpeed); 253 int currentEventUI = speedListenerUI.receivedEvent(vehicleSpeed); 254 Thread.sleep(WAIT_CALLBACK); 255 256 assertEquals(currentEventNormal, speedListenerNormal.receivedEvent(vehicleSpeed)); 257 assertNotEquals(currentEventUI, speedListenerUI.receivedEvent(vehicleSpeed)); 258 259 mCarPropertyManager.unregisterCallback(speedListenerUI); 260 Thread.sleep(WAIT_CALLBACK); 261 262 currentEventUI = speedListenerUI.receivedEvent(vehicleSpeed); 263 Thread.sleep(WAIT_CALLBACK); 264 assertEquals(currentEventUI, speedListenerUI.receivedEvent(vehicleSpeed)); 265 } 266 267 /** 268 * Returns true if set boolean value successfully. 269 * @param propId 270 * @param areaId 271 * @return 272 */ 273 private boolean setBooleanPropertyHelper(int propId, int areaId) { 274 boolean currentValue = mCarPropertyManager.getBooleanProperty(propId, areaId); 275 boolean expectedValue = !currentValue; 276 try { 277 mCarPropertyManager.setBooleanProperty(propId, areaId, expectedValue); 278 Thread.sleep(WAIT_CALLBACK); 279 currentValue = mCarPropertyManager.getBooleanProperty(propId, areaId); 280 return expectedValue == currentValue; 281 } catch (Exception e) { 282 Log.e(TAG, new StringBuilder() 283 .append("Failed to verify Property Id: 0x") 284 .append(toHexString(propId)) 285 .append(", in areaId: 0x") 286 .append(toHexString(areaId)) 287 .toString()); 288 } 289 return false; 290 } 291 292 private int[] getAreaIdsHelper(CarPropertyConfig config) { 293 if (config.isGlobalProperty()) { 294 int[] areaIds = {0}; 295 return areaIds; 296 } else { 297 return config.getAreaIds(); 298 } 299 } 300 301 } 302