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.CarNotConnectedException; 24 import android.car.hardware.CarPropertyConfig; 25 import android.car.hardware.CarPropertyValue; 26 import android.car.hardware.property.CarPropertyManagerBase; 27 import android.car.hardware.property.CarPropertyManagerBase.CarPropertyEventCallback; 28 import android.content.Context; 29 import android.os.Handler; 30 import android.os.IBinder; 31 import android.util.ArraySet; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.lang.ref.WeakReference; 36 import java.util.Collection; 37 import java.util.List; 38 39 /** 40 * API for controlling HVAC system in cars 41 * @hide 42 */ 43 @SystemApi 44 public final class CarHvacManager implements CarManagerBase { 45 private final static boolean DBG = false; 46 private final static String TAG = "CarHvacManager"; 47 private final CarPropertyManagerBase mMgr; 48 private final ArraySet<CarHvacEventCallback> mCallbacks = new ArraySet<>(); 49 private CarPropertyEventListenerToBase mListenerToBase = null; 50 51 /** 52 * HVAC property IDs for get/set methods 53 */ 54 /** 55 * Global HVAC properties. There is only a single instance in a car. 56 * Global properties are in the range of 0-0x3FFF. 57 */ 58 /** 59 * Mirror defrosters state, bool type 60 * true indicates mirror defroster is on 61 */ 62 public static final int ID_MIRROR_DEFROSTER_ON = 0x0001; 63 /** 64 * Steering wheel temp, int type 65 * Positive values indicate heating. 66 * Negative values indicate cooling 67 */ 68 public static final int ID_STEERING_WHEEL_TEMP = 0x0002; 69 /** 70 * Outside air temperature, float type 71 * Value is in degrees of ID_TEMPERATURE_UNITS 72 */ 73 public static final int ID_OUTSIDE_AIR_TEMP = 0x0003; 74 /** 75 * Temperature units being used, int type 76 * 0x30 = Celsius 77 * 0x31 = Fahrenheit 78 */ 79 public static final int ID_TEMPERATURE_UNITS = 0x0004; 80 81 82 /** 83 * The maximum id that can be assigned to global (non-zoned) property. 84 * @hide 85 */ 86 public static final int ID_MAX_GLOBAL_PROPERTY_ID = 0x3fff; 87 88 /** 89 * ID_ZONED_* represents properties available on a per-zone basis. All zones in a car are 90 * not required to have the same properties. Zone specific properties start at 0x4000. 91 */ 92 /** 93 * Temperature setpoint, float type 94 * Temperature set by the user, units are determined by ID_TEMPERTURE_UNITS property. 95 */ 96 public static final int ID_ZONED_TEMP_SETPOINT = 0x4001; 97 /** 98 * Actual temperature, float type 99 * Actual zone temperature is read only value, in terms of F or C. 100 */ 101 public static final int ID_ZONED_TEMP_ACTUAL = 0x4002; 102 /** 103 * HVAC system powered on / off, bool type 104 * In many vehicles, if the HVAC system is powered off, the SET and GET command will 105 * throw an IllegalStateException. To correct this, need to turn on the HVAC module first 106 * before manipulating a parameter. 107 */ 108 public static final int ID_ZONED_HVAC_POWER_ON = 0x4003; 109 /** 110 * Fan speed setpoint, int type 111 * Fan speed is an integer from 0-n, depending on number of fan speeds available. 112 */ 113 public static final int ID_ZONED_FAN_SPEED_SETPOINT = 0x4004; 114 /** 115 * Actual fan speed, int type 116 * Actual fan speed is a read-only value, expressed in RPM. 117 */ 118 public static final int ID_ZONED_FAN_SPEED_RPM = 0x4005; 119 /** Fan position available, int type 120 * Fan position is a bitmask of positions available for each zone. 121 */ 122 public static final int ID_ZONED_FAN_POSITION_AVAILABLE = 0x4006; 123 /** 124 * Current fan position setting, int type. The value must be one of the FAN_POSITION_* 125 * constants declared in {@link CarHvacManager}. 126 */ 127 public static final int ID_ZONED_FAN_POSITION = 0x4007; 128 /** 129 * Seat temperature, int type 130 * Seat temperature is negative for cooling, positive for heating. Temperature is a 131 * setting, i.e. -3 to 3 for 3 levels of cooling and 3 levels of heating. 132 */ 133 public static final int ID_ZONED_SEAT_TEMP = 0x4008; 134 /** 135 * Air ON, bool type 136 * true indicates AC is ON. 137 */ 138 public static final int ID_ZONED_AC_ON = 0x4009; 139 /** 140 * Automatic Mode ON, bool type 141 * true indicates HVAC is in automatic mode 142 */ 143 public static final int ID_ZONED_AUTOMATIC_MODE_ON = 0x400A; 144 /** 145 * Air recirculation ON, bool type 146 * true indicates recirculation is active. 147 */ 148 public static final int ID_ZONED_AIR_RECIRCULATION_ON = 0x400B; 149 /** 150 * Max AC ON, bool type 151 * true indicates MAX AC is ON 152 */ 153 public static final int ID_ZONED_MAX_AC_ON = 0x400C; 154 /** Dual zone ON, bool type 155 * true indicates dual zone mode is ON 156 */ 157 public static final int ID_ZONED_DUAL_ZONE_ON = 0x400D; 158 /** 159 * Max Defrost ON, bool type 160 * true indicates max defrost is active. 161 */ 162 public static final int ID_ZONED_MAX_DEFROST_ON = 0x400E; 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 = 0x5001; 169 170 /** @hide */ 171 @IntDef({ 172 ID_MIRROR_DEFROSTER_ON, 173 ID_STEERING_WHEEL_TEMP, 174 ID_OUTSIDE_AIR_TEMP, 175 ID_TEMPERATURE_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_POSITION_AVAILABLE, 181 ID_ZONED_FAN_POSITION, 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_WINDOW_DEFROSTER_ON, 191 }) 192 @Retention(RetentionPolicy.SOURCE) 193 public @interface PropertyId {} 194 195 /** 196 * Represents fan position when air flows through face directed vents. 197 * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property. 198 */ 199 public static final int FAN_POSITION_FACE = 1; 200 /** 201 * Represents fan position when air flows through floor directed vents. 202 * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property. 203 */ 204 public static final int FAN_POSITION_FLOOR = 2; 205 /** 206 * Represents fan position when air flows through face and floor directed vents. 207 * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property. 208 */ 209 public static final int FAN_POSITION_FACE_AND_FLOOR = 3; 210 /** 211 * Represents fan position when air flows through defrost vents. 212 * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property. 213 */ 214 public static final int FAN_POSITION_DEFROST = 4; 215 /** 216 * Represents fan position when air flows through defrost and floor directed vents. 217 * This constant must be used with {@link #ID_ZONED_FAN_POSITION} property. 218 */ 219 public static final int FAN_POSITION_DEFROST_AND_FLOOR = 5; 220 221 /** 222 * Application registers {@link CarHvacEventCallback} object to receive updates and changes to 223 * subscribed Car HVAC properties. 224 */ 225 public interface CarHvacEventCallback { 226 /** 227 * Called when a property is updated 228 * @param value Property that has been updated. 229 */ onChangeEvent(CarPropertyValue value)230 void onChangeEvent(CarPropertyValue value); 231 232 /** 233 * Called when an error is detected with a property 234 * @param propertyId 235 * @param zone 236 */ onErrorEvent(@ropertyId int propertyId, int zone)237 void onErrorEvent(@PropertyId int propertyId, int zone); 238 } 239 240 private static class CarPropertyEventListenerToBase implements CarPropertyEventCallback { 241 private final WeakReference<CarHvacManager> mManager; 242 CarPropertyEventListenerToBase(CarHvacManager manager)243 public CarPropertyEventListenerToBase(CarHvacManager manager) { 244 mManager = new WeakReference<>(manager); 245 } 246 247 @Override onChangeEvent(CarPropertyValue value)248 public void onChangeEvent(CarPropertyValue value) { 249 CarHvacManager manager = mManager.get(); 250 if (manager != null) { 251 manager.handleOnChangeEvent(value); 252 } 253 } 254 255 @Override onErrorEvent(int propertyId, int zone)256 public void onErrorEvent(int propertyId, int zone) { 257 CarHvacManager manager = mManager.get(); 258 if (manager != null) { 259 manager.handleOnErrorEvent(propertyId, zone); 260 } 261 } 262 } 263 handleOnChangeEvent(CarPropertyValue value)264 private void handleOnChangeEvent(CarPropertyValue value) { 265 Collection<CarHvacEventCallback> callbacks; 266 synchronized (this) { 267 callbacks = new ArraySet<>(mCallbacks); 268 } 269 if (!callbacks.isEmpty()) { 270 for (CarHvacEventCallback l: callbacks) { 271 l.onChangeEvent(value); 272 } 273 } 274 } 275 handleOnErrorEvent(int propertyId, int zone)276 private void handleOnErrorEvent(int propertyId, int zone) { 277 Collection<CarHvacEventCallback> callbacks; 278 synchronized (this) { 279 callbacks = new ArraySet<>(mCallbacks); 280 } 281 if (!callbacks.isEmpty()) { 282 for (CarHvacEventCallback l: callbacks) { 283 l.onErrorEvent(propertyId, zone); 284 } 285 } 286 } 287 288 /** 289 * Get an instance of the CarHvacManager. 290 * 291 * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead. 292 * @param service 293 * @param context 294 * @param handler 295 * @hide 296 */ CarHvacManager(IBinder service, Context context, Handler handler)297 public CarHvacManager(IBinder service, Context context, Handler handler) { 298 mMgr = new CarPropertyManagerBase(service, handler, DBG, TAG); 299 } 300 301 /** 302 * Determine if a property is zoned or not. 303 * @param propertyId 304 * @return true if property is a zoned type. 305 */ isZonedProperty(@ropertyId int propertyId)306 public static boolean isZonedProperty(@PropertyId int propertyId) { 307 return propertyId > ID_MAX_GLOBAL_PROPERTY_ID; 308 } 309 310 /** 311 * Implement wrappers for contained CarPropertyManagerBase object 312 * @param callback 313 * @throws CarNotConnectedException 314 */ registerCallback(CarHvacEventCallback callback)315 public synchronized void registerCallback(CarHvacEventCallback callback) throws 316 CarNotConnectedException { 317 if (mCallbacks.isEmpty()) { 318 mListenerToBase = new CarPropertyEventListenerToBase(this); 319 mMgr.registerCallback(mListenerToBase); 320 } 321 mCallbacks.add(callback); 322 } 323 324 /** 325 * Stop getting property updates for the given callback. If there are multiple registrations for 326 * this listener, all listening will be stopped. 327 * @param callback 328 */ unregisterCallback(CarHvacEventCallback callback)329 public synchronized void unregisterCallback(CarHvacEventCallback callback) { 330 mCallbacks.remove(callback); 331 if (mCallbacks.isEmpty()) { 332 mMgr.unregisterCallback(); 333 mListenerToBase = null; 334 } 335 } 336 337 /** 338 * Get list of properties available to Car Hvac Manager 339 * @return List of CarPropertyConfig objects available via Car Hvac Manager. 340 * @throws CarNotConnectedException if the connection to the car service has been lost. 341 */ getPropertyList()342 public List<CarPropertyConfig> getPropertyList() throws CarNotConnectedException { 343 return mMgr.getPropertyList(); 344 } 345 346 /** 347 * Get value of boolean property 348 * @param propertyId 349 * @param area 350 * @return value of requested boolean property 351 * @throws CarNotConnectedException 352 */ getBooleanProperty(@ropertyId int propertyId, int area)353 public boolean getBooleanProperty(@PropertyId int propertyId, int area) 354 throws CarNotConnectedException { 355 return mMgr.getBooleanProperty(propertyId, area); 356 } 357 358 /** 359 * Get value of float property 360 * @param propertyId 361 * @param area 362 * @return value of requested float property 363 * @throws CarNotConnectedException 364 */ getFloatProperty(@ropertyId int propertyId, int area)365 public float getFloatProperty(@PropertyId int propertyId, int area) 366 throws CarNotConnectedException { 367 return mMgr.getFloatProperty(propertyId, area); 368 } 369 370 /** 371 * Get value of integer property 372 * @param propertyId 373 * @param area 374 * @return value of requested integer property 375 * @throws CarNotConnectedException 376 */ getIntProperty(@ropertyId int propertyId, int area)377 public int getIntProperty(@PropertyId int propertyId, int area) 378 throws CarNotConnectedException { 379 return mMgr.getIntProperty(propertyId, area); 380 } 381 382 /** 383 * Set the value of a boolean property 384 * @param propertyId 385 * @param area 386 * @param val 387 * @throws CarNotConnectedException 388 */ setBooleanProperty(@ropertyId int propertyId, int area, boolean val)389 public void setBooleanProperty(@PropertyId int propertyId, int area, boolean val) 390 throws CarNotConnectedException { 391 mMgr.setBooleanProperty(propertyId, area, val); 392 } 393 394 /** 395 * Set the value of a float property 396 * @param propertyId 397 * @param area 398 * @param val 399 * @throws CarNotConnectedException 400 */ setFloatProperty(@ropertyId int propertyId, int area, float val)401 public void setFloatProperty(@PropertyId int propertyId, int area, float val) 402 throws CarNotConnectedException { 403 mMgr.setFloatProperty(propertyId, area, val); 404 } 405 406 /** 407 * Set the value of an integer property 408 * @param propertyId 409 * @param area 410 * @param val 411 * @throws CarNotConnectedException 412 */ setIntProperty(@ropertyId int propertyId, int area, int val)413 public void setIntProperty(@PropertyId int propertyId, int area, int val) 414 throws CarNotConnectedException { 415 mMgr.setIntProperty(propertyId, area, val); 416 } 417 418 /** @hide */ 419 @Override onCarDisconnected()420 public void onCarDisconnected() { 421 mMgr.onCarDisconnected(); 422 } 423 } 424