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