1 /*
2  * Copyright (C) 2015 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.hvac;
18 
19 import android.annotation.IntDef;
20 import android.annotation.SystemApi;
21 import android.car.Car;
22 import android.car.CarManagerBase;
23 import android.car.hardware.CarPropertyConfig;
24 import android.car.hardware.CarPropertyValue;
25 import android.car.hardware.property.CarPropertyManager;
26 import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
27 import android.car.hardware.property.ICarProperty;
28 import android.os.IBinder;
29 import android.util.ArraySet;
30 import android.util.Log;
31 
32 import com.android.internal.annotations.GuardedBy;
33 
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.lang.ref.WeakReference;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.List;
40 
41 /**
42  * @deprecated Use {@link CarPropertyManager} instead.
43  *
44  * API for controlling HVAC system in cars
45  * @hide
46  */
47 @Deprecated
48 @SystemApi
49 public final class CarHvacManager extends CarManagerBase {
50     private static final String TAG = "CarHvacManager";
51     private final CarPropertyManager mCarPropertyMgr;
52     @GuardedBy("mLock")
53     private CarPropertyEventListenerToBase mListenerToBase = null;
54 
55     private final Object mLock = new Object();
56 
57     @GuardedBy("mLock")
58     private final ArraySet<CarHvacEventCallback> mCallbacks = new ArraySet<>();
59 
60     /**
61      * HVAC property IDs for get/set methods
62      */
63     /**
64      * Mirror defrosters state, bool type
65      * true indicates mirror defroster is on
66      */
67     public static final int ID_MIRROR_DEFROSTER_ON = 0x1440050c;
68     /**
69      * Steering wheel temp, int type
70      * Positive values indicate heating.
71      * Negative values indicate cooling
72      */
73     public static final int ID_STEERING_WHEEL_HEAT = 0x1140050d;
74     /**
75      * Outside air temperature, float type
76      * Value is in degrees Celsius
77      */
78     public static final int ID_OUTSIDE_AIR_TEMP = 0x11600703;
79     /**
80      * Temperature units being used, int type
81      *  0x30 = Celsius
82      *  0x31 = Fahrenheit
83      */
84     public static final int ID_TEMPERATURE_DISPLAY_UNITS = 0x1140050e;
85 
86     /**
87      * Temperature setpoint, float type
88      * Temperature set by the user, units are in degrees Celsius.
89      */
90     public static final int ID_ZONED_TEMP_SETPOINT = 0x15600503;
91     /**
92      * Actual temperature, float type
93      * Actual zone temperature is read only value, in terms of F or C.
94      */
95     public static final int ID_ZONED_TEMP_ACTUAL = 0x15600502;
96     /**
97      * HVAC system powered on / off, bool type
98      * In many vehicles, if the HVAC system is powered off, the SET and GET command will
99      * throw an IllegalStateException.  To correct this, need to turn on the HVAC module first
100      * before manipulating a parameter.
101      */
102     public static final int ID_ZONED_HVAC_POWER_ON = 0x15200510;
103     /**
104      * Fan speed setpoint, int type
105      * Fan speed is an integer from 0-n, depending on number of fan speeds available.
106      */
107     public static final int ID_ZONED_FAN_SPEED_SETPOINT = 0x15400500;
108     /**
109      * Actual fan speed, int type
110      * Actual fan speed is a read-only value, expressed in RPM.
111      */
112     public static final int ID_ZONED_FAN_SPEED_RPM = 0x1540050f;
113     /**
114      *  Fan direction available, int vector type
115      *  Fan direction is a bitmask of directions available for each zone.
116      */
117     public static final int ID_ZONED_FAN_DIRECTION_AVAILABLE = 0x15410511;
118     /**
119      * Current fan direction setting, int type. The value must be one of the FAN_DIRECTION_AVAILABLE
120      * values declared above.
121      */
122     public static final int ID_ZONED_FAN_DIRECTION = 0x15400501;
123     /**
124      * Seat temperature, int type
125      * Seat temperature is negative for cooling, positive for heating.  Temperature is a
126      * setting, i.e. -3 to 3 for 3 levels of cooling and 3 levels of heating.
127      */
128     public static final int ID_ZONED_SEAT_TEMP = 0x1540050b;
129     /**
130      * Air ON, bool type
131      * true indicates AC is ON.
132      */
133     public static final int ID_ZONED_AC_ON = 0x15200505;
134     /**
135      * Automatic Mode ON, bool type
136      * true indicates HVAC is in automatic mode
137      */
138     public static final int ID_ZONED_AUTOMATIC_MODE_ON = 0x1520050A;
139     /**
140      * Air recirculation ON, bool type
141      * true indicates recirculation is active.
142      */
143     public static final int ID_ZONED_AIR_RECIRCULATION_ON = 0x15200508;
144     /**
145      * Max AC ON, bool type
146      * true indicates MAX AC is ON
147      */
148     public static final int ID_ZONED_MAX_AC_ON = 0x15200506;
149     /** Dual zone ON, bool type
150      * true indicates dual zone mode is ON
151      */
152     public static final int ID_ZONED_DUAL_ZONE_ON = 0x15200509;
153     /**
154      * Max Defrost ON, bool type
155      * true indicates max defrost is active.
156      */
157     public static final int ID_ZONED_MAX_DEFROST_ON = 0x15200507;
158     /**
159      * Automatic recirculation mode ON
160      * true indicates recirculation is in automatic mode
161      */
162     public static final int ID_ZONED_HVAC_AUTO_RECIRC_ON = 0x15200512;
163     /**
164      * Defroster ON, bool type
165      * Defroster controls are based on window position.
166      * True indicates the defroster is ON.
167      */
168     public static final int ID_WINDOW_DEFROSTER_ON = 0x13200504;
169 
170     /** @hide */
171     @IntDef({
172             ID_MIRROR_DEFROSTER_ON,
173             ID_STEERING_WHEEL_HEAT,
174             ID_OUTSIDE_AIR_TEMP,
175             ID_TEMPERATURE_DISPLAY_UNITS,
176             ID_ZONED_TEMP_SETPOINT,
177             ID_ZONED_TEMP_ACTUAL,
178             ID_ZONED_FAN_SPEED_SETPOINT,
179             ID_ZONED_FAN_SPEED_RPM,
180             ID_ZONED_FAN_DIRECTION_AVAILABLE,
181             ID_ZONED_FAN_DIRECTION,
182             ID_ZONED_SEAT_TEMP,
183             ID_ZONED_AC_ON,
184             ID_ZONED_AUTOMATIC_MODE_ON,
185             ID_ZONED_AIR_RECIRCULATION_ON,
186             ID_ZONED_MAX_AC_ON,
187             ID_ZONED_DUAL_ZONE_ON,
188             ID_ZONED_MAX_DEFROST_ON,
189             ID_ZONED_HVAC_POWER_ON,
190             ID_ZONED_HVAC_AUTO_RECIRC_ON,
191             ID_WINDOW_DEFROSTER_ON
192     })
193     @Retention(RetentionPolicy.SOURCE)
194     public @interface PropertyId {}
195     private final ArraySet<Integer> mHvacPropertyIds = new ArraySet<>(Arrays.asList(new Integer [] {
196             ID_MIRROR_DEFROSTER_ON,
197             ID_STEERING_WHEEL_HEAT,
198             ID_OUTSIDE_AIR_TEMP,
199             ID_TEMPERATURE_DISPLAY_UNITS,
200             ID_ZONED_TEMP_SETPOINT,
201             ID_ZONED_TEMP_ACTUAL,
202             ID_ZONED_FAN_SPEED_SETPOINT,
203             ID_ZONED_FAN_SPEED_RPM,
204             ID_ZONED_FAN_DIRECTION_AVAILABLE,
205             ID_ZONED_FAN_DIRECTION,
206             ID_ZONED_SEAT_TEMP,
207             ID_ZONED_AC_ON,
208             ID_ZONED_AUTOMATIC_MODE_ON,
209             ID_ZONED_AIR_RECIRCULATION_ON,
210             ID_ZONED_MAX_AC_ON,
211             ID_ZONED_DUAL_ZONE_ON,
212             ID_ZONED_MAX_DEFROST_ON,
213             ID_ZONED_HVAC_POWER_ON,
214             ID_ZONED_HVAC_AUTO_RECIRC_ON,
215             ID_WINDOW_DEFROSTER_ON
216     }));
217 
218 
219     /**
220      * Use {@link android.car.hardware.CarHvacFanDirection#FACE} instead.
221      * Represents fan direction when air flows through face directed vents.
222      * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
223      */
224     public static final int FAN_DIRECTION_FACE = 0x1;
225     /**
226      * Use {@link android.car.hardware.CarHvacFanDirection#FLOOR} instead.
227      * Represents fan direction when air flows through floor directed vents.
228      * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
229      */
230     public static final int FAN_DIRECTION_FLOOR = 0x2;
231     /**
232      * Use {@link android.car.hardware.CarHvacFanDirection#DEFROST} instead.
233      * Represents fan direction when air flows through defrost vents.
234      * This constant must be used with {@link #ID_ZONED_FAN_DIRECTION} property.
235      */
236     public static final int FAN_DIRECTION_DEFROST = 0x4;
237 
238     /**
239      * Application registers {@link CarHvacEventCallback} object to receive updates and changes to
240      * subscribed Car HVAC properties.
241      */
242     public interface CarHvacEventCallback {
243         /**
244          * Called when a property is updated
245          * @param value Property that has been updated.
246          */
onChangeEvent(CarPropertyValue value)247         void onChangeEvent(CarPropertyValue value);
248 
249         /**
250          * Called when an error is detected with a property
251          * @param propertyId
252          * @param zone
253          */
onErrorEvent(@ropertyId int propertyId, int zone)254         void onErrorEvent(@PropertyId int propertyId, int zone);
255     }
256 
257     private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback {
258         private final WeakReference<CarHvacManager> mManager;
259 
CarPropertyEventListenerToBase(CarHvacManager manager)260         CarPropertyEventListenerToBase(CarHvacManager manager) {
261             mManager = new WeakReference<>(manager);
262         }
263 
264         @Override
onChangeEvent(CarPropertyValue value)265         public void onChangeEvent(CarPropertyValue value) {
266             CarHvacManager manager = mManager.get();
267             if (manager != null) {
268                 manager.handleOnChangeEvent(value);
269             }
270         }
271 
272         @Override
onErrorEvent(int propertyId, int zone)273         public void onErrorEvent(int propertyId, int zone) {
274             CarHvacManager manager = mManager.get();
275             if (manager != null) {
276                 manager.handleOnErrorEvent(propertyId, zone);
277             }
278         }
279     }
280 
handleOnChangeEvent(CarPropertyValue value)281     private void handleOnChangeEvent(CarPropertyValue value) {
282         Collection<CarHvacEventCallback> callbacks;
283         synchronized (mLock) {
284             callbacks = new ArraySet<>(mCallbacks);
285         }
286         if (!callbacks.isEmpty()) {
287             for (CarHvacEventCallback l: callbacks) {
288                 l.onChangeEvent(value);
289             }
290         }
291     }
292 
handleOnErrorEvent(int propertyId, int zone)293     private void handleOnErrorEvent(int propertyId, int zone) {
294         Collection<CarHvacEventCallback> callbacks;
295         synchronized (mLock) {
296             callbacks = new ArraySet<>(mCallbacks);
297         }
298         if (!callbacks.isEmpty()) {
299             for (CarHvacEventCallback l: callbacks) {
300                 l.onErrorEvent(propertyId, zone);
301             }
302         }
303     }
304 
305     /**
306      * Get an instance of the CarHvacManager.
307      *
308      * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead.
309      * @param service
310      *
311      * @hide
312      */
CarHvacManager(Car car, IBinder service)313     public CarHvacManager(Car car, IBinder service) {
314         super(car);
315         ICarProperty mCarPropertyService = ICarProperty.Stub.asInterface(service);
316         mCarPropertyMgr = new CarPropertyManager(car, mCarPropertyService);
317     }
318 
319     /**
320      * Implement wrappers for contained CarPropertyManager object
321      * @param callback
322      */
registerCallback(CarHvacEventCallback callback)323     public void registerCallback(CarHvacEventCallback callback) {
324         synchronized (mLock) {
325             if (mCallbacks.isEmpty()) {
326                 mListenerToBase = new CarPropertyEventListenerToBase(this);
327             }
328             List<CarPropertyConfig> configs = getPropertyList();
329             for (CarPropertyConfig c : configs) {
330                 // Register each individual propertyId
331                 mCarPropertyMgr.registerCallback(mListenerToBase, c.getPropertyId(), 0);
332             }
333             mCallbacks.add(callback);
334         }
335     }
336 
337     /**
338      * Stop getting property updates for the given callback. If there are multiple registrations for
339      * this listener, all listening will be stopped.
340      * @param callback
341      */
unregisterCallback(CarHvacEventCallback callback)342     public void unregisterCallback(CarHvacEventCallback callback) {
343         synchronized (mLock) {
344             mCallbacks.remove(callback);
345             try {
346                 List<CarPropertyConfig> configs = getPropertyList();
347                 for (CarPropertyConfig c : configs) {
348                     // Register each individual propertyId
349                     mCarPropertyMgr.unregisterCallback(mListenerToBase, c.getPropertyId());
350 
351                 }
352             } catch (RuntimeException e) {
353                 Log.e(TAG, "getPropertyList exception ", e);
354             }
355             if (mCallbacks.isEmpty()) {
356                 mCarPropertyMgr.unregisterCallback(mListenerToBase);
357                 mListenerToBase = null;
358             }
359         }
360     }
361 
362     /**
363      * Get list of properties represented by Car Hvac Manager for this car.
364      * @return List of CarPropertyConfig objects available via Car Hvac Manager.
365      */
getPropertyList()366     public List<CarPropertyConfig> getPropertyList() {
367         return mCarPropertyMgr.getPropertyList(mHvacPropertyIds);
368     }
369 
370     /**
371      * Check whether a given property is available or disabled based on the cars current state.
372      * @return true if the property is AVAILABLE, false otherwise
373      */
isPropertyAvailable(@ropertyId int propertyId, int area)374     public boolean isPropertyAvailable(@PropertyId int propertyId, int area) {
375         return mCarPropertyMgr.isPropertyAvailable(propertyId, area);
376     }
377 
378     /**
379      * Get value of boolean property
380      * @param propertyId
381      * @param area
382      * @return value of requested boolean property
383      */
getBooleanProperty(@ropertyId int propertyId, int area)384     public boolean getBooleanProperty(@PropertyId int propertyId, int area) {
385         return mCarPropertyMgr.getBooleanProperty(propertyId, area);
386     }
387 
388     /**
389      * Get value of float property
390      * @param propertyId
391      * @param area
392      * @return value of requested float property
393      */
getFloatProperty(@ropertyId int propertyId, int area)394     public float getFloatProperty(@PropertyId int propertyId, int area) {
395         return mCarPropertyMgr.getFloatProperty(propertyId, area);
396     }
397 
398     /**
399      * Get value of integer property
400      * @param propertyId
401      * @param area
402      * @return value of requested integer property
403      */
getIntProperty(@ropertyId int propertyId, int area)404     public int getIntProperty(@PropertyId int propertyId, int area) {
405         return mCarPropertyMgr.getIntProperty(propertyId, area);
406     }
407 
408     /**
409      * Set the value of a boolean property
410      * @param propertyId
411      * @param area
412      * @param val
413      */
setBooleanProperty(@ropertyId int propertyId, int area, boolean val)414     public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val) {
415         if (mHvacPropertyIds.contains(propertyId)) {
416             mCarPropertyMgr.setBooleanProperty(propertyId, area, val);
417         }
418     }
419 
420     /**
421      * Set the value of a float property
422      * @param propertyId
423      * @param area
424      * @param val
425      */
setFloatProperty(@ropertyId int propertyId, int area, float val)426     public void setFloatProperty(@PropertyId int propertyId, int area, float val) {
427         if (mHvacPropertyIds.contains(propertyId)) {
428             mCarPropertyMgr.setFloatProperty(propertyId, area, val);
429         }
430     }
431 
432     /**
433      * Set the value of an integer property
434      * @param propertyId
435      * @param area
436      * @param val
437      */
setIntProperty(@ropertyId int propertyId, int area, int val)438     public void setIntProperty(@PropertyId int propertyId, int area, int val) {
439         if (mHvacPropertyIds.contains(propertyId)) {
440             mCarPropertyMgr.setIntProperty(propertyId, area, val);
441         }
442     }
443 
444     /** @hide */
onCarDisconnected()445     public void onCarDisconnected() {
446         synchronized (mLock) {
447             mCallbacks.clear();
448         }
449         mCarPropertyMgr.onCarDisconnected();
450     }
451 }
452