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 android.annotation.SystemApi; 20 import android.car.Car; 21 import android.car.CarManagerBase; 22 import android.car.CarNotConnectedException; 23 import android.car.hardware.property.CarPropertyManager; 24 import android.os.Handler; 25 import android.os.IBinder; 26 import android.util.ArraySet; 27 28 import com.android.internal.annotations.GuardedBy; 29 30 import java.lang.ref.WeakReference; 31 import java.util.ArrayList; 32 import java.util.Collection; 33 import java.util.List; 34 35 /** 36 * API to access custom vehicle properties defined by OEMs. 37 * <p> 38 * System permission {@link Car#PERMISSION_VENDOR_EXTENSION} is required to get this manager. 39 * </p> 40 * @hide 41 */ 42 @SystemApi 43 public final class CarVendorExtensionManager implements CarManagerBase { 44 45 private final static boolean DBG = false; 46 private final static String TAG = CarVendorExtensionManager.class.getSimpleName(); 47 private final CarPropertyManager mPropertyManager; 48 49 @GuardedBy("mLock") 50 private final ArraySet<CarVendorExtensionCallback> mCallbacks = new ArraySet<>(); 51 private final Object mLock = new Object(); 52 53 @GuardedBy("mLock") 54 private CarPropertyEventListenerToBase mListenerToBase = null; 55 56 private void handleOnChangeEvent(CarPropertyValue value) { 57 Collection<CarVendorExtensionCallback> callbacks; 58 synchronized (mLock) { 59 callbacks = new ArrayList<>(mCallbacks); 60 } 61 for (CarVendorExtensionCallback l: callbacks) { 62 l.onChangeEvent(value); 63 } 64 } 65 66 private void handleOnErrorEvent(int propertyId, int zone) { 67 Collection<CarVendorExtensionCallback> listeners; 68 synchronized (mLock) { 69 listeners = new ArrayList<>(mCallbacks); 70 } 71 for (CarVendorExtensionCallback l: listeners) { 72 l.onErrorEvent(propertyId, zone); 73 } 74 75 } 76 77 /** 78 * Creates an instance of the {@link CarVendorExtensionManager}. 79 * 80 * <p>Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead. 81 * @hide 82 */ 83 public CarVendorExtensionManager(IBinder service, Handler handler) { 84 mPropertyManager = new CarPropertyManager(service, handler, DBG, TAG); 85 } 86 87 /** 88 * Contains callback functions that will be called when some event happens with vehicle 89 * property. 90 */ 91 public interface CarVendorExtensionCallback { 92 /** Called when a property is updated */ 93 void onChangeEvent(CarPropertyValue value); 94 95 /** Called when an error is detected with a property */ 96 void onErrorEvent(int propertyId, int zone); 97 } 98 99 /** 100 * Registers listener. The methods of the listener will be called when new events arrived in 101 * the main thread. 102 */ 103 public void registerCallback(CarVendorExtensionCallback callback) 104 throws CarNotConnectedException { 105 synchronized (mLock) { 106 if (mCallbacks.isEmpty()) { 107 mListenerToBase = new CarPropertyEventListenerToBase(this); 108 } 109 110 List<CarPropertyConfig> configs = mPropertyManager.getPropertyList(); 111 for (CarPropertyConfig c : configs) { 112 // Register each individual propertyId 113 mPropertyManager.registerListener(mListenerToBase, c.getPropertyId(), 0); 114 } 115 mCallbacks.add(callback); 116 } 117 } 118 119 /** Unregisters listener that was previously registered. */ 120 public void unregisterCallback(CarVendorExtensionCallback callback) 121 throws CarNotConnectedException { 122 synchronized (mLock) { 123 mCallbacks.remove(callback); 124 List<CarPropertyConfig> configs = mPropertyManager.getPropertyList(); 125 for (CarPropertyConfig c : configs) { 126 // Register each individual propertyId 127 mPropertyManager.unregisterListener(mListenerToBase, c.getPropertyId()); 128 } 129 if (mCallbacks.isEmpty()) { 130 mListenerToBase = null; 131 } 132 } 133 } 134 135 /** Get list of properties represented by CarVendorExtensionManager for this car. */ 136 public List<CarPropertyConfig> getProperties() throws CarNotConnectedException { 137 return mPropertyManager.getPropertyList(); 138 } 139 140 /** 141 * Check whether a given property is available or disabled based on the cars current state. 142 * @return true if the property is AVAILABLE, false otherwise 143 */ 144 public boolean isPropertyAvailable(int propertyId, int area) 145 throws CarNotConnectedException { 146 return mPropertyManager.isPropertyAvailable(propertyId, area); 147 } 148 149 /** 150 * Returns property value. Use this function for global vehicle properties. 151 * 152 * @param propertyClass - data type of the given property, for example property that was 153 * defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using 154 * {@code Integer.class}. 155 * @param propId - property id which is matched with the one defined in vehicle HAL 156 * 157 * @throws CarNotConnectedException if the connection to the car service has been lost. 158 */ 159 public <E> E getGlobalProperty(Class<E> propertyClass, int propId) 160 throws CarNotConnectedException { 161 return getProperty(propertyClass, propId, 0 /* area */); 162 } 163 164 /** 165 * Returns property value. Use this function for "zoned" vehicle properties. 166 * 167 * @param propertyClass - data type of the given property, for example property that was 168 * defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using 169 * {@code Integer.class}. 170 * @param propId - property id which is matched with the one defined in vehicle HAL 171 * @param area - vehicle area (e.g. {@code VehicleAreaSeat.ROW_1_LEFT} 172 * or {@code VEHICLE_MIRROR_DRIVER_LEFT} 173 * 174 * @throws CarNotConnectedException if the connection to the car service has been lost. 175 */ 176 public <E> E getProperty(Class<E> propertyClass, int propId, int area) 177 throws CarNotConnectedException { 178 return mPropertyManager.getProperty(propertyClass, propId, area).getValue(); 179 } 180 181 /** 182 * Call this function to set a value to global vehicle property. 183 * 184 * @param propertyClass - data type of the given property, for example property that was 185 * defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using 186 * {@code Integer.class}. 187 * @param propId - property id which is matched with the one defined in vehicle HAL 188 * @param value - new value, this object should match a class provided in {@code propertyClass} 189 * argument. 190 * 191 * @throws CarNotConnectedException if the connection to the car service has been lost. 192 */ 193 public <E> void setGlobalProperty(Class<E> propertyClass, int propId, E value) 194 throws CarNotConnectedException { 195 mPropertyManager.setProperty(propertyClass, propId, 0 /* area */, value); 196 } 197 198 /** 199 * Call this function to set a value to "zoned" vehicle property. 200 * 201 * @param propertyClass - data type of the given property, for example property that was 202 * defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using 203 * {@code Integer.class}. 204 * @param propId - property id which is matched with the one defined in vehicle HAL 205 * @param area - vehicle area (e.g. {@code VehicleAreaSeat.ROW_1_LEFT} 206 * or {@code VEHICLE_MIRROR_DRIVER_LEFT} 207 * @param value - new value, this object should match a class provided in {@code propertyClass} 208 * argument. 209 * 210 * @throws CarNotConnectedException if the connection to the car service has been lost. 211 */ 212 public <E> void setProperty(Class<E> propertyClass, int propId, int area, E value) 213 throws CarNotConnectedException { 214 mPropertyManager.setProperty(propertyClass, propId, area, value); 215 } 216 217 /** @hide */ 218 @Override 219 public void onCarDisconnected() { 220 mPropertyManager.onCarDisconnected(); 221 } 222 private static class CarPropertyEventListenerToBase implements 223 CarPropertyManager.CarPropertyEventListener { 224 private final WeakReference<CarVendorExtensionManager> mManager; 225 226 CarPropertyEventListenerToBase(CarVendorExtensionManager manager) { 227 mManager = new WeakReference<>(manager); 228 } 229 230 @Override 231 public void onChangeEvent(CarPropertyValue value) { 232 CarVendorExtensionManager manager = mManager.get(); 233 if (manager != null) { 234 manager.handleOnChangeEvent(value); 235 } 236 } 237 238 @Override 239 public void onErrorEvent(int propertyId, int zone) { 240 CarVendorExtensionManager manager = mManager.get(); 241 if (manager != null) { 242 manager.handleOnErrorEvent(propertyId, zone); 243 } 244 } 245 } 246 } 247