• 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 java.lang.Integer.toHexString;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.nio.charset.Charset;
29 import java.nio.charset.StandardCharsets;
30 
31 /**
32  * Stores values broken down by area for a vehicle property.
33  *
34  * <p>This class is a java representation of {@code struct VehiclePropValue} defined in
35  * {@code hardware/interfaces/automotive/vehicle/2.0/types.hal}. See
36  * {@link com.android.car.hal.CarPropertyUtils} to learn conversion details.
37  *
38  * @param <T> refer to Parcel#writeValue(Object) to get a list of all supported types. The class
39  *            should be visible to framework as default class loader is being used here.
40  */
41 public final class CarPropertyValue<T> implements Parcelable {
42     private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
43 
44     private final int mPropertyId;
45     private final int mAreaId;
46     private final int mStatus;
47     private final long mTimestamp;
48     private final T mValue;
49 
50     @IntDef({
51         STATUS_AVAILABLE,
52         STATUS_UNAVAILABLE,
53         STATUS_ERROR
54     })
55     @Retention(RetentionPolicy.SOURCE)
56     public @interface PropertyStatus {}
57 
58     /**
59      * CarPropertyValue is available.
60      */
61     public static final int STATUS_AVAILABLE = 0;
62 
63     /**
64      * CarPropertyValue is unavailable.
65      */
66     public static final int STATUS_UNAVAILABLE = 1;
67 
68     /**
69      * CarPropertyVale has an error.
70      */
71     public static final int STATUS_ERROR = 2;
72 
73     /**
74      * Creates an instance of CarPropertyValue.
75      *
76      * @param propertyId Property ID
77      * @param areaId Area ID of Property
78      * @param value Value of Property
79      * @hide
80      */
CarPropertyValue(int propertyId, int areaId, T value)81     public CarPropertyValue(int propertyId, int areaId, T value) {
82         this(propertyId, areaId, 0, 0, value);
83     }
84 
85     /**
86      * Creates an instance of CarPropertyValue. The {@code timestamp} is the time in nanoseconds at
87      * which the event happened. For a given car property, each new CarPropertyValue should be
88      * monotonically increasing using the same time base as
89      * {@link SystemClock#elapsedRealtimeNanos()}.
90      *
91      * @param propertyId Property ID
92      * @param areaId     Area ID of Property
93      * @param status     Status of Property
94      * @param timestamp  Elapsed time in nanoseconds since boot
95      * @param value      Value of Property
96      * @hide
97      */
CarPropertyValue(int propertyId, int areaId, int status, long timestamp, T value)98     public CarPropertyValue(int propertyId, int areaId, int status, long timestamp, T value) {
99         mPropertyId = propertyId;
100         mAreaId = areaId;
101         mStatus = status;
102         mTimestamp = timestamp;
103         mValue = value;
104     }
105 
106     /**
107      * Creates an instance of CarPropertyValue.
108      *
109      * @param in Parcel to read
110      * @hide
111      */
112     @SuppressWarnings("unchecked")
CarPropertyValue(Parcel in)113     public CarPropertyValue(Parcel in) {
114         mPropertyId = in.readInt();
115         mAreaId = in.readInt();
116         mStatus = in.readInt();
117         mTimestamp = in.readLong();
118         String valueClassName = in.readString();
119         Class<?> valueClass;
120         try {
121             valueClass = Class.forName(valueClassName);
122         } catch (ClassNotFoundException e) {
123             throw new IllegalArgumentException("Class not found: " + valueClassName);
124         }
125 
126         if (String.class.equals(valueClass)) {
127             byte[] bytes = in.readBlob();
128             mValue = (T) new String(bytes, DEFAULT_CHARSET);
129         } else if (byte[].class.equals(valueClass)) {
130             mValue = (T) in.readBlob();
131         } else {
132             mValue = (T) in.readValue(valueClass.getClassLoader());
133         }
134     }
135 
136     public static final Creator<CarPropertyValue> CREATOR = new Creator<CarPropertyValue>() {
137         @Override
138         public CarPropertyValue createFromParcel(Parcel in) {
139             return new CarPropertyValue(in);
140         }
141 
142         @Override
143         public CarPropertyValue[] newArray(int size) {
144             return new CarPropertyValue[size];
145         }
146     };
147 
148     @Override
describeContents()149     public int describeContents() {
150         return 0;
151     }
152 
153     @Override
writeToParcel(Parcel dest, int flags)154     public void writeToParcel(Parcel dest, int flags) {
155         dest.writeInt(mPropertyId);
156         dest.writeInt(mAreaId);
157         dest.writeInt(mStatus);
158         dest.writeLong(mTimestamp);
159 
160         Class<?> valueClass = mValue == null ? null : mValue.getClass();
161         dest.writeString(valueClass == null ? null : valueClass.getName());
162 
163         // Special handling for String and byte[] to mitigate transaction buffer limitations.
164         if (String.class.equals(valueClass)) {
165             dest.writeBlob(((String) mValue).getBytes(DEFAULT_CHARSET));
166         } else if (byte[].class.equals(valueClass)) {
167             dest.writeBlob((byte[]) mValue);
168         } else {
169             dest.writeValue(mValue);
170         }
171     }
172 
173     /**
174      * @return Property id of CarPropertyValue
175      */
getPropertyId()176     public int getPropertyId() {
177         return mPropertyId;
178     }
179 
180     /**
181      * @return Area id of CarPropertyValue
182      */
getAreaId()183     public int getAreaId() {
184         return mAreaId;
185     }
186 
187     /**
188      * @return Status of CarPropertyValue
189      */
getStatus()190     public @PropertyStatus int getStatus() {
191         return mStatus;
192     }
193 
194     /**
195      * Returns the timestamp in nanoseconds at which the CarPropertyValue happened. For a given car
196      * property, each new CarPropertyValue should be monotonically increasing using the same time
197      * base as {@link SystemClock#elapsedRealtimeNanos()}.
198      *
199      * <p>NOTE: Timestamp should be synchronized with other signals from the platform (e.g.
200      * {@link Location} and {@link SensorEvent} instances). Ideally, timestamp synchronization
201      * error should be below 1 millisecond.
202      */
getTimestamp()203     public long getTimestamp() {
204         return mTimestamp;
205     }
206 
207     /**
208      * @return Value of CarPropertyValue
209      */
210     @NonNull
getValue()211     public T getValue() {
212         return mValue;
213     }
214 
215     /** @hide */
216     @Override
toString()217     public String toString() {
218         return "CarPropertyValue{"
219                 + "mPropertyId=0x" + toHexString(mPropertyId)
220                 + ", mAreaId=0x" + toHexString(mAreaId)
221                 + ", mStatus=" + mStatus
222                 + ", mTimestamp=" + mTimestamp
223                 + ", mValue=" + mValue
224                 + '}';
225     }
226 }
227