1 /* 2 * Copyright (C) 2016 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.hardware; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.car.VehicleAreaType; 24 import android.car.VehicleAreaType.VehicleAreaTypeValue; 25 import android.car.VehiclePropertyType; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.util.SparseArray; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.lang.reflect.Array; 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 37 /** 38 * Represents general information about car property such as data type and min/max ranges for car 39 * areas (if applicable). This class supposed to be immutable, parcelable and could be passed over. 40 * 41 * <p>Use {@link CarPropertyConfig#newBuilder} to create an instance of this class. 42 * 43 * @param <T> refer to Parcel#writeValue(Object) to get a list of all supported types. The class 44 * should be visible to framework as default class loader is being used here. 45 * 46 */ 47 public final class CarPropertyConfig<T> implements Parcelable { 48 private final int mAccess; 49 private final int mAreaType; 50 private final int mChangeMode; 51 private final ArrayList<Integer> mConfigArray; 52 private final String mConfigString; 53 private final float mMaxSampleRate; 54 private final float mMinSampleRate; 55 private final int mPropertyId; 56 private final SparseArray<AreaConfig<T>> mSupportedAreas; 57 private final Class<T> mType; 58 CarPropertyConfig(int access, int areaType, int changeMode, ArrayList<Integer> configArray, String configString, float maxSampleRate, float minSampleRate, int propertyId, SparseArray<AreaConfig<T>> supportedAreas, Class<T> type)59 private CarPropertyConfig(int access, int areaType, int changeMode, 60 ArrayList<Integer> configArray, String configString, 61 float maxSampleRate, float minSampleRate, int propertyId, 62 SparseArray<AreaConfig<T>> supportedAreas, Class<T> type) { 63 mAccess = access; 64 mAreaType = areaType; 65 mChangeMode = changeMode; 66 mConfigArray = configArray; 67 mConfigString = configString; 68 mMaxSampleRate = maxSampleRate; 69 mMinSampleRate = minSampleRate; 70 mPropertyId = propertyId; 71 mSupportedAreas = supportedAreas; 72 mType = type; 73 } 74 75 /** @hide */ 76 @IntDef(prefix = {"VEHICLE_PROPERTY_ACCESS"}, value = { 77 VEHICLE_PROPERTY_ACCESS_NONE, 78 VEHICLE_PROPERTY_ACCESS_READ, 79 VEHICLE_PROPERTY_ACCESS_WRITE, 80 VEHICLE_PROPERTY_ACCESS_READ_WRITE 81 }) 82 @Retention(RetentionPolicy.SOURCE) 83 public @interface VehiclePropertyAccessType {} 84 85 /** Property Access Unknown */ 86 public static final int VEHICLE_PROPERTY_ACCESS_NONE = 0; 87 /** The property is readable */ 88 public static final int VEHICLE_PROPERTY_ACCESS_READ = 1; 89 /** The property is writable */ 90 public static final int VEHICLE_PROPERTY_ACCESS_WRITE = 2; 91 /** The property is readable and writable */ 92 public static final int VEHICLE_PROPERTY_ACCESS_READ_WRITE = 3; 93 94 /** @hide */ 95 @IntDef(prefix = {"VEHICLE_PROPERTY_CHANGE_MODE"}, value = { 96 VEHICLE_PROPERTY_CHANGE_MODE_STATIC, 97 VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, 98 VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, 99 }) 100 @Retention(RetentionPolicy.SOURCE) 101 public @interface VehiclePropertyChangeModeType {} 102 103 /** Properties of this type must never be changed. */ 104 public static final int VEHICLE_PROPERTY_CHANGE_MODE_STATIC = 0; 105 /** Properties of this type must report when there is a change. */ 106 public static final int VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE = 1; 107 /** Properties of this type change continuously. */ 108 public static final int VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS = 2; 109 110 /** 111 * Return the access type of the car property. 112 * <p>The access type could be one of the following: 113 * <ul> 114 * <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_NONE}</li> 115 * <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}</li> 116 * <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_WRITE}</li> 117 * <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}</li> 118 * </ul> 119 * 120 * @return the access type of the car property. 121 */ getAccess()122 public @VehiclePropertyAccessType int getAccess() { 123 return mAccess; 124 } 125 126 /** 127 * Return the area type of the car property. 128 * <p>The area type could be one of the following: 129 * <ul> 130 * <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}</li> 131 * <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_WINDOW}</li> 132 * <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}</li> 133 * <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_DOOR}</li> 134 * <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_MIRROR}</li> 135 * <li>{@link VehicleAreaType#VEHICLE_AREA_TYPE_WHEEL}</li> 136 * </ul> 137 * 138 * @return the area type of the car property. 139 */ getAreaType()140 public @VehicleAreaTypeValue int getAreaType() { 141 return mAreaType; 142 } 143 144 /** 145 * Return the change mode of the car property. 146 * 147 * <p>The change mode could be one of the following: 148 * <ul> 149 * <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC }</li> 150 * <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}</li> 151 * <li>{@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS}</li> 152 * </ul> 153 * 154 * @return the change mode of properties. 155 */ getChangeMode()156 public @VehiclePropertyChangeModeType int getChangeMode() { 157 return mChangeMode; 158 } 159 160 /** 161 * 162 * @return Additional configuration parameters. For different properties, configArrays have 163 * different information. 164 */ 165 @NonNull getConfigArray()166 public List<Integer> getConfigArray() { 167 return Collections.unmodifiableList(mConfigArray); 168 } 169 170 /** 171 * 172 * @return Some properties may require additional information passed over this 173 * string. Most properties do not need to set this. 174 * @hide 175 */ getConfigString()176 public String getConfigString() { 177 return mConfigString; 178 } 179 180 /** 181 * 182 * @return Max sample rate in Hz. Must be defined for VehiclePropertyChangeMode::CONTINUOUS 183 * return 0 if change mode is not continuous. 184 */ getMaxSampleRate()185 public float getMaxSampleRate() { 186 return mMaxSampleRate; 187 } 188 189 /** 190 * 191 * @return Min sample rate in Hz.Must be defined for VehiclePropertyChangeMode::CONTINUOUS 192 * return 0 if change mode is not continuous. 193 */ getMinSampleRate()194 public float getMinSampleRate() { 195 return mMinSampleRate; 196 } 197 198 /** 199 * @return Property identifier 200 */ getPropertyId()201 public int getPropertyId() { 202 return mPropertyId; 203 } 204 205 /** 206 * Returns the value type of the vehicle property. 207 * <p>The value type could be one of the following: 208 * <ul> 209 * <li>Boolean</li> 210 * <li>Float</li> 211 * <li>Float[]</li> 212 * <li>Integer</li> 213 * <li>Integer[]</li> 214 * <li>Long</li> 215 * <li>Long[]</li> 216 * <li>String</li> 217 * <li>byte[]</li> 218 * <li>Object[]</li> 219 * </ul> 220 * 221 * @return the value type of the vehicle property. 222 */ 223 @NonNull getPropertyType()224 public Class<T> getPropertyType() { 225 return mType; 226 } 227 228 /** 229 * 230 * @return true if this property doesn't hold car area-specific configuration. 231 */ isGlobalProperty()232 public boolean isGlobalProperty() { 233 return mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL; 234 } 235 236 /** 237 * 238 * @return the number of areaIds for properties. 239 * @hide 240 */ getAreaCount()241 public int getAreaCount() { 242 return mSupportedAreas.size(); 243 } 244 245 /** 246 * 247 * @return Array of areaIds. An AreaID is a combination of one or more areas, 248 * and is represented using a bitmask of Area enums. Different AreaTypes may 249 * not be mixed in a single AreaID. For instance, a window area cannot be 250 * combined with a seat area in an AreaID. 251 * Rules for mapping a zoned property to AreaIDs: 252 * - A property must be mapped to an array of AreaIDs that are impacted when 253 * the property value changes. 254 * - Each element in the array must represent an AreaID, in which, the 255 * property value can only be changed together in all the areas within 256 * an AreaID and never independently. That is, when the property value 257 * changes in one of the areas in an AreaID in the array, then it must 258 * automatically change in all other areas in the AreaID. 259 * - The property value must be independently controllable in any two 260 * different AreaIDs in the array. 261 * - An area must only appear once in the array of AreaIDs. That is, an 262 * area must only be part of a single AreaID in the array. 263 */ 264 @NonNull getAreaIds()265 public int[] getAreaIds() { 266 int[] areaIds = new int[mSupportedAreas.size()]; 267 for (int i = 0; i < areaIds.length; i++) { 268 areaIds[i] = mSupportedAreas.keyAt(i); 269 } 270 return areaIds; 271 } 272 273 /** 274 * @return the first areaId. 275 * Throws {@link IllegalStateException} if supported area count not equals to one. 276 * @hide 277 */ getFirstAndOnlyAreaId()278 public int getFirstAndOnlyAreaId() { 279 if (mSupportedAreas.size() != 1) { 280 throw new IllegalStateException("Expected one and only area in this property. Prop: 0x" 281 + Integer.toHexString(mPropertyId)); 282 } 283 return mSupportedAreas.keyAt(0); 284 } 285 286 /** 287 * 288 * @param areaId 289 * @return true if areaId is existing. 290 * @hide 291 */ hasArea(int areaId)292 public boolean hasArea(int areaId) { 293 return mSupportedAreas.indexOfKey(areaId) >= 0; 294 } 295 296 /** 297 * 298 * @param areaId 299 * @return Min value in given areaId. Null if not have min value in given area. 300 */ 301 @Nullable getMinValue(int areaId)302 public T getMinValue(int areaId) { 303 AreaConfig<T> area = mSupportedAreas.get(areaId); 304 return area == null ? null : area.getMinValue(); 305 } 306 307 /** 308 * 309 * @param areaId 310 * @return Max value in given areaId. Null if not have max value in given area. 311 */ 312 @Nullable getMaxValue(int areaId)313 public T getMaxValue(int areaId) { 314 AreaConfig<T> area = mSupportedAreas.get(areaId); 315 return area == null ? null : area.getMaxValue(); 316 } 317 318 /** 319 * 320 * @return Min value in areaId 0. Null if not have min value. 321 */ 322 @Nullable getMinValue()323 public T getMinValue() { 324 AreaConfig<T> area = mSupportedAreas.get(0); 325 return area == null ? null : area.getMinValue(); 326 } 327 328 /** 329 * 330 * @return Max value in areaId 0. Null if not have max value. 331 */ 332 @Nullable getMaxValue()333 public T getMaxValue() { 334 AreaConfig<T> area = mSupportedAreas.get(0); 335 return area == null ? null : area.getMaxValue(); 336 } 337 338 @Override describeContents()339 public int describeContents() { 340 return 0; 341 } 342 343 344 @Override writeToParcel(Parcel dest, int flags)345 public void writeToParcel(Parcel dest, int flags) { 346 dest.writeInt(mAccess); 347 dest.writeInt(mAreaType); 348 dest.writeInt(mChangeMode); 349 dest.writeInt(mConfigArray.size()); 350 for (int i = 0; i < mConfigArray.size(); i++) { 351 dest.writeInt(mConfigArray.get(i)); 352 } 353 dest.writeString(mConfigString); 354 dest.writeFloat(mMaxSampleRate); 355 dest.writeFloat(mMinSampleRate); 356 dest.writeInt(mPropertyId); 357 dest.writeInt(mSupportedAreas.size()); 358 for (int i = 0; i < mSupportedAreas.size(); i++) { 359 dest.writeInt(mSupportedAreas.keyAt(i)); 360 dest.writeParcelable(mSupportedAreas.valueAt(i), flags); 361 } 362 dest.writeString(mType.getName()); 363 } 364 365 @SuppressWarnings("unchecked") CarPropertyConfig(Parcel in)366 private CarPropertyConfig(Parcel in) { 367 mAccess = in.readInt(); 368 mAreaType = in.readInt(); 369 mChangeMode = in.readInt(); 370 int configArraySize = in.readInt(); 371 mConfigArray = new ArrayList<Integer>(configArraySize); 372 for (int i = 0; i < configArraySize; i++) { 373 mConfigArray.add(in.readInt()); 374 } 375 mConfigString = in.readString(); 376 mMaxSampleRate = in.readFloat(); 377 mMinSampleRate = in.readFloat(); 378 mPropertyId = in.readInt(); 379 int areaSize = in.readInt(); 380 mSupportedAreas = new SparseArray<>(areaSize); 381 for (int i = 0; i < areaSize; i++) { 382 int areaId = in.readInt(); 383 AreaConfig<T> area = in.readParcelable(getClass().getClassLoader()); 384 mSupportedAreas.put(areaId, area); 385 } 386 String className = in.readString(); 387 try { 388 mType = (Class<T>) Class.forName(className); 389 } catch (ClassNotFoundException e) { 390 throw new IllegalArgumentException("Class not found: " + className); 391 } 392 } 393 394 public static final Creator<CarPropertyConfig> CREATOR = new Creator<CarPropertyConfig>() { 395 @Override 396 public CarPropertyConfig createFromParcel(Parcel in) { 397 return new CarPropertyConfig(in); 398 } 399 400 @Override 401 public CarPropertyConfig[] newArray(int size) { 402 return new CarPropertyConfig[size]; 403 } 404 }; 405 406 /** @hide */ 407 @Override toString()408 public String toString() { 409 return "CarPropertyConfig{" 410 + "mPropertyId=" + mPropertyId 411 + ", mAccess=" + mAccess 412 + ", mAreaType=" + mAreaType 413 + ", mChangeMode=" + mChangeMode 414 + ", mConfigArray=" + mConfigArray 415 + ", mConfigString=" + mConfigString 416 + ", mMaxSampleRate=" + mMaxSampleRate 417 + ", mMinSampleRate=" + mMinSampleRate 418 + ", mSupportedAreas=" + mSupportedAreas 419 + ", mType=" + mType 420 + '}'; 421 } 422 423 /** 424 * Represents min/max value of car property. 425 * @param <T> 426 * @hide 427 */ 428 public static class AreaConfig<T> implements Parcelable { 429 @Nullable private final T mMinValue; 430 @Nullable private final T mMaxValue; 431 AreaConfig(T minValue, T maxValue)432 private AreaConfig(T minValue, T maxValue) { 433 mMinValue = minValue; 434 mMaxValue = maxValue; 435 } 436 437 public static final Parcelable.Creator<AreaConfig<Object>> CREATOR = 438 getCreator(Object.class); 439 getCreator(final Class<E> clazz)440 private static <E> Parcelable.Creator<AreaConfig<E>> getCreator(final Class<E> clazz) { 441 return new Creator<AreaConfig<E>>() { 442 @Override 443 public AreaConfig<E> createFromParcel(Parcel source) { 444 return new AreaConfig<>(source); 445 } 446 447 @Override @SuppressWarnings("unchecked") 448 public AreaConfig<E>[] newArray(int size) { 449 return (AreaConfig<E>[]) Array.newInstance(clazz, size); 450 } 451 }; 452 } 453 454 @SuppressWarnings("unchecked") AreaConfig(Parcel in)455 private AreaConfig(Parcel in) { 456 mMinValue = (T) in.readValue(getClass().getClassLoader()); 457 mMaxValue = (T) in.readValue(getClass().getClassLoader()); 458 } 459 getMinValue()460 @Nullable public T getMinValue() { 461 return mMinValue; 462 } 463 getMaxValue()464 @Nullable public T getMaxValue() { 465 return mMaxValue; 466 } 467 468 @Override describeContents()469 public int describeContents() { 470 return 0; 471 } 472 473 @Override writeToParcel(Parcel dest, int flags)474 public void writeToParcel(Parcel dest, int flags) { 475 dest.writeValue(mMinValue); 476 dest.writeValue(mMaxValue); 477 } 478 479 @Override toString()480 public String toString() { 481 return "CarAreaConfig{" 482 + "mMinValue=" + mMinValue 483 + ", mMaxValue=" + mMaxValue 484 + '}'; 485 } 486 } 487 488 /** 489 * Prepare an instance of CarPropertyConfig 490 * 491 * @return Builder<T> 492 * @hide 493 */ 494 @SystemApi 495 public static <T> Builder<T> newBuilder(Class<T> type, int propertyId, int areaType, 496 int areaCapacity) { 497 return new Builder<>(areaCapacity, areaType, propertyId, type); 498 } 499 500 501 /** 502 * Prepare an instance of CarPropertyConfig 503 * 504 * @return Builder<T> 505 * @hide 506 */ 507 public static <T> Builder<T> newBuilder(Class<T> type, int propertyId, int areaType) { 508 return new Builder<>(0, areaType, propertyId, type); 509 } 510 511 512 /** 513 * @param <T> 514 * @hide 515 * */ 516 @SystemApi 517 public static class Builder<T> { 518 private int mAccess; 519 private final int mAreaType; 520 private int mChangeMode; 521 private final ArrayList<Integer> mConfigArray; 522 private String mConfigString; 523 private float mMaxSampleRate; 524 private float mMinSampleRate; 525 private final int mPropertyId; 526 private final SparseArray<AreaConfig<T>> mSupportedAreas; 527 private final Class<T> mType; 528 529 private Builder(int areaCapacity, int areaType, int propertyId, Class<T> type) { 530 mAreaType = areaType; 531 mConfigArray = new ArrayList<>(); 532 mPropertyId = propertyId; 533 if (areaCapacity != 0) { 534 mSupportedAreas = new SparseArray<>(areaCapacity); 535 } else { 536 mSupportedAreas = new SparseArray<>(); 537 } 538 mType = type; 539 } 540 541 /** 542 * Add supported areas parameter to CarPropertyConfig 543 * 544 * @return Builder<T> 545 */ 546 public Builder<T> addAreas(int[] areaIds) { 547 for (int id : areaIds) { 548 mSupportedAreas.put(id, null); 549 } 550 return this; 551 } 552 553 /** 554 * Add area to CarPropertyConfig 555 * 556 * @return Builder<T> 557 */ 558 public Builder<T> addArea(int areaId) { 559 return addAreaConfig(areaId, null, null); 560 } 561 562 /** 563 * Add areaConfig to CarPropertyConfig 564 * 565 * @return Builder<T> 566 */ 567 public Builder<T> addAreaConfig(int areaId, T min, T max) { 568 if (!isRangeAvailable(min, max)) { 569 mSupportedAreas.put(areaId, null); 570 } else { 571 mSupportedAreas.put(areaId, new AreaConfig<>(min, max)); 572 } 573 return this; 574 } 575 576 /** 577 * Set access parameter to CarPropertyConfig 578 * 579 * @return Builder<T> 580 */ 581 public Builder<T> setAccess(int access) { 582 mAccess = access; 583 return this; 584 } 585 586 /** 587 * Set changeMode parameter to CarPropertyConfig 588 * 589 * @return Builder<T> 590 */ 591 public Builder<T> setChangeMode(int changeMode) { 592 mChangeMode = changeMode; 593 return this; 594 } 595 596 /** 597 * Set configArray parameter to CarPropertyConfig 598 * 599 * @return Builder<T> 600 */ 601 public Builder<T> setConfigArray(ArrayList<Integer> configArray) { 602 mConfigArray.clear(); 603 mConfigArray.addAll(configArray); 604 return this; 605 } 606 607 /** 608 * Set configString parameter to CarPropertyConfig 609 * 610 * @return Builder<T> 611 */ 612 public Builder<T> setConfigString(String configString) { 613 mConfigString = configString; 614 return this; 615 } 616 617 /** 618 * Set maxSampleRate parameter to CarPropertyConfig 619 * 620 * @return Builder<T> 621 */ 622 public Builder<T> setMaxSampleRate(float maxSampleRate) { 623 mMaxSampleRate = maxSampleRate; 624 return this; 625 } 626 627 /** 628 * Set minSampleRate parameter to CarPropertyConfig 629 * 630 * @return Builder<T> 631 */ 632 public Builder<T> setMinSampleRate(float minSampleRate) { 633 mMinSampleRate = minSampleRate; 634 return this; 635 } 636 637 /** 638 * Builds a new {@link CarPropertyConfig}. 639 */ 640 public CarPropertyConfig<T> build() { 641 return new CarPropertyConfig<>(mAccess, mAreaType, mChangeMode, mConfigArray, 642 mConfigString, mMaxSampleRate, mMinSampleRate, 643 mPropertyId, mSupportedAreas, mType); 644 } 645 646 private boolean isRangeAvailable(T min, T max) { 647 if (min == null || max == null) { 648 return false; 649 } 650 int propertyType = mPropertyId & VehiclePropertyType.MASK; 651 switch (propertyType) { 652 case VehiclePropertyType.INT32: 653 return (Integer) min != 0 || (Integer) max != 0; 654 case VehiclePropertyType.INT64: 655 return (Long) min != 0L || (Long) max != 0L; 656 case VehiclePropertyType.FLOAT: 657 return (Float) min != 0f || (Float) max != 0f; 658 default: 659 return false; 660 } 661 } 662 } 663 } 664