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