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 android.car.feature.Flags.FLAG_CAR_PROPERTY_VALUE_PROPERTY_STATUS; 20 21 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE; 22 import static com.android.car.internal.util.DebugUtils.constantToString; 23 import static com.android.car.internal.util.DebugUtils.toAreaIdString; 24 25 import static java.lang.Integer.toHexString; 26 27 import android.annotation.FlaggedApi; 28 import android.annotation.IntDef; 29 import android.annotation.NonNull; 30 import android.annotation.SystemApi; 31 import android.car.VehiclePropertyIds; 32 import android.car.builtin.os.BuildHelper; 33 import android.car.feature.Flags; 34 import android.os.Parcel; 35 import android.os.Parcelable; 36 37 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 38 import com.android.car.internal.property.RawPropertyValue; 39 40 import java.lang.annotation.Retention; 41 import java.lang.annotation.RetentionPolicy; 42 import java.util.Arrays; 43 import java.util.Objects; 44 45 /** 46 * Stores a value for a vehicle property ID and area ID combination. 47 * 48 * Client should use {@code android.car.*} types when dealing with property ID, area ID or property 49 * value and MUST NOT use {@code android.hardware.automotive.vehicle.*} types directly. 50 * 51 * @param <T> refer to {@link Parcel#writeValue(java.lang.Object)} to get a list of all supported 52 * types. The class should be visible to framework as default class loader is being used 53 * here. 54 */ 55 public final class CarPropertyValue<T> implements Parcelable { 56 57 private final int mPropertyId; 58 private final int mAreaId; 59 private final int mStatus; 60 private final long mTimestampNanos; 61 private final RawPropertyValue<T> mValue; 62 private final boolean mIsSimulationPropId; 63 64 /** @removed accidentally exposed previously */ 65 @IntDef({ 66 STATUS_AVAILABLE, 67 STATUS_UNAVAILABLE, 68 STATUS_ERROR 69 }) 70 @Retention(RetentionPolicy.SOURCE) 71 public @interface PropertyStatus {} 72 73 /** 74 * {@code CarPropertyValue} is available. 75 */ 76 public static final int STATUS_AVAILABLE = 0; 77 78 /** 79 * {@code CarPropertyValue} is unavailable. 80 */ 81 public static final int STATUS_UNAVAILABLE = 1; 82 83 /** 84 * {@code CarPropertyValue} has an error. 85 */ 86 public static final int STATUS_ERROR = 2; 87 88 /** 89 * Creates an instance of {@code CarPropertyValue}. 90 * 91 * @param propertyId The property identifier, see constants in 92 * {@link android.car.VehiclePropertyIds} for system defined property IDs. 93 * @param areaId The area identifier. Must be {@code 0} if property is 94 * {@link android.car.VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}. Otherwise, it 95 * must be one or more OR'd together constants of this property's 96 * {@link android.car.VehicleAreaType}: 97 * <ul> 98 * <li>{@code VehicleAreaWindow}</li> 99 * <li>{@code VehicleAreaDoor}</li> 100 * <li>{@link android.car.VehicleAreaSeat}</li> 101 * <li>{@code VehicleAreaMirror}</li> 102 * <li>{@link android.car.VehicleAreaWheel}</li> 103 * </ul> 104 * @param value Value of Property 105 * @hide 106 */ CarPropertyValue(int propertyId, int areaId, T value)107 public CarPropertyValue(int propertyId, int areaId, T value) { 108 this(propertyId, areaId, /* timestampNanos= */ 0, value); 109 } 110 111 /** 112 * Creates an instance of {@code CarPropertyValue}. The {@code timestampNanos} is the time in 113 * nanoseconds at which the event happened. For a given car property, each new {@code 114 * CarPropertyValue} should be monotonically increasing using the same time base as 115 * {@link android.os.SystemClock#elapsedRealtimeNanos()}. 116 * 117 * 118 * @param propertyId The property identifier, see constants in 119 * {@link android.car.VehiclePropertyIds} for system defined property IDs. 120 * @param areaId The area identifier. Must be {@code 0} if property is 121 * {@link android.car.VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}. Otherwise, it 122 * must be one or more OR'd together constants of this property's 123 * {@link android.car.VehicleAreaType}: 124 * <ul> 125 * <li>{@code VehicleAreaWindow}</li> 126 * <li>{@code VehicleAreaDoor}</li> 127 * <li>{@link android.car.VehicleAreaSeat}</li> 128 * <li>{@code VehicleAreaMirror}</li> 129 * <li>{@link android.car.VehicleAreaWheel}</li> 130 * </ul> 131 * @param timestampNanos Elapsed time in nanoseconds since boot 132 * @param value Value of Property 133 * @hide 134 */ CarPropertyValue(int propertyId, int areaId, long timestampNanos, T value)135 public CarPropertyValue(int propertyId, int areaId, long timestampNanos, T value) { 136 this(propertyId, areaId, CarPropertyValue.STATUS_AVAILABLE, timestampNanos, value); 137 } 138 139 /** 140 * Creates an instance of {@code CarPropertyValue}. The {@code timestampNanos} is the time in 141 * nanoseconds at which the event happened. For a given car property, each new {@code 142 * CarPropertyValue} should be monotonically increasing using the same time base as 143 * {@link android.os.SystemClock#elapsedRealtimeNanos()}. 144 * 145 * @param propertyId The property identifier, see constants in 146 * {@link android.car.VehiclePropertyIds} for system defined property IDs. 147 * @param areaId The area identifier. Must be {@code 0} if property is 148 * {@link android.car.VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}. Otherwise, it 149 * must be one or more OR'd together constants of this property's 150 * {@link android.car.VehicleAreaType}: 151 * <ul> 152 * <li>{@code VehicleAreaWindow}</li> 153 * <li>{@code VehicleAreaDoor}</li> 154 * <li>{@link android.car.VehicleAreaSeat}</li> 155 * <li>{@code VehicleAreaMirror}</li> 156 * <li>{@link android.car.VehicleAreaWheel}</li> 157 * </ul> 158 * @param status The status of the property. 159 * @param timestampNanos Elapsed time in nanoseconds since boot 160 * @param rawPropertyValue Value of the property. 161 * 162 * @hide 163 */ CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, RawPropertyValue<T> rawPropertyValue)164 public CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, 165 RawPropertyValue<T> rawPropertyValue) { 166 this(propertyId, areaId, status, timestampNanos, rawPropertyValue, 167 /* isSimulationPropId= */ false); 168 } 169 170 /** 171 * Creates an instance of {@code CarPropertyValue}. The {@code timestampNanos} is the time in 172 * nanoseconds at which the event happened. For a given car property, each new {@code 173 * CarPropertyValue} should be monotonically increasing using the same time base as 174 * {@link android.os.SystemClock#elapsedRealtimeNanos()}. 175 * 176 * @param propertyId The property identifier, see constants in 177 * {@link android.car.VehiclePropertyIds} for system defined property IDs. 178 * @param areaId The area identifier. Must be {@code 0} if property is 179 * {@link android.car.VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}. Otherwise, it 180 * must be one or more OR'd together constants of this property's 181 * {@link android.car.VehicleAreaType}: 182 * <ul> 183 * <li>{@code VehicleAreaWindow}</li> 184 * <li>{@code VehicleAreaDoor}</li> 185 * <li>{@link android.car.VehicleAreaSeat}</li> 186 * <li>{@code VehicleAreaMirror}</li> 187 * <li>{@link android.car.VehicleAreaWheel}</li> 188 * </ul> 189 * @param status The status of the property. 190 * @param timestampNanos Elapsed time in nanoseconds since boot 191 * @param rawPropertyValue Value of the property. 192 * @param isSimulationPropId If the property is a Simulation property. 193 * 194 * @hide 195 */ CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, RawPropertyValue<T> rawPropertyValue, boolean isSimulationPropId)196 public CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, 197 RawPropertyValue<T> rawPropertyValue, boolean isSimulationPropId) { 198 mPropertyId = propertyId; 199 mAreaId = areaId; 200 mStatus = status; 201 mTimestampNanos = timestampNanos; 202 mValue = rawPropertyValue; 203 mIsSimulationPropId = isSimulationPropId; 204 } 205 206 207 /** 208 * @hide 209 * 210 * @deprecated use {@link CarPropertyValue#CarPropertyValue(int, int, long, T)} instead 211 */ 212 @Deprecated CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, T value)213 public CarPropertyValue(int propertyId, int areaId, int status, long timestampNanos, T value) { 214 215 this(propertyId, areaId, status, timestampNanos, new RawPropertyValue( 216 Objects.requireNonNull(value, "value for propertyId: " 217 + VehiclePropertyIds.toString(propertyId) + ", areaId: " 218 + toAreaIdString(propertyId, areaId) + ", status: " + status 219 + " must not be null") 220 )); 221 } 222 223 /** 224 * Creates an instance of {@code CarPropertyValue}. 225 * 226 * @param in Parcel to read 227 * @hide 228 */ 229 @SuppressWarnings("unchecked") CarPropertyValue(Parcel in)230 public CarPropertyValue(Parcel in) { 231 mPropertyId = in.readInt(); 232 mAreaId = in.readInt(); 233 mStatus = in.readInt(); 234 mTimestampNanos = in.readLong(); 235 mValue = (RawPropertyValue<T>) in.readParcelable(RawPropertyValue.class.getClassLoader(), 236 RawPropertyValue.class); 237 mIsSimulationPropId = in.readBoolean(); 238 } 239 240 public static final Creator<CarPropertyValue> CREATOR = new Creator<CarPropertyValue>() { 241 @Override 242 public CarPropertyValue createFromParcel(Parcel in) { 243 return new CarPropertyValue(in); 244 } 245 246 @Override 247 public CarPropertyValue[] newArray(int size) { 248 return new CarPropertyValue[size]; 249 } 250 }; 251 252 @Override 253 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE) describeContents()254 public int describeContents() { 255 return 0; 256 } 257 258 @Override writeToParcel(Parcel dest, int flags)259 public void writeToParcel(Parcel dest, int flags) { 260 dest.writeInt(mPropertyId); 261 dest.writeInt(mAreaId); 262 dest.writeInt(mStatus); 263 dest.writeLong(mTimestampNanos); 264 dest.writeParcelable(mValue, /* parcelableFlags= */ 0); 265 dest.writeBoolean(mIsSimulationPropId); 266 } 267 268 /** 269 * Returns the property identifier. 270 * 271 * @return The property identifier of {@code CarPropertyValue}. See constants in 272 * {@link android.car.VehiclePropertyIds} for some system defined possible values. 273 */ getPropertyId()274 public int getPropertyId() { 275 return mPropertyId; 276 } 277 278 /** 279 * Returns the area identifier. 280 * 281 * @return The area identifier of {@code CarPropertyValue}, If property is 282 * {@link android.car.VehicleAreaType#VEHICLE_AREA_TYPE_GLOBAL}, it will be {@code 0}. 283 * Otherwise, it will be on or more OR'd together constants of this property's 284 * {@link android.car.VehicleAreaType}: 285 * <ul> 286 * <li>{@code VehicleAreaWindow}</li> 287 * <li>{@code VehicleAreaDoor}</li> 288 * <li>{@link android.car.VehicleAreaSeat}</li> 289 * <li>{@code VehicleAreaMirror}</li> 290 * <li>{@link android.car.VehicleAreaWheel}</li> 291 * </ul> 292 */ getAreaId()293 public int getAreaId() { 294 return mAreaId; 295 } 296 297 /** 298 * @return The property status of {@code CarPropertyValue} 299 */ 300 @FlaggedApi(FLAG_CAR_PROPERTY_VALUE_PROPERTY_STATUS) 301 @PropertyStatus getPropertyStatus()302 public int getPropertyStatus() { 303 return mStatus; 304 } 305 306 /** 307 * @return Status of {@code CarPropertyValue} 308 * @deprecated Use {@link #getPropertyStatus} instead. 309 */ 310 @Deprecated 311 @PropertyStatus getStatus()312 public int getStatus() { 313 return mStatus; 314 } 315 316 /** 317 * Returns the timestamp in nanoseconds at which the {@code CarPropertyValue} happened. For a 318 * given car property, each new {@code CarPropertyValue} should be monotonically increasing 319 * using the same time base as {@link android.os.SystemClock#elapsedRealtimeNanos()}. 320 * 321 * <p>NOTE: Timestamp should be synchronized with other signals from the platform (e.g. 322 * {@link android.location.Location} and {@link android.hardware.SensorEvent} instances). 323 * Ideally, timestamp synchronization error should be below 1 millisecond. 324 */ getTimestamp()325 public long getTimestamp() { 326 return mTimestampNanos; 327 } 328 329 /** 330 * Returns the value for {@code CarPropertyValue}. 331 * 332 * <p> 333 * <b>Note:</b>Caller must check the value of {@link #getPropertyStatus()}. Only use 334 * {@link #getValue()} when {@link #getPropertyStatus()} is {@link #STATUS_AVAILABLE}. If not, 335 * {@link #getValue()} is meaningless. 336 */ 337 @NonNull getValue()338 public T getValue() { 339 return mValue.getTypedValue(); 340 } 341 342 /** 343 * Gets the internal raw property value. 344 * 345 * @hide 346 */ getRawPropertyValue()347 public RawPropertyValue getRawPropertyValue() { 348 return mValue; 349 } 350 351 /** 352 * Returns weather the propertyId is Simulation Property Id. 353 * 354 * <p>Simulation property is a property which is used by car service and vehicle hardware but 355 * is not defined in {@link android.car.VehiclePropertyIds} 356 * 357 * @return This will only be {@code true} if returned from 358 * {@link android.car.hardware.property.CarPropertySimulationManager}. 359 * 360 * @hide 361 */ 362 @SystemApi 363 @FlaggedApi(Flags.FLAG_CAR_PROPERTY_SIMULATION) isPropertyIdSimulationPropId()364 public boolean isPropertyIdSimulationPropId() { 365 if (!BuildHelper.isDebuggableBuild()) { 366 throw new IllegalStateException("Build is not eng or user-debug"); 367 } 368 return mIsSimulationPropId; 369 } 370 371 /** @hide */ 372 @Override toString()373 public String toString() { 374 String propertyIdToString = VehiclePropertyIds.toString(mPropertyId); 375 if (Flags.carPropertySimulation()) { 376 if (isPropertyIdSimulationPropId()) { 377 propertyIdToString = Integer.toHexString(mPropertyId); 378 } 379 } 380 String propertyValueString = "CarPropertyValue{" 381 + "mPropertyId=0x" + toHexString(mPropertyId) 382 + ", propertyName=" + propertyIdToString 383 + ", mAreaId=" + toAreaIdString(mPropertyId, mAreaId) 384 + ", mStatus=" + constantToString(CarPropertyValue.class, "STATUS_", mStatus) 385 + ", mTimestampNanos=" + mTimestampNanos 386 + ", mValue=" + mValue; 387 if (Flags.carPropertySimulation()) { 388 if (isPropertyIdSimulationPropId()) { 389 return propertyValueString 390 + ", mIsSimulationPropId=" + mIsSimulationPropId 391 + '}'; 392 } 393 } 394 return propertyValueString + '}'; 395 } 396 397 /** Generates hash code for this instance. */ 398 @Override hashCode()399 public int hashCode() { 400 return Arrays.hashCode(new Object[]{ 401 mPropertyId, mAreaId, mStatus, mTimestampNanos, mValue}); 402 } 403 404 /** Checks equality with passed {@code object}. */ 405 @Override equals(Object object)406 public boolean equals(Object object) { 407 if (this == object) { 408 return true; 409 } 410 if (!(object instanceof CarPropertyValue<?>)) { 411 return false; 412 } 413 CarPropertyValue<?> carPropertyValue = (CarPropertyValue<?>) object; 414 return mPropertyId == carPropertyValue.mPropertyId && mAreaId == carPropertyValue.mAreaId 415 && mStatus == carPropertyValue.mStatus 416 && mTimestampNanos == carPropertyValue.mTimestampNanos 417 && Objects.equals(mValue, carPropertyValue.mValue); 418 } 419 } 420