• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static java.lang.Integer.toHexString;
22 
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.car.VehiclePropertyIds;
26 import android.car.annotation.AddedInOrBefore;
27 import android.car.builtin.os.ParcelHelper;
28 import android.os.Parcel;
29 import android.os.Parcelable;
30 
31 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 import java.nio.charset.Charset;
36 import java.nio.charset.StandardCharsets;
37 import java.util.Objects;
38 
39 /**
40  * Stores a value for a vehicle property ID and area ID combination.
41  *
42  * Client should use {@code android.car.*} types when dealing with property ID, area ID or property
43  * value and MUST NOT use {@code android.hardware.automotive.vehicle.*} types directly.
44  *
45  * @param <T> refer to {@link Parcel#writeValue(java.lang.Object)} to get a list of all supported
46  *            types. The class should be visible to framework as default class loader is being used
47  *            here.
48  */
49 public final class CarPropertyValue<T> implements Parcelable {
50     private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
51 
52     private final int mPropertyId;
53     private final int mAreaId;
54     private final int mStatus;
55     private final long mTimestampNanos;
56     private final T mValue;
57 
58     @IntDef({
59         STATUS_AVAILABLE,
60         STATUS_UNAVAILABLE,
61         STATUS_ERROR
62     })
63     @Retention(RetentionPolicy.SOURCE)
64     public @interface PropertyStatus {}
65 
66     /**
67      * {@code CarPropertyValue} is available.
68      */
69     @AddedInOrBefore(majorVersion = 33)
70     public static final int STATUS_AVAILABLE = 0;
71 
72     /**
73      * {@code CarPropertyValue} is unavailable.
74      */
75     @AddedInOrBefore(majorVersion = 33)
76     public static final int STATUS_UNAVAILABLE = 1;
77 
78     /**
79      * {@code CarPropertyValue} has an error.
80      */
81     @AddedInOrBefore(majorVersion = 33)
82     public static final int STATUS_ERROR = 2;
83 
84     /**
85      * Creates an instance of {@code CarPropertyValue}.
86      *
87      * @param propertyId Property ID, must be one of enums in
88      *   {@link android.car.VehiclePropertyIds}.
89      * @param areaId Area ID of Property, must be one of enums in one of the following classes:
90      *   <ul>
91      *     <li><{@code VehicleAreaWindow}</li>
92      *     <li><{@code VehicleAreaDoor}</li>
93      *     <li><{@link android.car.VehicleAreaSeat}</li>
94      *     <li><{@code VehicleAreaMirror}</li>
95      *     <li><{@link android.car.VehicleAreaWheel}</li>
96      *   </ul>
97      *   or 0 for global property.
98      * @param value Value of Property
99      * @hide
100      */
CarPropertyValue(int propertyId, int areaId, T value)101     public CarPropertyValue(int propertyId, int areaId, T value) {
102         this(propertyId, areaId, /* timestampNanos= */ 0, value);
103     }
104 
105     /**
106      * Creates an instance of {@code CarPropertyValue}. The {@code timestampNanos} is the time in
107      * nanoseconds at which the event happened. For a given car property, each new {@code
108      * CarPropertyValue} should be monotonically increasing using the same time base as
109      * {@link SystemClock#elapsedRealtimeNanos()}.
110      *
111      * @param propertyId Property ID, must be one of enums in
112      *   {@link android.car.VehiclePropertyIds}.
113      * @param areaId     Area ID of Property, must be one of enums in one of the following classes:
114      *   <ul>
115      *     <li><{@code VehicleAreaWindow}</li>
116      *     <li><{@code VehicleAreaDoor}</li>
117      *     <li><{@link android.car.VehicleAreaSeat}</li>
118      *     <li><{@code VehicleAreaMirror}</li>
119      *     <li><{@link android.car.VehicleAreaWheel}</li>
120      *   </ul>
121      *   or 0 for global property.
122      * @param timestampNanos  Elapsed time in nanoseconds since boot
123      * @param value      Value of Property
124      * @hide
125      */
CarPropertyValue(int propertyId, int areaId, long timestampNanos, T value)126     public CarPropertyValue(int propertyId, int areaId, long timestampNanos, T value) {
127         this(propertyId, areaId, CarPropertyValue.STATUS_AVAILABLE, timestampNanos, value);
128     }
129 
130     /**
131      * @hide
132      *
133      * @deprecated use {@link CarPropertyValue#CarPropertyValue(int, int, long, T)} instead
134      */
135     @Deprecated
CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, T value)136     public CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, T value) {
137         mPropertyId = propertyId;
138         mAreaId = areaId;
139         mStatus = status;
140         mTimestampNanos = timestampNanos;
141         mValue = value;
142     }
143 
144     /**
145      * Creates an instance of {@code CarPropertyValue}.
146      *
147      * @param in Parcel to read
148      * @hide
149      */
150     @SuppressWarnings("unchecked")
CarPropertyValue(Parcel in)151     public CarPropertyValue(Parcel in) {
152         mPropertyId = in.readInt();
153         mAreaId = in.readInt();
154         mStatus = in.readInt();
155         mTimestampNanos = in.readLong();
156         String valueClassName = in.readString();
157         Class<?> valueClass;
158         try {
159             valueClass = Class.forName(valueClassName);
160         } catch (ClassNotFoundException e) {
161             throw new IllegalArgumentException("Class not found: " + valueClassName, e);
162         }
163 
164         if (String.class.equals(valueClass)) {
165             byte[] bytes = ParcelHelper.readBlob(in);
166             mValue = (T) new String(bytes, DEFAULT_CHARSET);
167         } else if (byte[].class.equals(valueClass)) {
168             mValue = (T) ParcelHelper.readBlob(in);
169         } else {
170             mValue = (T) in.readValue(valueClass.getClassLoader());
171         }
172     }
173 
174     @AddedInOrBefore(majorVersion = 33)
175     public static final Creator<CarPropertyValue> CREATOR = new Creator<CarPropertyValue>() {
176         @Override
177         public CarPropertyValue createFromParcel(Parcel in) {
178             return new CarPropertyValue(in);
179         }
180 
181         @Override
182         public CarPropertyValue[] newArray(int size) {
183             return new CarPropertyValue[size];
184         }
185     };
186 
187     @Override
188     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
189     @AddedInOrBefore(majorVersion = 33)
describeContents()190     public int describeContents() {
191         return 0;
192     }
193 
194     @Override
195     @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)196     public void writeToParcel(Parcel dest, int flags) {
197         dest.writeInt(mPropertyId);
198         dest.writeInt(mAreaId);
199         dest.writeInt(mStatus);
200         dest.writeLong(mTimestampNanos);
201 
202         Class<?> valueClass = mValue == null ? null : mValue.getClass();
203         dest.writeString(valueClass == null ? null : valueClass.getName());
204 
205         // Special handling for String and byte[] to mitigate transaction buffer limitations.
206         if (String.class.equals(valueClass)) {
207             ParcelHelper.writeBlob(dest, ((String) mValue).getBytes(DEFAULT_CHARSET));
208         } else if (byte[].class.equals(valueClass)) {
209             ParcelHelper.writeBlob(dest, (byte[]) mValue);
210         } else {
211             dest.writeValue(mValue);
212         }
213     }
214 
215     /**
216      * @return Property id of {@code CarPropertyValue}, must be one of enums in
217      *   {@link android.car.VehiclePropertyIds}.
218      */
219     @AddedInOrBefore(majorVersion = 33)
getPropertyId()220     public int getPropertyId() {
221         return mPropertyId;
222     }
223 
224     /**
225      * @return Area id of {@code CarPropertyValue}, must be one of enums in one of the following
226      * classes:
227      *   <ul>
228      *     <li><{@code VehicleAreaWindow}</li>
229      *     <li><{@code VehicleAreaDoor}</li>
230      *     <li><{@link android.car.VehicleAreaSeat}</li>
231      *     <li><{@code VehicleAreaMirror}</li>
232      *     <li><{@link android.car.VehicleAreaWheel}</li>
233      *   </ul>
234      *   or 0 for global property.
235      */
236     @AddedInOrBefore(majorVersion = 33)
getAreaId()237     public int getAreaId() {
238         return mAreaId;
239     }
240 
241     /**
242      * @return Status of {@code CarPropertyValue}
243      *
244      * @deprecated This should be added back in next major Android release.
245      */
246     @AddedInOrBefore(majorVersion = 33)
getStatus()247     public @PropertyStatus int getStatus() {
248         return mStatus;
249     }
250 
251     /**
252      * Returns the timestamp in nanoseconds at which the {@code CarPropertyValue} happened. For a
253      * given car property, each new {@code CarPropertyValue} should be monotonically increasing
254      * using the same time base as {@link android.os.SystemClock#elapsedRealtimeNanos()}.
255      *
256      * <p>NOTE: Timestamp should be synchronized with other signals from the platform (e.g.
257      * {@link android.location.Location} and {@link android.hardware.SensorEvent} instances).
258      * Ideally, timestamp synchronization error should be below 1 millisecond.
259      */
260     @AddedInOrBefore(majorVersion = 33)
getTimestamp()261     public long getTimestamp() {
262         return mTimestampNanos;
263     }
264 
265     /**
266      * Returns the value for {@code CarPropertyValue}.
267      *
268      * <p>
269      * <b>Note:</b>Caller must check the value of {@link #getStatus()}. Only use
270      * {@link #getValue()} when {@link #getStatus()} is {@link #STATUS_AVAILABLE}. If not,
271      * {@link #getValue()} is meaningless.
272      */
273     @NonNull
274     @AddedInOrBefore(majorVersion = 33)
getValue()275     public T getValue() {
276         return mValue;
277     }
278 
279     /** @hide */
280     @Override
toString()281     public String toString() {
282         return "CarPropertyValue{"
283                 + "mPropertyId=0x" + toHexString(mPropertyId)
284                 + ", propertyName=" + VehiclePropertyIds.toString(mPropertyId)
285                 + ", mAreaId=0x" + toHexString(mAreaId)
286                 + ", mStatus=" + mStatus
287                 + ", mTimestampNanos=" + mTimestampNanos
288                 + ", mValue=" + mValue
289                 + '}';
290     }
291 
292     /** Generates hash code for this instance. */
293     @Override
hashCode()294     public int hashCode() {
295         return Objects.hash(mPropertyId, mAreaId, mStatus, mTimestampNanos, mValue);
296     }
297 
298     /** Checks equality with passed {@code object}. */
299     @Override
equals(Object object)300     public boolean equals(Object object) {
301         if (this == object) {
302             return true;
303         }
304         if (!(object instanceof CarPropertyValue<?>)) {
305             return false;
306         }
307         CarPropertyValue<?> carPropertyValue = (CarPropertyValue<?>) object;
308         return mPropertyId == carPropertyValue.mPropertyId && mAreaId == carPropertyValue.mAreaId
309                 && mStatus == carPropertyValue.mStatus
310                 && mTimestampNanos == carPropertyValue.mTimestampNanos
311                 && Objects.equals(mValue, carPropertyValue.mValue);
312     }
313 }
314