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 17package android.car.hardware; 18 19import android.annotation.Nullable; 20import android.annotation.SystemApi; 21import android.car.VehicleAreaType; 22import android.os.Parcel; 23import android.os.Parcelable; 24import android.util.SparseArray; 25 26import java.lang.reflect.Array; 27 28/** 29 * Represents general information about car property such as data type and min/max ranges for car 30 * areas (if applicable). This class supposed to be immutable, parcelable and could be passed over. 31 * 32 * <p>Use {@link CarPropertyConfig#newBuilder} to create an instance of this class. 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 * @hide 38 */ 39@SystemApi 40public class CarPropertyConfig<T> implements Parcelable { 41 private final int mPropertyId; 42 private final Class<T> mType; 43 private final int mAreaType; 44 private final SparseArray<AreaConfig<T>> mSupportedAreas; 45 46 private CarPropertyConfig(Class<T> type, int propertyId, int areaType, 47 SparseArray<AreaConfig<T>> supportedAreas) { 48 mPropertyId = propertyId; 49 mType = type; 50 mAreaType = areaType; 51 mSupportedAreas = supportedAreas; 52 } 53 54 public int getPropertyId() { return mPropertyId; } 55 public Class<T> getPropertyType() { return mType; } 56 public @VehicleAreaType.VehicleAreaTypeValue int getAreaType() { return mAreaType; } 57 58 /** Returns true if this property doesn't hold car area-specific configuration */ 59 public boolean isGlobalProperty() { 60 return mAreaType == VehicleAreaType.VEHICLE_AREA_TYPE_NONE; 61 } 62 63 public int getAreaCount() { 64 return mSupportedAreas.size(); 65 } 66 67 public int[] getAreaIds() { 68 int[] areaIds = new int[mSupportedAreas.size()]; 69 for (int i = 0; i < areaIds.length; i++) { 70 areaIds[i] = mSupportedAreas.keyAt(i); 71 } 72 return areaIds; 73 } 74 75 /** 76 * Returns the first areaId. 77 * Throws {@link IllegalStateException} if supported area count not equals to one. 78 * */ 79 public int getFirstAndOnlyAreaId() { 80 if (mSupportedAreas.size() != 1) { 81 throw new IllegalStateException("Expected one and only area in this property. Prop: 0x" 82 + Integer.toHexString(mPropertyId)); 83 } 84 return mSupportedAreas.keyAt(0); 85 } 86 87 public boolean hasArea(int areaId) { 88 return mSupportedAreas.indexOfKey(areaId) >= 0; 89 } 90 91 @Nullable 92 public T getMinValue(int areaId) { 93 AreaConfig<T> area = mSupportedAreas.get(areaId); 94 return area == null ? null : area.getMinValue(); 95 } 96 97 @Nullable 98 public T getMaxValue(int areaId) { 99 AreaConfig<T> area = mSupportedAreas.get(areaId); 100 return area == null ? null : area.getMaxValue(); 101 } 102 103 @Nullable 104 public T getMinValue() { 105 AreaConfig<T> area = mSupportedAreas.valueAt(0); 106 return area == null ? null : area.getMinValue(); 107 } 108 109 @Nullable 110 public T getMaxValue() { 111 AreaConfig<T> area = mSupportedAreas.valueAt(0); 112 return area == null ? null : area.getMaxValue(); 113 } 114 115 @Override 116 public int describeContents() { 117 return 0; 118 } 119 120 @Override 121 public void writeToParcel(Parcel dest, int flags) { 122 dest.writeInt(mPropertyId); 123 dest.writeString(mType.getName()); 124 dest.writeInt(mAreaType); 125 dest.writeInt(mSupportedAreas.size()); 126 for (int i = 0; i < mSupportedAreas.size(); i++) { 127 dest.writeInt(mSupportedAreas.keyAt(i)); 128 dest.writeParcelable(mSupportedAreas.valueAt(i), flags); 129 } 130 } 131 132 @SuppressWarnings("unchecked") 133 private CarPropertyConfig(Parcel in) { 134 mPropertyId = in.readInt(); 135 String className = in.readString(); 136 try { 137 mType = (Class<T>) Class.forName(className); 138 } catch (ClassNotFoundException e) { 139 throw new IllegalArgumentException("Class not found: " + className); 140 } 141 mAreaType = in.readInt(); 142 int areaSize = in.readInt(); 143 mSupportedAreas = new SparseArray<>(areaSize); 144 for (int i = 0; i < areaSize; i++) { 145 int areaId = in.readInt(); 146 AreaConfig<T> area = in.readParcelable(getClass().getClassLoader()); 147 mSupportedAreas.put(areaId, area); 148 } 149 } 150 151 public static final Creator<CarPropertyConfig> CREATOR = new Creator<CarPropertyConfig>() { 152 @Override 153 public CarPropertyConfig createFromParcel(Parcel in) { 154 return new CarPropertyConfig(in); 155 } 156 157 @Override 158 public CarPropertyConfig[] newArray(int size) { 159 return new CarPropertyConfig[size]; 160 } 161 }; 162 163 @Override 164 public String toString() { 165 return "CarPropertyConfig{" + 166 "mPropertyId=" + mPropertyId + 167 ", mType=" + mType + 168 ", mAreaType=" + mAreaType + 169 ", mSupportedAreas=" + mSupportedAreas + 170 '}'; 171 } 172 173 public static class AreaConfig<T> implements Parcelable { 174 @Nullable private final T mMinValue; 175 @Nullable private final T mMaxValue; 176 177 private AreaConfig(T minValue, T maxValue) { 178 mMinValue = minValue; 179 mMaxValue = maxValue; 180 } 181 182 public static final Parcelable.Creator<AreaConfig<Object>> CREATOR 183 = getCreator(Object.class); 184 185 private static <E> Parcelable.Creator<AreaConfig<E>> getCreator(final Class<E> clazz) { 186 return new Creator<AreaConfig<E>>() { 187 @Override 188 public AreaConfig<E> createFromParcel(Parcel source) { 189 return new AreaConfig<>(source); 190 } 191 192 @Override @SuppressWarnings("unchecked") 193 public AreaConfig<E>[] newArray(int size) { 194 return (AreaConfig<E>[]) Array.newInstance(clazz, size); 195 } 196 }; 197 } 198 199 @SuppressWarnings("unchecked") 200 private AreaConfig(Parcel in) { 201 mMinValue = (T) in.readValue(getClass().getClassLoader()); 202 mMaxValue = (T) in.readValue(getClass().getClassLoader()); 203 } 204 205 @Nullable public T getMinValue() { return mMinValue; } 206 @Nullable public T getMaxValue() { return mMaxValue; } 207 208 @Override 209 public int describeContents() { 210 return 0; 211 } 212 213 @Override 214 public void writeToParcel(Parcel dest, int flags) { 215 dest.writeValue(mMinValue); 216 dest.writeValue(mMaxValue); 217 } 218 219 @Override 220 public String toString() { 221 return "CarAreaConfig{" + 222 "mMinValue=" + mMinValue + 223 ", mMaxValue=" + mMaxValue + 224 '}'; 225 } 226 } 227 228 public static <T> Builder<T> newBuilder(Class<T> clazz, int propertyId, int areaType, 229 int areaCapacity) { 230 return new Builder<>(clazz, propertyId, areaType, areaCapacity); 231 } 232 233 234 public static <T> Builder<T> newBuilder(Class<T> clazz, int propertyId, int areaType) { 235 return newBuilder(clazz, propertyId, areaType, 0); 236 } 237 238 public static class Builder<T> { 239 private final Class<T> mType; 240 private final int mPropertyId; 241 private final int mAreaType; 242 private final SparseArray<AreaConfig<T>> mAreas; 243 244 private Builder(Class<T> type, int propertyId, int areaType, int areaCapacity) { 245 mType = type; 246 mPropertyId = propertyId; 247 mAreaType = areaType; 248 if (areaCapacity != 0) { 249 mAreas = new SparseArray<>(areaCapacity); 250 } else { 251 mAreas = new SparseArray<>(); 252 } 253 } 254 255 public Builder<T> addAreas(int[] areaIds) { 256 for (int id : areaIds) { 257 mAreas.put(id, null); 258 } 259 return this; 260 } 261 262 public Builder<T> addArea(int areaId) { 263 return addAreaConfig(areaId, null, null); 264 } 265 266 public Builder<T> addAreaConfig(int areaId, T min, T max) { 267 if (min == null && max == null) { 268 mAreas.put(areaId, null); 269 } else { 270 mAreas.put(areaId, new AreaConfig<>(min, max)); 271 } 272 return this; 273 } 274 275 public CarPropertyConfig<T> build() { 276 return new CarPropertyConfig<>(mType, mPropertyId, mAreaType, mAreas); 277 } 278 } 279} 280