/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.car.hardware; import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.car.VehicleAreaType; import android.car.VehicleAreaType.VehicleAreaTypeValue; import android.car.VehiclePropertyIds; import android.car.feature.Flags; import android.car.hardware.property.AreaIdConfig; import android.os.Parcel; import android.os.Parcelable; import android.util.SparseArray; import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Represents general information about car property such as data type and min/max ranges for car * areas (if applicable). This class supposed to be immutable, parcelable and could be passed over. * * @param refer to {@link Parcel#writeValue(java.lang.Object)} to get a list of all supported * types. The class should be visible to framework as default class loader is being used here. * */ public final class CarPropertyConfig implements Parcelable { private static final String TAG = CarPropertyConfig.class.getSimpleName(); private final int mAccess; private final int mAreaType; private final int mChangeMode; private final ArrayList mConfigArray; private final String mConfigString; private final float mMaxSampleRate; private final float mMinSampleRate; private final int mPropertyId; private final List> mAreaIdConfigs; private final SparseArray> mAreaIdToAreaIdConfig; private final Class mType; private CarPropertyConfig(int access, int areaType, int changeMode, ArrayList configArray, String configString, float maxSampleRate, float minSampleRate, int propertyId, List> areaIdConfigs, Class type) { mAccess = access; mAreaType = areaType; mChangeMode = changeMode; mConfigArray = configArray; mConfigString = configString; mMaxSampleRate = maxSampleRate; mMinSampleRate = minSampleRate; mPropertyId = propertyId; mAreaIdConfigs = areaIdConfigs; mAreaIdToAreaIdConfig = generateAreaIdToAreaIdConfig(areaIdConfigs); mType = type; } /** @hide */ @IntDef(prefix = {"VEHICLE_PROPERTY_ACCESS"}, value = { VEHICLE_PROPERTY_ACCESS_NONE, VEHICLE_PROPERTY_ACCESS_READ, VEHICLE_PROPERTY_ACCESS_WRITE, VEHICLE_PROPERTY_ACCESS_READ_WRITE }) @Retention(RetentionPolicy.SOURCE) public @interface VehiclePropertyAccessType {} /** Property Access Unknown */ public static final int VEHICLE_PROPERTY_ACCESS_NONE = 0; /** The property is readable */ public static final int VEHICLE_PROPERTY_ACCESS_READ = 1; /** The property is writable */ public static final int VEHICLE_PROPERTY_ACCESS_WRITE = 2; /** The property is readable and writable */ public static final int VEHICLE_PROPERTY_ACCESS_READ_WRITE = 3; /** @hide */ @IntDef(prefix = {"VEHICLE_PROPERTY_CHANGE_MODE"}, value = { VEHICLE_PROPERTY_CHANGE_MODE_STATIC, VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE, VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS, }) @Retention(RetentionPolicy.SOURCE) public @interface VehiclePropertyChangeModeType {} /** Properties of this type must never be changed. */ public static final int VEHICLE_PROPERTY_CHANGE_MODE_STATIC = 0; /** Properties of this type must report when there is a change. */ public static final int VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE = 1; /** Properties of this type change continuously. */ public static final int VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS = 2; /** * Returns the access type of the car property. *

The access type could be one of the following: *

    *
  • {@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_NONE}
  • *
  • {@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ}
  • *
  • {@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_WRITE}
  • *
  • {@link CarPropertyConfig#VEHICLE_PROPERTY_ACCESS_READ_WRITE}
  • *
* * @return the access type of the car property. */ public @VehiclePropertyAccessType int getAccess() { return mAccess; } /** * Returns the area type of the car property. *

The area type could be one of the following: *

    *
  • {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}
  • *
  • {@link VehicleAreaType#VEHICLE_AREA_TYPE_WINDOW}
  • *
  • {@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}
  • *
  • {@link VehicleAreaType#VEHICLE_AREA_TYPE_DOOR}
  • *
  • {@link VehicleAreaType#VEHICLE_AREA_TYPE_MIRROR}
  • *
  • {@link VehicleAreaType#VEHICLE_AREA_TYPE_WHEEL}
  • *
  • {@link VehicleAreaType#VEHICLE_AREA_TYPE_VENDOR}
  • *
* * @return the area type of the car property. */ public @VehicleAreaTypeValue int getAreaType() { return mAreaType; } /** * Returns the change mode of the car property. * *

The change mode could be one of the following: *

    *
  • {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_STATIC }
  • *
  • {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_ONCHANGE}
  • *
  • {@link CarPropertyConfig#VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS}
  • *
* * @return the change mode of properties. */ public @VehiclePropertyChangeModeType int getChangeMode() { return mChangeMode; } /** * Returns the optional additional configuration parameters. * * @return Additional configuration parameters. For different properties, configArrays have * different information. */ @NonNull public List getConfigArray() { return Collections.unmodifiableList(mConfigArray); } /** * Returns the optional additional configuration information. * * @return Some properties may require additional information passed over this * string. Most properties do not need to set this. * @hide */ public String getConfigString() { return mConfigString; } /** * Returns the max sample rate in Hz. * * @return Max sample rate in Hz. Must be defined for {@link * #VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS} return 0 if change mode is not continuous. */ public float getMaxSampleRate() { return mMaxSampleRate; } /** * Returns the min sample rate in Hz. * * @return Min sample rate in Hz. Must be defined for {@link * #VEHICLE_PROPERTY_CHANGE_MODE_CONTINUOUS} return 0 if change mode is not continuous. */ public float getMinSampleRate() { return mMinSampleRate; } /** * Returns the property identifier. * * @return Property identifier, must be one of enums in * {@link android.car.VehiclePropertyIds}. */ public int getPropertyId() { return mPropertyId; } /** * Returns the value type of the vehicle property. *

The value type could be one of the following: *

    *
  • Boolean
  • *
  • Float
  • *
  • Float[]
  • *
  • Integer
  • *
  • Integer[]
  • *
  • Long
  • *
  • Long[]
  • *
  • String
  • *
  • byte[]
  • *
  • Object[]
  • *
* * @return the value type of the vehicle property. */ @NonNull public Class getPropertyType() { return mType; } /** * Returns a list of {@link AreaIdConfig} for this property. * * @return list of {@link AreaIdConfig} instances for this property. */ @NonNull public List> getAreaIdConfigs() { return Collections.unmodifiableList(mAreaIdConfigs); } /** * Returns the {@link AreaIdConfig} for the specified {@code areaId}. * * @return {@link AreaIdConfig} instance for passed {@code areaId} * @throws IllegalArgumentException if {@code areaId} is not supported for property */ @NonNull public AreaIdConfig getAreaIdConfig(int areaId) { if (!mAreaIdToAreaIdConfig.contains(areaId)) { throw new IllegalArgumentException("Area ID: " + Integer.toHexString(areaId) + " is not supported for property ID: " + VehiclePropertyIds.toString( mPropertyId)); } return mAreaIdToAreaIdConfig.get(areaId); } /** * Returns whether this property is area type {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}. * * @return true if this property is area type {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}. */ public boolean isGlobalProperty() { return mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL; } /** * Returns the number of areaIds for the property. * * @return the number of areaIds for the property. * @hide */ public int getAreaCount() { return mAreaIdConfigs.size(); } /** * Returns a list of area IDs supported for the vehicle property. * *

An area represents a unique element of a {@link VehicleAreaType}. For instance, if the * {@link VehicleAreaType} is {@link VehicleAreaType#VEHICLE_AREA_TYPE_SEAT}, then an example * area is {@link android.car.VehicleAreaSeat#SEAT_ROW_1_LEFT}. * *

An area ID is a combination of one or more areas, and is created by bitwise "OR"ing the * areas together. Areas from different {@link VehicleAreaType} values will not be mixed in a * single area ID. For example, a {@link android.car.VehicleAreaWheel} area cannot be combined * with a {@link android.car.VehicleAreaSeat} area in an area ID. * *

For properties that return {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL} for {@link * #getAreaType()}, they only support a single area ID of {@code 0}. * *

Rules for mapping a non {@link VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL} property to area * IDs: *

    *
  • A property is mapped to a set of area IDs that are impacted when the property value * changes. *
  • An area cannot be part of multiple area IDs, it will only be part of a single area ID. *
  • When the property value changes in one of the areas in an area ID, then it will * automatically change in all other areas in the area ID. *
  • The property value will be independently controllable in any two different area IDs. *
* * @return the array of supported area IDs. */ @NonNull public int[] getAreaIds() { int[] areaIds = new int[mAreaIdConfigs.size()]; for (int i = 0; i < areaIds.length; i++) { areaIds[i] = mAreaIdConfigs.get(i).getAreaId(); } return areaIds; } /** * @return the first areaId. * Throws {@link java.lang.IllegalStateException} if supported area count not equals to one. * @hide */ public int getFirstAndOnlyAreaId() { if (mAreaIdConfigs.size() != 1) { throw new IllegalStateException("Expected one and only area in this property. PropId: " + VehiclePropertyIds.toString(mPropertyId)); } return mAreaIdConfigs.get(0).getAreaId(); } /** * Verify if the areaId passed as a parameter exists. * @hide */ public boolean hasArea(int areaId) { return mAreaIdToAreaIdConfig.indexOfKey(areaId) >= 0; } /** * @deprecated - use {@link #getAreaIdConfigs()} or {@link #getAreaIdConfig(int)} instead. * * @param areaId the area ID * @return min value in given areaId. Null if not have min value in given area */ @Deprecated @Nullable public T getMinValue(int areaId) { AreaIdConfig areaIdConfig = mAreaIdToAreaIdConfig.get(areaId); return areaIdConfig == null ? null : areaIdConfig.getMinValue(); } /** * @deprecated - use {@link #getAreaIdConfigs()} or {@link #getAreaIdConfig(int)} instead. * * @param areaId the area ID * @return max value in given areaId. Null if not have max value in given area */ @Deprecated @Nullable public T getMaxValue(int areaId) { AreaIdConfig areaIdConfig = mAreaIdToAreaIdConfig.get(areaId); return areaIdConfig == null ? null : areaIdConfig.getMaxValue(); } /** * @deprecated - use {@link #getAreaIdConfigs()} or {@link #getAreaIdConfig(int)} instead. * * @return Min value in areaId 0. Null if not have min value. */ @Deprecated @Nullable public T getMinValue() { AreaIdConfig areaIdConfig = mAreaIdToAreaIdConfig.get(0); return areaIdConfig == null ? null : areaIdConfig.getMinValue(); } /** * @deprecated - use {@link #getAreaIdConfigs()} or {@link #getAreaIdConfig(int)} instead. * * @return Max value in areaId 0. Null if not have max value. */ @Deprecated @Nullable public T getMaxValue() { AreaIdConfig areaIdConfig = mAreaIdToAreaIdConfig.get(0); return areaIdConfig == null ? null : areaIdConfig.getMaxValue(); } @Override @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mAccess); dest.writeInt(mAreaType); dest.writeInt(mChangeMode); dest.writeInt(mConfigArray.size()); for (int i = 0; i < mConfigArray.size(); i++) { dest.writeInt(mConfigArray.get(i)); } dest.writeString(mConfigString); dest.writeFloat(mMaxSampleRate); dest.writeFloat(mMinSampleRate); dest.writeInt(mPropertyId); dest.writeList(mAreaIdConfigs); dest.writeString(mType.getName()); } @SuppressWarnings("unchecked") private CarPropertyConfig(Parcel in) { mAccess = in.readInt(); mAreaType = in.readInt(); mChangeMode = in.readInt(); int configArraySize = in.readInt(); mConfigArray = new ArrayList(configArraySize); for (int i = 0; i < configArraySize; i++) { mConfigArray.add(in.readInt()); } mConfigString = in.readString(); mMaxSampleRate = in.readFloat(); mMinSampleRate = in.readFloat(); mPropertyId = in.readInt(); mAreaIdConfigs = in.readArrayList(getClass().getClassLoader()); mAreaIdToAreaIdConfig = generateAreaIdToAreaIdConfig(mAreaIdConfigs); String className = in.readString(); try { mType = (Class) Class.forName(className); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Class not found: " + className, e); } } public static final Creator CREATOR = new Creator() { @Override public CarPropertyConfig createFromParcel(Parcel in) { return new CarPropertyConfig(in); } @Override public CarPropertyConfig[] newArray(int size) { return new CarPropertyConfig[size]; } }; /** @hide */ @Override public String toString() { return "CarPropertyConfig{" + "mPropertyId=" + VehiclePropertyIds.toString(mPropertyId) + ", mAccess=" + mAccess + ", mAreaType=" + mAreaType + ", mChangeMode=" + mChangeMode + ", mConfigArray=" + mConfigArray + ", mConfigString=" + mConfigString + ", mMaxSampleRate=" + mMaxSampleRate + ", mMinSampleRate=" + mMinSampleRate + ", mAreaIdConfigs =" + mAreaIdConfigs + ", mType=" + mType + '}'; } /** * Represents min/max value of car property. * * @param The property type * @hide * @deprecated This API is deprecated in favor of {@link * android.car.hardware.property.AreaIdConfig} which allows properties to specify which enum * values are supported. This API will be marked as {@code @removed} in the next major release * and hard removed in the release after that. */ @Deprecated public static class AreaConfig implements Parcelable { @Nullable private final T mMinValue; @Nullable private final T mMaxValue; @SuppressWarnings("unused") private AreaConfig(T minValue, T maxValue) { mMinValue = minValue; mMaxValue = maxValue; } public static final Parcelable.Creator> CREATOR = getCreator(Object.class); private static Parcelable.Creator> getCreator(final Class clazz) { return new Creator>() { @Override public AreaConfig createFromParcel(Parcel source) { return new AreaConfig<>(source); } @Override @SuppressWarnings("unchecked") public AreaConfig[] newArray(int size) { return (AreaConfig[]) Array.newInstance(clazz, size); } }; } @SuppressWarnings("unchecked") private AreaConfig(Parcel in) { mMinValue = (T) in.readValue(getClass().getClassLoader()); mMaxValue = (T) in.readValue(getClass().getClassLoader()); } @Nullable public T getMinValue() { return mMinValue; } @Nullable public T getMaxValue() { return mMaxValue; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeValue(mMinValue); dest.writeValue(mMaxValue); } @Override public String toString() { return "CarAreaConfig{" + "mMinValue=" + mMinValue + ", mMaxValue=" + mMaxValue + '}'; } } /** * Prepare an instance of {@link CarPropertyConfig} * * @return Builder * @hide * @deprecated marked as deprecated because clients should not have direct access to the * CarPropertyConfig.Builder class */ @Deprecated @SystemApi public static Builder newBuilder(Class type, int propertyId, int areaType, int areaCapacity) { return new Builder<>(areaType, propertyId, type); } /** * Prepare an instance of {@link CarPropertyConfig} * * @return Builder * @hide */ public static Builder newBuilder(Class type, int propertyId, int areaType) { return new Builder<>(areaType, propertyId, type); } /** * Builder for making new {@code CarPropertyConfig} objects. * * @param * @hide * @deprecated marked as deprecated because clients should not have direct access to the * CarPropertyConfig.Builder class */ @Deprecated @SystemApi public static class Builder { private int mAccess = VEHICLE_PROPERTY_ACCESS_NONE; private final int mAreaType; private int mChangeMode; private final ArrayList mConfigArray = new ArrayList<>(); private String mConfigString; private float mMaxSampleRate; private float mMinSampleRate; private final int mPropertyId; private final List> mAreaIdConfigs = new ArrayList<>(); private final Class mType; private Builder(int areaType, int propertyId, Class type) { mAreaType = areaType; mPropertyId = propertyId; mType = type; } /** * Add supported areas parameter to {@link CarPropertyConfig} * *

This function uses the access set in the builder to define the area ID's access level. * Make sure to call {@link CarPropertyConfig.Builder#setAccess(int)} before calling this * function. * * @return Builder * @removed - use {@link #addAreaIdConfig(AreaIdConfig)} instead. */ @Deprecated public Builder addAreas(int[] areaIds) { for (int areaId : areaIds) { AreaIdConfig.Builder areaIdConfigBuilder = Flags.areaIdConfigAccess() ? new AreaIdConfig.Builder(mAccess, areaId) : new AreaIdConfig.Builder(areaId); mAreaIdConfigs.add(areaIdConfigBuilder.build()); } return this; } /** * Add {@code areaId} to {@link CarPropertyConfig} * *

This function uses the access set in the builder to define the area's access level. * Make sure to call {@link CarPropertyConfig.Builder#setAccess(int)} before calling this * function. * * @return Builder * @removed - use {@link #addAreaIdConfig(AreaIdConfig)} instead. */ @Deprecated public Builder addArea(int areaId) { AreaIdConfig.Builder areaIdConfigBuilder = Flags.areaIdConfigAccess() ? new AreaIdConfig.Builder(mAccess, areaId) : new AreaIdConfig.Builder(areaId); mAreaIdConfigs.add(areaIdConfigBuilder.build()); return this; } /** * Add {@code areaConfig} to {@link CarPropertyConfig} * *

This function uses the access set in the builder to define the area's access level. * Make sure to call {@link CarPropertyConfig.Builder#setAccess(int)} before calling this * function. * * @return Builder * @removed - use {@link #addAreaIdConfig(AreaIdConfig)} instead. */ @Deprecated public Builder addAreaConfig(int areaId, T min, T max) { AreaIdConfig.Builder areaIdConfigBuilder = Flags.areaIdConfigAccess() ? new AreaIdConfig.Builder(mAccess, areaId) : new AreaIdConfig.Builder(areaId); mAreaIdConfigs.add(areaIdConfigBuilder.setMinValue(min).setMaxValue(max).build()); return this; } /** * Add {@link AreaIdConfig} to {@link CarPropertyConfig}. * * @return Builder */ @NonNull public Builder addAreaIdConfig(@NonNull AreaIdConfig areaIdConfig) { mAreaIdConfigs.add(areaIdConfig); return this; } /** * Set {@code access} parameter to {@link CarPropertyConfig} * * @return Builder */ public Builder setAccess(int access) { mAccess = access; return this; } /** * Set {@code changeMode} parameter to {@link CarPropertyConfig} * * @return Builder */ public Builder setChangeMode(int changeMode) { mChangeMode = changeMode; return this; } /** * Set {@code configArray} parameter to {@link CarPropertyConfig} * * @return Builder */ public Builder setConfigArray(ArrayList configArray) { mConfigArray.clear(); mConfigArray.addAll(configArray); return this; } /** * Set {@code configString} parameter to {@link CarPropertyConfig} * * @return Builder */ public Builder setConfigString(String configString) { mConfigString = configString; return this; } /** * Set {@code maxSampleRate} parameter to {@link CarPropertyConfig} * * @return Builder */ public Builder setMaxSampleRate(float maxSampleRate) { mMaxSampleRate = maxSampleRate; return this; } /** * Set {@code minSampleRate} parameter to {@link CarPropertyConfig} * * @return Builder */ public Builder setMinSampleRate(float minSampleRate) { mMinSampleRate = minSampleRate; return this; } /** * Builds a new {@link CarPropertyConfig}. */ public CarPropertyConfig build() { return new CarPropertyConfig<>(mAccess, mAreaType, mChangeMode, mConfigArray, mConfigString, mMaxSampleRate, mMinSampleRate, mPropertyId, mAreaIdConfigs, mType); } } private static SparseArray> generateAreaIdToAreaIdConfig( List> areaIdConfigs) { SparseArray> areaIdToAreaIdConfig = new SparseArray<>(areaIdConfigs.size()); for (int i = 0; i < areaIdConfigs.size(); i++) { AreaIdConfig areaIdConfig = areaIdConfigs.get(i); areaIdToAreaIdConfig.put(areaIdConfig.getAreaId(), areaIdConfig); } return areaIdToAreaIdConfig; } }