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 * @param <T> refer to Parcel#writeValue(Object) to get a list of all supported types. The class 35 * should be visible to framework as default class loader is being used here. 36 * 37 */ 38 public final class CarPropertyValue<T> implements Parcelable { 39 private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; 40 41 private final int mPropertyId; 42 private final int mAreaId; 43 private final int mStatus; 44 private final long mTimestamp; 45 private final T mValue; 46 47 @IntDef({ 48 STATUS_AVAILABLE, 49 STATUS_UNAVAILABLE, 50 STATUS_ERROR 51 }) 52 @Retention(RetentionPolicy.SOURCE) 53 public @interface PropertyStatus {} 54 55 /** 56 * CarPropertyValue is available. 57 */ 58 public static final int STATUS_AVAILABLE = 0; 59 60 /** 61 * CarPropertyValue is unavailable. 62 */ 63 public static final int STATUS_UNAVAILABLE = 1; 64 65 /** 66 * CarPropertyVale has an error. 67 */ 68 public static final int STATUS_ERROR = 2; 69 70 /** 71 * Get an instance of CarPropertyValue 72 * @param propertyId Property ID 73 * @param areaId Area ID of Property 74 * @param value Value of Property 75 * @hide 76 */ CarPropertyValue(int propertyId, int areaId, T value)77 public CarPropertyValue(int propertyId, int areaId, T value) { 78 this(propertyId, areaId, 0, 0, value); 79 } 80 81 /** 82 * Get an instance of CarPropertyValue 83 * @param propertyId Property ID 84 * @param areaId Area ID of Property 85 * @param status Status of Property 86 * @param timestamp Timestamp in nanosecond 87 * @param value Value of Property 88 * @hide 89 */ CarPropertyValue(int propertyId, int areaId, int status, long timestamp, T value)90 public CarPropertyValue(int propertyId, int areaId, int status, long timestamp, T value) { 91 mPropertyId = propertyId; 92 mAreaId = areaId; 93 mStatus = status; 94 mTimestamp = timestamp; 95 mValue = value; 96 } 97 98 /** 99 * Get an instance of CarPropertyValue 100 * @param in Parcel to read 101 * @hide 102 */ 103 @SuppressWarnings("unchecked") CarPropertyValue(Parcel in)104 public CarPropertyValue(Parcel in) { 105 mPropertyId = in.readInt(); 106 mAreaId = in.readInt(); 107 mStatus = in.readInt(); 108 mTimestamp = in.readLong(); 109 String valueClassName = in.readString(); 110 Class<?> valueClass; 111 try { 112 valueClass = Class.forName(valueClassName); 113 } catch (ClassNotFoundException e) { 114 throw new IllegalArgumentException("Class not found: " + valueClassName); 115 } 116 117 if (String.class.equals(valueClass)) { 118 byte[] bytes = in.readBlob(); 119 mValue = (T) new String(bytes, DEFAULT_CHARSET); 120 } else if (byte[].class.equals(valueClass)) { 121 mValue = (T) in.readBlob(); 122 } else { 123 mValue = (T) in.readValue(valueClass.getClassLoader()); 124 } 125 } 126 127 public static final Creator<CarPropertyValue> CREATOR = new Creator<CarPropertyValue>() { 128 @Override 129 public CarPropertyValue createFromParcel(Parcel in) { 130 return new CarPropertyValue(in); 131 } 132 133 @Override 134 public CarPropertyValue[] newArray(int size) { 135 return new CarPropertyValue[size]; 136 } 137 }; 138 139 @Override describeContents()140 public int describeContents() { 141 return 0; 142 } 143 144 @Override writeToParcel(Parcel dest, int flags)145 public void writeToParcel(Parcel dest, int flags) { 146 dest.writeInt(mPropertyId); 147 dest.writeInt(mAreaId); 148 dest.writeInt(mStatus); 149 dest.writeLong(mTimestamp); 150 151 Class<?> valueClass = mValue == null ? null : mValue.getClass(); 152 dest.writeString(valueClass == null ? null : valueClass.getName()); 153 154 // Special handling for String and byte[] to mitigate transaction buffer limitations. 155 if (String.class.equals(valueClass)) { 156 dest.writeBlob(((String) mValue).getBytes(DEFAULT_CHARSET)); 157 } else if (byte[].class.equals(valueClass)) { 158 dest.writeBlob((byte[]) mValue); 159 } else { 160 dest.writeValue(mValue); 161 } 162 } 163 164 /** 165 * @return Property id of CarPropertyValue 166 */ getPropertyId()167 public int getPropertyId() { 168 return mPropertyId; 169 } 170 171 /** 172 * @return Area id of CarPropertyValue 173 */ getAreaId()174 public int getAreaId() { 175 return mAreaId; 176 } 177 178 /** 179 * @return Status of CarPropertyValue 180 */ getStatus()181 public @PropertyStatus int getStatus() { 182 return mStatus; 183 } 184 185 /** 186 * @return Timestamp of CarPropertyValue 187 */ getTimestamp()188 public long getTimestamp() { 189 return mTimestamp; 190 } 191 192 /** 193 * @return Value of CarPropertyValue 194 */ 195 @NonNull getValue()196 public T getValue() { 197 return mValue; 198 } 199 200 /** @hide */ 201 @Override toString()202 public String toString() { 203 return "CarPropertyValue{" 204 + "mPropertyId=0x" + toHexString(mPropertyId) 205 + ", mAreaId=0x" + toHexString(mAreaId) 206 + ", mStatus=" + mStatus 207 + ", mTimestamp=" + mTimestamp 208 + ", mValue=" + mValue 209 + '}'; 210 } 211 } 212