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