1 /* 2 * Copyright (C) 2023 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 android.car.cts.utils; 18 19 import static android.Manifest.permission.ACCESS_FINE_LOCATION; 20 21 import static com.google.common.truth.Truth.assertThat; 22 import static com.google.common.truth.Truth.assertWithMessage; 23 24 import android.car.Car; 25 import android.car.VehicleAreaType; 26 import android.car.VehiclePropertyIds; 27 import android.car.VehicleUnit; 28 import android.car.feature.Flags; 29 import android.car.hardware.CarHvacFanDirection; 30 import android.car.hardware.CarPropertyConfig; 31 import android.car.hardware.CarPropertyValue; 32 import android.car.hardware.property.CarPropertyManager; 33 import android.car.hardware.property.LocationCharacterization; 34 import android.car.hardware.property.VehicleAutonomousState; 35 import android.car.hardware.property.VehicleSizeClass; 36 import android.car.hardware.property.VehicleTurnSignal; 37 import android.util.ArraySet; 38 39 import com.google.common.collect.ImmutableList; 40 import com.google.common.collect.ImmutableSet; 41 import com.google.common.collect.Sets; 42 43 import java.util.Arrays; 44 import java.util.List; 45 import java.util.stream.Collectors; 46 47 /** 48 * Provides a list of verifiers for vehicle properties. 49 */ 50 public class VehiclePropertyVerifiers { 51 VehiclePropertyVerifiers()52 private VehiclePropertyVerifiers() { 53 throw new UnsupportedOperationException("Should only be used as a static class"); 54 } 55 56 private static final int LOCATION_CHARACTERIZATION_VALID_VALUES_MASK = 57 LocationCharacterization.PRIOR_LOCATIONS 58 | LocationCharacterization.GYROSCOPE_FUSION 59 | LocationCharacterization.ACCELEROMETER_FUSION 60 | LocationCharacterization.COMPASS_FUSION 61 | LocationCharacterization.WHEEL_SPEED_FUSION 62 | LocationCharacterization.STEERING_ANGLE_FUSION 63 | LocationCharacterization.CAR_SPEED_FUSION 64 | LocationCharacterization.DEAD_RECKONED 65 | LocationCharacterization.RAW_GNSS_ONLY; 66 67 private static final ImmutableSet<Integer> HVAC_TEMPERATURE_DISPLAY_UNITS = 68 ImmutableSet.<Integer>builder().add(VehicleUnit.CELSIUS, 69 VehicleUnit.FAHRENHEIT).build(); 70 71 private static final ImmutableSet<Integer> SINGLE_HVAC_FAN_DIRECTIONS = 72 ImmutableSet.of( 73 CarHvacFanDirection.UNKNOWN, 74 CarHvacFanDirection.FACE, 75 CarHvacFanDirection.FLOOR, 76 CarHvacFanDirection.DEFROST); 77 78 private static final ImmutableSet<Integer> ALL_POSSIBLE_HVAC_FAN_DIRECTIONS = 79 generateAllPossibleHvacFanDirections(); 80 81 private static final ImmutableSet<Integer> CAR_HVAC_FAN_DIRECTION_UNWRITABLE_STATES = 82 ImmutableSet.<Integer>builder() 83 .add( 84 CarHvacFanDirection.UNKNOWN) 85 .build(); 86 private static final ImmutableSet<Integer> VEHICLE_SIZE_CLASSES = 87 ImmutableSet.<Integer>builder() 88 .add( 89 VehicleSizeClass.EPA_TWO_SEATER, 90 VehicleSizeClass.EPA_MINICOMPACT, 91 VehicleSizeClass.EPA_SUBCOMPACT, 92 VehicleSizeClass.EPA_COMPACT, 93 VehicleSizeClass.EPA_MIDSIZE, 94 VehicleSizeClass.EPA_LARGE, 95 VehicleSizeClass.EPA_SMALL_STATION_WAGON, 96 VehicleSizeClass.EPA_MIDSIZE_STATION_WAGON, 97 VehicleSizeClass.EPA_LARGE_STATION_WAGON, 98 VehicleSizeClass.EPA_SMALL_PICKUP_TRUCK, 99 VehicleSizeClass.EPA_STANDARD_PICKUP_TRUCK, 100 VehicleSizeClass.EPA_VAN, 101 VehicleSizeClass.EPA_MINIVAN, 102 VehicleSizeClass.EPA_SMALL_SUV, 103 VehicleSizeClass.EPA_STANDARD_SUV, 104 VehicleSizeClass.EU_A_SEGMENT, 105 VehicleSizeClass.EU_B_SEGMENT, 106 VehicleSizeClass.EU_C_SEGMENT, 107 VehicleSizeClass.EU_D_SEGMENT, 108 VehicleSizeClass.EU_E_SEGMENT, 109 VehicleSizeClass.EU_F_SEGMENT, 110 VehicleSizeClass.EU_J_SEGMENT, 111 VehicleSizeClass.EU_M_SEGMENT, 112 VehicleSizeClass.EU_S_SEGMENT, 113 VehicleSizeClass.JPN_KEI, 114 VehicleSizeClass.JPN_SMALL_SIZE, 115 VehicleSizeClass.JPN_NORMAL_SIZE, 116 VehicleSizeClass.US_GVWR_CLASS_1_CV, 117 VehicleSizeClass.US_GVWR_CLASS_2_CV, 118 VehicleSizeClass.US_GVWR_CLASS_3_CV, 119 VehicleSizeClass.US_GVWR_CLASS_4_CV, 120 VehicleSizeClass.US_GVWR_CLASS_5_CV, 121 VehicleSizeClass.US_GVWR_CLASS_6_CV, 122 VehicleSizeClass.US_GVWR_CLASS_7_CV, 123 VehicleSizeClass.US_GVWR_CLASS_8_CV) 124 .build(); 125 private static final ImmutableSet<Integer> TURN_SIGNAL_STATES = 126 ImmutableSet.<Integer>builder().add(VehicleTurnSignal.STATE_NONE, 127 VehicleTurnSignal.STATE_RIGHT, VehicleTurnSignal.STATE_LEFT).build(); 128 private static final ImmutableSet<Integer> VEHICLE_AUTONOMOUS_STATES = 129 ImmutableSet.<Integer>builder() 130 .add( 131 VehicleAutonomousState.LEVEL_0, 132 VehicleAutonomousState.LEVEL_1, 133 VehicleAutonomousState.LEVEL_2, 134 VehicleAutonomousState.LEVEL_3, 135 VehicleAutonomousState.LEVEL_4, 136 VehicleAutonomousState.LEVEL_5) 137 .build(); 138 139 /** Gets the verifier builder for PERF_STEERING_ANGLE. */ getPerfSteeringAngleVerifierBuilder()140 public static VehiclePropertyVerifier.Builder<Float> getPerfSteeringAngleVerifierBuilder() { 141 VehiclePropertyVerifier.Builder<Float> verifierBuilder = 142 VehiclePropertyVerifier.newBuilder( 143 VehiclePropertyIds.PERF_STEERING_ANGLE, 144 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 145 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 146 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, 147 Float.class) 148 .addReadPermission(Car.PERMISSION_READ_STEERING_STATE); 149 150 return Flags.vehicleProperty25q23pPermissions() 151 ? verifierBuilder.addReadPermission(Car.PERMISSION_READ_STEERING_STATE_3P) 152 : verifierBuilder; 153 } 154 155 /** 156 * Gets the verifier builder for LOCATION_CHARACTERIZATION. 157 */ 158 public static VehiclePropertyVerifier.Builder<Integer> getLocationCharacterizationVerifierBuilder()159 getLocationCharacterizationVerifierBuilder() { 160 return getLocationCharacterizationVerifierBuilder( 161 /* carPropertyManager= */ null, VehiclePropertyIds.LOCATION_CHARACTERIZATION, 162 ACCESS_FINE_LOCATION); 163 } 164 165 /** 166 * Gets the verifier for LOCATION_CHARACTERIZATION. 167 */ getLocationCharacterizationVerifier( CarPropertyManager carPropertyManager)168 public static VehiclePropertyVerifier<Integer> getLocationCharacterizationVerifier( 169 CarPropertyManager carPropertyManager) { 170 return getLocationCharacterizationVerifier( 171 carPropertyManager, 172 VehiclePropertyIds.LOCATION_CHARACTERIZATION, 173 ACCESS_FINE_LOCATION); 174 } 175 176 /** 177 * Gets the verifier for backported LOCATION_CHARACTERIZATION. 178 * 179 * @param carPropertyManager the car property manager instance. 180 * @param propertyId the backported property ID. 181 * @param readPermission the permission for the backported property. 182 */ getLocationCharacterizationVerifier( CarPropertyManager carPropertyManager, int propertyId, String readPermission)183 public static VehiclePropertyVerifier<Integer> getLocationCharacterizationVerifier( 184 CarPropertyManager carPropertyManager, 185 int propertyId, String readPermission) { 186 var builder = getLocationCharacterizationVerifierBuilder( 187 carPropertyManager, propertyId, readPermission); 188 if (VehiclePropertyVerifier.isAtLeastU()) { 189 builder.requireProperty(); 190 } 191 return builder.build(); 192 } 193 194 /** 195 * Gets the verifier for {@code HVAC_DEFROSTER}. 196 */ getHvacDefrosterVerifier( CarPropertyManager carPropertyManager)197 public static VehiclePropertyVerifier<Boolean> getHvacDefrosterVerifier( 198 CarPropertyManager carPropertyManager) { 199 return getHvacDefrosterVerifierBuilder().setCarPropertyManager(carPropertyManager).build(); 200 } 201 202 /** 203 * Gets the verifier builder for {@code HVAC_DEFROSTER}. 204 */ getHvacDefrosterVerifierBuilder()205 public static VehiclePropertyVerifier.Builder<Boolean> getHvacDefrosterVerifierBuilder() { 206 return VehiclePropertyVerifier.newBuilder( 207 VehiclePropertyIds.HVAC_DEFROSTER, 208 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 209 VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW, 210 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 211 Boolean.class) 212 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 213 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 214 } 215 216 /** 217 * Gets the verifier for {@code HVAC_SIDE_MIRROR_HEAT}. 218 */ getHvacSideMirrorHeatVerifier( CarPropertyManager carPropertyManager)219 public static VehiclePropertyVerifier<Integer> getHvacSideMirrorHeatVerifier( 220 CarPropertyManager carPropertyManager) { 221 return getHvacSideMirrorHeatVerifierBuilder().setCarPropertyManager(carPropertyManager) 222 .build(); 223 } 224 225 /** 226 * Gets the verifier builder for {@code HVAC_SIDE_MIRROR_HEAT}. 227 */ getHvacSideMirrorHeatVerifierBuilder()228 public static VehiclePropertyVerifier.Builder<Integer> getHvacSideMirrorHeatVerifierBuilder() { 229 return VehiclePropertyVerifier.newBuilder( 230 VehiclePropertyIds.HVAC_SIDE_MIRROR_HEAT, 231 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 232 VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR, 233 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 234 Integer.class) 235 .requireMinMaxValues() 236 .requireMinValuesToBeZero() 237 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 238 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 239 } 240 241 /** 242 * Gets the verifier for {@code HVAC_STEERING_WHEEL_HEAT}. 243 */ getHvacSteeringWheelHeatVerifier( CarPropertyManager carPropertyManager)244 public static VehiclePropertyVerifier<Integer> getHvacSteeringWheelHeatVerifier( 245 CarPropertyManager carPropertyManager) { 246 return getHvacSteeringWheelHeatVerifierBuilder().setCarPropertyManager(carPropertyManager) 247 .build(); 248 } 249 250 /** 251 * Gets the verifier builder for {@code HVAC_STEERING_WHEEL_HEAT}. 252 */ 253 public static VehiclePropertyVerifier.Builder<Integer> getHvacSteeringWheelHeatVerifierBuilder()254 getHvacSteeringWheelHeatVerifierBuilder() { 255 return VehiclePropertyVerifier.newBuilder( 256 VehiclePropertyIds.HVAC_STEERING_WHEEL_HEAT, 257 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 258 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 259 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 260 Integer.class) 261 .requireMinMaxValues() 262 .requireZeroToBeContainedInMinMaxRanges() 263 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 264 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 265 } 266 267 /** 268 * Gets the verifier for {@code HVAC_TEMPERATURE_DISPLAY_UNITS}. 269 */ getHvacTemperatureDisplayUnitsVerifier( CarPropertyManager carPropertyManager)270 public static VehiclePropertyVerifier<Integer> getHvacTemperatureDisplayUnitsVerifier( 271 CarPropertyManager carPropertyManager) { 272 return getHvacTemperatureDisplayUnitsVerifierBuilder() 273 .setCarPropertyManager(carPropertyManager).build(); 274 } 275 276 /** 277 * Gets the verifier builder for {@code HVAC_TEMPERATURE_DISPLAY_UNITS}. 278 */ 279 public static VehiclePropertyVerifier.Builder<Integer> getHvacTemperatureDisplayUnitsVerifierBuilder()280 getHvacTemperatureDisplayUnitsVerifierBuilder() { 281 VehiclePropertyVerifier.Builder builder = VehiclePropertyVerifier.newBuilder( 282 VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS, 283 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 284 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 285 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 286 Integer.class) 287 .setAllPossibleEnumValues(HVAC_TEMPERATURE_DISPLAY_UNITS) 288 .setPossibleConfigArrayValues(HVAC_TEMPERATURE_DISPLAY_UNITS) 289 .requirePropertyValueTobeInConfigArray() 290 .verifySetterWithConfigArrayValues() 291 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 292 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 293 294 if (VehiclePropertyVerifier.isAtLeastU()) { 295 builder.addReadPermission(Car.PERMISSION_READ_DISPLAY_UNITS); 296 } 297 return builder; 298 } 299 300 /** 301 * Gets the verifier for {@code HVAC_TEMPERATURE_VALUE_SUGGESTION}. 302 */ getHvacTemperatureValueSuggestionVerifier( CarPropertyManager carPropertyManager)303 public static VehiclePropertyVerifier<Float[]> getHvacTemperatureValueSuggestionVerifier( 304 CarPropertyManager carPropertyManager) { 305 return getHvacTemperatureValueSuggestionVerifierBuilder() 306 .setCarPropertyManager(carPropertyManager).build(); 307 } 308 309 /** 310 * Gets the verifier builder for {@code HVAC_TEMPERATURE_VALUE_SUGGESTION}. 311 */ 312 public static VehiclePropertyVerifier.Builder<Float[]> getHvacTemperatureValueSuggestionVerifierBuilder()313 getHvacTemperatureValueSuggestionVerifierBuilder() { 314 return VehiclePropertyVerifier.newBuilder( 315 VehiclePropertyIds.HVAC_TEMPERATURE_VALUE_SUGGESTION, 316 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 317 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 318 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 319 Float[].class) 320 .setCarPropertyConfigVerifier( 321 (verifierContext, carPropertyConfig) -> { 322 // HVAC_TEMPERATURE_VALUE_SUGGESTION's access must be read+write. 323 assertThat((Flags.areaIdConfigAccess() 324 ? carPropertyConfig.getAreaIdConfig(0).getAccess() 325 : carPropertyConfig.getAccess())).isEqualTo( 326 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE); 327 }) 328 .setCarPropertyValueVerifier( 329 (verifierContext, carPropertyConfig, propertyId, areaId, timestampNanos, 330 temperatureSuggestion) -> { 331 assertWithMessage( 332 "HVAC_TEMPERATURE_VALUE_SUGGESTION Float[] value" 333 + " must be size 4.") 334 .that(temperatureSuggestion.length) 335 .isEqualTo(4); 336 337 Float requestedTempUnits = temperatureSuggestion[1]; 338 assertWithMessage( 339 "The value at index 1 must be one of" 340 + " {VehicleUnit#CELSIUS, VehicleUnit#FAHRENHEIT}" 341 + " which correspond to values {" 342 + (float) VehicleUnit.CELSIUS 343 + ", " 344 + (float) VehicleUnit.FAHRENHEIT 345 + "}.") 346 .that(requestedTempUnits) 347 .isIn(ImmutableList.of((float) VehicleUnit.CELSIUS, 348 (float) VehicleUnit.FAHRENHEIT)); 349 }) 350 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 351 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 352 } 353 354 /** 355 * Gets the verifier for {@code HVAC_POWER_ON}. 356 */ getHvacPowerOnVerifier( CarPropertyManager carPropertyManager)357 public static VehiclePropertyVerifier<Boolean> getHvacPowerOnVerifier( 358 CarPropertyManager carPropertyManager) { 359 return getHvacPowerOnVerifierBuilder().setCarPropertyManager(carPropertyManager) 360 .build(); 361 } 362 363 /** 364 * Gets the verifier builder for {@code HVAC_POWER_ON}. 365 */ getHvacPowerOnVerifierBuilder()366 public static VehiclePropertyVerifier.Builder<Boolean> getHvacPowerOnVerifierBuilder() { 367 return VehiclePropertyVerifier.newBuilder( 368 VehiclePropertyIds.HVAC_POWER_ON, 369 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 370 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 371 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 372 Boolean.class) 373 .setConfigArrayVerifier( 374 (verifierContext, configArray) -> { 375 CarPropertyConfig<?> hvacPowerOnCarPropertyConfig = 376 verifierContext.getCarPropertyManager().getCarPropertyConfig( 377 VehiclePropertyIds.HVAC_POWER_ON); 378 for (int powerDependentProperty : configArray) { 379 CarPropertyConfig<?> powerDependentCarPropertyConfig = 380 verifierContext.getCarPropertyManager() 381 .getCarPropertyConfig(powerDependentProperty); 382 if (powerDependentCarPropertyConfig == null) { 383 continue; 384 } 385 assertWithMessage( 386 "HVAC_POWER_ON configArray must only contain" 387 + " VehicleAreaSeat type properties: " 388 + VehiclePropertyIds.toString( 389 powerDependentProperty)) 390 .that(powerDependentCarPropertyConfig.getAreaType()) 391 .isEqualTo(VehicleAreaType.VEHICLE_AREA_TYPE_SEAT); 392 393 for (int powerDependentAreaId : 394 powerDependentCarPropertyConfig.getAreaIds()) { 395 boolean powerDependentAreaIdIsContained = false; 396 for (int hvacPowerOnAreaId : 397 hvacPowerOnCarPropertyConfig.getAreaIds()) { 398 if ((powerDependentAreaId & hvacPowerOnAreaId) 399 == powerDependentAreaId) { 400 powerDependentAreaIdIsContained = true; 401 break; 402 } 403 } 404 assertWithMessage( 405 "HVAC_POWER_ON's area IDs must contain the area IDs" 406 + " of power dependent property: " 407 + VehiclePropertyIds.toString( 408 powerDependentProperty)).that( 409 powerDependentAreaIdIsContained).isTrue(); 410 } 411 } 412 }) 413 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 414 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 415 } 416 417 /** 418 * Gets the verifier for {@code HVAC_FAN_SPEED}. 419 */ 420 public static VehiclePropertyVerifier<Integer> getHvacFanSpeedVerifier( 421 CarPropertyManager carPropertyManager) { 422 return getHvacFanSpeedVerifierBuilder().setCarPropertyManager(carPropertyManager).build(); 423 } 424 425 /** 426 * Gets the verifier builder for {@code HVAC_FAN_SPEED}. 427 */ 428 public static VehiclePropertyVerifier.Builder<Integer> getHvacFanSpeedVerifierBuilder() { 429 return VehiclePropertyVerifier.newBuilder( 430 VehiclePropertyIds.HVAC_FAN_SPEED, 431 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 432 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 433 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 434 Integer.class) 435 .requireMinMaxValues() 436 .setPossiblyDependentOnHvacPowerOn() 437 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 438 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 439 } 440 441 /** 442 * Gets the verifier for {@code HVAC_FAN_DIRECTION_AVAILABLE}. 443 */ 444 public static VehiclePropertyVerifier<Integer[]> getHvacFanDirectionAvailableVerifier( 445 CarPropertyManager carPropertyManager) { 446 return getHvacFanDirectionAvailableVerifierBuilder() 447 .setCarPropertyManager(carPropertyManager).build(); 448 } 449 450 /** 451 * Gets the verifier for {@code HVAC_FAN_DIRECTION_AVAILABLE}. 452 */ 453 public static VehiclePropertyVerifier.Builder<Integer[]> 454 getHvacFanDirectionAvailableVerifierBuilder() { 455 return VehiclePropertyVerifier.newBuilder( 456 VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE, 457 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 458 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 459 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC, 460 Integer[].class) 461 .setPossiblyDependentOnHvacPowerOn() 462 .setAreaIdsVerifier( 463 (verifierContext, areaIds) -> { 464 CarPropertyConfig<?> hvacFanDirectionCarPropertyConfig = 465 verifierContext.getCarPropertyManager().getCarPropertyConfig( 466 VehiclePropertyIds.HVAC_FAN_DIRECTION); 467 assertWithMessage( 468 "HVAC_FAN_DIRECTION must be implemented if " 469 + "HVAC_FAN_DIRECTION_AVAILABLE is implemented") 470 .that(hvacFanDirectionCarPropertyConfig) 471 .isNotNull(); 472 473 assertWithMessage( 474 "HVAC_FAN_DIRECTION_AVAILABLE area IDs must match the" 475 + " area IDs of HVAC_FAN_DIRECTION") 476 .that( 477 Arrays.stream(areaIds) 478 .boxed() 479 .collect(Collectors.toList())) 480 .containsExactlyElementsIn( 481 Arrays.stream( 482 hvacFanDirectionCarPropertyConfig 483 .getAreaIds()) 484 .boxed() 485 .collect(Collectors.toList())); 486 }) 487 .setCarPropertyValueVerifier( 488 (verifierContext, carPropertyConfig, propertyId, areaId, timestampNanos, 489 fanDirectionValues) -> { 490 assertWithMessage( 491 "HVAC_FAN_DIRECTION_AVAILABLE area ID: " 492 + areaId 493 + " must have at least 1 fan direction defined") 494 .that(fanDirectionValues.length) 495 .isAtLeast(1); 496 assertWithMessage( 497 "HVAC_FAN_DIRECTION_AVAILABLE area ID: " 498 + areaId 499 + " must have only unique fan direction" 500 + " values: " 501 + Arrays.toString(fanDirectionValues)) 502 .that(fanDirectionValues.length) 503 .isEqualTo(ImmutableSet.copyOf(fanDirectionValues).size()); 504 for (Integer fanDirection : fanDirectionValues) { 505 assertWithMessage( 506 "HVAC_FAN_DIRECTION_AVAILABLE's area ID: " 507 + areaId 508 + " must be a valid combination of fan" 509 + " directions") 510 .that(fanDirection) 511 .isIn(ALL_POSSIBLE_HVAC_FAN_DIRECTIONS); 512 } 513 }) 514 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 515 } 516 517 /** 518 * Gets the verifier for {@code HVAC_FAN_DIRECTION}. 519 */ 520 public static VehiclePropertyVerifier<Integer> getHvacFanDirectionVerifier( 521 CarPropertyManager carPropertyManager) { 522 return getHvacFanDirectionVerifierBuilder().setCarPropertyManager(carPropertyManager) 523 .build(); 524 } 525 526 /** 527 * Gets the verifier builder for {@code HVAC_FAN_DIRECTION}. 528 */ 529 public static VehiclePropertyVerifier.Builder<Integer> getHvacFanDirectionVerifierBuilder() { 530 var builder = VehiclePropertyVerifier.newBuilder( 531 VehiclePropertyIds.HVAC_FAN_DIRECTION, 532 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 533 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 534 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 535 Integer.class) 536 .setPossiblyDependentOnHvacPowerOn() 537 .setAreaIdsVerifier( 538 (verifierContext, areaIds) -> { 539 CarPropertyConfig<?> hvacFanDirectionAvailableConfig = 540 verifierContext.getCarPropertyManager().getCarPropertyConfig( 541 VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE); 542 assertWithMessage( 543 "HVAC_FAN_DIRECTION_AVAILABLE must be implemented if " 544 + "HVAC_FAN_DIRECTION is implemented") 545 .that(hvacFanDirectionAvailableConfig) 546 .isNotNull(); 547 548 assertWithMessage( 549 "HVAC_FAN_DIRECTION area IDs must match the area IDs of" 550 + " HVAC_FAN_DIRECTION_AVAILABLE") 551 .that( 552 Arrays.stream(areaIds) 553 .boxed() 554 .collect(Collectors.toList())) 555 .containsExactlyElementsIn( 556 Arrays.stream( 557 hvacFanDirectionAvailableConfig 558 .getAreaIds()) 559 .boxed() 560 .collect(Collectors.toList())); 561 }) 562 .setCarPropertyValueVerifier( 563 (verifierContext, carPropertyConfig, propertyId, areaId, timestampNanos, 564 hvacFanDirection) -> { 565 CarPropertyValue<Integer[]> hvacFanDirectionAvailableCarPropertyValue = 566 verifierContext.getCarPropertyManager().getProperty( 567 VehiclePropertyIds.HVAC_FAN_DIRECTION_AVAILABLE, 568 areaId); 569 assertWithMessage( 570 "HVAC_FAN_DIRECTION_AVAILABLE value must be available") 571 .that(hvacFanDirectionAvailableCarPropertyValue) 572 .isNotNull(); 573 574 assertWithMessage( 575 "HVAC_FAN_DIRECTION_AVAILABLE area ID: " 576 + areaId 577 + " must include all possible fan direction" 578 + " values") 579 .that(hvacFanDirection) 580 .isIn( 581 Arrays.asList( 582 hvacFanDirectionAvailableCarPropertyValue 583 .getValue())); 584 }) 585 .setAllPossibleUnwritableValues(CAR_HVAC_FAN_DIRECTION_UNWRITABLE_STATES) 586 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 587 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 588 589 if (VehiclePropertyVerifier.isAtLeastU()) { 590 builder.setAllPossibleUnwritableValues(CAR_HVAC_FAN_DIRECTION_UNWRITABLE_STATES); 591 } 592 return builder; 593 } 594 595 /** 596 * Gets the verifier for {@code HVAC_TEMPERATURE_CURRENT}. 597 */ 598 public static VehiclePropertyVerifier<Float> getHvacTemperatureCurrentVerifier( 599 CarPropertyManager carPropertyManager) { 600 return getHvacTemperatureCurrentVerifierBuilder() 601 .setCarPropertyManager(carPropertyManager).build(); 602 } 603 604 /** 605 * Gets the verifier builder for {@code HVAC_TEMPERATURE_CURRENT}. 606 */ 607 public static VehiclePropertyVerifier.Builder<Float> 608 getHvacTemperatureCurrentVerifierBuilder() { 609 return VehiclePropertyVerifier.newBuilder( 610 VehiclePropertyIds.HVAC_TEMPERATURE_CURRENT, 611 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 612 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 613 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 614 Float.class) 615 .setPossiblyDependentOnHvacPowerOn() 616 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 617 } 618 619 /** 620 * Gets the verifier for {@code HVAC_TEMPERATURE_SET}. 621 */ 622 public static VehiclePropertyVerifier<Float> getHvacTemperatureSetVerifier( 623 CarPropertyManager carPropertyManager) { 624 return getHvacTemperatureSetVerifierBuilder().setCarPropertyManager(carPropertyManager) 625 .build(); 626 } 627 628 /** 629 * Gets the verifier builder for {@code HVAC_TEMPERATURE_SET}. 630 */ 631 public static VehiclePropertyVerifier.Builder<Float> getHvacTemperatureSetVerifierBuilder() { 632 return VehiclePropertyVerifier.newBuilder( 633 VehiclePropertyIds.HVAC_TEMPERATURE_SET, 634 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 635 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 636 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 637 Float.class) 638 .setPossiblyDependentOnHvacPowerOn() 639 .requireMinMaxValues() 640 .setCarPropertyConfigVerifier( 641 (verifierContext, carPropertyConfig) -> { 642 List<Integer> configArray = carPropertyConfig.getConfigArray(); 643 if (configArray.isEmpty()) { 644 return; 645 } 646 assertWithMessage("HVAC_TEMPERATURE_SET config array must be size 6") 647 .that(configArray.size()) 648 .isEqualTo(6); 649 650 assertWithMessage( 651 "HVAC_TEMPERATURE_SET lower bound must be less" 652 + " than the upper bound for the supported" 653 + " temperatures in Celsius") 654 .that(configArray.get(0)) 655 .isLessThan(configArray.get(1)); 656 assertWithMessage( 657 "HVAC_TEMPERATURE_SET increment in Celsius" 658 + " must be greater than 0") 659 .that(configArray.get(2)) 660 .isGreaterThan(0); 661 assertWithMessage( 662 "HVAC_TEMPERATURE_SET increment in Celsius must" 663 + " be less than the difference between the" 664 + " upper and lower bound supported" 665 + " temperatures") 666 .that(configArray.get(2)) 667 .isLessThan(configArray.get(1) - configArray.get(0)); 668 assertWithMessage( 669 "HVAC_TEMPERATURE_SET increment in Celsius must" 670 + " evenly space the gap between upper and" 671 + " lower bound") 672 .that( 673 (configArray.get(1) - configArray.get(0)) 674 % configArray.get(2)) 675 .isEqualTo(0); 676 assertWithMessage( 677 "HVAC_TEMPERATURE_SET lower bound must be less" 678 + " than the upper bound for the supported" 679 + " temperatures in Fahrenheit") 680 .that(configArray.get(3)) 681 .isLessThan(configArray.get(4)); 682 assertWithMessage( 683 "HVAC_TEMPERATURE_SET increment in Fahrenheit" 684 + " must be greater than 0") 685 .that(configArray.get(5)) 686 .isGreaterThan(0); 687 assertWithMessage( 688 "HVAC_TEMPERATURE_SET increment in Fahrenheit" 689 + " must be less than the difference" 690 + " between the upper and lower bound" 691 + " supported temperatures") 692 .that(configArray.get(5)) 693 .isLessThan(configArray.get(4) - configArray.get(3)); 694 assertWithMessage( 695 "HVAC_TEMPERATURE_SET increment in Fahrenheit" 696 + " must evenly space the gap between upper" 697 + " and lower bound") 698 .that( 699 (configArray.get(4) - configArray.get(3)) 700 % configArray.get(5)) 701 .isEqualTo(0); 702 assertWithMessage( 703 "HVAC_TEMPERATURE_SET number of supported values for " 704 + "Celsius and Fahrenheit must be equal.").that( 705 (configArray.get(1) - configArray.get(0)) 706 / configArray.get(2)).isEqualTo( 707 (configArray.get(4) - configArray.get(3)) 708 / configArray.get(5)); 709 710 int[] supportedAreaIds = carPropertyConfig.getAreaIds(); 711 int configMinValue = configArray.get(0); 712 int configMaxValue = configArray.get(1); 713 for (int i = 0; i < supportedAreaIds.length; i++) { 714 int areaId = supportedAreaIds[i]; 715 Float minValueFloat = (Float) carPropertyConfig.getMinValue(areaId); 716 Integer minValueInt = (int) (minValueFloat * 10); 717 assertWithMessage( 718 "HVAC_TEMPERATURE_SET minimum value: " + minValueInt 719 + " at areaId: " + areaId + " must be equal to minimum" 720 + " value specified in config" 721 + " array: " + configMinValue) 722 .that(minValueInt) 723 .isEqualTo(configMinValue); 724 725 Float maxValueFloat = (Float) carPropertyConfig.getMaxValue(areaId); 726 Integer maxValueInt = (int) (maxValueFloat * 10); 727 assertWithMessage( 728 "HVAC_TEMPERATURE_SET maximum value: " + maxValueInt 729 + " at areaId: " + areaId + " must be equal to maximum" 730 + " value specified in config" 731 + " array: " + configMaxValue) 732 .that(maxValueInt) 733 .isEqualTo(configMaxValue); 734 } 735 }) 736 .setCarPropertyValueVerifier( 737 (verifierContext, carPropertyConfig, propertyId, areaId, timestampNanos, 738 tempInCelsius) -> { 739 List<Integer> configArray = carPropertyConfig.getConfigArray(); 740 if (configArray.isEmpty()) { 741 return; 742 } 743 Integer minTempInCelsius = configArray.get(0); 744 Integer maxTempInCelsius = configArray.get(1); 745 Integer incrementInCelsius = configArray.get(2); 746 VehiclePropertyVerifier.verifyHvacTemperatureIsValid(tempInCelsius, 747 minTempInCelsius, maxTempInCelsius, incrementInCelsius); 748 }) 749 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 750 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 751 } 752 753 /** 754 * Gets the verifier for {@code HVAC_AC_ON}. 755 */ 756 public static VehiclePropertyVerifier<Boolean> getHvacAcOnVerifier( 757 CarPropertyManager carPropertyManager) { 758 return getHvacAcOnVerifierBuilder().setCarPropertyManager(carPropertyManager).build(); 759 } 760 761 /** 762 * Gets the verifier for {@code HVAC_AC_ON}. 763 */ 764 public static VehiclePropertyVerifier.Builder<Boolean> getHvacAcOnVerifierBuilder() { 765 return VehiclePropertyVerifier.newBuilder( 766 VehiclePropertyIds.HVAC_AC_ON, 767 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 768 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 769 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 770 Boolean.class) 771 .setPossiblyDependentOnHvacPowerOn() 772 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 773 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 774 } 775 776 /** 777 * Gets the verifier for {@code HVAC_ELECTRIC_DEFROSTER_ON}. 778 */ 779 public static VehiclePropertyVerifier<Boolean> getHvacMaxAcOnVerifier( 780 CarPropertyManager carPropertyManager) { 781 return getHvacMaxAcOnVerifierBuilder().setCarPropertyManager(carPropertyManager).build(); 782 } 783 784 /** 785 * Gets the verifier builder for {@code HVAC_ELECTRIC_DEFROSTER_ON}. 786 */ 787 public static VehiclePropertyVerifier.Builder<Boolean> getHvacMaxAcOnVerifierBuilder() { 788 return VehiclePropertyVerifier.newBuilder( 789 VehiclePropertyIds.HVAC_MAX_AC_ON, 790 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 791 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 792 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 793 Boolean.class) 794 .setPossiblyDependentOnHvacPowerOn() 795 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 796 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 797 } 798 799 /** 800 * Gets the verifier for {@code HVAC_MAX_DEFROST_ON}. 801 */ 802 public static VehiclePropertyVerifier<Boolean> getHvacMaxDefrostOnVerifier( 803 CarPropertyManager carPropertyManager) { 804 return getHvacMaxDefrostOnVerifierBuilder().setCarPropertyManager(carPropertyManager) 805 .build(); 806 } 807 808 /** 809 * Gets the verifier builder for {@code HVAC_MAX_DEFROST_ON}. 810 */ 811 public static VehiclePropertyVerifier.Builder<Boolean> getHvacMaxDefrostOnVerifierBuilder() { 812 return VehiclePropertyVerifier.newBuilder( 813 VehiclePropertyIds.HVAC_MAX_DEFROST_ON, 814 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 815 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 816 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 817 Boolean.class) 818 .setPossiblyDependentOnHvacPowerOn() 819 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 820 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 821 } 822 823 /** 824 * Gets the verifier for {@code HVAC_RECIRC_ON}. 825 */ 826 public static VehiclePropertyVerifier<Boolean> getHvacRecircOnVerifier( 827 CarPropertyManager carPropertyManager) { 828 return getHvacRecircOnVerifierBuilder().setCarPropertyManager(carPropertyManager) 829 .build(); 830 } 831 832 /** 833 * Gets the verifier builder for {@code HVAC_RECIRC_ON}. 834 */ 835 public static VehiclePropertyVerifier.Builder<Boolean> getHvacRecircOnVerifierBuilder() { 836 return VehiclePropertyVerifier.newBuilder( 837 VehiclePropertyIds.HVAC_RECIRC_ON, 838 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 839 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 840 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 841 Boolean.class) 842 .setPossiblyDependentOnHvacPowerOn() 843 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 844 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 845 } 846 847 /** 848 * Gets the verifier for {@code HVAC_AUTO_ON}. 849 */ 850 public static VehiclePropertyVerifier<Boolean> getHvacAutoOnVerifier( 851 CarPropertyManager carPropertyManager) { 852 return getHvacAutoOnVerifierBuilder().setCarPropertyManager(carPropertyManager).build(); 853 } 854 855 /** 856 * Gets the verifier builder for {@code HVAC_AUTO_ON}. 857 */ 858 public static VehiclePropertyVerifier.Builder<Boolean> getHvacAutoOnVerifierBuilder() { 859 return VehiclePropertyVerifier.newBuilder( 860 VehiclePropertyIds.HVAC_AUTO_ON, 861 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 862 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 863 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 864 Boolean.class) 865 .setPossiblyDependentOnHvacPowerOn() 866 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 867 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 868 } 869 870 /** 871 * Gets the verifier for {@code HVAC_SEAT_TEMPERATURE}. 872 */ 873 public static VehiclePropertyVerifier<Integer> getHvacSeatTemperatureVerifier( 874 CarPropertyManager carPropertyManager) { 875 return getHvacSeatTemperatureVerifierBuilder().setCarPropertyManager(carPropertyManager) 876 .build(); 877 } 878 879 /** 880 * Gets the verifier builder for {@code HVAC_SEAT_TEMPERATURE}. 881 */ 882 public static VehiclePropertyVerifier.Builder<Integer> 883 getHvacSeatTemperatureVerifierBuilder() { 884 return VehiclePropertyVerifier.newBuilder( 885 VehiclePropertyIds.HVAC_SEAT_TEMPERATURE, 886 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 887 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 888 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 889 Integer.class) 890 .setPossiblyDependentOnHvacPowerOn() 891 .requireMinMaxValues() 892 .requireZeroToBeContainedInMinMaxRanges() 893 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 894 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 895 } 896 897 /** 898 * Gets the verifier for {@code HVAC_ACTUAL_FAN_SPEED_RPM}. 899 */ 900 public static VehiclePropertyVerifier<Integer> getHvacActualFanSpeedRpmVerifier( 901 CarPropertyManager carPropertyManager) { 902 return getHvacActualFanSpeedRpmVerifierBuilder().setCarPropertyManager(carPropertyManager) 903 .build(); 904 } 905 906 /** 907 * Gets the verifier builder for {@code HVAC_ACTUAL_FAN_SPEED_RPM}. 908 */ 909 public static VehiclePropertyVerifier.Builder<Integer> 910 getHvacActualFanSpeedRpmVerifierBuilder() { 911 return VehiclePropertyVerifier.newBuilder( 912 VehiclePropertyIds.HVAC_ACTUAL_FAN_SPEED_RPM, 913 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 914 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 915 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 916 Integer.class) 917 .setPossiblyDependentOnHvacPowerOn() 918 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 919 } 920 921 /** 922 * Gets the verifier for {@code HVAC_AUTO_RECIRC_ON}. 923 */ 924 public static VehiclePropertyVerifier<Boolean> getHvacAutoRecircOnVerifier( 925 CarPropertyManager carPropertyManager) { 926 return getHvacAutoRecircOnVerifierBuilder().setCarPropertyManager(carPropertyManager) 927 .build(); 928 } 929 930 /** 931 * Gets the verifier builder for {@code HVAC_AUTO_RECIRC_ON}. 932 */ 933 public static VehiclePropertyVerifier.Builder<Boolean> getHvacAutoRecircOnVerifierBuilder() { 934 return VehiclePropertyVerifier.newBuilder( 935 VehiclePropertyIds.HVAC_AUTO_RECIRC_ON, 936 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 937 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 938 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 939 Boolean.class) 940 .setPossiblyDependentOnHvacPowerOn() 941 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 942 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 943 } 944 945 /** 946 * Gets the verifier for {@code HVAC_SEAT_VENTILATION}. 947 */ 948 public static VehiclePropertyVerifier<Integer> getHvacSeatVentilationVerifier( 949 CarPropertyManager carPropertyManager) { 950 return getHvacSeatVentilationVerifierBuilder().setCarPropertyManager(carPropertyManager) 951 .build(); 952 } 953 954 /** 955 * Gets the verifier builder for {@code HVAC_SEAT_VENTILATION}. 956 */ 957 public static VehiclePropertyVerifier.Builder<Integer> 958 getHvacSeatVentilationVerifierBuilder() { 959 return VehiclePropertyVerifier.newBuilder( 960 VehiclePropertyIds.HVAC_SEAT_VENTILATION, 961 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 962 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 963 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 964 Integer.class) 965 .setPossiblyDependentOnHvacPowerOn() 966 .requireMinMaxValues() 967 .requireMinValuesToBeZero() 968 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 969 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 970 } 971 972 /** 973 * Gets the verifier for {@code HVAC_DUAL_ON}. 974 */ 975 public static VehiclePropertyVerifier<Boolean> getHvacDualOnVerifier( 976 CarPropertyManager carPropertyManager) { 977 return getHvacDualOnVerifierBuilder().setCarPropertyManager(carPropertyManager).build(); 978 } 979 980 /** 981 * Gets the verifier builder for {@code HVAC_DUAL_ON}. 982 */ 983 public static VehiclePropertyVerifier.Builder<Boolean> getHvacDualOnVerifierBuilder() { 984 return VehiclePropertyVerifier.newBuilder( 985 VehiclePropertyIds.HVAC_DUAL_ON, 986 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 987 VehicleAreaType.VEHICLE_AREA_TYPE_SEAT, 988 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 989 Boolean.class) 990 .setPossiblyDependentOnHvacPowerOn() 991 .setAreaIdsVerifier( 992 (verifierContext, areaIds) -> { 993 CarPropertyConfig<?> hvacTempSetCarPropertyConfig = 994 verifierContext.getCarPropertyManager().getCarPropertyConfig( 995 VehiclePropertyIds.HVAC_TEMPERATURE_SET); 996 if (hvacTempSetCarPropertyConfig == null) { 997 return; 998 } 999 ImmutableSet<Integer> hvacTempSetAreaIds = 1000 ImmutableSet.copyOf( 1001 Arrays.stream(hvacTempSetCarPropertyConfig.getAreaIds()) 1002 .boxed() 1003 .collect(Collectors.toList())); 1004 ImmutableSet.Builder<Integer> allPossibleHvacDualOnAreaIdsBuilder = 1005 ImmutableSet.builder(); 1006 for (int i = 2; i <= hvacTempSetAreaIds.size(); i++) { 1007 allPossibleHvacDualOnAreaIdsBuilder.addAll( 1008 Sets.combinations(hvacTempSetAreaIds, i).stream() 1009 .map( 1010 areaIdCombo -> { 1011 Integer possibleHvacDualOnAreaId = 0; 1012 for (Integer areaId : areaIdCombo) { 1013 possibleHvacDualOnAreaId |= areaId; 1014 } 1015 return possibleHvacDualOnAreaId; 1016 }) 1017 .collect(Collectors.toList())); 1018 } 1019 ImmutableSet<Integer> allPossibleHvacDualOnAreaIds = 1020 allPossibleHvacDualOnAreaIdsBuilder.build(); 1021 for (int areaId : areaIds) { 1022 assertWithMessage( 1023 "HVAC_DUAL_ON area ID: " 1024 + areaId 1025 + " must be a combination of" 1026 + " HVAC_TEMPERATURE_SET area IDs: " 1027 + Arrays.toString( 1028 hvacTempSetCarPropertyConfig 1029 .getAreaIds())) 1030 .that(areaId) 1031 .isIn(allPossibleHvacDualOnAreaIds); 1032 } 1033 }) 1034 .addReadPermission(Car.PERMISSION_CONTROL_CAR_CLIMATE) 1035 .addWritePermission(Car.PERMISSION_CONTROL_CAR_CLIMATE); 1036 } 1037 1038 private static VehiclePropertyVerifier.Builder<Integer> 1039 getLocationCharacterizationVerifierBuilder( 1040 CarPropertyManager carPropertyManager, 1041 int locPropertyId, String readPermission) { 1042 return VehiclePropertyVerifier.newBuilder( 1043 locPropertyId, 1044 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1045 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1046 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC, 1047 Integer.class) 1048 .setCarPropertyValueVerifier( 1049 (verifierContext, carPropertyConfig, propertyId, areaId, timestampNanos, 1050 value) -> { 1051 boolean deadReckonedIsSet = (value 1052 & LocationCharacterization.DEAD_RECKONED) 1053 == LocationCharacterization.DEAD_RECKONED; 1054 boolean rawGnssOnlyIsSet = (value 1055 & LocationCharacterization.RAW_GNSS_ONLY) 1056 == LocationCharacterization.RAW_GNSS_ONLY; 1057 assertWithMessage("LOCATION_CHARACTERIZATION must not be 0 " 1058 + "Found value: " + value) 1059 .that(value) 1060 .isNotEqualTo(0); 1061 assertWithMessage("LOCATION_CHARACTERIZATION must not have any bits " 1062 + "set outside of the bit flags defined in " 1063 + "LocationCharacterization. Found value: " + value) 1064 .that(value & LOCATION_CHARACTERIZATION_VALID_VALUES_MASK) 1065 .isEqualTo(value); 1066 assertWithMessage("LOCATION_CHARACTERIZATION must have one of " 1067 + "DEAD_RECKONED or RAW_GNSS_ONLY set. They both cannot be set " 1068 + "either. Found value: " + value) 1069 .that(deadReckonedIsSet ^ rawGnssOnlyIsSet) 1070 .isTrue(); 1071 }) 1072 .setCarPropertyManager(carPropertyManager) 1073 .addReadPermission(readPermission); 1074 } 1075 1076 private static ImmutableSet<Integer> generateAllPossibleHvacFanDirections() { 1077 ImmutableSet.Builder<Integer> allPossibleFanDirectionsBuilder = ImmutableSet.builder(); 1078 for (int i = 1; i <= SINGLE_HVAC_FAN_DIRECTIONS.size(); i++) { 1079 allPossibleFanDirectionsBuilder.addAll(Sets.combinations(SINGLE_HVAC_FAN_DIRECTIONS, 1080 i).stream().map(hvacFanDirectionCombo -> { 1081 Integer possibleHvacFanDirection = 0; 1082 for (Integer hvacFanDirection : hvacFanDirectionCombo) { 1083 possibleHvacFanDirection |= hvacFanDirection; 1084 } 1085 return possibleHvacFanDirection; 1086 }).collect(Collectors.toList())); 1087 } 1088 return allPossibleFanDirectionsBuilder.build(); 1089 } 1090 1091 1092 /** 1093 * Gets the verifier for {@link VehiclePropertyIds#INFO_MODEL_TRIM}. 1094 */ 1095 public static VehiclePropertyVerifier.Builder<String> getInfoModelTrimVerifierBuilder() { 1096 return VehiclePropertyVerifier.newBuilder( 1097 VehiclePropertyIds.INFO_MODEL_TRIM, 1098 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1099 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1100 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC, 1101 String.class) 1102 .addReadPermission(Car.PERMISSION_CAR_INFO); 1103 } 1104 1105 public static VehiclePropertyVerifier.Builder<Integer[]> 1106 getInfoVehicleSizeClassVerifierBuilder() { 1107 return VehiclePropertyVerifier.newBuilder( 1108 VehiclePropertyIds.INFO_VEHICLE_SIZE_CLASS, 1109 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1110 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1111 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_STATIC, 1112 Integer[].class) 1113 .setCarPropertyValueVerifier( 1114 (verifierContext, carPropertyConfig, propertyId, areaId, timestampNanos, 1115 sizeClasses) -> { 1116 ArraySet<Integer> presentStandards = new ArraySet<>(); 1117 for (int sizeClass : sizeClasses) { 1118 assertWithMessage("Size class " + sizeClass + " doesn't exist in " 1119 + "possible values: " + VEHICLE_SIZE_CLASSES) 1120 .that(VEHICLE_SIZE_CLASSES.contains(sizeClass)).isTrue(); 1121 int standard = sizeClass & 0xf00; 1122 assertWithMessage("Multiple values from the standard of size class " 1123 + sizeClass + " are in use.") 1124 .that(presentStandards.contains(standard)).isFalse(); 1125 presentStandards.add(standard); 1126 } 1127 }) 1128 .addReadPermission(Car.PERMISSION_CAR_INFO); 1129 } 1130 1131 /** 1132 * Gets the verifier for {@link VehiclePropertyIds#TURN_SIGNAL_LIGHT_STATE}. 1133 */ 1134 public static VehiclePropertyVerifier.Builder<Integer> 1135 getTurnSignalLightStateVerifierBuilder() { 1136 ImmutableSet<Integer> combinedCarPropertyValues = ImmutableSet.<Integer>builder() 1137 .addAll(TURN_SIGNAL_STATES) 1138 .add(VehicleTurnSignal.STATE_LEFT | VehicleTurnSignal.STATE_RIGHT) 1139 .build(); 1140 1141 return VehiclePropertyVerifier.newBuilder( 1142 VehiclePropertyIds.TURN_SIGNAL_LIGHT_STATE, 1143 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1144 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1145 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 1146 Integer.class) 1147 .setAllPossibleEnumValues(combinedCarPropertyValues) 1148 .addReadPermission(Car.PERMISSION_READ_EXTERIOR_LIGHTS) 1149 .addReadPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS); 1150 } 1151 1152 /** 1153 * Gets the verifier for {@link VehiclePropertyIds#TURN_SIGNAL_SWITCH}. 1154 */ 1155 public static VehiclePropertyVerifier.Builder<Integer> getTurnSignalSwitchVerifierBuilder() { 1156 return VehiclePropertyVerifier.newBuilder( 1157 VehiclePropertyIds.TURN_SIGNAL_SWITCH, 1158 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 1159 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1160 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 1161 Integer.class) 1162 .setAllPossibleEnumValues(TURN_SIGNAL_STATES) 1163 .addReadPermission(Car.PERMISSION_READ_EXTERIOR_LIGHTS) 1164 .addReadPermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS) 1165 .addWritePermission(Car.PERMISSION_CONTROL_EXTERIOR_LIGHTS); 1166 } 1167 1168 public static VehiclePropertyVerifier.Builder<Float> 1169 getInstantaneousFuelEconomyVerifierBuilder() { 1170 return VehiclePropertyVerifier.newBuilder( 1171 VehiclePropertyIds.INSTANTANEOUS_FUEL_ECONOMY, 1172 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1173 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1174 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, 1175 Float.class) 1176 .addReadPermission(Car.PERMISSION_MILEAGE_3P); 1177 } 1178 1179 public static VehiclePropertyVerifier.Builder<Float> 1180 getInstantaneousEvEfficiencyVerifierBuilder() { 1181 return VehiclePropertyVerifier.newBuilder( 1182 VehiclePropertyIds.INSTANTANEOUS_EV_EFFICIENCY, 1183 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1184 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1185 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, 1186 Float.class) 1187 .addReadPermission(Car.PERMISSION_MILEAGE_3P); 1188 } 1189 1190 public static VehiclePropertyVerifier.Builder<Boolean> getVehicleHornEngagedVerifierBuilder() { 1191 return VehiclePropertyVerifier.newBuilder( 1192 VehiclePropertyIds.VEHICLE_HORN_ENGAGED, 1193 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ_WRITE, 1194 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1195 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 1196 Boolean.class) 1197 .addReadPermission(Car.PERMISSION_READ_CAR_HORN) 1198 .addReadPermission(Car.PERMISSION_CONTROL_CAR_HORN) 1199 .addWritePermission(Car.PERMISSION_CONTROL_CAR_HORN); 1200 } 1201 1202 public static VehiclePropertyVerifier.Builder<Integer> 1203 getVehicleDrivingAutomationTargetLevelVerifierBuilder() { 1204 return VehiclePropertyVerifier.newBuilder( 1205 VehiclePropertyIds.VEHICLE_DRIVING_AUTOMATION_TARGET_LEVEL, 1206 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1207 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1208 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 1209 Integer.class) 1210 .setAllPossibleEnumValues(VEHICLE_AUTONOMOUS_STATES) 1211 .addReadPermission(Car.PERMISSION_CAR_DRIVING_STATE); 1212 } 1213 1214 public static VehiclePropertyVerifier.Builder<Float> 1215 getAcceleratorPedalCompressionPercentageVerifierBuilder() { 1216 return VehiclePropertyVerifier.newBuilder( 1217 VehiclePropertyIds.ACCELERATOR_PEDAL_COMPRESSION_PERCENTAGE, 1218 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1219 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1220 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, 1221 Float.class) 1222 .addReadPermission(Car.PERMISSION_READ_CAR_PEDALS); 1223 } 1224 1225 public static VehiclePropertyVerifier.Builder<Float> 1226 getBrakePedalCompressionPercentageVerifierBuilder() { 1227 return VehiclePropertyVerifier.newBuilder( 1228 VehiclePropertyIds.BRAKE_PEDAL_COMPRESSION_PERCENTAGE, 1229 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1230 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1231 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, 1232 Float.class) 1233 .addReadPermission(Car.PERMISSION_READ_CAR_PEDALS); 1234 } 1235 1236 public static VehiclePropertyVerifier.Builder<Float> 1237 getBrakePadWearPercentageVerifierBuilder() { 1238 return VehiclePropertyVerifier.newBuilder( 1239 VehiclePropertyIds.BRAKE_PAD_WEAR_PERCENTAGE, 1240 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1241 VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL, 1242 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 1243 Float.class) 1244 .addReadPermission(Car.PERMISSION_READ_BRAKE_INFO); 1245 } 1246 1247 public static VehiclePropertyVerifier.Builder<Boolean> 1248 getBrakeFluidLevelLowVerifierBuilder() { 1249 return VehiclePropertyVerifier.newBuilder( 1250 VehiclePropertyIds.BRAKE_FLUID_LEVEL_LOW, 1251 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1252 VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL, 1253 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 1254 Boolean.class) 1255 .addReadPermission(Car.PERMISSION_READ_BRAKE_INFO); 1256 } 1257 1258 public static VehiclePropertyVerifier.Builder<Integer> 1259 getVehiclePassiveSuspensionHeightVerifierBuilder() { 1260 return VehiclePropertyVerifier.newBuilder( 1261 VehiclePropertyIds.VEHICLE_PASSIVE_SUSPENSION_HEIGHT, 1262 CarPropertyConfig.VEHICLE_PROPERTY_ACCESS_READ, 1263 VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL, 1264 CarPropertyConfig.VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, 1265 Integer.class) 1266 .requireMinMaxValues() 1267 .requireZeroToBeContainedInMinMaxRanges() 1268 .addReadPermission(Car.PERMISSION_CAR_DYNAMICS_STATE); 1269 } 1270 } 1271