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