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 android.car.hardware.property.CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR; 20 import static android.car.hardware.property.CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE; 21 import static android.car.hardware.property.CarPropertyManager.STATUS_ERROR_TIMEOUT; 22 23 import static com.google.common.truth.Truth.assertThat; 24 import static com.google.common.truth.Truth.assertWithMessage; 25 26 import static org.junit.Assert.assertThrows; 27 28 import android.car.Car; 29 import android.car.VehicleAreaType; 30 import android.car.VehicleAreaWheel; 31 import android.car.VehiclePropertyIds; 32 import android.car.hardware.CarPropertyConfig; 33 import android.car.hardware.CarPropertyValue; 34 import android.car.hardware.property.CarInternalErrorException; 35 import android.car.hardware.property.CarPropertyManager; 36 import android.car.hardware.property.CarPropertyManager.GetPropertyRequest; 37 import android.car.hardware.property.CarPropertyManager.GetPropertyResult; 38 import android.car.hardware.property.CarPropertyManager.PropertyAsyncError; 39 import android.car.hardware.property.CarPropertyManager.SetPropertyRequest; 40 import android.car.hardware.property.CarPropertyManager.SetPropertyResult; 41 import android.car.hardware.property.PropertyAccessDeniedSecurityException; 42 import android.car.hardware.property.PropertyNotAvailableAndRetryException; 43 import android.car.hardware.property.PropertyNotAvailableException; 44 import android.car.hardware.property.VehicleHalStatusCode; 45 import android.hardware.automotive.vehicle.RawPropValues; 46 import android.hardware.automotive.vehicle.VehicleArea; 47 import android.hardware.automotive.vehicle.VehicleAreaSeat; 48 import android.hardware.automotive.vehicle.VehiclePropValue; 49 import android.hardware.automotive.vehicle.VehicleProperty; 50 import android.hardware.automotive.vehicle.VehiclePropertyGroup; 51 import android.hardware.automotive.vehicle.VehiclePropertyStatus; 52 import android.hardware.automotive.vehicle.VehiclePropertyType; 53 import android.hardware.automotive.vehicle.VehicleVendorPermission; 54 import android.os.Build; 55 import android.os.Handler; 56 import android.os.HandlerThread; 57 import android.os.ServiceSpecificException; 58 import android.os.SystemClock; 59 import android.util.ArraySet; 60 import android.util.Log; 61 import android.util.SparseArray; 62 63 import androidx.annotation.NonNull; 64 import androidx.test.ext.junit.runners.AndroidJUnit4; 65 import androidx.test.filters.MediumTest; 66 67 import com.android.car.hal.test.AidlMockedVehicleHal.VehicleHalPropertyHandler; 68 import com.android.car.test.TestPropertyAsyncCallback; 69 70 import com.google.common.truth.Truth; 71 72 import org.junit.Assert; 73 import org.junit.Rule; 74 import org.junit.Test; 75 import org.junit.rules.TestName; 76 import org.junit.runner.RunWith; 77 78 import java.time.Duration; 79 import java.util.ArrayList; 80 import java.util.Arrays; 81 import java.util.Collections; 82 import java.util.List; 83 import java.util.Set; 84 import java.util.concurrent.CountDownLatch; 85 import java.util.concurrent.Executor; 86 import java.util.concurrent.TimeUnit; 87 88 /** 89 * Test for {@link android.car.hardware.property.CarPropertyManager} 90 * 91 * Tests {@link android.car.hardware.property.CarPropertyManager} and the related car service 92 * logic. Uses {@link com.android.car.hal.test.AidlMockedVehicleHal} as the mocked vehicle HAL 93 * implementation. 94 * 95 * Caller should uses {@code addAidlProperty} in {@link #configureMockedHal} to configure the 96 * supported proeprties. 97 * 98 * Caller could also use {@link MockedCarTestBase#getAidlMockedVehicleHal} to further configure 99 * the vehicle HAL. 100 */ 101 @RunWith(AndroidJUnit4.class) 102 @MediumTest 103 public class CarPropertyManagerTest extends MockedCarTestBase { 104 105 private static final String TAG = CarPropertyManagerTest.class.getSimpleName(); 106 107 private static final String TEST_VIN = "test_vin"; 108 109 /** 110 * configArray[0], 1 indicates the property has a String value 111 * configArray[1], 1 indicates the property has a Boolean value . 112 * configArray[2], 1 indicates the property has an Integer value 113 * configArray[3], the number indicates the size of Integer[] in the property. 114 * configArray[4], 1 indicates the property has a Long value . 115 * configArray[5], the number indicates the size of Long[] in the property. 116 * configArray[6], 1 indicates the property has a Float value . 117 * configArray[7], the number indicates the size of Float[] in the property. 118 * configArray[8], the number indicates the size of byte[] in the property. 119 */ 120 private static final java.util.Collection<Integer> CONFIG_ARRAY_1 = 121 Arrays.asList(1, 0, 1, 0, 1, 0, 0, 0, 0); 122 private static final java.util.Collection<Integer> CONFIG_ARRAY_2 = 123 Arrays.asList(1, 1, 1, 0, 0, 0, 0, 2, 0); 124 private static final java.util.Collection<Integer> CONFIG_ARRAY_3 = 125 Arrays.asList(0, 1, 1, 0, 0, 0, 1, 0, 0); 126 private static final Object[] EXPECTED_VALUE_1 = {"android", 1, 1L}; 127 private static final Object[] EXPECTED_VALUE_2 = {"android", true, 3, 1.1f, 2f}; 128 private static final Object[] EXPECTED_VALUE_3 = {true, 1, 2.2f}; 129 130 private static final int CUSTOM_SEAT_INT_PROP_1 = 131 0x1201 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.SEAT; 132 private static final int CUSTOM_SEAT_INT_PROP_2 = 133 0x1202 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.SEAT; 134 135 private static final int CUSTOM_SEAT_MIXED_PROP_ID_1 = 136 0x1101 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.SEAT; 137 private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_2 = 138 0x1102 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL; 139 private static final int CUSTOM_GLOBAL_MIXED_PROP_ID_3 = 140 0x1110 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.MIXED | VehicleArea.GLOBAL; 141 142 private static final int CUSTOM_GLOBAL_INT_ARRAY_PROP = 143 0x1103 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32_VEC 144 | VehicleArea.GLOBAL; 145 private static final Integer[] FAKE_INT_ARRAY_VALUE = {1, 2}; 146 private static final boolean FAKE_BOOLEAN_PROPERTY_VALUE = true; 147 private static final float FAKE_FLOAT_PROPERTY_VALUE = 3f; 148 private static final int FAKE_INT_PROPERTY_VALUE = 3; 149 150 // A property that always returns null to simulate an unavailable property. 151 private static final int NULL_VALUE_PROP = 152 0x1108 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 153 | VehicleArea.GLOBAL; 154 155 // Vendor properties for testing exceptions. 156 private static final int PROP_VALUE_STATUS_ERROR_INT_ARRAY = 157 0x1104 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32_VEC 158 | VehicleArea.GLOBAL; 159 private static final int PROP_VALUE_STATUS_ERROR_BOOLEAN = 160 0x1105 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.BOOLEAN 161 | VehicleArea.GLOBAL; 162 private static final int PROP_VALUE_STATUS_UNAVAILABLE_FLOAT = 163 0x1106 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.FLOAT 164 | VehicleArea.GLOBAL; 165 private static final int PROP_VALUE_STATUS_UNAVAILABLE_INT = 166 0x1107 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 167 | VehicleArea.GLOBAL; 168 private static final int PROP_VALUE_STATUS_UNKNOWN_INT_ARRAY = 169 0x1108 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32_VEC 170 | VehicleArea.GLOBAL; 171 private static final int PROP_VALUE_STATUS_UNAVAILABLE_SEAT = 172 0x1109 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 173 | VehicleArea.SEAT; 174 175 private static final int PROP_CAUSE_STATUS_CODE_TRY_AGAIN = 176 0x1201 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 177 private static final int PROP_CAUSE_STATUS_CODE_INVALID_ARG = 178 0x1202 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 179 private static final int PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE = 180 0x1203 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 181 private static final int PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR = 182 0x1204 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 183 private static final int PROP_CAUSE_STATUS_CODE_ACCESS_DENIED = 184 0x1205 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 185 private static final int PROP_CAUSE_STATUS_CODE_UNKNOWN = 186 0x1206 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 187 private static final int PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE = 188 0x1207 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 189 private static final int PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE = 190 0x1208 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 191 192 // Vendor properties for testing permissions 193 private static final int PROP_WITH_READ_ONLY_PERMISSION = 194 0x1301 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 195 private static final int PROP_WITH_WRITE_ONLY_PERMISSION = 196 0x1302 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 197 private static final int SUPPORT_CUSTOM_PERMISSION = 287313669; 198 private static final java.util.Collection<Integer> VENDOR_PERMISSION_CONFIG = 199 Collections.unmodifiableList( 200 Arrays.asList(PROP_WITH_READ_ONLY_PERMISSION, 201 VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_1, 202 VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE, 203 PROP_WITH_WRITE_ONLY_PERMISSION, 204 VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE, 205 VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_1)); 206 207 private static final int PROP_ERROR_EVENT_NOT_AVAILABLE_DISABLED = 208 0x1401 | VehiclePropertyGroup.VENDOR | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 209 210 211 // Use FAKE_PROPERTY_ID to test api return null or throw exception. 212 private static final int FAKE_PROPERTY_ID = 0x111; 213 214 // This is a property returned by VHAL, but is unsupported in car service. 215 // It must be filtered out at car service layer. 216 private static final int PROP_UNSUPPORTED = 217 0x0100 | VehiclePropertyGroup.SYSTEM | VehiclePropertyType.INT32 | VehicleArea.GLOBAL; 218 219 private static final int DRIVER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_LEFT 220 | VehicleAreaSeat.ROW_2_LEFT; 221 private static final int PASSENGER_SIDE_AREA_ID = VehicleAreaSeat.ROW_1_RIGHT 222 | VehicleAreaSeat.ROW_2_CENTER 223 | VehicleAreaSeat.ROW_2_RIGHT; 224 private static final float INIT_TEMP_VALUE = 16f; 225 private static final float CHANGED_TEMP_VALUE = 20f; 226 private static final int CALLBACK_SHORT_TIMEOUT_MS = 350; // ms 227 // Wait for CarPropertyManager register/unregister listener 228 private static final long WAIT_FOR_NO_EVENTS = 50; 229 private static final int VENDOR_CODE_FOR_NOT_AVAILABLE = 0x00ab; 230 private static final int VENDOR_CODE_FOR_INTERNAL_ERROR = 0x0abc; 231 private static final int NOT_AVAILABLE_WITH_VENDOR_CODE = VENDOR_CODE_FOR_NOT_AVAILABLE << 16 232 | VehicleHalStatusCode.STATUS_NOT_AVAILABLE; 233 private static final int INTERNAL_ERROR_WITH_VENDOR_CODE = VENDOR_CODE_FOR_INTERNAL_ERROR << 16 234 | VehicleHalStatusCode.STATUS_INTERNAL_ERROR; 235 236 private static final List<Integer> USER_HAL_PROPERTIES = Arrays.asList( 237 VehiclePropertyIds.INITIAL_USER_INFO, 238 VehiclePropertyIds.SWITCH_USER, 239 VehiclePropertyIds.CREATE_USER, 240 VehiclePropertyIds.REMOVE_USER, 241 VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION 242 ); 243 244 private CarPropertyManager mManager; 245 246 private final HandlerThread mHandlerThread = new HandlerThread(getClass().getSimpleName()); 247 private Handler mHandler; 248 249 @Rule 250 public TestName mTestName = new TestName(); 251 252 @Override setUp()253 public void setUp() throws Exception { 254 super.setUp(); 255 setUpTargetSdk(); 256 mHandlerThread.start(); 257 mHandler = new Handler(mHandlerThread.getLooper()); 258 mManager = (CarPropertyManager) getCar().getCarManager(Car.PROPERTY_SERVICE); 259 assertThat(mManager).isNotNull(); 260 } 261 262 @Override tearDown()263 public void tearDown() throws Exception { 264 super.tearDown(); 265 mHandlerThread.quitSafely(); 266 } 267 setUpTargetSdk()268 private void setUpTargetSdk() { 269 getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; 270 if (mTestName.getMethodName().endsWith("BeforeR")) { 271 getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.Q; 272 } else if (mTestName.getMethodName().endsWith("BeforeS") 273 || mTestName.getMethodName().endsWith("AfterR")) { 274 getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.R; 275 } else if (mTestName.getMethodName().endsWith("AfterS")) { 276 getContext().getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.S; 277 } 278 } 279 280 @Test testMixedPropertyConfigs()281 public void testMixedPropertyConfigs() { 282 List<CarPropertyConfig> configs = mManager.getPropertyList(); 283 for (CarPropertyConfig cfg : configs) { 284 switch (cfg.getPropertyId()) { 285 case CUSTOM_SEAT_MIXED_PROP_ID_1: 286 assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_1) 287 .inOrder(); 288 break; 289 case CUSTOM_GLOBAL_MIXED_PROP_ID_2: 290 assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_2) 291 .inOrder(); 292 break; 293 case CUSTOM_GLOBAL_MIXED_PROP_ID_3: 294 assertThat(cfg.getConfigArray()).containsExactlyElementsIn(CONFIG_ARRAY_3) 295 .inOrder(); 296 break; 297 case VehiclePropertyIds.HVAC_TEMPERATURE_SET: 298 case PROP_CAUSE_STATUS_CODE_ACCESS_DENIED: 299 case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR: 300 case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE: 301 case PROP_CAUSE_STATUS_CODE_TRY_AGAIN: 302 case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE: 303 case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE: 304 case PROP_CAUSE_STATUS_CODE_INVALID_ARG: 305 case PROP_CAUSE_STATUS_CODE_UNKNOWN: 306 case CUSTOM_SEAT_INT_PROP_1: 307 case CUSTOM_SEAT_INT_PROP_2: 308 case CUSTOM_GLOBAL_INT_ARRAY_PROP: 309 case PROP_VALUE_STATUS_ERROR_INT_ARRAY: 310 case PROP_VALUE_STATUS_UNKNOWN_INT_ARRAY: 311 case PROP_VALUE_STATUS_ERROR_BOOLEAN: 312 case PROP_VALUE_STATUS_UNAVAILABLE_INT: 313 case PROP_VALUE_STATUS_UNAVAILABLE_FLOAT: 314 case PROP_VALUE_STATUS_UNAVAILABLE_SEAT: 315 case NULL_VALUE_PROP: 316 case SUPPORT_CUSTOM_PERMISSION: 317 case PROP_WITH_READ_ONLY_PERMISSION: 318 case PROP_WITH_WRITE_ONLY_PERMISSION: 319 case VehiclePropertyIds.INFO_VIN: 320 case VehiclePropertyIds.TIRE_PRESSURE: 321 case VehiclePropertyIds.FUEL_DOOR_OPEN: 322 case VehiclePropertyIds.EPOCH_TIME: 323 case PROP_ERROR_EVENT_NOT_AVAILABLE_DISABLED: 324 break; 325 default: 326 Assert.fail("Unexpected CarPropertyConfig: " + cfg); 327 } 328 } 329 } 330 331 @Test testGetMixTypeProperty()332 public void testGetMixTypeProperty() { 333 mManager.setProperty(Object[].class, CUSTOM_SEAT_MIXED_PROP_ID_1, 334 DRIVER_SIDE_AREA_ID, EXPECTED_VALUE_1); 335 CarPropertyValue<Object[]> result = mManager.getProperty( 336 CUSTOM_SEAT_MIXED_PROP_ID_1, DRIVER_SIDE_AREA_ID); 337 assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_1); 338 339 mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_2, 340 0, EXPECTED_VALUE_2); 341 result = mManager.getProperty( 342 CUSTOM_GLOBAL_MIXED_PROP_ID_2, 0); 343 assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_2); 344 345 mManager.setProperty(Object[].class, CUSTOM_GLOBAL_MIXED_PROP_ID_3, 346 0, EXPECTED_VALUE_3); 347 result = mManager.getProperty( 348 CUSTOM_GLOBAL_MIXED_PROP_ID_3, 0); 349 assertThat(result.getValue()).isEqualTo(EXPECTED_VALUE_3); 350 } 351 352 /** 353 * Test {@link android.car.hardware.property.CarPropertyManager#getIntArrayProperty(int, int)} 354 */ 355 @Test testGetIntArrayProperty()356 public void testGetIntArrayProperty() { 357 mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, 0, 358 FAKE_INT_ARRAY_VALUE); 359 360 int[] result = mManager.getIntArrayProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP, 0); 361 assertThat(result).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE); 362 } 363 364 /** 365 * Test {@link CarPropertyManager#getIntArrayProperty(int, int)} when vhal returns a value with 366 * error status before S. 367 */ 368 @Test testGetIntArrayPropertyWithErrorStatusBeforeS()369 public void testGetIntArrayPropertyWithErrorStatusBeforeS() { 370 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 371 .isLessThan(Build.VERSION_CODES.S); 372 assertThat(mManager.getIntArrayProperty(PROP_VALUE_STATUS_ERROR_INT_ARRAY, 0)).isEqualTo( 373 new int[0]); 374 } 375 376 /** 377 * Test {@link CarPropertyManager#getIntArrayProperty(int, int)} when vhal returns a value with 378 * error status equal or after S. 379 */ 380 @Test testGetIntArrayPropertyWithErrorStatusEqualAfterS()381 public void testGetIntArrayPropertyWithErrorStatusEqualAfterS() { 382 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 383 .isAtLeast(Build.VERSION_CODES.S); 384 assertThrows(CarInternalErrorException.class, 385 () -> mManager.getIntArrayProperty(PROP_VALUE_STATUS_ERROR_INT_ARRAY, 0)); 386 } 387 388 /** 389 * Test {@link CarPropertyManager#getIntArrayProperty(int, int)} when vhal returns a value with 390 * unknown status before S. 391 */ 392 @Test testGetIntArrayPropertyWithUnknownStatusBeforeS()393 public void testGetIntArrayPropertyWithUnknownStatusBeforeS() { 394 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 395 .isLessThan(Build.VERSION_CODES.S); 396 assertThat(mManager.getIntArrayProperty(PROP_VALUE_STATUS_UNKNOWN_INT_ARRAY, 0)).isEqualTo( 397 new int[0]); 398 } 399 400 /** 401 * Test {@link CarPropertyManager#getIntArrayProperty(int, int)} when vhal returns a value with 402 * unknown status equal or after S. 403 */ 404 @Test testGetIntArrayPropertyWithUnknownStatusEqualAfterS()405 public void testGetIntArrayPropertyWithUnknownStatusEqualAfterS() { 406 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 407 .isAtLeast(Build.VERSION_CODES.S); 408 assertThrows(CarInternalErrorException.class, 409 () -> mManager.getIntArrayProperty(PROP_VALUE_STATUS_UNKNOWN_INT_ARRAY, 0)); 410 } 411 412 /** 413 * Test {@link CarPropertyManager#getIntProperty(int, int)} when vhal returns a value with 414 * unavailable status before S. 415 */ 416 @Test testGetIntPropertyWithUnavailableStatusBeforeS()417 public void testGetIntPropertyWithUnavailableStatusBeforeS() { 418 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 419 .isLessThan(Build.VERSION_CODES.S); 420 assertThat( 421 mManager.getIntProperty(PROP_VALUE_STATUS_UNAVAILABLE_INT, 0)).isEqualTo(0); 422 } 423 424 /** 425 * Test {@link CarPropertyManager#getIntProperty(int, int)} when vhal returns a value with 426 * unavailable status equal or after R. 427 */ 428 @Test testGetIntPropertyWithUnavailableStatusEqualAfterS()429 public void testGetIntPropertyWithUnavailableStatusEqualAfterS() { 430 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 431 .isAtLeast(Build.VERSION_CODES.R); 432 assertThrows(PropertyNotAvailableException.class, 433 () -> mManager.getIntProperty(PROP_VALUE_STATUS_UNAVAILABLE_INT, 0)); 434 } 435 436 /** 437 * Test {@link CarPropertyManager#getBooleanProperty(int, int)} when vhal returns a value with 438 * error status before R. 439 */ 440 @Test testGetBooleanPropertyWithErrorStatusBeforeS()441 public void testGetBooleanPropertyWithErrorStatusBeforeS() { 442 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 443 .isLessThan(Build.VERSION_CODES.S); 444 assertThat(mManager.getBooleanProperty(PROP_VALUE_STATUS_ERROR_BOOLEAN, 0)).isEqualTo( 445 false); 446 } 447 448 /** 449 * Test {@link CarPropertyManager#getBooleanProperty(int, int)} when vhal returns a value with 450 * error status equal or after R. 451 */ 452 @Test testGetBooleanPropertyWithErrorStatusEqualAfterS()453 public void testGetBooleanPropertyWithErrorStatusEqualAfterS() { 454 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 455 .isAtLeast(Build.VERSION_CODES.R); 456 assertThrows(CarInternalErrorException.class, 457 () -> mManager.getBooleanProperty(PROP_VALUE_STATUS_ERROR_BOOLEAN, 0)); 458 } 459 460 /** 461 * Test {@link CarPropertyManager#getFloatProperty(int, int)} when vhal returns a value with 462 * unavailable status before S. 463 */ 464 @Test testGetFloatPropertyWithUnavailableStatusBeforeS()465 public void testGetFloatPropertyWithUnavailableStatusBeforeS() { 466 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 467 .isLessThan(Build.VERSION_CODES.S); 468 assertThat(mManager.getFloatProperty(PROP_VALUE_STATUS_UNAVAILABLE_FLOAT, 0)).isEqualTo(0f); 469 } 470 471 /** 472 * Test {@link CarPropertyManager#getFloatProperty(int, int)} when vhal returns a value with 473 * unavailable status equal or after R. 474 */ 475 @Test testGetFloatPropertyWithUnavailableStatusEqualAfterS()476 public void testGetFloatPropertyWithUnavailableStatusEqualAfterS() { 477 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 478 .isAtLeast(Build.VERSION_CODES.R); 479 assertThrows(PropertyNotAvailableException.class, 480 () -> mManager.getFloatProperty(PROP_VALUE_STATUS_UNAVAILABLE_FLOAT, 0)); 481 } 482 483 /** 484 * Test {@link CarPropertyManager#getProperty(Class, int, int)} 485 */ 486 @Test testGetPropertyWithClass()487 public void testGetPropertyWithClass() { 488 mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, 0, 489 FAKE_INT_ARRAY_VALUE); 490 491 CarPropertyValue<Integer[]> result = mManager.getProperty(Integer[].class, 492 CUSTOM_GLOBAL_INT_ARRAY_PROP, 0); 493 assertThat(result.getValue()).asList().containsExactlyElementsIn(FAKE_INT_ARRAY_VALUE); 494 } 495 496 /** 497 * Test {@link CarPropertyManager#isPropertyAvailable(int, int)} 498 */ 499 @Test testIsPropertyAvailable()500 public void testIsPropertyAvailable() { 501 assertThat(mManager.isPropertyAvailable(CUSTOM_GLOBAL_INT_ARRAY_PROP, 0)).isFalse(); 502 503 mManager.setProperty(Integer[].class, CUSTOM_GLOBAL_INT_ARRAY_PROP, 0, 504 FAKE_INT_ARRAY_VALUE); 505 506 assertThat(mManager.isPropertyAvailable(CUSTOM_GLOBAL_INT_ARRAY_PROP, 0)).isTrue(); 507 } 508 509 /** 510 * Test {@link CarPropertyManager#getWritePermission(int)} 511 * and {@link CarPropertyManager#getWritePermission(int)} 512 */ 513 @Test testGetPermission()514 public void testGetPermission() { 515 String hvacReadPermission = mManager.getReadPermission( 516 VehiclePropertyIds.HVAC_TEMPERATURE_SET); 517 assertThat(hvacReadPermission).isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE); 518 String hvacWritePermission = mManager.getWritePermission( 519 VehiclePropertyIds.HVAC_TEMPERATURE_SET); 520 assertThat(hvacWritePermission).isEqualTo(Car.PERMISSION_CONTROL_CAR_CLIMATE); 521 522 // For read-only property 523 String vinReadPermission = mManager.getReadPermission(VehiclePropertyIds.INFO_VIN); 524 assertThat(vinReadPermission).isEqualTo(Car.PERMISSION_IDENTIFICATION); 525 String vinWritePermission = mManager.getWritePermission(VehiclePropertyIds.INFO_VIN); 526 assertThat(vinWritePermission).isNull(); 527 } 528 529 @Test testGetPropertyConfig()530 public void testGetPropertyConfig() { 531 CarPropertyConfig<?> config = mManager.getCarPropertyConfig(CUSTOM_SEAT_MIXED_PROP_ID_1); 532 assertThat(config.getPropertyId()).isEqualTo(CUSTOM_SEAT_MIXED_PROP_ID_1); 533 // returns null if it cannot find the propertyConfig for the property. 534 assertThat(mManager.getCarPropertyConfig(FAKE_PROPERTY_ID)).isNull(); 535 } 536 537 @Test testGetPropertyConfig_withReadOnlyPermission()538 public void testGetPropertyConfig_withReadOnlyPermission() { 539 CarPropertyConfig<?> configForReadOnlyProperty = mManager 540 .getCarPropertyConfig(PROP_WITH_READ_ONLY_PERMISSION); 541 542 assertThat(configForReadOnlyProperty).isNotNull(); 543 assertThat(configForReadOnlyProperty.getPropertyId()) 544 .isEqualTo(PROP_WITH_READ_ONLY_PERMISSION); 545 } 546 547 @Test testGetPropertyConfig_withWriteOnlyPermission()548 public void testGetPropertyConfig_withWriteOnlyPermission() { 549 CarPropertyConfig<?> configForWriteOnlyProperty = mManager 550 .getCarPropertyConfig(PROP_WITH_WRITE_ONLY_PERMISSION); 551 552 assertThat(configForWriteOnlyProperty).isNotNull(); 553 assertThat(configForWriteOnlyProperty.getPropertyId()) 554 .isEqualTo(PROP_WITH_WRITE_ONLY_PERMISSION); 555 } 556 557 @Test testGetAreaId()558 public void testGetAreaId() { 559 int result = mManager.getAreaId(CUSTOM_SEAT_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_1_LEFT); 560 assertThat(result).isEqualTo(DRIVER_SIDE_AREA_ID); 561 //test for the GLOBAL property 562 int globalAreaId = 563 mManager.getAreaId(CUSTOM_GLOBAL_MIXED_PROP_ID_2, VehicleAreaSeat.ROW_1_LEFT); 564 assertThat(globalAreaId).isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL); 565 //test exception 566 assertThrows(IllegalArgumentException.class, () -> mManager.getAreaId( 567 CUSTOM_SEAT_MIXED_PROP_ID_1, VehicleAreaSeat.ROW_3_CENTER)); 568 assertThrows(IllegalArgumentException.class, () -> mManager.getAreaId(FAKE_PROPERTY_ID, 569 VehicleAreaSeat.ROW_1_LEFT)); 570 } 571 572 @Test testRegisterPropertyGetInitialValueHandleNotAvailableStatusCode()573 public void testRegisterPropertyGetInitialValueHandleNotAvailableStatusCode() throws Exception { 574 TestCallback callback = new TestCallback(/* initValueCount= */ 1, 575 /* changeEventCount= */ 0, /* errorEventCount= */ 0); 576 577 mManager.registerCallback(callback, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 578 CarPropertyManager.SENSOR_RATE_ONCHANGE); 579 580 callback.assertRegisterCompleted(); 581 List<CarPropertyValue> carPropertyValues = callback.getInitialValues(); 582 assertThat(carPropertyValues).hasSize(1); 583 assertThat(carPropertyValues.get(0).getStatus()).isEqualTo( 584 CarPropertyValue.STATUS_UNAVAILABLE); 585 } 586 587 @Test testRegisterPropertyGetInitialValueHandleAccessDeniedStatusCodes()588 public void testRegisterPropertyGetInitialValueHandleAccessDeniedStatusCodes() 589 throws Exception { 590 TestCallback callback = new TestCallback(/* initValueCount= */ 1, 591 /* changeEventCount= */ 0, /* errorEventCount= */ 0); 592 593 mManager.registerCallback(callback, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 594 CarPropertyManager.SENSOR_RATE_ONCHANGE); 595 596 callback.assertRegisterCompleted(); 597 List<CarPropertyValue> carPropertyValues = callback.getInitialValues(); 598 assertThat(carPropertyValues).hasSize(1); 599 assertThat(carPropertyValues.get(0).getStatus()).isEqualTo( 600 CarPropertyValue.STATUS_ERROR); 601 } 602 603 @Test testRegisterPropertyGetInitialValueHandleInternalErrorStatusCodes()604 public void testRegisterPropertyGetInitialValueHandleInternalErrorStatusCodes() 605 throws Exception { 606 TestCallback callback = new TestCallback(/* initValueCount= */ 1, 607 /* changeEventCount= */ 0, /* errorEventCount= */ 0); 608 609 mManager.registerCallback(callback, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 610 CarPropertyManager.SENSOR_RATE_ONCHANGE); 611 612 callback.assertRegisterCompleted(); 613 List<CarPropertyValue> carPropertyValues = callback.getInitialValues(); 614 assertThat(carPropertyValues).hasSize(1); 615 assertThat(carPropertyValues.get(0).getStatus()).isEqualTo( 616 CarPropertyValue.STATUS_ERROR); 617 } 618 619 @Test testRegisterPropertyGetInitialValueHandleInvalidArgStatusCode()620 public void testRegisterPropertyGetInitialValueHandleInvalidArgStatusCode() throws Exception { 621 TestCallback callback = new TestCallback(/* initValueCount= */ 1, 622 /* changeEventCount= */ 0, /* errorEventCount= */ 0); 623 624 mManager.registerCallback(callback, PROP_CAUSE_STATUS_CODE_INVALID_ARG, 625 CarPropertyManager.SENSOR_RATE_ONCHANGE); 626 627 // We should not receive any initial value event. 628 assertThrows(IllegalStateException.class, () -> callback.assertRegisterCompleted( 629 /* timeoutInMs=*/ 1000)); 630 } 631 632 @Test testRegisterPropertyGetInitialValueHandleTryAgainStatusCode()633 public void testRegisterPropertyGetInitialValueHandleTryAgainStatusCode() throws Exception { 634 TestCallback callback = new TestCallback(/* initValueCount= */ 1, 635 /* changeEventCount= */ 0, /* errorEventCount= */ 0); 636 637 mManager.registerCallback(callback, PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 638 CarPropertyManager.SENSOR_RATE_ONCHANGE); 639 640 // We should not receive any initial value event. 641 assertThrows(IllegalStateException.class, () -> callback.assertRegisterCompleted( 642 /* timeoutInMs=*/ 1000)); 643 } 644 645 @Test testNotReceiveOnErrorEvent()646 public void testNotReceiveOnErrorEvent() throws Exception { 647 TestCallback callback = new TestCallback(/* initValueCount= */ 2, /* changeEventCount= */ 0, 648 /* errorEventCount= */ 1); 649 mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 650 CarPropertyManager.SENSOR_RATE_ONCHANGE); 651 callback.assertRegisterCompleted(); 652 injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 653 VehicleHalStatusCode.STATUS_INTERNAL_ERROR); 654 // app never change the value of HVAC_TEMPERATURE_SET, it won't get an error code. 655 callback.assertOnErrorEventNotCalled(); 656 } 657 658 @Test testReceiveOnErrorEvent()659 public void testReceiveOnErrorEvent() throws Exception { 660 TestCallback callback = new TestCallback(/* initValueCount= */ 2, /* changeEventCount= */ 0, 661 /* errorEventCount= */ 1); 662 mManager.registerCallback(callback, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 663 CarPropertyManager.SENSOR_RATE_ONCHANGE); 664 callback.assertRegisterCompleted(); 665 mManager.setFloatProperty( 666 VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 667 CHANGED_TEMP_VALUE); 668 injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 669 VehicleHalStatusCode.STATUS_INTERNAL_ERROR); 670 callback.assertOnErrorEventCalled(); 671 assertThat(callback.getErrorCode()).isEqualTo( 672 CarPropertyManager.CAR_SET_PROPERTY_ERROR_CODE_UNKNOWN); 673 } 674 675 @Test testNotReceiveOnErrorEventAfterUnregister()676 public void testNotReceiveOnErrorEventAfterUnregister() throws Exception { 677 TestCallback callback1 = new TestCallback(/* initValueCount= */ 2, 678 /* changeEventCount= */ 0, /* errorEventCount= */ 1); 679 mManager.registerCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 680 CarPropertyManager.SENSOR_RATE_ONCHANGE); 681 callback1.assertRegisterCompleted(); 682 TestCallback callback2 = new TestCallback(/* initValueCount= */ 2, 683 /* changeEventCount= */ 0, /* errorEventCount= */ 1); 684 mManager.registerCallback(callback2, VehiclePropertyIds.HVAC_TEMPERATURE_SET, 685 CarPropertyManager.SENSOR_RATE_ONCHANGE); 686 mManager.setFloatProperty( 687 VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 688 CHANGED_TEMP_VALUE); 689 mManager.unregisterCallback(callback1, VehiclePropertyIds.HVAC_TEMPERATURE_SET); 690 SystemClock.sleep(WAIT_FOR_NO_EVENTS); 691 injectErrorEvent(VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, 692 VehicleHalStatusCode.STATUS_INTERNAL_ERROR); 693 // callback1 is unregistered 694 callback1.assertOnErrorEventNotCalled(); 695 callback2.assertOnErrorEventCalled(); 696 } 697 698 @Test testSetterExceptionsBeforeR()699 public void testSetterExceptionsBeforeR() { 700 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 701 .isLessThan(Build.VERSION_CODES.R); 702 703 assertThrows(IllegalStateException.class, 704 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 705 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 706 assertThrows(IllegalStateException.class, 707 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 708 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 709 assertThrows(IllegalStateException.class, 710 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 711 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 712 assertThrows(IllegalArgumentException.class, 713 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG, 714 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 715 assertThrows(RuntimeException.class, 716 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 717 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 718 } 719 720 @Test testSetterExceptionsEqualAfterR()721 public void testSetterExceptionsEqualAfterR() { 722 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 723 .isAtLeast(Build.VERSION_CODES.Q); 724 725 assertThrows(PropertyAccessDeniedSecurityException.class, 726 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 727 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 728 assertThrows(PropertyNotAvailableAndRetryException.class, 729 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 730 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 731 assertThrows(PropertyNotAvailableException.class, 732 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 733 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 734 assertThrows(CarInternalErrorException.class, 735 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 736 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 737 assertThrows(IllegalArgumentException.class, 738 () -> mManager.setProperty(Integer.class, PROP_CAUSE_STATUS_CODE_INVALID_ARG, 739 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 740 assertThrows(IllegalArgumentException.class, 741 () -> mManager.setProperty(Integer.class, PROP_UNSUPPORTED, 742 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1)); 743 } 744 745 @Test testGetterExceptionsBeforeR()746 public void testGetterExceptionsBeforeR() { 747 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 748 .isLessThan(Build.VERSION_CODES.R); 749 750 assertThrows(IllegalStateException.class, 751 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 0)); 752 assertThrows(IllegalStateException.class, 753 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 0)); 754 755 assertThrows(IllegalArgumentException.class, 756 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 0)); 757 assertThrows(IllegalArgumentException.class, 758 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 0)); 759 760 assertThrows(IllegalStateException.class, 761 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 0)); 762 assertThrows(IllegalStateException.class, 763 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 0)); 764 765 assertThrows(IllegalStateException.class, 766 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 0)); 767 assertThrows(IllegalStateException.class, 768 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 0)); 769 770 assertThrows(IllegalStateException.class, () -> mManager.getProperty(NULL_VALUE_PROP, 0)); 771 assertThrows(IllegalStateException.class, 772 () -> mManager.getIntProperty(NULL_VALUE_PROP, 0)); 773 774 Truth.assertThat(mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 0)).isNull(); 775 assertThat(mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 0)).isEqualTo(0); 776 777 } 778 779 @Test testGetterExceptionsEqualAfterR()780 public void testGetterExceptionsEqualAfterR() { 781 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 782 .isAtLeast(Build.VERSION_CODES.R); 783 784 assertThrows(PropertyAccessDeniedSecurityException.class, 785 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 0)); 786 assertThrows(PropertyAccessDeniedSecurityException.class, 787 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 0)); 788 assertThrows(IllegalArgumentException.class, 789 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 0)); 790 assertThrows(IllegalArgumentException.class, 791 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, 0)); 792 793 assertThrows(PropertyNotAvailableAndRetryException.class, 794 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 0)); 795 assertThrows(PropertyNotAvailableAndRetryException.class, 796 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 0)); 797 798 assertThrows(PropertyNotAvailableException.class, 799 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 0)); 800 assertThrows(PropertyNotAvailableException.class, 801 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 0)); 802 803 assertThrows(CarInternalErrorException.class, 804 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 0)); 805 assertThrows(CarInternalErrorException.class, 806 () -> mManager.getIntProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, 0)); 807 808 assertThrows(PropertyNotAvailableException.class, 809 () -> mManager.getProperty(NULL_VALUE_PROP, 0)); 810 assertThrows(PropertyNotAvailableException.class, 811 () -> mManager.getIntProperty(NULL_VALUE_PROP, 0)); 812 assertThrows(IllegalArgumentException.class, 813 () -> mManager.getProperty(PROP_UNSUPPORTED, 0)); 814 assertThrows(PropertyNotAvailableException.class, 815 () -> mManager.getIntProperty(NULL_VALUE_PROP, 0)); 816 } 817 818 @Test testOnChangeEventWithSameAreaId()819 public void testOnChangeEventWithSameAreaId() throws Exception { 820 // init 821 TestCallback callback = new TestCallback(/* initValueCount= */ 2, /* changeEventCount= */ 1, 822 /* errorEventCount= */ 0); 823 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0); 824 callback.assertRegisterCompleted(); 825 826 VehiclePropValue firstFakeValueDriveSide = new VehiclePropValue(); 827 firstFakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_1; 828 firstFakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID; 829 firstFakeValueDriveSide.value = new RawPropValues(); 830 firstFakeValueDriveSide.value.int32Values = new int[]{2}; 831 firstFakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos(); 832 VehiclePropValue secFakeValueDriveSide = new VehiclePropValue(); 833 secFakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_1; 834 secFakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID; 835 secFakeValueDriveSide.value = new RawPropValues(); 836 secFakeValueDriveSide.value.int32Values = new int[]{3}; // 0 in HAL indicate false; 837 secFakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos(); 838 // inject the new event first 839 getAidlMockedVehicleHal().injectEvent(secFakeValueDriveSide); 840 // inject the old event 841 getAidlMockedVehicleHal().injectEvent(firstFakeValueDriveSide); 842 843 List<CarPropertyValue> events = callback.waitAndGetChangeEvents(); 844 845 // Client should only get the new event 846 assertThat(events).hasSize(1); 847 assertThat(events.get(0).getValue()).isEqualTo(3); 848 849 } 850 851 @Test testOnChangeEventWithDifferentAreaId()852 public void testOnChangeEventWithDifferentAreaId() throws Exception { 853 // init 854 TestCallback callback = new TestCallback(/* initValueCount= */ 2, /* changeEventCount= */ 2, 855 /* errorEventCount= */ 0); 856 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_2, 0); 857 callback.assertRegisterCompleted(); 858 VehiclePropValue fakeValueDriveSide = new VehiclePropValue(); 859 fakeValueDriveSide.prop = CUSTOM_SEAT_INT_PROP_2; 860 fakeValueDriveSide.areaId = DRIVER_SIDE_AREA_ID; 861 fakeValueDriveSide.value = new RawPropValues(); 862 fakeValueDriveSide.value.int32Values = new int[]{4}; 863 fakeValueDriveSide.timestamp = SystemClock.elapsedRealtimeNanos(); 864 865 VehiclePropValue fakeValuePsgSide = new VehiclePropValue(); 866 fakeValuePsgSide.prop = CUSTOM_SEAT_INT_PROP_2; 867 fakeValuePsgSide.areaId = PASSENGER_SIDE_AREA_ID; 868 fakeValuePsgSide.value = new RawPropValues(); 869 fakeValuePsgSide.value.int32Values = new int[]{5}; 870 fakeValuePsgSide.timestamp = SystemClock.elapsedRealtimeNanos(); 871 872 // inject passenger event before driver event 873 getAidlMockedVehicleHal().injectEvent(fakeValuePsgSide); 874 getAidlMockedVehicleHal().injectEvent(fakeValueDriveSide); 875 876 List<CarPropertyValue> events = callback.waitAndGetChangeEvents(); 877 878 // both events should be received by listener 879 assertThat(events).hasSize(2); 880 assertThat(events.get(0).getValue()).isEqualTo(5); 881 assertThat(events.get(1).getValue()).isEqualTo(4); 882 } 883 884 @Test testOnChangeEventPropErrorStatus()885 public void testOnChangeEventPropErrorStatus() throws Exception { 886 // init 887 TestCallback callback = new TestCallback(/* initValueCount= */ 2, /* changeEventCount= */ 1, 888 /* errorEventCount= */ 0); 889 890 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0); 891 892 callback.assertRegisterCompleted(/* timeoutMs= */ 1000); 893 894 VehiclePropValue prop = new VehiclePropValue(); 895 prop.prop = CUSTOM_SEAT_INT_PROP_1; 896 prop.areaId = DRIVER_SIDE_AREA_ID; 897 prop.value = new RawPropValues(); 898 prop.status = VehiclePropertyStatus.ERROR; 899 prop.timestamp = SystemClock.elapsedRealtimeNanos(); 900 901 getAidlMockedVehicleHal().injectEvent(prop); 902 903 List<CarPropertyValue> carPropertyValues = callback.waitAndGetChangeEvents(); 904 assertThat(carPropertyValues).hasSize(1); 905 assertThat(carPropertyValues.get(0).getStatus()).isEqualTo(CarPropertyValue.STATUS_ERROR); 906 } 907 908 @Test testOnChangeEventPropUnavailableStatus()909 public void testOnChangeEventPropUnavailableStatus() throws Exception { 910 // init 911 TestCallback callback = new TestCallback(/* initValueCount= */ 2, /* changeEventCount= */ 1, 912 /* errorEventCount= */ 0); 913 914 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0); 915 916 callback.assertRegisterCompleted(); 917 918 VehiclePropValue prop = new VehiclePropValue(); 919 prop.prop = CUSTOM_SEAT_INT_PROP_1; 920 prop.areaId = DRIVER_SIDE_AREA_ID; 921 prop.value = new RawPropValues(); 922 prop.status = VehiclePropertyStatus.UNAVAILABLE; 923 prop.timestamp = SystemClock.elapsedRealtimeNanos(); 924 925 getAidlMockedVehicleHal().injectEvent(prop); 926 927 List<CarPropertyValue> carPropertyValues = callback.waitAndGetChangeEvents(); 928 assertThat(carPropertyValues).hasSize(1); 929 assertThat(carPropertyValues.get(0).getStatus()).isEqualTo( 930 CarPropertyValue.STATUS_UNAVAILABLE); 931 } 932 933 @Test testOnChangeEventInvalidPayload()934 public void testOnChangeEventInvalidPayload() throws Exception { 935 // init 936 TestCallback callback = new TestCallback(/* initValueCount= */ 2, /* changeEventCount= */ 0, 937 /* errorEventCount= */ 0); 938 mManager.registerCallback(callback, CUSTOM_SEAT_INT_PROP_1, 0); 939 callback.assertRegisterCompleted(); 940 941 List<VehiclePropValue> props = new ArrayList<>(); 942 VehiclePropValue emptyProp = new VehiclePropValue(); 943 emptyProp.prop = CUSTOM_SEAT_INT_PROP_1; 944 props.add(emptyProp); 945 946 VehiclePropValue twoIntsProp = new VehiclePropValue(); 947 twoIntsProp.prop = CUSTOM_SEAT_INT_PROP_1; 948 twoIntsProp.value = new RawPropValues(); 949 twoIntsProp.value.int32Values = new int[]{0, 1}; 950 props.add(twoIntsProp); 951 952 VehiclePropValue propWithFloat = new VehiclePropValue(); 953 propWithFloat.prop = CUSTOM_SEAT_INT_PROP_1; 954 propWithFloat.value = new RawPropValues(); 955 propWithFloat.value.floatValues = new float[]{0f}; 956 props.add(propWithFloat); 957 958 VehiclePropValue propWithString = new VehiclePropValue(); 959 propWithString.prop = CUSTOM_SEAT_INT_PROP_1; 960 propWithString.value = new RawPropValues(); 961 propWithString.value.stringValue = "1234"; 962 props.add(propWithString); 963 964 for (VehiclePropValue prop : props) { 965 // inject passenger event before driver event 966 getAidlMockedVehicleHal().injectEvent(prop); 967 968 assertThat(callback.getChangeEventCounter()).isEqualTo(0); 969 } 970 } 971 972 @Test registerCallback_handlesContinuousPropertyUpdateRate()973 public void registerCallback_handlesContinuousPropertyUpdateRate() throws Exception { 974 float wheelLeftFrontValue = 11.11f; 975 long wheelLeftFrontTimestampNanos = Duration.ofSeconds(1).toNanos(); 976 977 float notNewEnoughWheelLeftFrontValue = 22.22f; 978 long notNewEnoughWheelLeftFrontTimestampNanos = Duration.ofMillis(1999).toNanos(); 979 980 float newEnoughWheelLeftFrontValue = 33.33f; 981 long newEnoughWheelLeftFrontTimestampNanos = Duration.ofSeconds(2).toNanos(); 982 983 TestCallback callback = new TestCallback(/* initValueCount= */ 4, /* changeEventCount= */ 2, 984 /* errorEventCount= */ 0); 985 assertThat(mManager.registerCallback(callback, VehiclePropertyIds.TIRE_PRESSURE, 986 1f)).isTrue(); 987 callback.assertRegisterCompleted(); 988 989 long currentElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos(); 990 getAidlMockedVehicleHal().injectEvent( 991 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 992 wheelLeftFrontValue, 993 currentElapsedRealtimeNanos + wheelLeftFrontTimestampNanos)); 994 getAidlMockedVehicleHal().injectEvent( 995 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 996 notNewEnoughWheelLeftFrontValue, 997 currentElapsedRealtimeNanos + notNewEnoughWheelLeftFrontTimestampNanos)); 998 getAidlMockedVehicleHal().injectEvent( 999 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 1000 newEnoughWheelLeftFrontValue, 1001 currentElapsedRealtimeNanos + newEnoughWheelLeftFrontTimestampNanos)); 1002 1003 List<CarPropertyValue> carPropertyValues = callback.waitAndGetChangeEvents(); 1004 assertThat(carPropertyValues).hasSize(2); 1005 1006 assertTirePressureCarPropertyValue(carPropertyValues.get(0), 1007 VehicleAreaWheel.WHEEL_LEFT_FRONT, wheelLeftFrontValue, 1008 currentElapsedRealtimeNanos + wheelLeftFrontTimestampNanos); 1009 1010 assertTirePressureCarPropertyValue(carPropertyValues.get(1), 1011 VehicleAreaWheel.WHEEL_LEFT_FRONT, newEnoughWheelLeftFrontValue, 1012 currentElapsedRealtimeNanos + newEnoughWheelLeftFrontTimestampNanos); 1013 } 1014 1015 @Test registerCallback_handlesOutOfTimeOrderEventsWithDifferentAreaIds()1016 public void registerCallback_handlesOutOfTimeOrderEventsWithDifferentAreaIds() 1017 throws Exception { 1018 float wheelLeftFrontValue = 11.11f; 1019 long wheelLeftFrontTimestampNanos = Duration.ofSeconds(4).toNanos(); 1020 1021 float wheelRightFrontValue = 22.22f; 1022 long wheelRightFrontTimestampNanos = Duration.ofSeconds(3).toNanos(); 1023 1024 float wheelLeftRearValue = 33.33f; 1025 long wheelLeftRearTimestampNanos = Duration.ofSeconds(2).toNanos(); 1026 1027 float wheelRightRearValue = 44.44f; 1028 long wheelRightRearTimestampNanos = Duration.ofSeconds(1).toNanos(); 1029 1030 // Initially we have 4 area Ids, so we will have 4 initial values. In the test we will 1031 // inject 4 events which will generate 4 change events. 1032 TestCallback callback = new TestCallback(/* initValueCount= */ 4, /* changeEventCount= */ 4, 1033 /* errorEventCount= */ 0); 1034 // AidlMockedVehicleHal will not actually genenerate property events for continuous 1035 // property, so the subscription rate does not matter. 1036 assertThat(mManager.registerCallback(callback, VehiclePropertyIds.TIRE_PRESSURE, 1f)) 1037 .isTrue(); 1038 1039 callback.assertRegisterCompleted(); 1040 1041 long currentElapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos(); 1042 // inject events in time order from newest to oldest 1043 getAidlMockedVehicleHal().injectEvent( 1044 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_FRONT, 1045 wheelLeftFrontValue, 1046 currentElapsedRealtimeNanos + wheelLeftFrontTimestampNanos)); 1047 getAidlMockedVehicleHal().injectEvent( 1048 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_RIGHT_FRONT, 1049 wheelRightFrontValue, 1050 currentElapsedRealtimeNanos + wheelRightFrontTimestampNanos)); 1051 getAidlMockedVehicleHal().injectEvent( 1052 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_LEFT_REAR, 1053 wheelLeftRearValue, 1054 currentElapsedRealtimeNanos + wheelLeftRearTimestampNanos)); 1055 getAidlMockedVehicleHal().injectEvent( 1056 newTirePressureVehiclePropValue(VehicleAreaWheel.WHEEL_RIGHT_REAR, 1057 wheelRightRearValue, 1058 currentElapsedRealtimeNanos + wheelRightRearTimestampNanos)); 1059 1060 List<CarPropertyValue> carPropertyValues = callback.waitAndGetChangeEvents(); 1061 assertThat(carPropertyValues).hasSize(4); 1062 1063 assertTirePressureCarPropertyValue(carPropertyValues.get(0), 1064 VehicleAreaWheel.WHEEL_LEFT_FRONT, wheelLeftFrontValue, 1065 currentElapsedRealtimeNanos + wheelLeftFrontTimestampNanos); 1066 1067 assertTirePressureCarPropertyValue(carPropertyValues.get(1), 1068 VehicleAreaWheel.WHEEL_RIGHT_FRONT, wheelRightFrontValue, 1069 currentElapsedRealtimeNanos + wheelRightFrontTimestampNanos); 1070 1071 assertTirePressureCarPropertyValue(carPropertyValues.get(2), 1072 VehicleAreaWheel.WHEEL_LEFT_REAR, wheelLeftRearValue, 1073 currentElapsedRealtimeNanos + wheelLeftRearTimestampNanos); 1074 1075 assertTirePressureCarPropertyValue(carPropertyValues.get(3), 1076 VehicleAreaWheel.WHEEL_RIGHT_REAR, wheelRightRearValue, 1077 currentElapsedRealtimeNanos + wheelRightRearTimestampNanos); 1078 } 1079 1080 @Test testGetPropertiesAsync()1081 public void testGetPropertiesAsync() throws Exception { 1082 List<GetPropertyRequest> getPropertyRequests = new ArrayList<>(); 1083 Executor callbackExecutor = new HandlerExecutor(mHandler); 1084 Set<Integer> requestIds = new ArraySet(); 1085 1086 // Regular property. 1087 GetPropertyRequest vinRequest = mManager.generateGetPropertyRequest( 1088 VehiclePropertyIds.INFO_VIN, /* areaId= */ 0); 1089 // Property with area. 1090 GetPropertyRequest hvacTempDriverRequest = mManager.generateGetPropertyRequest( 1091 VehiclePropertyIds.HVAC_TEMPERATURE_SET, DRIVER_SIDE_AREA_ID); 1092 GetPropertyRequest hvacTempPsgRequest = mManager.generateGetPropertyRequest( 1093 VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID); 1094 1095 getPropertyRequests.add(vinRequest); 1096 getPropertyRequests.add(hvacTempDriverRequest); 1097 getPropertyRequests.add(hvacTempPsgRequest); 1098 1099 requestIds.add(vinRequest.getRequestId()); 1100 requestIds.add(hvacTempDriverRequest.getRequestId()); 1101 requestIds.add(hvacTempPsgRequest.getRequestId()); 1102 1103 int resultCount = 3; 1104 int errorCount = 0; 1105 1106 int vendorErrorRequestId = 0; 1107 1108 // A list of properties that will generate error results. 1109 for (int propId : List.of( 1110 PROP_VALUE_STATUS_ERROR_INT_ARRAY, 1111 PROP_VALUE_STATUS_ERROR_BOOLEAN, 1112 PROP_VALUE_STATUS_UNAVAILABLE_INT, 1113 PROP_VALUE_STATUS_UNAVAILABLE_FLOAT, 1114 PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 1115 PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 1116 PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 1117 PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE, 1118 PROP_CAUSE_STATUS_CODE_INVALID_ARG 1119 )) { 1120 GetPropertyRequest errorRequest = mManager.generateGetPropertyRequest( 1121 propId, /* areaId= */ 0); 1122 getPropertyRequests.add(errorRequest); 1123 requestIds.add(errorRequest.getRequestId()); 1124 errorCount++; 1125 if (propId == PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE) { 1126 vendorErrorRequestId = errorRequest.getRequestId(); 1127 } 1128 } 1129 1130 GetPropertyRequest unavailableDriverRequest = mManager.generateGetPropertyRequest( 1131 PROP_VALUE_STATUS_UNAVAILABLE_SEAT, DRIVER_SIDE_AREA_ID); 1132 getPropertyRequests.add(unavailableDriverRequest); 1133 requestIds.add(unavailableDriverRequest.getRequestId()); 1134 errorCount++; 1135 1136 GetPropertyRequest unavailablePsgRequest = mManager.generateGetPropertyRequest( 1137 PROP_VALUE_STATUS_UNAVAILABLE_SEAT, PASSENGER_SIDE_AREA_ID); 1138 getPropertyRequests.add(unavailablePsgRequest); 1139 requestIds.add(unavailablePsgRequest.getRequestId()); 1140 errorCount++; 1141 1142 TestPropertyAsyncCallback callback = new TestPropertyAsyncCallback( 1143 requestIds); 1144 mManager.getPropertiesAsync(getPropertyRequests, /* timeoutInMs= */ 1000, 1145 /* cancellationSignal= */ null, callbackExecutor, callback); 1146 1147 // Make the timeout longer than the timeout specified in getPropertiesAsync since the 1148 // error callback will be delivered after the request timed-out. 1149 callback.waitAndFinish(/* timeoutInMs= */ 2000); 1150 1151 assertThat(callback.getTestErrors()).isEmpty(); 1152 List<GetPropertyResult<?>> results = callback.getGetResultList(); 1153 assertThat(results.size()).isEqualTo(resultCount); 1154 assertThat(callback.getErrorList().size()).isEqualTo(errorCount); 1155 for (GetPropertyResult<?> result : results) { 1156 int resultRequestId = result.getRequestId(); 1157 if (resultRequestId == vinRequest.getRequestId()) { 1158 assertThat(result.getValue().getClass()).isEqualTo(String.class); 1159 assertThat(result.getValue()).isEqualTo(TEST_VIN); 1160 } else if (resultRequestId == hvacTempDriverRequest.getRequestId() 1161 || resultRequestId == hvacTempPsgRequest.getRequestId()) { 1162 assertThat(result.getValue().getClass()).isEqualTo(Float.class); 1163 assertThat(result.getValue()).isEqualTo(INIT_TEMP_VALUE); 1164 } else { 1165 Assert.fail("unknown result request Id: " + resultRequestId); 1166 } 1167 } 1168 for (PropertyAsyncError error : callback.getErrorList()) { 1169 assertThat(error.getErrorCode()).isNotEqualTo(0); 1170 int propertyId = error.getPropertyId(); 1171 if (propertyId == PROP_VALUE_STATUS_ERROR_INT_ARRAY 1172 || propertyId == PROP_VALUE_STATUS_ERROR_BOOLEAN 1173 || propertyId == PROP_CAUSE_STATUS_CODE_ACCESS_DENIED 1174 || propertyId == PROP_CAUSE_STATUS_CODE_INVALID_ARG) { 1175 assertWithMessage("receive correct error for property ID: " + propertyId) 1176 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_INTERNAL_ERROR); 1177 assertThat(error.getVendorErrorCode()).isEqualTo(0); 1178 } 1179 if (propertyId == PROP_VALUE_STATUS_UNAVAILABLE_INT 1180 || propertyId == PROP_VALUE_STATUS_UNAVAILABLE_FLOAT 1181 || propertyId == PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE) { 1182 assertWithMessage("receive correct error for property ID: " + propertyId) 1183 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_NOT_AVAILABLE); 1184 assertThat(error.getVendorErrorCode()).isEqualTo(0); 1185 } 1186 if (propertyId == PROP_CAUSE_STATUS_CODE_TRY_AGAIN) { 1187 assertWithMessage("receive correct error for property ID: " + propertyId) 1188 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_TIMEOUT); 1189 assertThat(error.getVendorErrorCode()).isEqualTo(0); 1190 } 1191 if (error.getRequestId() == vendorErrorRequestId) { 1192 assertWithMessage("receive correct error for property ID: " + propertyId) 1193 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_INTERNAL_ERROR); 1194 assertThat(error.getVendorErrorCode()).isEqualTo(VENDOR_CODE_FOR_INTERNAL_ERROR); 1195 } 1196 } 1197 } 1198 1199 @Test testSetPropertiesAsync()1200 public void testSetPropertiesAsync() throws Exception { 1201 List<SetPropertyRequest<?>> setPropertyRequests = new ArrayList<>(); 1202 Executor callbackExecutor = new HandlerExecutor(mHandler); 1203 Set<Integer> requestIds = new ArraySet(); 1204 1205 // Global read-write property. 1206 SetPropertyRequest<Boolean> fuelDoorOpenRequest = mManager.generateSetPropertyRequest( 1207 VehiclePropertyIds.FUEL_DOOR_OPEN, 0, true); 1208 // Seat area type read-write property. 1209 float tempValue1 = 10.1f; 1210 // This is less than minValue: 10, so it should be set to min value instead. 1211 float tempValue2 = 9.9f; 1212 SetPropertyRequest<Float> hvacTempDriverRequest = mManager.generateSetPropertyRequest( 1213 VehiclePropertyIds.HVAC_TEMPERATURE_SET, DRIVER_SIDE_AREA_ID, tempValue1); 1214 SetPropertyRequest<Float> hvacTempPsgRequest = mManager.generateSetPropertyRequest( 1215 VehiclePropertyIds.HVAC_TEMPERATURE_SET, PASSENGER_SIDE_AREA_ID, tempValue2); 1216 SetPropertyRequest<Long> writeOnlyPropRequest = mManager.generateSetPropertyRequest( 1217 VehiclePropertyIds.EPOCH_TIME, 0, /* value= */ 1L); 1218 // Write only property with the default waitForProperty set to true should generate error. 1219 writeOnlyPropRequest.setWaitForPropertyUpdate(false); 1220 1221 setPropertyRequests.add(fuelDoorOpenRequest); 1222 setPropertyRequests.add(hvacTempDriverRequest); 1223 setPropertyRequests.add(hvacTempPsgRequest); 1224 setPropertyRequests.add(writeOnlyPropRequest); 1225 1226 requestIds.add(fuelDoorOpenRequest.getRequestId()); 1227 requestIds.add(hvacTempDriverRequest.getRequestId()); 1228 requestIds.add(hvacTempPsgRequest.getRequestId()); 1229 requestIds.add(writeOnlyPropRequest.getRequestId()); 1230 1231 List<Integer> successPropIds = List.of( 1232 VehiclePropertyIds.FUEL_DOOR_OPEN, 1233 VehiclePropertyIds.HVAC_TEMPERATURE_SET, 1234 VehiclePropertyIds.EPOCH_TIME); 1235 1236 int resultCount = requestIds.size(); 1237 int errorCount = 0; 1238 int vendorErrorRequestId = 0; 1239 1240 // A list of properties that will generate error results. 1241 List<Integer> errorPropIds = List.of( 1242 PROP_CAUSE_STATUS_CODE_TRY_AGAIN, 1243 PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, 1244 PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, 1245 PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE, 1246 PROP_CAUSE_STATUS_CODE_INVALID_ARG, 1247 PROP_ERROR_EVENT_NOT_AVAILABLE_DISABLED); 1248 for (int propId : errorPropIds) { 1249 SetPropertyRequest<Integer> errorRequest = mManager.generateSetPropertyRequest( 1250 propId, /* areaId= */ 0, /* value= */ 1); 1251 setPropertyRequests.add(errorRequest); 1252 requestIds.add(errorRequest.getRequestId()); 1253 errorCount++; 1254 if (propId == PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE) { 1255 vendorErrorRequestId = errorRequest.getRequestId(); 1256 } 1257 } 1258 1259 long startTime = SystemClock.elapsedRealtimeNanos(); 1260 TestPropertyAsyncCallback callback = new TestPropertyAsyncCallback(requestIds); 1261 1262 mManager.setPropertiesAsync(setPropertyRequests, /* timeoutInMs= */ 1000, 1263 /* cancellationSignal= */ null, callbackExecutor, callback); 1264 1265 // Make the timeout longer than the timeout specified in setPropertiesAsync since the 1266 // error callback will be delivered after the request timed-out. 1267 callback.waitAndFinish(/* timeoutInMs= */ 2000); 1268 1269 assertThat(callback.getTestErrors()).isEmpty(); 1270 List<SetPropertyResult> results = callback.getSetResultList(); 1271 assertThat(results.size()).isEqualTo(resultCount); 1272 assertThat(callback.getErrorList().size()).isEqualTo(errorCount); 1273 for (SetPropertyResult result : results) { 1274 assertThat(result.getPropertyId()).isIn(successPropIds); 1275 if (result.getPropertyId() == VehiclePropertyIds.HVAC_TEMPERATURE_SET) { 1276 assertThat(result.getAreaId()).isIn(List.of( 1277 DRIVER_SIDE_AREA_ID, PASSENGER_SIDE_AREA_ID)); 1278 } 1279 assertThat(result.getUpdateTimestampNanos()).isGreaterThan(startTime); 1280 } 1281 for (PropertyAsyncError error : callback.getErrorList()) { 1282 int propertyId = error.getPropertyId(); 1283 assertThat(propertyId).isIn(errorPropIds); 1284 assertThat(error.getAreaId()).isEqualTo(0); 1285 if (propertyId == PROP_CAUSE_STATUS_CODE_ACCESS_DENIED 1286 || propertyId == PROP_CAUSE_STATUS_CODE_INVALID_ARG) { 1287 assertWithMessage("receive correct error for property ID: " + propertyId) 1288 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_INTERNAL_ERROR); 1289 assertThat(error.getVendorErrorCode()).isEqualTo(0); 1290 } 1291 if (propertyId == PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE 1292 || propertyId == PROP_ERROR_EVENT_NOT_AVAILABLE_DISABLED) { 1293 assertWithMessage("receive correct error for property ID: " + propertyId) 1294 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_NOT_AVAILABLE); 1295 assertThat(error.getVendorErrorCode()).isEqualTo(0); 1296 } 1297 if (propertyId == PROP_CAUSE_STATUS_CODE_TRY_AGAIN) { 1298 assertWithMessage("receive correct error for property ID: " + propertyId) 1299 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_TIMEOUT); 1300 assertThat(error.getVendorErrorCode()).isEqualTo(0); 1301 } 1302 if (error.getRequestId() == vendorErrorRequestId) { 1303 assertWithMessage("receive correct error for property ID: " + propertyId) 1304 .that(error.getErrorCode()).isEqualTo(STATUS_ERROR_NOT_AVAILABLE); 1305 assertThat(error.getVendorErrorCode()).isEqualTo(VENDOR_CODE_FOR_NOT_AVAILABLE); 1306 } 1307 } 1308 } 1309 1310 @Test testGetVendorErrorCode_forGetProperty_throwsNotAvailable_EqualAfterR()1311 public void testGetVendorErrorCode_forGetProperty_throwsNotAvailable_EqualAfterR() { 1312 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 1313 .isAtLeast(Build.VERSION_CODES.R); 1314 PropertyNotAvailableException thrown = assertThrows(PropertyNotAvailableException.class, 1315 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE, 1316 /* areaId= */ 0)); 1317 1318 assertThat(thrown.getVendorErrorCode()).isEqualTo(VENDOR_CODE_FOR_NOT_AVAILABLE); 1319 } 1320 1321 @Test testGetVendorErrorCode_forGetProperty_throwsInternalError_EqualAfterR()1322 public void testGetVendorErrorCode_forGetProperty_throwsInternalError_EqualAfterR() { 1323 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 1324 .isAtLeast(Build.VERSION_CODES.R); 1325 CarInternalErrorException thrown = assertThrows(CarInternalErrorException.class, 1326 () -> mManager.getProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE, 1327 /* areaId= */ 0)); 1328 1329 assertThat(thrown.getVendorErrorCode()).isEqualTo(VENDOR_CODE_FOR_INTERNAL_ERROR); 1330 } 1331 1332 @Test testGetVendorErrorCode_forSetProperty_throwsNotAvailable_EqualAfterR()1333 public void testGetVendorErrorCode_forSetProperty_throwsNotAvailable_EqualAfterR() { 1334 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 1335 .isAtLeast(Build.VERSION_CODES.R); 1336 PropertyNotAvailableException thrown = assertThrows(PropertyNotAvailableException.class, 1337 () -> mManager.setProperty(Integer.class, 1338 PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE, /* areaId= */ 0, 1339 /* val= */ 0)); 1340 1341 assertThat(thrown.getVendorErrorCode()).isEqualTo(VENDOR_CODE_FOR_NOT_AVAILABLE); 1342 } 1343 1344 @Test testGetVendorErrorCode_forSetProperty_throwsInternalError_EqualAfterR()1345 public void testGetVendorErrorCode_forSetProperty_throwsInternalError_EqualAfterR() { 1346 Truth.assertThat(getContext().getApplicationInfo().targetSdkVersion) 1347 .isAtLeast(Build.VERSION_CODES.R); 1348 CarInternalErrorException thrown = assertThrows(CarInternalErrorException.class, 1349 () -> mManager.setProperty(Integer.class, 1350 PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE, /* areaId= */0, 1351 /* val= */ 0)); 1352 1353 assertThat(thrown.getVendorErrorCode()).isEqualTo(VENDOR_CODE_FOR_INTERNAL_ERROR); 1354 } 1355 1356 @Override configureMockedHal()1357 protected void configureMockedHal() { 1358 PropertyHandler handler = new PropertyHandler(); 1359 addAidlProperty(CUSTOM_SEAT_MIXED_PROP_ID_1, handler).setConfigArray(CONFIG_ARRAY_1) 1360 .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID); 1361 addAidlProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_2, handler).setConfigArray(CONFIG_ARRAY_2); 1362 addAidlProperty(CUSTOM_GLOBAL_MIXED_PROP_ID_3, handler).setConfigArray(CONFIG_ARRAY_3); 1363 addAidlProperty(CUSTOM_GLOBAL_INT_ARRAY_PROP, handler); 1364 1365 addAidlProperty(VehicleProperty.TIRE_PRESSURE, handler).addAreaConfig( 1366 VehicleAreaWheel.WHEEL_LEFT_REAR).addAreaConfig( 1367 VehicleAreaWheel.WHEEL_RIGHT_REAR).addAreaConfig( 1368 VehicleAreaWheel.WHEEL_RIGHT_FRONT).addAreaConfig( 1369 VehicleAreaWheel.WHEEL_LEFT_FRONT).setChangeMode( 1370 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS).setMaxSampleRate( 1371 10).setMinSampleRate(1); 1372 1373 VehiclePropValue tempValue = new VehiclePropValue(); 1374 tempValue.value = new RawPropValues(); 1375 tempValue.value.floatValues = new float[]{INIT_TEMP_VALUE}; 1376 tempValue.prop = VehicleProperty.HVAC_TEMPERATURE_SET; 1377 addAidlProperty(VehicleProperty.HVAC_TEMPERATURE_SET, tempValue) 1378 .addAreaConfig(DRIVER_SIDE_AREA_ID, /* minValue = */ 10, /* maxValue = */ 20) 1379 .addAreaConfig(PASSENGER_SIDE_AREA_ID, /* minValue = */ 10, /* maxValue = */ 20); 1380 VehiclePropValue vinValue = new VehiclePropValue(); 1381 vinValue.value = new RawPropValues(); 1382 vinValue.value.stringValue = TEST_VIN; 1383 vinValue.prop = VehicleProperty.INFO_VIN; 1384 addAidlProperty(VehicleProperty.INFO_VIN, vinValue); 1385 addAidlProperty(VehicleProperty.FUEL_DOOR_OPEN); 1386 addAidlProperty(VehicleProperty.ANDROID_EPOCH_TIME); 1387 1388 addAidlProperty(PROP_VALUE_STATUS_ERROR_INT_ARRAY, handler); 1389 addAidlProperty(PROP_VALUE_STATUS_UNKNOWN_INT_ARRAY, handler); 1390 addAidlProperty(PROP_VALUE_STATUS_UNAVAILABLE_INT, handler); 1391 addAidlProperty(PROP_VALUE_STATUS_UNAVAILABLE_FLOAT, handler); 1392 addAidlProperty(PROP_VALUE_STATUS_ERROR_BOOLEAN, handler); 1393 addAidlProperty(PROP_VALUE_STATUS_UNAVAILABLE_SEAT, handler) 1394 .addAreaConfig(DRIVER_SIDE_AREA_ID).addAreaConfig(PASSENGER_SIDE_AREA_ID) 1395 .setChangeMode(CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS) 1396 .setMaxSampleRate(10).setMinSampleRate(1); 1397 1398 addAidlProperty(PROP_CAUSE_STATUS_CODE_ACCESS_DENIED, handler); 1399 addAidlProperty(PROP_CAUSE_STATUS_CODE_TRY_AGAIN, handler); 1400 addAidlProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR, handler); 1401 addAidlProperty(PROP_CAUSE_STATUS_CODE_INVALID_ARG, handler); 1402 addAidlProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE, handler); 1403 addAidlProperty(PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE, handler); 1404 addAidlProperty(PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE, handler); 1405 1406 addAidlProperty(PROP_CAUSE_STATUS_CODE_UNKNOWN, handler); 1407 1408 addAidlProperty(CUSTOM_SEAT_INT_PROP_1, handler).addAreaConfig(DRIVER_SIDE_AREA_ID) 1409 .addAreaConfig(PASSENGER_SIDE_AREA_ID); 1410 addAidlProperty(CUSTOM_SEAT_INT_PROP_2, handler).addAreaConfig(DRIVER_SIDE_AREA_ID) 1411 .addAreaConfig(PASSENGER_SIDE_AREA_ID); 1412 1413 addAidlProperty(NULL_VALUE_PROP, handler); 1414 addAidlProperty(PROP_UNSUPPORTED, handler); 1415 addAidlProperty(PROP_ERROR_EVENT_NOT_AVAILABLE_DISABLED, handler); 1416 1417 // Add properties for permission testing. 1418 addAidlProperty(SUPPORT_CUSTOM_PERMISSION, handler).setConfigArray( 1419 VENDOR_PERMISSION_CONFIG); 1420 addAidlProperty(PROP_WITH_READ_ONLY_PERMISSION, handler); 1421 addAidlProperty(PROP_WITH_WRITE_ONLY_PERMISSION, handler); 1422 1423 addAidlProperty(PROP_UNSUPPORTED, handler); 1424 } 1425 1426 private class PropertyHandler implements VehicleHalPropertyHandler { 1427 SparseArray<SparseArray<VehiclePropValue>> mValueByAreaIdByPropId = new SparseArray<>(); 1428 1429 @Override onPropertySet2(VehiclePropValue value)1430 public synchronized boolean onPropertySet2(VehiclePropValue value) { 1431 // Simulate VehicleHal.set() behavior. 1432 if (value.prop == PROP_ERROR_EVENT_NOT_AVAILABLE_DISABLED) { 1433 injectErrorEvent(PROP_ERROR_EVENT_NOT_AVAILABLE_DISABLED, /* areaId= */ 0, 1434 VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED); 1435 // Don't generate property change event. 1436 return false; 1437 } 1438 1439 int statusCode = mapPropertyToVhalStatusCode(value.prop); 1440 if (statusCode != VehicleHalStatusCode.STATUS_OK) { 1441 // The ServiceSpecificException here would pass the statusCode back to caller. 1442 throw new ServiceSpecificException(statusCode); 1443 } 1444 1445 int areaId = value.areaId; 1446 int propId = value.prop; 1447 if (mValueByAreaIdByPropId.get(propId) == null) { 1448 mValueByAreaIdByPropId.put(propId, new SparseArray<>()); 1449 } 1450 mValueByAreaIdByPropId.get(propId).put(areaId, value); 1451 return true; 1452 } 1453 1454 @Override onPropertyGet(VehiclePropValue value)1455 public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) { 1456 // Simulate VehicleHal.get() behavior. 1457 int vhalStatusCode = mapPropertyToVhalStatusCode(value.prop); 1458 if (vhalStatusCode != VehicleHalStatusCode.STATUS_OK) { 1459 // The ServiceSpecificException here would pass the statusCode back to caller. 1460 throw new ServiceSpecificException(vhalStatusCode); 1461 } 1462 1463 if (value.prop == NULL_VALUE_PROP) { 1464 // Return null to simulate an unavailable property. 1465 // HAL implementation should return STATUS_TRY_AGAIN when a property is unavailable, 1466 // however, it may also return null with STATUS_OKAY, and we want to handle this 1467 // properly. 1468 return null; 1469 } 1470 1471 VehiclePropValue returnValue = new VehiclePropValue(); 1472 returnValue.prop = value.prop; 1473 returnValue.areaId = value.areaId; 1474 returnValue.timestamp = SystemClock.elapsedRealtimeNanos(); 1475 returnValue.value = new RawPropValues(); 1476 int propertyStatus = mapPropertyToVehiclePropertyStatus(value.prop); 1477 if (propertyStatus != VehiclePropertyStatus.AVAILABLE) { 1478 returnValue.status = propertyStatus; 1479 return returnValue; 1480 } 1481 if (mValueByAreaIdByPropId.get(value.prop) == null) { 1482 return null; 1483 } 1484 return mValueByAreaIdByPropId.get(value.prop).get(value.areaId); 1485 } 1486 1487 @Override onPropertySubscribe(int property, float sampleRate)1488 public synchronized void onPropertySubscribe(int property, float sampleRate) { 1489 Log.d(TAG, "onPropertySubscribe property " 1490 + property + " sampleRate " + sampleRate); 1491 } 1492 1493 @Override onPropertyUnsubscribe(int property)1494 public synchronized void onPropertyUnsubscribe(int property) { 1495 Log.d(TAG, "onPropertyUnSubscribe property " + property); 1496 } 1497 } 1498 propToString(int propertyId)1499 private static String propToString(int propertyId) { 1500 return VehiclePropertyIds.toString(propertyId) + " (" + propertyId + ")"; 1501 } 1502 mapPropertyToVhalStatusCode(int propId)1503 private static int mapPropertyToVhalStatusCode(int propId) { 1504 switch (propId) { 1505 case PROP_CAUSE_STATUS_CODE_TRY_AGAIN: 1506 return VehicleHalStatusCode.STATUS_TRY_AGAIN; 1507 case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE: 1508 return VehicleHalStatusCode.STATUS_NOT_AVAILABLE; 1509 case PROP_CAUSE_STATUS_CODE_ACCESS_DENIED: 1510 return VehicleHalStatusCode.STATUS_ACCESS_DENIED; 1511 case PROP_CAUSE_STATUS_CODE_INVALID_ARG: 1512 return VehicleHalStatusCode.STATUS_INVALID_ARG; 1513 case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR: 1514 return VehicleHalStatusCode.STATUS_INTERNAL_ERROR; 1515 case PROP_CAUSE_STATUS_CODE_UNKNOWN: 1516 return -1; 1517 case PROP_CAUSE_STATUS_CODE_INTERNAL_ERROR_WITH_VENDOR_CODE: 1518 return INTERNAL_ERROR_WITH_VENDOR_CODE; 1519 case PROP_CAUSE_STATUS_CODE_NOT_AVAILABLE_WITH_VENDOR_CODE: 1520 return NOT_AVAILABLE_WITH_VENDOR_CODE; 1521 default: 1522 return VehicleHalStatusCode.STATUS_OK; 1523 } 1524 } 1525 mapPropertyToVehiclePropertyStatus(int propId)1526 private static int mapPropertyToVehiclePropertyStatus(int propId) { 1527 switch (propId) { 1528 case PROP_VALUE_STATUS_ERROR_INT_ARRAY: 1529 case PROP_VALUE_STATUS_ERROR_BOOLEAN: 1530 return VehiclePropertyStatus.ERROR; 1531 case PROP_VALUE_STATUS_UNAVAILABLE_INT: 1532 case PROP_VALUE_STATUS_UNAVAILABLE_FLOAT: 1533 return VehiclePropertyStatus.UNAVAILABLE; 1534 case PROP_VALUE_STATUS_UNKNOWN_INT_ARRAY: 1535 return -1; 1536 default: 1537 return VehiclePropertyStatus.AVAILABLE; 1538 } 1539 } 1540 newTirePressureVehiclePropValue(int areaId, float floatValue, long timestampNanos)1541 private static VehiclePropValue newTirePressureVehiclePropValue(int areaId, float floatValue, 1542 long timestampNanos) { 1543 VehiclePropValue vehiclePropValue = new VehiclePropValue(); 1544 vehiclePropValue.prop = VehiclePropertyIds.TIRE_PRESSURE; 1545 vehiclePropValue.areaId = areaId; 1546 vehiclePropValue.value = new RawPropValues(); 1547 vehiclePropValue.value.floatValues = new float[]{floatValue}; 1548 vehiclePropValue.timestamp = timestampNanos; 1549 return vehiclePropValue; 1550 } 1551 assertTirePressureCarPropertyValue(CarPropertyValue<?> carPropertyValue, int areaId, float floatValue, long timestampNanos)1552 private static void assertTirePressureCarPropertyValue(CarPropertyValue<?> carPropertyValue, 1553 int areaId, float floatValue, long timestampNanos) { 1554 assertThat(carPropertyValue.getPropertyId()).isEqualTo(VehiclePropertyIds.TIRE_PRESSURE); 1555 assertThat(carPropertyValue.getAreaId()).isEqualTo(areaId); 1556 assertThat(carPropertyValue.getStatus()).isEqualTo(CarPropertyValue.STATUS_AVAILABLE); 1557 assertThat(carPropertyValue.getTimestamp()).isEqualTo(timestampNanos); 1558 assertThat(carPropertyValue.getValue()).isEqualTo(floatValue); 1559 } 1560 1561 private static class TestCallback implements CarPropertyManager.CarPropertyEventCallback { 1562 private static final String CALLBACK_TAG = "ErrorEventTest"; 1563 1564 private final int mInitValueCount; 1565 private final int mChangeEventCount; 1566 private final int mErrorEventCount; 1567 private CountDownLatch mInitialValueCdLatch; 1568 private CountDownLatch mChangeEventCdLatch; 1569 private CountDownLatch mErrorEventCdLatch; 1570 1571 private final Object mLock = new Object(); 1572 private final List<CarPropertyValue> mChangeEvents = new ArrayList<>(); 1573 private final List<CarPropertyValue> mInitialValues = new ArrayList<>(); 1574 private Integer mErrorCode; 1575 TestCallback(int initValueCount, int changeEventCount, int errorEventCount)1576 TestCallback(int initValueCount, int changeEventCount, int errorEventCount) { 1577 mInitValueCount = initValueCount; 1578 mChangeEventCount = changeEventCount; 1579 mErrorEventCount = errorEventCount; 1580 // We expect to receive one initial event for each area. 1581 mInitialValueCdLatch = new CountDownLatch(mInitValueCount); 1582 mChangeEventCdLatch = new CountDownLatch(mChangeEventCount); 1583 mErrorEventCdLatch = new CountDownLatch(mErrorEventCount); 1584 } 1585 1586 @Override onChangeEvent(CarPropertyValue carPropertyValue)1587 public void onChangeEvent(CarPropertyValue carPropertyValue) { 1588 Log.d(CALLBACK_TAG, "onChangeEvent: " + carPropertyValue); 1589 synchronized (mLock) { 1590 if (mInitialValueCdLatch.getCount() > 0) { 1591 mInitialValueCdLatch.countDown(); 1592 mInitialValues.add(carPropertyValue); 1593 } else { 1594 mChangeEventCdLatch.countDown(); 1595 mChangeEvents.add(carPropertyValue); 1596 } 1597 } 1598 } 1599 1600 @Override onErrorEvent(int propId, int areaId)1601 public void onErrorEvent(int propId, int areaId) { 1602 Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " areaId: " + areaId); 1603 synchronized (mLock) { 1604 mErrorEventCdLatch.countDown(); 1605 } 1606 } 1607 1608 @Override onErrorEvent(int propId, int areaId, int errorCode)1609 public void onErrorEvent(int propId, int areaId, int errorCode) { 1610 Log.d(CALLBACK_TAG, "onErrorEvent, propId: " + propId + " areaId: " + areaId 1611 + "errorCode: " + errorCode); 1612 synchronized (mLock) { 1613 mErrorCode = errorCode; 1614 mErrorEventCdLatch.countDown(); 1615 } 1616 } 1617 getErrorCode()1618 public Integer getErrorCode() { 1619 synchronized (mLock) { 1620 return mErrorCode; 1621 } 1622 } 1623 assertOnErrorEventCalled()1624 public void assertOnErrorEventCalled() throws InterruptedException { 1625 if (!mErrorEventCdLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1626 long got = mErrorEventCount - mErrorEventCdLatch.getCount(); 1627 throw new IllegalStateException("Does not receive enough error events before " 1628 + CALLBACK_SHORT_TIMEOUT_MS + " ms, got: " + got 1629 + ", expected: " + mErrorEventCount); 1630 } 1631 } 1632 assertOnErrorEventNotCalled()1633 public void assertOnErrorEventNotCalled() throws InterruptedException { 1634 if (mErrorEventCdLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1635 long got = mErrorEventCount - mErrorEventCdLatch.getCount(); 1636 throw new IllegalStateException("Receive more error events than expected after " 1637 + CALLBACK_SHORT_TIMEOUT_MS + " ms, got: " + got 1638 + ", expected less than: " + mErrorEventCount); 1639 } 1640 } 1641 assertRegisterCompleted()1642 public void assertRegisterCompleted() throws InterruptedException { 1643 assertRegisterCompleted(CALLBACK_SHORT_TIMEOUT_MS); 1644 } 1645 assertRegisterCompleted(int timeoutMs)1646 public void assertRegisterCompleted(int timeoutMs) throws InterruptedException { 1647 if (!mInitialValueCdLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) { 1648 long got = mInitValueCount - mInitialValueCdLatch.getCount(); 1649 throw new IllegalStateException("Does not receive enough initial value events " 1650 + "before " + CALLBACK_SHORT_TIMEOUT_MS + " ms, got: " + got 1651 + ", expected: " + mInitValueCount); 1652 } 1653 } 1654 getChangeEventCounter()1655 public int getChangeEventCounter() { 1656 synchronized (mLock) { 1657 return mChangeEvents.size(); 1658 } 1659 } 1660 waitAndGetChangeEvents()1661 public List<CarPropertyValue> waitAndGetChangeEvents() throws InterruptedException { 1662 if (!mChangeEventCdLatch.await(CALLBACK_SHORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1663 long got = mChangeEventCount - mChangeEventCdLatch.getCount(); 1664 throw new IllegalStateException("Does not receive enough property events before " 1665 + CALLBACK_SHORT_TIMEOUT_MS + " ms, got: " + got 1666 + ", expected: " + mChangeEventCount); 1667 } 1668 synchronized (mLock) { 1669 return mChangeEvents; 1670 } 1671 } 1672 getInitialValues()1673 public List<CarPropertyValue> getInitialValues() { 1674 synchronized (mLock) { 1675 return mInitialValues; 1676 } 1677 } 1678 } 1679 1680 // This is almost the same as {@link android.os.HandlerExecutor} except that it will not throw 1681 // exception even if the underlying handler is already shut down. 1682 private static class HandlerExecutor implements Executor { 1683 private final Handler mHandler; 1684 HandlerExecutor(@onNull Handler handler)1685 HandlerExecutor(@NonNull Handler handler) { 1686 mHandler = handler; 1687 } 1688 1689 @Override execute(Runnable command)1690 public void execute(Runnable command) { 1691 mHandler.post(command); 1692 } 1693 } 1694 1695 } 1696