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 17 package com.android.car; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import static org.junit.Assert.fail; 23 import static org.testng.Assert.assertThrows; 24 25 import android.car.Car; 26 import android.car.VehicleAreaType; 27 import android.car.VehicleAreaWheel; 28 import android.car.VehiclePropertyIds; 29 import android.car.hardware.CarPropertyConfig; 30 import android.car.hardware.CarPropertyValue; 31 import android.car.hardware.property.CarInternalErrorException; 32 import android.car.hardware.property.CarPropertyManager; 33 import android.car.hardware.property.PropertyAccessDeniedSecurityException; 34 import android.car.hardware.property.PropertyNotAvailableAndRetryException; 35 import android.car.hardware.property.PropertyNotAvailableException; 36 import android.car.hardware.property.VehicleHalStatusCode; 37 import android.car.test.util.Visitor; 38 import android.hardware.automotive.vehicle.RawPropValues; 39 import android.hardware.automotive.vehicle.VehicleArea; 40 import android.hardware.automotive.vehicle.VehicleAreaSeat; 41 import android.hardware.automotive.vehicle.VehiclePropValue; 42 import android.hardware.automotive.vehicle.VehiclePropertyGroup; 43 import android.hardware.automotive.vehicle.VehiclePropertyType; 44 import android.hardware.automotive.vehicle.VehicleVendorPermission; 45 import android.os.Build; 46 import android.os.ServiceSpecificException; 47 import android.os.SystemClock; 48 import android.util.ArraySet; 49 import android.util.Log; 50 51 import androidx.test.ext.junit.runners.AndroidJUnit4; 52 import androidx.test.filters.MediumTest; 53 54 import com.android.car.hal.test.AidlMockedVehicleHal.VehicleHalPropertyHandler; 55 56 import com.google.common.truth.Truth; 57 58 import org.junit.Assert; 59 import org.junit.Rule; 60 import org.junit.Test; 61 import org.junit.rules.TestName; 62 import org.junit.runner.RunWith; 63 64 import java.time.Duration; 65 import java.util.ArrayList; 66 import java.util.Arrays; 67 import java.util.Collections; 68 import java.util.HashMap; 69 import java.util.List; 70 import java.util.concurrent.ConcurrentHashMap; 71 import java.util.concurrent.CountDownLatch; 72 import java.util.concurrent.TimeUnit; 73 74 /** 75 * Test for {@link android.car.hardware.property.CarPropertyManager} 76 */ 77 @RunWith(AndroidJUnit4.class) 78 @MediumTest 79 public class CarPropertyManagerTest extends MockedCarTestBase { 80 81 private static final String TAG = CarPropertyManagerTest.class.getSimpleName(); 82 83 /** 84 * configArray[0], 1 indicates the property has a String value 85 * configArray[1], 1 indicates the property has a Boolean value . 86 * configArray[2], 1 indicates the property has a Integer value 87 * configArray[3], the number indicates the size of Integer[] in the property. 88 * configArray[4], 1 indicates the property has a Long value . 89 * configArray[5], the number indicates the size of Long[] in the property. 90 * configArray[6], 1 indicates the property has a Float value . 91 * configArray[7], the number indicates the size of Float[] in the property. 92 * configArray[8], the number indicates the size of byte[] in the property. 93 */ 94 private static final java.util.Collection<Integer> CONFIG_ARRAY_1 = 95 Arrays.asList(1, 0, 1, 0, 1, 0, 0, 0, 0); 96 private static final java.util.Collection<Integer> CONFIG_ARRAY_2 = 97 Arrays.asList(1, 1, 1, 0, 0, 0, 0, 2, 0); 98 private static final java.util.Collection<Integer> CONFIG_ARRAY_3 = 99 Arrays.asList(0, 1, 1, 0, 0, 0, 1, 0, 0); 100 private static final Object[] EXPECTED_VALUE_1 = {"android", 1, 1L}; 101 private static final Object[] EXPECTED_VALUE_2 = {"android", true, 3, 1.1f, 2f}; 102 private static final Object[] EXPECTED_VALUE_3 = {true, 1, 2.2f}; 103 104 private static final int CUSTOM_SEAT_INT_PROP_1 = 105 0x1201 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.SEAT; 106 private static final int CUSTOM_SEAT_INT_PROP_2 = 107 0x1202 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.SEAT; 108 109 private static final int CUSTOM_SEAT_MIXED_PROP_ID_1 = 110 0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.SEAT; 111 private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_2 = 112 0x1102 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL; 113 private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_3 = 114 0x1110 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL; 115 116 private static final int CUSTOM_GLOBAL_INT_ARRAY_PROP = 117 0x1103 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32_VEC 118 | VehicleArea.GLOBAL; 119 private static final Integer[] FAKE_INT_ARRAY_VALUE = {1, 2}; 120 121 private static final int INT_ARRAY_PROP_STATUS_ERROR = 122 0x1104 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32_VEC 123 | VehicleArea.GLOBAL; 124 125 private static final int BOOLEAN_PROP_STATUS_ERROR = 126 0x1105 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.BOOLEAN 127 | VehicleArea.GLOBAL; 128 private static final boolean FAKE_BOOLEAN_PROPERTY_VALUE = true; 129 private static final int FLOAT_PROP_STATUS_UNAVAILABLE = 130 0x1106 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.FLOAT 131 | VehicleArea.GLOBAL; 132 private static final float FAKE_FLOAT_PROPERTY_VALUE = 3f; 133 private static final int INT_PROP_STATUS_UNAVAILABLE = 134 0x1107 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 135 | VehicleArea.GLOBAL; 136 private static final int FAKE_INT_PROPERTY_VALUE = 3; 137 // A property that always returns null to simulate an unavailable property. 138 private static final int NULL_VALUE_PROP = 139 0x1108 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 140 | VehicleArea.GLOBAL; 141 142 // Vendor properties for testing exceptions. 143 private static final int PROP_CAUSE_STATUS_CODE_TRY_AGAIN = 144 0x1201 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 145 private static final int PROP_CAUSE_STATUS_CODE_INVALID_ARG = 146 0x1202 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 147 private static final int PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE = 148 0x1203 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 149 private static final int PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR = 150 0x1204 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 151 private static final int PROP_CAUSE_STATUS_CODE_ACCESS_DENIED = 152 0x1205 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 153 154 // Vendor properties for testing permissions 155 private static final int PROP_WITH_READ_ONLY_PERMISSION = 156 0x1301 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 157 private static final int PROP_WITH_WRITE_ONLY_PERMISSION = 158 0x1302 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 159 private static final int SUPPORT_CUSTOM_PERMISSION = 287313669; 160 private static final java.util.Collection<Integer> VENDOR_PERMISSION_CONFIG = 161 Collections.unmodifiableList( 162 Arrays.asList(PROP_WITH_READ_ONLY_PERMISSION, 163 VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_1, 164 VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE, 165 PROP_WITH_WRITE_ONLY_PERMISSION, 166 VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE, 167 VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_1)); 168 169 170 // Use FAKE_PROPERTY_ID to test api return null or throw exception. 171 private static final int FAKE_PROPERTY_ID = 0x111; 172 173 private static final int DRIVER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_LEFT 174 | VehicleAreaSeat.ROW_2_LEFT; 175 private static final int PASSENGER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_RIGHT 176 | VehicleAreaSeat.ROW_2_CENTER 177 | VehicleAreaSeat.ROW_2_RIGHT; 178 private static final float INIT_TEMP_VALUE = 16f; 179 private static final float CHANGED_TEMP_VALUE = 20f; 180 private static final int CALLBACK_SHORT_TIMEOUT_MS = 350; // ms 181 // Wait for CarPropertyManager register/unregister listener 182 private static final long WAIT_FOR_NO_EVENTS = 50; 183 184 private static final List<Integer> USER_HAL_PROPERTIES = Arrays.asList( 185 VehiclePropertyIds.INITIAL_USER_INFO, 186 VehiclePropertyIds.SWITCH_USER, 187 VehiclePropertyIds.CREATE_USER, 188 VehiclePropertyIds.REMOVE_USER, 189 VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION 190 ); 191 192 private CarPropertyManager mManager; 193 194 @Rule public TestName mTestName = new TestName(); 195 196 @Override setUp()197 public void setUp() throws Exception { 198 super.setUp(); 199 setUpTargetSdk(); 200 mManager = (CarPropertyManager) getCar().getCarManager(Car.PROPERTY_SERVICE); 201 assertThat(mManager).isNotNull(); 202 } 203 setUpTargetSdk()204 private void setUpTargetSdk() { 205 if (mTestName.getMethodName().endsWith("InQ")) { 206 getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.Q; 207 } else if (mTestName.getMethodName().endsWith("AfterQ")) { 208 getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R; 209 } else if (mTestName.getMethodName().endsWith("AfterR")) { 210 getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S; 211 } 212 } 213 214 @Test testMixedPropertyConfigs()215 public void testMixedPropertyConfigs() { 216 List<CarPropertyConfig> configs = mManager.getPropertyList(); 217 for (CarPropertyConfig cfg : configs) { 218 switch (cfg.getPropertyId()) { 219 case CUSTOM_SEAT_MIXED_PROP_ID_1: 220 assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_1) 221 .inOrder(); 222 break; 223 case CUSTOM_GLOBAL_MIXED_PROP_ID_2: 224 assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_2) 225 .inOrder(); 226 break; 227 case CUSTOM_GLOBAL_MIXED_PROP_ID_3: 228 assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_3) 229 .inOrder(); 230 break; 231 case VehiclePropertyIds.HVAC_TEMPERATURE_SET: 232 case PROP_CAUSE_STATUS_CODE_ACCESS_DENIED: 233 case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR: 234 case PROP_CAUSE_STATUS_CODE_TRY_AGAIN: 235 case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE: 236 case PROP_CAUSE_STATUS_CODE_INVALID_ARG: 237 case CUSTOM_SEAT_INT_PROP_1: 238 case CUSTOM_SEAT_INT_PROP_2: 239 case CUSTOM_GLOBAL_INT_ARRAY_PROP: 240 case INT_ARRAY_PROP_STATUS_ERROR: 241 case BOOLEAN_PROP_STATUS_ERROR: 242 case INT_PROP_STATUS_UNAVAILABLE: 243 case FLOAT_PROP_STATUS_UNAVAILABLE: 244 case VehiclePropertyIds.INFO_VIN: 245 case NULL_VALUE_PROP: 246 case SUPPORT_CUSTOM_PERMISSION: 247 case PROP_WITH_READ_ONLY_PERMISSION: 248 case PROP_WITH_WRITE_ONLY_PERMISSION: 249 case VehiclePropertyIds.TIRE_PRESSURE: 250 break; 251 default: 252 Assert.fail("Unexpected CarPropertyConfig: " + cfg.toString()); 253 } 254 } 255 } 256 257 @Test testGetMixTypeProperty()258 public void testGetMixTypeProperty() { 259 mManager.setProperty(Object[].class, CUSTOM_SEAT_MIXED_PROP_ID_1, 260 0, EXPECTED_VALUE_1); 261 CarPropertyValue<Object[]> result = mManager.getProperty( 262 CUSTOM_SEAT_MIXED_PROP_ID_1, 0); 263 assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_1); 264 265 mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_2, 266 0, EXPECTED_VALUE_2); 267 result = mManager.getProperty( 268 CUSTOM_GLOBAL_MIXED_PROP_ID_2, 0); 269 assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_2); 270 271 mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_3, 272 0, EXPECTED_VALUE_3); 273 result = mManager.getProperty( 274 CUSTOM_GLOBAL_MIXED_PROP_ID_3, 0); 275 assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_3); 276 } 277 278 /** 279 * Test {@link android.car.hardware.property.CarPropertyManager#getIntArrayProperty(int, int)} 280 */ 281 @Test testGetIntArrayProperty()282 public void testGetIntArrayProperty() { 283 mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL, 284 FAKE_INT_ARRAY_VALUE); 285 286 int[] result = mManager.getIntArrayProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP, 287 VehicleArea.GLOBAL); 288 assertThat(result).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE); 289 } 290 291 /** 292 * Test {@link CarPropertyManager#getIntArrayProperty(int, int)} when vhal returns a value with 293 * error status. 294 */ 295 @Test testGetIntArrayPropertyWithErrorStatusAfterR()296 public void testGetIntArrayPropertyWithErrorStatusAfterR() { 297 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 298 .isGreaterThan(Build.VERSION_CODES.R); 299 mManager.setProperty(Integer[].class, INT_ARRAY_PROP_STATUS_ERROR, 300 VehicleArea.GLOBAL, FAKE_INT_ARRAY_VALUE); 301 assertThrows(CarInternalErrorException.class, 302 () -> mManager.getIntArrayProperty(INT_ARRAY_PROP_STATUS_ERROR, 303 VehicleArea.GLOBAL)); 304 } 305 306 /** 307 * Test {@link CarPropertyManager#getIntProperty(int, int)} when vhal returns a value with 308 * unavailable status. 309 */ 310 @Test testGetIntPropertyWithUnavailableStatusAfterR()311 public void testGetIntPropertyWithUnavailableStatusAfterR() { 312 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 313 .isGreaterThan(Build.VERSION_CODES.R); 314 mManager.setProperty(Integer.class, INT_PROP_STATUS_UNAVAILABLE, 315 VehicleArea.GLOBAL, FAKE_INT_PROPERTY_VALUE); 316 assertThrows(PropertyNotAvailableException.class, 317 () -> mManager.getIntProperty(INT_PROP_STATUS_UNAVAILABLE, VehicleArea.GLOBAL)); 318 319 } 320 321 /** 322 * Test {@link CarPropertyManager#getBooleanProperty(int, int)} when vhal returns a value with 323 * error status. 324 */ 325 @Test testGetBooleanPropertyWithErrorStatusAfterR()326 public void testGetBooleanPropertyWithErrorStatusAfterR() { 327 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 328 .isGreaterThan(Build.VERSION_CODES.R); 329 mManager.setProperty(Boolean.class, BOOLEAN_PROP_STATUS_ERROR, 330 VehicleArea.GLOBAL, FAKE_BOOLEAN_PROPERTY_VALUE); 331 assertThrows(CarInternalErrorException.class, 332 () -> mManager.getBooleanProperty(BOOLEAN_PROP_STATUS_ERROR, VehicleArea.GLOBAL)); 333 } 334 335 /** 336 * Test {@link CarPropertyManager#getFloatProperty(int, int)} when vhal returns a value with 337 * unavailable status. 338 */ 339 @Test testGetFloatPropertyWithUnavailableStatusAfterR()340 public void testGetFloatPropertyWithUnavailableStatusAfterR() { 341 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 342 .isGreaterThan(Build.VERSION_CODES.R); 343 mManager.setProperty(Float.class, FLOAT_PROP_STATUS_UNAVAILABLE, 344 VehicleArea.GLOBAL, FAKE_FLOAT_PROPERTY_VALUE); 345 assertThrows(PropertyNotAvailableException.class, 346 () -> mManager.getFloatProperty(FLOAT_PROP_STATUS_UNAVAILABLE, VehicleArea.GLOBAL)); 347 } 348 349 /** 350 * Test {@link CarPropertyManager#getProperty(Class, int, int)} 351 */ 352 @Test testGetPropertyWithClass()353 public void testGetPropertyWithClass() { 354 mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL, 355 FAKE_INT_ARRAY_VALUE); 356 357 CarPropertyValue<Integer[]> result = mManager.getProperty(Integer[].class, 358 CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL); 359 assertThat(result.getValue()).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE); 360 } 361 362 /** 363 * Test {@link CarPropertyManager#isPropertyAvailable(int, int)} 364 */ 365 @Test testIsPropertyAvailable()366 public void testIsPropertyAvailable() { 367 assertThat(mManager.isPropertyAvailable(FAKE_PROPERTY_ID, VehicleArea.GLOBAL)).isFalse(); 368 assertThat(mManager.isPropertyAvailable(CUSTOM_GLOBAL_INT_ARRAY_PROP, VehicleArea.GLOBAL)) 369 .isTrue(); 370 } 371 372 /** 373 * Test {@link CarPropertyManager#getWritePermission(int)} 374 * and {@link CarPropertyManager#getWritePermission(int)} 375 */ 376 @Test testGetPermission()377 public void testGetPermission() { 378 String hvacReadPermission = mManager.getReadPermission( 379 VehiclePropertyIds.HVAC_TEMPERATURE_SET); 380 assertThat(hvacReadPermission).isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE); 381 String hvacWritePermission = mManager.getWritePermission( 382 VehiclePropertyIds.HVAC_TEMPERATURE_SET); 383 assertThat(hvacWritePermission).isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE); 384 385 // For read-only property 386 String vinReadPermission = mManager.getReadPermission(VehiclePropertyIds.INFO_VIN); 387 assertThat(vinReadPermission).isEqualTo(Car.PERMISSION_IDENTIFICATION); 388 String vinWritePermission = mManager.getWritePermission(VehiclePropertyIds.INFO_VIN); 389 assertThat(vinWritePermission).isNull(); 390 } 391 392 @Test testGetPropertyConfig()393 public void testGetPropertyConfig() { 394 CarPropertyConfig config = mManager.getCarPropertyConfig(CUSTOM_SEAT_MIXED_PROP_ID_1); 395 assertThat(config.getPropertyId()).isEqualTo(CUSTOM_SEAT_MIXED_PROP_ID_1); 396 // return null if can not find the propertyConfig for the property. 397 assertThat(mManager.getCarPropertyConfig(FAKE_PROPERTY_ID)).isNull(); 398 } 399 400 @Test testGetPropertyConfig_withReadOnlyPermission()401 public void testGetPropertyConfig_withReadOnlyPermission() { 402 CarPropertyConfig configForReadOnlyProperty = mManager 403 .getCarPropertyConfig(PROP_WITH_READ_ONLY_PERMISSION); 404 405 assertThat(configForReadOnlyProperty).isNotNull(); 406 assertThat(configForReadOnlyProperty.getPropertyId()) 407 .isEqualTo(PROP_WITH_READ_ONLY_PERMISSION); 408 } 409 410 @Test testGetPropertyConfig_withWriteOnlyPermission()411 public void testGetPropertyConfig_withWriteOnlyPermission() { 412 CarPropertyConfig configForWriteOnlyProperty = mManager 413 .getCarPropertyConfig(PROP_WITH_WRITE_ONLY_PERMISSION); 414 415 assertThat(configForWriteOnlyProperty).isNotNull(); 416 assertThat(configForWriteOnlyProperty.getPropertyId()) 417 .isEqualTo(PROP_WITH_WRITE_ONLY_PERMISSION); 418 } 419 420 @Test testGetAreaId()421 public void testGetAreaId() { 422 int result = mManager.getAreaId(CUSTOM_SEAT_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_1_LEFT); 423 assertThat(result).isEqualTo(DRIVER_SIDE_AREA_ID); 424 //test for the GLOBAL property 425 int globalAreaId = 426 mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_2, VehicleAreaSeat.ROW_1_LEFT); 427 assertThat(globalAreaId).isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL); 428 //test exception 429 assertThrows(IllegalArgumentException.class, () -> mManager.getAreaId( 430 CUSTOM_SEAT_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_3_CENTER)); 431 assertThrows(IllegalArgumentException.class, () -> mManager.getAreaId(FAKE_PROPERTY_ID, 432 VehicleAreaSeat.ROW_1_LEFT)); 433 } 434 435 @Test testRegisterPropertyUnavailable()436 public void testRegisterPropertyUnavailable() throws Exception { 437 TestSequenceCallback callback = new TestSequenceCallback(1); 438 // Registering a property which has an unavailable initial value 439 // won't throw ServiceSpecificException. 440 mManager.registerCallback(callback, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 441 CarPropertyManager.SENSOR_RATE_ONCHANGE); 442 // initial value is unavailable, should not get any callback. 443 assertThrows(IllegalStateException.class, callback::assertOnChangeEventCalled); 444 } 445 446 @Test testNotReceiveOnErrorEvent()447 public void testNotReceiveOnErrorEvent() throws Exception { 448 TestErrorCallback callback = new TestErrorCallback(); 449 mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 450 CarPropertyManager.SENSOR_RATE_ONCHANGE); 451 callback.assertRegisterCompleted(); 452 injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 453 CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN); 454 // app never change the value of HVAC_TEMPERATURE_SET, it won't get an error code. 455 callback.assertOnErrorEventNotCalled(); 456 } 457 458 @Test testReceiveOnErrorEvent()459 public void testReceiveOnErrorEvent() throws Exception { 460 TestErrorCallback callback = new TestErrorCallback(); 461 mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 462 CarPropertyManager.SENSOR_RATE_ONCHANGE); 463 callback.assertRegisterCompleted(); 464 mManager.setFloatProperty( 465 VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 466 CHANGED_TEMP_VALUE); 467 injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 468 CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN); 469 callback.assertOnErrorEventCalled(); 470 assertThat(callback.mReceivedErrorEventWithErrorCode).isTrue(); 471 assertThat(callback.mErrorCode).isEqualTo( 472 CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN); 473 assertThat(callback.mReceivedErrorEventWithOutErrorCode).isFalse(); 474 } 475 476 @Test testNotReceiveOnErrorEventAfterUnregister()477 public void testNotReceiveOnErrorEventAfterUnregister() throws Exception { 478 TestErrorCallback callback1 = new TestErrorCallback(); 479 mManager.registerCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 480 CarPropertyManager.SENSOR_RATE_ONCHANGE); 481 callback1.assertRegisterCompleted(); 482 TestErrorCallback callback2 = new TestErrorCallback(); 483 mManager.registerCallback(callback2, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 484 CarPropertyManager.SENSOR_RATE_ONCHANGE); 485 mManager.setFloatProperty( 486 VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 487 CHANGED_TEMP_VALUE); 488 mManager.unregisterCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET); 489 SystemClock.sleep(WAIT_FOR_NO_EVENTS); 490 injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 491 CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN); 492 // callback1 is unregistered 493 callback1.assertOnErrorEventNotCalled(); 494 callback2.assertOnErrorEventCalled(); 495 } 496 @Test testSetterExceptionsInQ()497 public void testSetterExceptionsInQ() { 498 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 499 .isEqualTo(Build.VERSION_CODES.Q); 500 501 assertThrows(IllegalStateException.class, 502 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 503 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 504 assertThrows(IllegalStateException.class, 505 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 506 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 507 assertThrows(IllegalStateException.class, 508 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 509 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 510 assertThrows(IllegalArgumentException.class, 511 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG, 512 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 513 assertThrows(RuntimeException.class, 514 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 515 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 516 } 517 518 @Test testSetterExceptionsAfterQ()519 public void testSetterExceptionsAfterQ() { 520 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 521 .isGreaterThan(Build.VERSION_CODES.Q); 522 523 assertThrows(PropertyAccessDeniedSecurityException.class, 524 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 525 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 526 assertThrows(PropertyNotAvailableAndRetryException.class, 527 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 528 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 529 assertThrows(PropertyNotAvailableException.class, 530 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 531 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 532 assertThrows(CarInternalErrorException.class, 533 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 534 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 535 assertThrows(IllegalArgumentException.class, 536 ()->mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG, 537 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 538 } 539 540 @Test testGetterExceptionsInQ()541 public void testGetterExceptionsInQ() { 542 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 543 .isEqualTo(Build.VERSION_CODES.Q); 544 545 assertThrows(IllegalStateException.class, 546 ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 547 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 548 assertThrows(IllegalStateException.class, 549 ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 550 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 551 552 assertThrows(IllegalArgumentException.class, 553 ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 554 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 555 assertThrows(IllegalArgumentException.class, 556 ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 557 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 558 559 assertThrows(IllegalStateException.class, 560 ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 561 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 562 assertThrows(IllegalStateException.class, 563 ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 564 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 565 566 assertThrows(IllegalStateException.class, 567 ()->mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 568 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 569 assertThrows(IllegalStateException.class, 570 ()->mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 571 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 572 573 assertThrows(IllegalStateException.class, 574 ()->mManager.getProperty(NULL_VALUE_PROP, 575 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 576 577 Truth.assertThat(mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 578 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)).isNull(); 579 580 } 581 582 @Test testGetterExceptionsAfterQ()583 public void testGetterExceptionsAfterQ() { 584 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 585 .isAtLeast(Build.VERSION_CODES.R); 586 587 assertThrows(PropertyAccessDeniedSecurityException.class, 588 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 589 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 590 assertThrows(PropertyAccessDeniedSecurityException.class, 591 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 592 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 593 assertThrows(IllegalArgumentException.class, 594 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 595 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 596 assertThrows(IllegalArgumentException.class, 597 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 598 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 599 600 assertThrows(PropertyNotAvailableAndRetryException.class, 601 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 602 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 603 assertThrows(PropertyNotAvailableAndRetryException.class, 604 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 605 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 606 607 assertThrows(PropertyNotAvailableException.class, 608 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 609 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 610 assertThrows(PropertyNotAvailableException.class, 611 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 612 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 613 614 assertThrows(CarInternalErrorException.class, 615 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 616 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 617 assertThrows(CarInternalErrorException.class, 618 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 619 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 620 621 assertThrows(PropertyNotAvailableException.class, 622 ()->mManager.getProperty(NULL_VALUE_PROP, 623 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL)); 624 } 625 626 @Test testOnChangeEventWithSameAreaId()627 public void testOnChangeEventWithSameAreaId() throws Exception { 628 // init 629 mManager.setProperty(Integer.class, 630 CUSTOM_SEAT_INT_PROP_1, DRIVER_SIDE_AREA_ID, 1); 631 TestSequenceCallback callback = new TestSequenceCallback(1); 632 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0); 633 callback.assertRegisterCompleted(); 634 635 VehiclePropValue firstFakeValueDriveSide = new VehiclePropValue(); 636 firstFakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_1; 637 firstFakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID; 638 firstFakeValueDriveSide.value = new RawPropValues(); 639 firstFakeValueDriveSide.value.int32Values = new int[]{2}; 640 firstFakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos(); 641 VehiclePropValue secFakeValueDriveSide = new VehiclePropValue(); 642 secFakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_1; 643 secFakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID; 644 secFakeValueDriveSide.value = new RawPropValues(); 645 secFakeValueDriveSide.value.int32Values = new int[]{3}; // 0 in HAL indicate false; 646 secFakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos(); 647 // inject the new event first 648 getAidlMockedVehicleHal().injectEvent(secFakeValueDriveSide); 649 // inject the old event 650 getAidlMockedVehicleHal().injectEvent(firstFakeValueDriveSide); 651 callback.assertOnChangeEventCalled(); 652 // Client should only get the new event 653 assertThat((int) callback.getLastCarPropertyValue(CUSTOM_SEAT_INT_PROP_1).getValue()) 654 .isEqualTo(3); 655 assertThat(callback.getEventCounter()).isEqualTo(1); 656 657 } 658 659 @Test testOnChangeEventWithDifferentAreaId()660 public void testOnChangeEventWithDifferentAreaId() throws Exception { 661 // init 662 mManager.setProperty(Integer.class, 663 CUSTOM_SEAT_INT_PROP_2, DRIVER_SIDE_AREA_ID, 1); 664 TestSequenceCallback callback = new TestSequenceCallback(2); 665 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_2, 0); 666 callback.assertRegisterCompleted(); 667 VehiclePropValue fakeValueDriveSide = new VehiclePropValue(); 668 fakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_2; 669 fakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID; 670 fakeValueDriveSide.value = new RawPropValues(); 671 fakeValueDriveSide.value.int32Values = new int[]{4}; 672 fakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos(); 673 674 VehiclePropValue fakeValuePsgSide = new VehiclePropValue(); 675 fakeValuePsgSide.prop = CUSTOM_SEAT_INT_PROP_2; 676 fakeValuePsgSide.areaId = PASSENGER_SIDE_AREA_ID; 677 fakeValuePsgSide.value = new RawPropValues(); 678 fakeValuePsgSide.value.int32Values = new int[]{5}; 679 fakeValuePsgSide.timestamp = SystemClock.elapsedRealtimeNanos(); 680 681 // inject passenger event before driver event 682 getAidlMockedVehicleHal().injectEvent(fakeValuePsgSide); 683 getAidlMockedVehicleHal().injectEvent(fakeValueDriveSide); 684 callback.assertOnChangeEventCalled(); 685 686 // both events should be received by listener 687 assertThat((int) callback.getLastCarPropertyValue(CUSTOM_SEAT_INT_PROP_2).getValue()) 688 .isEqualTo(4); 689 assertThat(callback.getEventCounter()).isEqualTo(2); 690 } 691 692 @Test testOnChangeEventInvalidPayload()693 public void testOnChangeEventInvalidPayload() throws Exception { 694 // init 695 mManager.setProperty(Integer.class, CUSTOM_SEAT_INT_PROP_1, DRIVER_SIDE_AREA_ID, 1); 696 TestSequenceCallback callback = new TestSequenceCallback(0); 697 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0); 698 callback.assertRegisterCompleted(); 699 700 List<VehiclePropValue> props = new ArrayList<VehiclePropValue>(); 701 VehiclePropValue emptyProp = new VehiclePropValue(); 702 emptyProp.prop = CUSTOM_SEAT_INT_PROP_1; 703 props.add(emptyProp); 704 705 VehiclePropValue twoIntsProp = new VehiclePropValue(); 706 twoIntsProp.prop = CUSTOM_SEAT_INT_PROP_1; 707 twoIntsProp.value = new RawPropValues(); 708 twoIntsProp.value.int32Values = new int[]{0, 1}; 709 props.add(twoIntsProp); 710 711 VehiclePropValue propWithFloat = new VehiclePropValue(); 712 propWithFloat.prop = CUSTOM_SEAT_INT_PROP_1; 713 propWithFloat.value = new RawPropValues(); 714 propWithFloat.value.floatValues = new float[]{0f}; 715 props.add(propWithFloat); 716 717 VehiclePropValue propWithString = new VehiclePropValue(); 718 propWithString.prop = CUSTOM_SEAT_INT_PROP_1; 719 propWithString.value = new RawPropValues(); 720 propWithString.value.stringValue = "1234"; 721 props.add(propWithString); 722 723 for (VehiclePropValue prop: props) { 724 // inject passenger event before driver event 725 getAidlMockedVehicleHal().injectEvent(prop); 726 assertThat(callback.getEventCounter()).isEqualTo(0); 727 } 728 } 729 730 @Test testUserHal_getProperty()731 public void testUserHal_getProperty() { 732 userHalPropertiesTest("getProperty()", (prop) -> 733 mManager.getProperty(prop, /* areaId= */ 0)); 734 } 735 736 @Test testUserHal_getBooleanProperty()737 public void testUserHal_getBooleanProperty() { 738 userHalPropertiesTest("getBooleanProperty()", (prop) -> 739 mManager.getBooleanProperty(prop, /* areaId= */ 0)); 740 } 741 742 @Test testUserHal_getIntProperty()743 public void testUserHal_getIntProperty() { 744 userHalPropertiesTest("getIntProperty()", (prop) -> 745 mManager.getIntProperty(prop, /* areaId= */ 0)); 746 } 747 748 @Test testUserHal_getIntArrayProperty()749 public void testUserHal_getIntArrayProperty() { 750 userHalPropertiesTest("getIntArrayProperty()", (prop) -> 751 mManager.getIntArrayProperty(prop, /* areaId= */ 0)); 752 } 753 754 @Test testUserHal_getFloatProperty()755 public void testUserHal_getFloatProperty() { 756 userHalPropertiesTest("getFloatProperty()", (prop) -> 757 mManager.getFloatProperty(prop, /* areaId= */ 0)); 758 } 759 760 @Test testUserHal_getPropertyList()761 public void testUserHal_getPropertyList() { 762 userHalPropertiesTest("getPropertyList()", (prop) -> { 763 ArraySet<Integer> list = new ArraySet<>(); 764 list.add(prop); 765 mManager.getPropertyList(list); 766 }); 767 } 768 769 @Test testUserHal_getCarPropertyConfig()770 public void testUserHal_getCarPropertyConfig() { 771 userHalPropertiesTest("getCarPropertyConfig()", (prop) -> 772 mManager.getCarPropertyConfig(prop)); 773 } 774 775 @Test testUserHal_getAreaId()776 public void testUserHal_getAreaId() { 777 userHalPropertiesTest("getAreaId()", (prop) -> 778 mManager.getAreaId(prop, /* areaId= */ 0)); 779 } 780 781 @Test testUserHal_getReadPermission()782 public void testUserHal_getReadPermission() { 783 userHalPropertiesTest("getReadPermission()", (prop) -> 784 mManager.getReadPermission(prop)); 785 } 786 787 @Test testUserHal_getWritePermission()788 public void testUserHal_getWritePermission() { 789 userHalPropertiesTest("getWritePermission()", (prop) -> 790 mManager.getWritePermission(prop)); 791 } 792 793 @Test testUserHal_isPropertyAvailable()794 public void testUserHal_isPropertyAvailable() { 795 userHalPropertiesTest("isPropertyAvailable()", (prop) -> 796 mManager.isPropertyAvailable(prop, /* area= */ 0)); 797 } 798 799 @Test testUserHal_setProperty()800 public void testUserHal_setProperty() { 801 userHalPropertiesTest("setProperty()", (prop) -> 802 mManager.setProperty(Object.class, prop, /* areaId= */ 0, /* val= */ null)); 803 } 804 805 @Test testUserHal_setBooleanProperty()806 public void testUserHal_setBooleanProperty() { 807 userHalPropertiesTest("setBooleanProperty()", (prop) -> 808 mManager.setBooleanProperty(prop, /* areaId= */ 0, /* val= */ true)); 809 } 810 811 @Test testUserHal_setFloatProperty()812 public void testUserHal_setFloatProperty() { 813 userHalPropertiesTest("setFloatProperty()", (prop) -> 814 mManager.setFloatProperty(prop, /* areaId= */ 0, /* val= */ 0.0F)); 815 } 816 817 @Test testUserHal_setIntProperty()818 public void testUserHal_setIntProperty() { 819 userHalPropertiesTest("setIntProperty()", (prop) -> 820 mManager.setIntProperty(prop, /* areaId= */ 0, /* val= */ 0)); 821 } 822 823 @Test registerCallback_handlesContinuousPropertyUpdateRate()824 public void registerCallback_handlesContinuousPropertyUpdateRate() { 825 float wheelLeftFrontValue = 11.11f; 826 long wheelLeftFrontTimestampNanos = Duration.ofSeconds(1).toNanos(); 827 828 float notNewEnoughWheelLeftFrontValue = 22.22f; 829 long notNewEnoughWheelLeftFrontTimestampNanos = Duration.ofMillis(1999).toNanos(); 830 831 float newEnoughWheelLeftFrontValue = 33.33f; 832 long newEnoughWheelLeftFrontTimestampNanos = Duration.ofSeconds(2).toNanos(); 833 834 TestCallback testCallback = new TestCallback(2); 835 assertThat(mManager.registerCallback(testCallback, VehiclePropertyIds.TIRE_PRESSURE, 836 1f)).isTrue(); 837 838 getAidlMockedVehicleHal().injectEvent( 839 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 840 wheelLeftFrontValue, wheelLeftFrontTimestampNanos)); 841 getAidlMockedVehicleHal().injectEvent( 842 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 843 notNewEnoughWheelLeftFrontValue, notNewEnoughWheelLeftFrontTimestampNanos)); 844 getAidlMockedVehicleHal().injectEvent( 845 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 846 newEnoughWheelLeftFrontValue, newEnoughWheelLeftFrontTimestampNanos)); 847 848 List<CarPropertyValue<?>> carPropertyValues = testCallback.getCarPropertyValues(); 849 assertThat(carPropertyValues).hasSize(2); 850 851 assertTirePressureCarPropertyValue(carPropertyValues.get(0), 852 VehicleAreaWheel.WHEEL_LEFT_FRONT, wheelLeftFrontValue, 853 wheelLeftFrontTimestampNanos); 854 855 assertTirePressureCarPropertyValue(carPropertyValues.get(1), 856 VehicleAreaWheel.WHEEL_LEFT_FRONT, newEnoughWheelLeftFrontValue, 857 newEnoughWheelLeftFrontTimestampNanos); 858 } 859 860 @Test registerCallback_handlesOutOfTimeOrderEventsWithDifferentAreaIds()861 public void registerCallback_handlesOutOfTimeOrderEventsWithDifferentAreaIds() { 862 float wheelLeftFrontValue = 11.11f; 863 long wheelLeftFrontTimestampNanos = Duration.ofSeconds(4).toNanos(); 864 865 float wheelRightFrontValue = 22.22f; 866 long wheelRightFrontTimestampNanos = Duration.ofSeconds(3).toNanos(); 867 868 float wheelLeftRearValue = 33.33f; 869 long wheelLeftRearTimestampNanos = Duration.ofSeconds(2).toNanos(); 870 871 float wheelRightRearValue = 44.44f; 872 long wheelRightRearTimestampNanos = Duration.ofSeconds(1).toNanos(); 873 874 TestCallback testCallback = new TestCallback(4); 875 assertThat(mManager.registerCallback(testCallback, VehiclePropertyIds.TIRE_PRESSURE, 876 1f)).isTrue(); 877 878 // inject events in time order from newest to oldest 879 getAidlMockedVehicleHal().injectEvent( 880 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 881 wheelLeftFrontValue, wheelLeftFrontTimestampNanos)); 882 getAidlMockedVehicleHal().injectEvent( 883 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_RIGHT_FRONT, 884 wheelRightFrontValue, wheelRightFrontTimestampNanos)); 885 getAidlMockedVehicleHal().injectEvent( 886 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_REAR, 887 wheelLeftRearValue, wheelLeftRearTimestampNanos)); 888 getAidlMockedVehicleHal().injectEvent( 889 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_RIGHT_REAR, 890 wheelRightRearValue, wheelRightRearTimestampNanos)); 891 892 List<CarPropertyValue<?>> carPropertyValues = testCallback.getCarPropertyValues(); 893 assertThat(carPropertyValues).hasSize(4); 894 895 assertTirePressureCarPropertyValue(carPropertyValues.get(0), 896 VehicleAreaWheel.WHEEL_LEFT_FRONT, wheelLeftFrontValue, 897 wheelLeftFrontTimestampNanos); 898 899 assertTirePressureCarPropertyValue(carPropertyValues.get(1), 900 VehicleAreaWheel.WHEEL_RIGHT_FRONT, wheelRightFrontValue, 901 wheelRightFrontTimestampNanos); 902 903 assertTirePressureCarPropertyValue(carPropertyValues.get(2), 904 VehicleAreaWheel.WHEEL_LEFT_REAR, wheelLeftRearValue, wheelLeftRearTimestampNanos); 905 906 assertTirePressureCarPropertyValue(carPropertyValues.get(3), 907 VehicleAreaWheel.WHEEL_RIGHT_REAR, wheelRightRearValue, 908 wheelRightRearTimestampNanos); 909 } 910 userHalPropertiesTest(String method, Visitor<Integer> visitor)911 private void userHalPropertiesTest(String method, Visitor<Integer> visitor) { 912 List<String> failedProperties = new ArrayList<String>(); 913 for (int propertyId : USER_HAL_PROPERTIES) { 914 try { 915 visitor.visit(propertyId); 916 failedProperties.add(propToString(propertyId)); 917 } catch (IllegalArgumentException e) { 918 // expected 919 } 920 } 921 if (!failedProperties.isEmpty()) { 922 fail(method + " should not support these properties: " + failedProperties); 923 } 924 } 925 926 @Override configureMockedHal()927 protected void configureMockedHal() { 928 PropertyHandler handler = new PropertyHandler(); 929 addAidlProperty(CUSTOM_SEAT_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1) 930 .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID); 931 addAidlProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_2, handler).setConfigArray(CONFIG_ARRAY_2); 932 addAidlProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_3, handler).setConfigArray(CONFIG_ARRAY_3); 933 addAidlProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP, handler); 934 935 addAidlProperty(INT_ARRAY_PROP_STATUS_ERROR, handler); 936 addAidlProperty(INT_PROP_STATUS_UNAVAILABLE, handler); 937 addAidlProperty(FLOAT_PROP_STATUS_UNAVAILABLE, handler); 938 addAidlProperty(BOOLEAN_PROP_STATUS_ERROR, handler); 939 addAidlProperty(VehiclePropertyIds.TIRE_PRESSURE, handler).addAreaConfig( 940 VehicleAreaWheel.WHEEL_LEFT_REAR).addAreaConfig( 941 VehicleAreaWheel.WHEEL_RIGHT_REAR).addAreaConfig( 942 VehicleAreaWheel.WHEEL_RIGHT_FRONT).addAreaConfig( 943 VehicleAreaWheel.WHEEL_LEFT_FRONT).setChangeMode( 944 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS).setMaxSampleRate( 945 10).setMinSampleRate(1); 946 947 VehiclePropValue tempValue = new VehiclePropValue(); 948 tempValue.value = new RawPropValues(); 949 tempValue.value.floatValues = new float[]{INIT_TEMP_VALUE}; 950 tempValue.prop = VehiclePropertyIds.HVAC_TEMPERATURE_SET; 951 addAidlProperty(VehiclePropertyIds.HVAC_TEMPERATURE_SET, tempValue) 952 .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID); 953 addAidlProperty(VehiclePropertyIds.INFO_VIN); 954 955 addAidlProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, handler); 956 addAidlProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, handler); 957 addAidlProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, handler); 958 addAidlProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, handler); 959 addAidlProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, handler); 960 961 addAidlProperty(CUSTOM_SEAT_INT_PROP_1, handler).addAreaConfig(DRIVER_SIDE_AREA_ID) 962 .addAreaConfig(PASSENGER_SIDE_AREA_ID); 963 addAidlProperty(CUSTOM_SEAT_INT_PROP_2, handler).addAreaConfig(DRIVER_SIDE_AREA_ID) 964 .addAreaConfig(PASSENGER_SIDE_AREA_ID); 965 966 addAidlProperty(NULL_VALUE_PROP, handler); 967 968 // Add properties for permission testing. 969 addAidlProperty(SUPPORT_CUSTOM_PERMISSION, handler).setConfigArray( 970 VENDOR_PERMISSION_CONFIG); 971 addAidlProperty(PROP_WITH_READ_ONLY_PERMISSION, handler); 972 addAidlProperty(PROP_WITH_WRITE_ONLY_PERMISSION, handler); 973 } 974 975 private class PropertyHandler implements VehicleHalPropertyHandler { 976 HashMap<Integer, VehiclePropValue> mMap = new HashMap<>(); 977 @Override onPropertySet(VehiclePropValue value)978 public synchronized void onPropertySet(VehiclePropValue value) { 979 // Simulate HalClient.set() behavior. 980 int statusCode = mapPropertyToVhalStatusCode(value.prop); 981 if (statusCode != VehicleHalStatusCode.STATUS_OK) { 982 // The ServiceSpecificException here would pass the statusCode back to caller. 983 throw new ServiceSpecificException(statusCode); 984 } 985 986 mMap.put(value.prop, value); 987 } 988 989 @Override onPropertyGet(VehiclePropValue value)990 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 991 // Simulate HalClient.get() behavior. 992 int vhalStatusCode = mapPropertyToVhalStatusCode(value.prop); 993 if (vhalStatusCode != VehicleHalStatusCode.STATUS_OK) { 994 // The ServiceSpecificException here would pass the statusCode back to caller. 995 throw new ServiceSpecificException(vhalStatusCode); 996 } 997 998 int propertyStatus = mapPropertyToCarPropertyStatusCode(value.prop); 999 if (value.prop == NULL_VALUE_PROP) { 1000 // Return null to simulate an unavailable property. 1001 // HAL implementation should return STATUS_TRY_AGAIN when a property is unavailable, 1002 // however, it may also return null with STATUS_OKAY and we want to handle this 1003 // properly. 1004 return null; 1005 } 1006 VehiclePropValue currentValue = mMap.get(value.prop); 1007 if (currentValue == null) { 1008 return value; 1009 } else { 1010 currentValue.status = propertyStatus; 1011 } 1012 return currentValue; 1013 } 1014 1015 @Override onPropertySubscribe(int property, float sampleRate)1016 public synchronized void onPropertySubscribe(int property, float sampleRate) { 1017 Log.d(TAG, "onPropertySubscribe property " 1018 + property + " sampleRate " + sampleRate); 1019 } 1020 1021 @Override onPropertyUnsubscribe(int property)1022 public synchronized void onPropertyUnsubscribe(int property) { 1023 Log.d(TAG, "onPropertyUnSubscribe property " + property); 1024 } 1025 } 1026 propToString(int propertyId)1027 private static String propToString(int propertyId) { 1028 return VehiclePropertyIds.toString(propertyId) + " (" + propertyId + ")"; 1029 } 1030 mapPropertyToVhalStatusCode(int propId)1031 private static int mapPropertyToVhalStatusCode(int propId) { 1032 switch (propId) { 1033 case PROP_CAUSE_STATUS_CODE_TRY_AGAIN: 1034 return VehicleHalStatusCode.STATUS_TRY_AGAIN; 1035 case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE: 1036 return VehicleHalStatusCode.STATUS_NOT_AVAILABLE; 1037 case PROP_CAUSE_STATUS_CODE_ACCESS_DENIED: 1038 return VehicleHalStatusCode.STATUS_ACCESS_DENIED; 1039 case PROP_CAUSE_STATUS_CODE_INVALID_ARG: 1040 return VehicleHalStatusCode.STATUS_INVALID_ARG; 1041 case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR: 1042 return VehicleHalStatusCode.STATUS_INTERNAL_ERROR; 1043 default: 1044 return VehicleHalStatusCode.STATUS_OK; 1045 } 1046 } 1047 mapPropertyToCarPropertyStatusCode(int propId)1048 private static int mapPropertyToCarPropertyStatusCode(int propId) { 1049 switch (propId) { 1050 case INT_ARRAY_PROP_STATUS_ERROR: 1051 case BOOLEAN_PROP_STATUS_ERROR: 1052 return CarPropertyValue.STATUS_ERROR; 1053 case INT_PROP_STATUS_UNAVAILABLE: 1054 case FLOAT_PROP_STATUS_UNAVAILABLE: 1055 return CarPropertyValue.STATUS_UNAVAILABLE; 1056 default: 1057 return CarPropertyValue.STATUS_AVAILABLE; 1058 } 1059 } 1060 newTirePressureVehiclePropValue(int areaId, float floatValue, long timestampNanos)1061 private static VehiclePropValue newTirePressureVehiclePropValue(int areaId, float floatValue, 1062 long timestampNanos) { 1063 VehiclePropValue vehiclePropValue = new VehiclePropValue(); 1064 vehiclePropValue.prop = VehiclePropertyIds.TIRE_PRESSURE; 1065 vehiclePropValue.areaId = areaId; 1066 vehiclePropValue.value = new RawPropValues(); 1067 vehiclePropValue.value.floatValues = new float[]{floatValue}; 1068 vehiclePropValue.timestamp = timestampNanos; 1069 return vehiclePropValue; 1070 } 1071 assertTirePressureCarPropertyValue(CarPropertyValue<?> carPropertyValue, int areaId, float floatValue, long timestampNanos)1072 private static void assertTirePressureCarPropertyValue(CarPropertyValue<?> carPropertyValue, 1073 int areaId, float floatValue, long timestampNanos) { 1074 assertThat(carPropertyValue.getPropertyId()).isEqualTo(VehiclePropertyIds.TIRE_PRESSURE); 1075 assertThat(carPropertyValue.getAreaId()).isEqualTo(areaId); 1076 assertThat(carPropertyValue.getStatus()).isEqualTo(CarPropertyValue.STATUS_AVAILABLE); 1077 assertThat(carPropertyValue.getTimestamp()).isEqualTo(timestampNanos); 1078 assertThat(carPropertyValue.getValue()).isEqualTo(floatValue); 1079 } 1080 1081 private static class TestErrorCallback implements CarPropertyManager.CarPropertyEventCallback { 1082 1083 private static final String CALLBACK_TAG = "ErrorEventTest"; 1084 private boolean mReceivedErrorEventWithErrorCode = false; 1085 private boolean mReceivedErrorEventWithOutErrorCode = false; 1086 private int mErrorCode; 1087 private final CountDownLatch mEventsCountDownLatch = new CountDownLatch(1); 1088 private final CountDownLatch mRegisterCountDownLatch = new CountDownLatch(2); 1089 @Override onChangeEvent(CarPropertyValue value)1090 public void onChangeEvent(CarPropertyValue value) { 1091 Log.d(CALLBACK_TAG, "onChangeEvent: " + value); 1092 mRegisterCountDownLatch.countDown(); 1093 } 1094 1095 @Override onErrorEvent(int propId, int zone)1096 public void onErrorEvent(int propId, int zone) { 1097 mReceivedErrorEventWithOutErrorCode = true; 1098 Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " zone: " + zone); 1099 mEventsCountDownLatch.countDown(); 1100 } 1101 1102 @Override onErrorEvent(int propId, int areaId, int errorCode)1103 public void onErrorEvent(int propId, int areaId, int errorCode) { 1104 mReceivedErrorEventWithErrorCode = true; 1105 mErrorCode = errorCode; 1106 Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " areaId: " + areaId 1107 + "errorCode: " + errorCode); 1108 mEventsCountDownLatch.countDown(); 1109 } 1110 assertOnErrorEventCalled()1111 public void assertOnErrorEventCalled() throws InterruptedException { 1112 if (!mEventsCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1113 throw new IllegalStateException("Callback is not called in " 1114 + CALLBACK_SHORT_TIMEOUT_MS + " ms."); 1115 } 1116 } 1117 assertOnErrorEventNotCalled()1118 public void assertOnErrorEventNotCalled() throws InterruptedException { 1119 if (mEventsCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1120 throw new IllegalStateException("Callback is called in " + CALLBACK_SHORT_TIMEOUT_MS 1121 + " ms."); 1122 } 1123 } 1124 assertRegisterCompleted()1125 public void assertRegisterCompleted() throws InterruptedException { 1126 if (!mRegisterCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1127 throw new IllegalStateException("Register failed in " + CALLBACK_SHORT_TIMEOUT_MS 1128 + " ms."); 1129 } 1130 } 1131 } 1132 1133 private static class TestCallback implements CarPropertyManager.CarPropertyEventCallback { 1134 private final List<CarPropertyValue<?>> mCarPropertyValues = new ArrayList<>(); 1135 private final int mNumberOfExpectedCarPropertyValues; 1136 private final CountDownLatch mCountDownLatch; 1137 TestCallback(int numberOfExpectedCarPropertyValues)1138 TestCallback(int numberOfExpectedCarPropertyValues) { 1139 mNumberOfExpectedCarPropertyValues = numberOfExpectedCarPropertyValues; 1140 mCountDownLatch = new CountDownLatch(numberOfExpectedCarPropertyValues); 1141 } 1142 1143 @Override onChangeEvent(CarPropertyValue carPropertyValue)1144 public void onChangeEvent(CarPropertyValue carPropertyValue) { 1145 mCarPropertyValues.add(carPropertyValue); 1146 mCountDownLatch.countDown(); 1147 } 1148 1149 @Override onErrorEvent(int propertyId, int areaId)1150 public void onErrorEvent(int propertyId, int areaId) { 1151 Log.e(TAG, "TestCallback onErrorEvent - property ID: " + propertyId + " areaId: " 1152 + areaId); 1153 } 1154 getCarPropertyValues()1155 public List<CarPropertyValue<?>> getCarPropertyValues() { 1156 try { 1157 assertWithMessage("Expected " + mNumberOfExpectedCarPropertyValues 1158 + " CarPropertyValues before timeout, but only received: " 1159 + mCarPropertyValues.size()).that( 1160 mCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, 1161 TimeUnit.MILLISECONDS)).isTrue(); 1162 1163 } catch (InterruptedException e) { 1164 fail("TestCallback was interrupted: " + e); 1165 } 1166 return mCarPropertyValues; 1167 } 1168 } 1169 1170 private class TestSequenceCallback implements CarPropertyManager.CarPropertyEventCallback { 1171 1172 private ConcurrentHashMap<Integer, CarPropertyValue> mRecorder = new ConcurrentHashMap<>(); 1173 private int mCounter = 0; 1174 private final CountDownLatch mEventsCountDownLatch; 1175 private final CountDownLatch mRegisterCountDownLatch = new CountDownLatch(2); 1176 @Override onChangeEvent(CarPropertyValue value)1177 public void onChangeEvent(CarPropertyValue value) { 1178 Log.e(TAG, "onChanged get a event " + value); 1179 mRecorder.put(value.getPropertyId(), value); 1180 mRegisterCountDownLatch.countDown(); 1181 // Skip initial events 1182 if (value.getTimestamp() != 0) { 1183 mCounter++; 1184 mEventsCountDownLatch.countDown(); 1185 } 1186 } 1187 TestSequenceCallback(int expectedTimes)1188 TestSequenceCallback(int expectedTimes) { 1189 mEventsCountDownLatch = new CountDownLatch(expectedTimes); 1190 } 1191 1192 @Override onErrorEvent(int properId, int zone)1193 public void onErrorEvent(int properId, int zone) { 1194 Log.e(TAG, "TestSequenceCallback get an onErrorEvent"); 1195 } 1196 getLastCarPropertyValue(int propId)1197 public CarPropertyValue getLastCarPropertyValue(int propId) { 1198 return mRecorder.get(propId); 1199 } 1200 getEventCounter()1201 public int getEventCounter() { 1202 return mCounter; 1203 } 1204 assertOnChangeEventCalled()1205 public void assertOnChangeEventCalled() throws InterruptedException { 1206 if (!mEventsCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1207 throw new IllegalStateException("Callback is not called in " 1208 + CALLBACK_SHORT_TIMEOUT_MS + " ms."); 1209 } 1210 } 1211 assertRegisterCompleted()1212 public void assertRegisterCompleted() throws InterruptedException { 1213 if (!mRegisterCountDownLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1214 throw new IllegalStateException("Register failed in " + CALLBACK_SHORT_TIMEOUT_MS 1215 + " ms."); 1216 } 1217 } 1218 } 1219 1220 } 1221