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.CarPropertyManagerBase;
24 import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Looper;
28 import android.util.ArraySet;
29 
30 import com.android.internal.annotations.GuardedBy;
31 
32 import java.util.List;
33 
34 /**
35  * API to access custom vehicle properties defined by OEMs.
36  * <p>
37  * System permission {@link Car#PERMISSION_VENDOR_EXTENSION} is required to get this manager.
38  * </p>
39  * @hide
40  */
41 @SystemApi
42 public final class CarVendorExtensionManager implements CarManagerBase {
43 
44     private final static boolean DBG = false;
45     private final static String TAG = CarVendorExtensionManager.class.getSimpleName();
46     private final CarPropertyManagerBase mPropertyManager;
47 
48     @GuardedBy("mLock")
49     private ArraySet<CarVendorExtensionCallback> mCallbacks;
50     private final Object mLock = new Object();
51 
52     /**
53      * Creates an instance of the {@link CarVendorExtensionManager}.
54      *
55      * <p>Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
56      * @hide
57      */
CarVendorExtensionManager(IBinder service, Handler handler)58     public CarVendorExtensionManager(IBinder service, Handler handler) {
59         mPropertyManager = new CarPropertyManagerBase(service, handler, DBG, TAG);
60     }
61 
62     /**
63      * Contains callback functions that will be called when some event happens with vehicle
64      * property.
65      */
66     public interface CarVendorExtensionCallback {
67         /** Called when a property is updated */
onChangeEvent(CarPropertyValue value)68         void onChangeEvent(CarPropertyValue value);
69 
70         /** Called when an error is detected with a property */
onErrorEvent(int propertyId, int zone)71         void onErrorEvent(int propertyId, int zone);
72     }
73 
74     /**
75      * Registers listener. The methods of the listener will be called when new events arrived in
76      * the main thread.
77      */
registerCallback(CarVendorExtensionCallback callback)78     public void registerCallback(CarVendorExtensionCallback callback)
79             throws CarNotConnectedException {
80         synchronized (mLock) {
81             if (mCallbacks == null) {
82                 mPropertyManager.registerCallback(new CarPropertyEventCallback() {
83                     @Override
84                     public void onChangeEvent(CarPropertyValue value) {
85                         for (CarVendorExtensionCallback listener: getCallbacks()) {
86                             listener.onChangeEvent(value);
87                         }
88                     }
89 
90                     @Override
91                     public void onErrorEvent(int propertyId, int zone) {
92                         for (CarVendorExtensionCallback listener: getCallbacks()) {
93                             listener.onErrorEvent(propertyId, zone);
94                         }
95                     }
96                 });
97                 mCallbacks = new ArraySet<>(1 /* We expect at least one element */);
98             }
99             mCallbacks.add(callback);
100         }
101     }
102 
103     /** Unregisters listener that was previously registered. */
unregisterCallback(CarVendorExtensionCallback callback)104     public void unregisterCallback(CarVendorExtensionCallback callback) {
105         synchronized (mLock) {
106             mCallbacks.remove(callback);
107             if (mCallbacks.isEmpty()) {
108                 mPropertyManager.unregisterCallback();
109                 mCallbacks = null;
110             }
111         }
112     }
113 
114     /** Returns copy of listeners. Thread safe. */
getCallbacks()115     private CarVendorExtensionCallback[] getCallbacks() {
116         synchronized (mLock) {
117             return mCallbacks.toArray(new CarVendorExtensionCallback[mCallbacks.size()]);
118         }
119     }
120 
getProperties()121     public List<CarPropertyConfig> getProperties() throws CarNotConnectedException {
122         return mPropertyManager.getPropertyList();
123     }
124 
125     /**
126      * Returns property value. Use this function for global vehicle properties.
127      *
128      * @param propertyClass - data type of the given property, for example property that was
129      *        defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
130      *        {@code Integer.class}.
131      * @param propId - property id which is matched with the one defined in vehicle HAL
132      *
133      * @throws CarNotConnectedException if the connection to the car service has been lost.
134      */
getGlobalProperty(Class<E> propertyClass, int propId)135     public <E> E getGlobalProperty(Class<E> propertyClass, int propId)
136             throws CarNotConnectedException {
137         return getProperty(propertyClass, propId, 0 /* area */);
138     }
139 
140     /**
141      * Returns property value. Use this function for "zoned" vehicle properties.
142      *
143      * @param propertyClass - data type of the given property, for example property that was
144      *        defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
145      *        {@code Integer.class}.
146      * @param propId - property id which is matched with the one defined in vehicle HAL
147      * @param area - vehicle area (e.g. {@code VehicleAreaZone.ROW_1_LEFT}
148      *        or {@code VEHICLE_MIRROR_DRIVER_LEFT}
149      *
150      * @throws CarNotConnectedException if the connection to the car service has been lost.
151      */
getProperty(Class<E> propertyClass, int propId, int area)152     public <E> E getProperty(Class<E> propertyClass, int propId, int area)
153             throws CarNotConnectedException {
154         return mPropertyManager.getProperty(propertyClass, propId, area).getValue();
155     }
156 
157     /**
158      * Call this function to set a value to global vehicle property.
159      *
160      * @param propertyClass - data type of the given property, for example property that was
161      *        defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
162      *        {@code Integer.class}.
163      * @param propId - property id which is matched with the one defined in vehicle HAL
164      * @param value - new value, this object should match a class provided in {@code propertyClass}
165      *        argument.
166      *
167      * @throws CarNotConnectedException if the connection to the car service has been lost.
168      */
setGlobalProperty(Class<E> propertyClass, int propId, E value)169     public <E> void setGlobalProperty(Class<E> propertyClass, int propId, E value)
170             throws CarNotConnectedException {
171         mPropertyManager.setProperty(propertyClass, propId, 0 /* area */, value);
172     }
173 
174     /**
175      * Call this function to set a value to "zoned" vehicle property.
176      *
177      * @param propertyClass - data type of the given property, for example property that was
178      *        defined as {@code VEHICLE_VALUE_TYPE_INT32} in vehicle HAL could be accessed using
179      *        {@code Integer.class}.
180      * @param propId - property id which is matched with the one defined in vehicle HAL
181      * @param area - vehicle area (e.g. {@code VehicleAreaZone.ROW_1_LEFT}
182      *        or {@code VEHICLE_MIRROR_DRIVER_LEFT}
183      * @param value - new value, this object should match a class provided in {@code propertyClass}
184      *        argument.
185      *
186      * @throws CarNotConnectedException if the connection to the car service has been lost.
187      */
setProperty(Class<E> propertyClass, int propId, int area, E value)188     public <E> void setProperty(Class<E> propertyClass, int propId, int area, E value)
189             throws CarNotConnectedException {
190         mPropertyManager.setProperty(propertyClass, propId, area, value);
191     }
192 
193     /** @hide */
194     @Override
onCarDisconnected()195     public void onCarDisconnected() {
196         mPropertyManager.onCarDisconnected();
197     }
198 }
199