• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 com.android.car.hal;
18 
19 import android.car.VehiclePropertyIds;
20 import android.car.hardware.CarPropertyValue;
21 import android.hardware.automotive.vehicle.VehiclePropertyStatus;
22 import android.hardware.automotive.vehicle.VehiclePropertyType;
23 import android.util.Log;
24 
25 import com.android.car.internal.property.CarPropertyHelper;
26 
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.List;
30 
31 /**
32  * HalPropValue represents a vehicle property value.
33  *
34  * It could be used to convert between AIDL or HIDL VehiclePropValue used in vehicle HAL and
35  * {@link CarPropertyValue} used in CarPropertyManager.
36  */
37 public abstract class HalPropValue {
38     private static final String TAG = HalPropValue.class.getSimpleName();
39 
40     /**
41      * Gets the timestamp.
42      *
43      * @return The timestamp.
44      */
getTimestamp()45     public abstract long getTimestamp();
46 
47     /**
48      * Gets the area ID.
49      *
50      * @return The area ID.
51      */
getAreaId()52     public abstract int getAreaId();
53 
54     /**
55      * Gets the property ID.
56      *
57      * @return The property ID.
58      */
getPropId()59     public abstract int getPropId();
60 
61     /**
62      * Gets the property status.
63      *
64      * @return The property status.
65      */
getStatus()66     public abstract int getStatus();
67 
68     /**
69      * Get stored int32 values size.
70      *
71      * @return The size for the stored int32 values.
72      */
getInt32ValuesSize()73     public abstract int getInt32ValuesSize();
74 
75     /**
76      * Gets the int32 value at index.
77      *
78      * @param index The index.
79      * @return The int32 value at index.
80      */
getInt32Value(int index)81     public abstract int getInt32Value(int index);
82 
83     /**
84      * Dump all int32 values as a string. Used for debugging.
85      *
86      * @return A String representation of all int32 values.
87      */
dumpInt32Values()88     public abstract String dumpInt32Values();
89 
90     /**
91      * Get stored float values size.
92      *
93      * @return The size for the stored float values.
94      */
getFloatValuesSize()95     public abstract int getFloatValuesSize();
96 
97     /**
98      * Gets the float value at index.
99      *
100      * @param index The index.
101      * @return The float value at index.
102      */
getFloatValue(int index)103     public abstract float getFloatValue(int index);
104 
105     /**
106      * Dump all float values as a string. Used for debugging.
107      *
108      * @return A String representation of all float values.
109      */
dumpFloatValues()110     public abstract String dumpFloatValues();
111 
112     /**
113      * Get stored inn64 values size.
114      *
115      * @return The size for the stored inn64 values.
116      */
getInt64ValuesSize()117     public abstract int getInt64ValuesSize();
118 
119     /**
120      * Gets the int64 value at index.
121      *
122      * @param index The index.
123      * @return The int64 value at index.
124      */
getInt64Value(int index)125     public abstract long getInt64Value(int index);
126 
127     /**
128      * Dump all int64 values as a string. Used for debugging.
129      *
130      * @return A String representation of all int64 values.
131      */
dumpInt64Values()132     public abstract String dumpInt64Values();
133 
134     /**
135      * Get stored byte values size.
136      *
137      * @return The size for the stored byte values.
138      */
getByteValuesSize()139     public abstract int getByteValuesSize();
140 
141     /**
142      * Gets the byte value at index.
143      *
144      * @param index The index.
145      * @return The byte value at index.
146      */
getByteValue(int index)147     public abstract byte getByteValue(int index);
148 
149     /**
150      * Gets the byte values.
151      *
152      * @return The byte values.
153      */
getByteArray()154     public abstract byte[] getByteArray();
155 
156     /**
157      * Gets the string value.
158      *
159      * @return The stored string value.
160      */
getStringValue()161     public abstract String getStringValue();
162 
163     /**
164      * Converts to an AIDL/HIDL VehiclePropValue that could be used to sent to vehicle HAL.
165      *
166      * @return An AIDL or HIDL VehiclePropValue.
167      */
toVehiclePropValue()168     public abstract Object toVehiclePropValue();
169 
170     /**
171      * Turns this class to a {@link CarPropertyValue}.
172      *
173      * @param mgrPropId The property ID used in {@link android.car.VehiclePropertyIds}.
174      * @param config The config for the property.
175      * @return A CarPropertyValue that could be passed to upper layer
176      * @throws IllegalStateException If property has unsupported type
177      */
toCarPropertyValue(int mgrPropId, HalPropConfig config)178     public CarPropertyValue toCarPropertyValue(int mgrPropId, HalPropConfig config) {
179         if (isMixedTypeProperty(getPropId())) {
180             int[] configArray = config.getConfigArray();
181             boolean containStringType = configArray[0] == 1;
182             boolean containBooleanType = configArray[1] == 1;
183             return toMixedCarPropertyValue(mgrPropId, containBooleanType, containStringType);
184         }
185         return toCarPropertyValue(mgrPropId);
186     }
187 
188     /**
189      * Check whether this property is equal to another property.
190      *
191      * @param argument The property to compare.
192      * @return true if equal, false if not.
193      */
194     @Override
equals(Object argument)195     public boolean equals(Object argument) {
196         if (!(argument instanceof HalPropValue)) {
197             return false;
198         }
199 
200         HalPropValue other = (HalPropValue) argument;
201 
202         if (other.getPropId() != getPropId()) {
203             Log.i(TAG, "Property ID mismatch, got " + other.getPropId() + " want "
204                     + getPropId());
205             return false;
206         }
207         if (other.getAreaId() != getAreaId()) {
208             Log.i(TAG, "Area ID mismatch, got " + other.getAreaId() + " want " + getAreaId());
209             return false;
210         }
211         if (other.getStatus() != getStatus()) {
212             Log.i(TAG, "Status mismatch, got " + other.getStatus() + " want " + getStatus());
213             return false;
214         }
215         if (other.getTimestamp() != getTimestamp()) {
216             Log.i(TAG, "Timestamp mismatch, got " + other.getTimestamp() + " want "
217                     + getTimestamp());
218             return false;
219         }
220         if (!equalInt32Values(other)) {
221             Log.i(TAG, "Int32Values mismatch, got " + other.dumpInt32Values() + " want "
222                     + dumpInt32Values());
223             return false;
224         }
225         if (!equalFloatValues(other)) {
226             Log.i(TAG, "FloatValues mismatch, got " + other.dumpFloatValues() + " want "
227                     + dumpFloatValues());
228             return false;
229         }
230         if (!equalInt64Values(other)) {
231             Log.i(TAG, "Int64Values mismatch, got " + other.dumpInt64Values() + " want "
232                     + dumpInt64Values());
233             return false;
234         }
235         if (!Arrays.equals(other.getByteArray(), getByteArray())) {
236             Log.i(TAG, "ByteValues mismatch, got " + Arrays.toString(other.getByteArray())
237                     + " want " + Arrays.toString(getByteArray()));
238             return false;
239         }
240         if (!other.getStringValue().equals(getStringValue())) {
241             Log.i(TAG, "StringValue mismatch, got " + other.getStringValue() + " want "
242                     + getStringValue());
243             return false;
244         }
245         return true;
246     }
247 
248     /**
249      * Get the hashCode for this value.
250      */
251     @Override
hashCode()252     public abstract int hashCode();
253 
isMixedTypeProperty(int prop)254     protected static boolean isMixedTypeProperty(int prop) {
255         return (prop & VehiclePropertyType.MASK) == VehiclePropertyType.MIXED;
256     }
257 
getFloatContainerArray()258     protected abstract Float[] getFloatContainerArray();
259 
getInt32ContainerArray()260     protected abstract Integer[] getInt32ContainerArray();
261 
getInt64ContainerArray()262     protected abstract Long[] getInt64ContainerArray();
263 
toCarPropertyValue(int propertyId)264     private CarPropertyValue<?> toCarPropertyValue(int propertyId) {
265         Class<?> clazz = CarPropertyUtils.getJavaClass(getPropId() & VehiclePropertyType.MASK);
266         int areaId = getAreaId();
267         int status = vehiclePropertyStatusToCarPropertyStatus(getStatus());
268         long timestampNanos = getTimestamp();
269         Object value = null;
270 
271         if (Boolean.class == clazz) {
272             if (getInt32ValuesSize() > 0) {
273                 value = Boolean.valueOf(getInt32Value(0) == 1);
274             } else if (status == CarPropertyValue.STATUS_AVAILABLE) {
275                 status = CarPropertyValue.STATUS_ERROR;
276             }
277         } else if (Float.class == clazz) {
278             if (getFloatValuesSize() > 0) {
279                 value = Float.valueOf(getFloatValue(0));
280             } else if (status == CarPropertyValue.STATUS_AVAILABLE) {
281                 status = CarPropertyValue.STATUS_ERROR;
282             }
283         } else if (Integer.class == clazz) {
284             if (getInt32ValuesSize() > 0) {
285                 value = Integer.valueOf(getInt32Value(0));
286             } else if (status == CarPropertyValue.STATUS_AVAILABLE) {
287                 status = CarPropertyValue.STATUS_ERROR;
288             }
289         } else if (Long.class == clazz) {
290             if (getInt64ValuesSize() > 0) {
291                 value = Long.valueOf(getInt64Value(0));
292             } else if (status == CarPropertyValue.STATUS_AVAILABLE) {
293                 status = CarPropertyValue.STATUS_ERROR;
294             }
295         } else if (Float[].class == clazz) {
296             value = getFloatContainerArray();
297         } else if (Integer[].class == clazz) {
298             value = getInt32ContainerArray();
299         } else if (Long[].class == clazz) {
300             value = getInt64ContainerArray();
301         } else if (String.class == clazz) {
302             value = getStringValue();
303         } else if (byte[].class == clazz) {
304             value = getByteArray();
305         } else {
306             throw new IllegalStateException(
307                     "Unexpected type " + clazz + " - propertyId: " + VehiclePropertyIds.toString(
308                             propertyId));
309         }
310         if (value == null) {
311             value = CarPropertyHelper.getDefaultValue(clazz);
312         }
313         return new CarPropertyValue<>(propertyId, areaId, status, timestampNanos, value);
314     }
315 
toMixedCarPropertyValue( int propertyId, boolean containBoolean, boolean containString)316     private CarPropertyValue<?> toMixedCarPropertyValue(
317             int propertyId, boolean containBoolean, boolean containString) {
318         int areaId = getAreaId();
319         int status = vehiclePropertyStatusToCarPropertyStatus(getStatus());
320         long timestampNanos = getTimestamp();
321 
322         List<Object> valuesList = new ArrayList<>();
323         if (containString) {
324             valuesList.add(getStringValue());
325         }
326         if (containBoolean) {
327             if (getInt32ValuesSize() > 0) {
328                 boolean boolValue = getInt32Value(0) == 1;
329                 valuesList.add(boolValue);
330                 for (int i = 1; i < getInt32ValuesSize(); i++) {
331                     valuesList.add(getInt32Value(i));
332                 }
333             } else if (status == CarPropertyValue.STATUS_AVAILABLE) {
334                 status = CarPropertyValue.STATUS_ERROR;
335             }
336         } else {
337             for (int i = 0; i < getInt32ValuesSize(); i++) {
338                 valuesList.add(getInt32Value(i));
339             }
340         }
341         for (int i = 0; i < getInt64ValuesSize(); i++) {
342             valuesList.add(getInt64Value(i));
343         }
344         for (int i = 0; i < getFloatValuesSize(); i++) {
345             valuesList.add(getFloatValue(i));
346         }
347         for (int i = 0; i < getByteValuesSize(); i++) {
348             valuesList.add(getByteValue(i));
349         }
350         return new CarPropertyValue<>(propertyId, areaId, status, timestampNanos,
351                 valuesList.toArray());
352     }
353 
equalInt32Values(HalPropValue argument)354     private boolean equalInt32Values(HalPropValue argument) {
355         if (getInt32ValuesSize() != argument.getInt32ValuesSize()) {
356             return false;
357         }
358         for (int i = 0; i < getInt32ValuesSize(); i++) {
359             if (getInt32Value(i) != argument.getInt32Value(i)) {
360                 return false;
361             }
362         }
363         return true;
364     }
365 
equalFloatValues(HalPropValue argument)366     private boolean equalFloatValues(HalPropValue argument) {
367         if (getFloatValuesSize() != argument.getFloatValuesSize()) {
368             return false;
369         }
370         for (int i = 0; i < getFloatValuesSize(); i++) {
371             if (getFloatValue(i) != argument.getFloatValue(i)) {
372                 return false;
373             }
374         }
375         return true;
376     }
377 
equalInt64Values(HalPropValue argument)378     private boolean equalInt64Values(HalPropValue argument) {
379         if (getInt64ValuesSize() != argument.getInt64ValuesSize()) {
380             return false;
381         }
382         for (int i = 0; i < getInt64ValuesSize(); i++) {
383             if (getInt64Value(i) != argument.getInt64Value(i)) {
384                 return false;
385             }
386         }
387         return true;
388     }
389 
vehiclePropertyStatusToCarPropertyStatus( @ehiclePropertyStatus int status)390     private static @CarPropertyValue.PropertyStatus int vehiclePropertyStatusToCarPropertyStatus(
391             @VehiclePropertyStatus int status) {
392         switch (status) {
393             case VehiclePropertyStatus.AVAILABLE:
394                 return CarPropertyValue.STATUS_AVAILABLE;
395             case VehiclePropertyStatus.ERROR:
396                 return CarPropertyValue.STATUS_ERROR;
397             case VehiclePropertyStatus.UNAVAILABLE:
398                 return CarPropertyValue.STATUS_UNAVAILABLE;
399         }
400         return CarPropertyValue.STATUS_ERROR;
401     }
402 }
403