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 package com.android.car.hvac; 17 18 import android.app.Service; 19 import android.car.VehicleAreaSeat; 20 import android.car.VehicleAreaWindow; 21 import android.car.hardware.CarPropertyConfig; 22 import android.car.hardware.CarPropertyValue; 23 import android.car.hardware.hvac.CarHvacManager; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.os.AsyncTask; 27 import android.os.Binder; 28 import android.os.Handler; 29 import android.os.IBinder; 30 import android.os.SystemProperties; 31 import android.support.car.Car; 32 import android.support.car.CarNotConnectedException; 33 import android.support.car.CarConnectionCallback; 34 import android.util.Log; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 39 import javax.annotation.concurrent.GuardedBy; 40 41 public class HvacController extends Service { 42 private static final String DEMO_MODE_PROPERTY = "android.car.hvac.demo"; 43 private static final String TAG = "HvacController"; 44 private static final int DRIVER_ZONE_ID = VehicleAreaSeat.SEAT_ROW_1_LEFT | 45 VehicleAreaSeat.SEAT_ROW_2_LEFT | VehicleAreaSeat.SEAT_ROW_2_CENTER; 46 private static final int PASSENGER_ZONE_ID = VehicleAreaSeat.SEAT_ROW_1_RIGHT | 47 VehicleAreaSeat.SEAT_ROW_2_RIGHT; 48 49 public static final int[] AIRFLOW_STATES = new int[]{ 50 CarHvacManager.FAN_DIRECTION_FACE, 51 CarHvacManager.FAN_DIRECTION_FLOOR, 52 (CarHvacManager.FAN_DIRECTION_FACE | CarHvacManager.FAN_DIRECTION_FLOOR) 53 }; 54 // Hardware specific value for the front seats 55 public static final int SEAT_ALL = VehicleAreaSeat.SEAT_ROW_1_LEFT | 56 VehicleAreaSeat.SEAT_ROW_1_RIGHT | VehicleAreaSeat.SEAT_ROW_2_LEFT | 57 VehicleAreaSeat.SEAT_ROW_2_CENTER | VehicleAreaSeat.SEAT_ROW_2_RIGHT; 58 59 /** 60 * Callback for receiving updates from the hvac manager. A Callback can be 61 * registered using {@link #registerCallback}. 62 */ 63 public static abstract class Callback { 64 onPassengerTemperatureChange(CarPropertyValue propValue)65 public void onPassengerTemperatureChange(CarPropertyValue propValue) { 66 } 67 onDriverTemperatureChange(CarPropertyValue propValue)68 public void onDriverTemperatureChange(CarPropertyValue propValue) { 69 } 70 onFanSpeedChange(int position)71 public void onFanSpeedChange(int position) { 72 } 73 onAcStateChange(boolean isOn)74 public void onAcStateChange(boolean isOn) { 75 } 76 onFrontDefrosterChange(boolean isOn)77 public void onFrontDefrosterChange(boolean isOn) { 78 } 79 onRearDefrosterChange(boolean isOn)80 public void onRearDefrosterChange(boolean isOn) { 81 } 82 onPassengerSeatWarmerChange(int level)83 public void onPassengerSeatWarmerChange(int level) { 84 } 85 onDriverSeatWarmerChange(int level)86 public void onDriverSeatWarmerChange(int level) { 87 } 88 onFanDirectionChange(int direction)89 public void onFanDirectionChange(int direction) { 90 } 91 onAirCirculationChange(boolean isOn)92 public void onAirCirculationChange(boolean isOn) { 93 } 94 onAutoModeChange(boolean isOn)95 public void onAutoModeChange(boolean isOn) { 96 } 97 onHvacPowerChange(boolean isOn)98 public void onHvacPowerChange(boolean isOn){ 99 } 100 } 101 102 public class LocalBinder extends Binder { getService()103 HvacController getService() { 104 return HvacController.this; 105 } 106 } 107 108 private final Binder mBinder = new LocalBinder(); 109 110 private Car mCarApiClient; 111 private CarHvacManager mHvacManager; 112 private Object mHvacManagerReady = new Object(); 113 114 private HvacPolicy mPolicy; 115 @GuardedBy("mCallbacks") 116 private List<Callback> mCallbacks = new ArrayList<>(); 117 private DataStore mDataStore = new DataStore(); 118 119 @Override onCreate()120 public void onCreate() { 121 super.onCreate(); 122 if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { 123 if (SystemProperties.getBoolean(DEMO_MODE_PROPERTY, false)) { 124 IBinder binder = (new LocalHvacPropertyService()).getCarPropertyService(); 125 initHvacManager(new CarHvacManager(binder, this, new Handler())); 126 return; 127 } 128 129 mCarApiClient = Car.createCar(this, mCarConnectionCallback); 130 mCarApiClient.connect(); 131 } 132 } 133 134 @Override onDestroy()135 public void onDestroy() { 136 super.onDestroy(); 137 if (mHvacManager != null) { 138 mHvacManager.unregisterCallback(mHardwareCallback); 139 } 140 if (mCarApiClient != null) { 141 mCarApiClient.disconnect(); 142 } 143 } 144 145 @Override onStartCommand(Intent intent, int flags, int startId)146 public int onStartCommand(Intent intent, int flags, int startId) { 147 return START_STICKY; 148 } 149 150 @Override onBind(Intent intent)151 public IBinder onBind(Intent intent) { 152 return mBinder; 153 } 154 registerCallback(Callback callback)155 public void registerCallback(Callback callback) { 156 synchronized (mCallbacks) { 157 mCallbacks.add(callback); 158 } 159 } 160 unregisterCallback(Callback callback)161 public void unregisterCallback(Callback callback) { 162 synchronized (mCallbacks) { 163 mCallbacks.remove(callback); 164 } 165 } 166 initHvacManager(CarHvacManager carHvacManager)167 private void initHvacManager(CarHvacManager carHvacManager) { 168 mHvacManager = carHvacManager; 169 List<CarPropertyConfig> properties = null; 170 try { 171 properties = mHvacManager.getPropertyList(); 172 mPolicy = new HvacPolicy(HvacController.this, properties); 173 mHvacManager.registerCallback(mHardwareCallback); 174 } catch (android.car.CarNotConnectedException e) { 175 Log.e(TAG, "Car not connected in HVAC"); 176 } 177 178 } 179 180 private final CarConnectionCallback mCarConnectionCallback = 181 new CarConnectionCallback() { 182 @Override 183 public void onConnected(Car car) { 184 synchronized (mHvacManagerReady) { 185 try { 186 initHvacManager((CarHvacManager) mCarApiClient.getCarManager( 187 android.car.Car.HVAC_SERVICE)); 188 mHvacManagerReady.notifyAll(); 189 } catch (CarNotConnectedException e) { 190 Log.e(TAG, "Car not connected in onServiceConnected"); 191 } 192 } 193 } 194 195 @Override 196 public void onDisconnected(Car car) { 197 } 198 }; 199 200 private final CarHvacManager.CarHvacEventCallback mHardwareCallback = 201 new CarHvacManager.CarHvacEventCallback() { 202 @Override 203 public void onChangeEvent(final CarPropertyValue val) { 204 int areaId = val.getAreaId(); 205 switch (val.getPropertyId()) { 206 case CarHvacManager.ID_ZONED_AC_ON: 207 handleAcStateUpdate(getValue(val)); 208 break; 209 case CarHvacManager.ID_ZONED_FAN_DIRECTION: 210 handleFanPositionUpdate(areaId, getValue(val)); 211 break; 212 case CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT: 213 handleFanSpeedUpdate(areaId, getValue(val)); 214 break; 215 case CarHvacManager.ID_ZONED_TEMP_SETPOINT: 216 handleTempUpdate(val); 217 break; 218 case CarHvacManager.ID_WINDOW_DEFROSTER_ON: 219 handleDefrosterUpdate(areaId, getValue(val)); 220 break; 221 case CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON: 222 handleAirCirculationUpdate(getValue(val)); 223 break; 224 case CarHvacManager.ID_ZONED_SEAT_TEMP: 225 handleSeatWarmerUpdate(areaId, getValue(val)); 226 break; 227 case CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON: 228 handleAutoModeUpdate(getValue(val)); 229 break; 230 case CarHvacManager.ID_ZONED_HVAC_POWER_ON: 231 handleHvacPowerOn(getValue(val)); 232 break; 233 default: 234 if (Log.isLoggable(TAG, Log.DEBUG)) { 235 Log.d(TAG, "Unhandled HVAC event, id: " + val.getPropertyId()); 236 } 237 } 238 } 239 240 @Override 241 public void onErrorEvent(final int propertyId, final int zone) { 242 } 243 }; 244 245 @SuppressWarnings("unchecked") getValue(CarPropertyValue propertyValue)246 public static <E> E getValue(CarPropertyValue propertyValue) { 247 return (E) propertyValue.getValue(); 248 } 249 isAvailable(CarPropertyValue propertyValue)250 public static boolean isAvailable(CarPropertyValue propertyValue) { 251 return propertyValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE; 252 } 253 handleHvacPowerOn(boolean isOn)254 void handleHvacPowerOn(boolean isOn) { 255 boolean shouldPropagate = mDataStore.shouldPropagateHvacPowerUpdate(isOn); 256 if (Log.isLoggable(TAG, Log.DEBUG)) { 257 Log.d(TAG, "Hvac Power On: " + isOn + " should propagate: " + shouldPropagate); 258 } 259 if (shouldPropagate) { 260 synchronized (mCallbacks) { 261 for (int i = 0; i < mCallbacks.size(); i++) { 262 mCallbacks.get(i).onHvacPowerChange(isOn); 263 } 264 } 265 } 266 } 267 handleSeatWarmerUpdate(int zone, int level)268 void handleSeatWarmerUpdate(int zone, int level) { 269 boolean shouldPropagate = mDataStore.shouldPropagateSeatWarmerLevelUpdate(zone, level); 270 if (Log.isLoggable(TAG, Log.DEBUG)) { 271 Log.d(TAG, "Seat Warmer Update, zone: " + zone + " level: " + level + 272 " should propagate: " + shouldPropagate); 273 } 274 if (shouldPropagate) { 275 synchronized (mCallbacks) { 276 for (int i = 0; i < mCallbacks.size(); i++) { 277 if (zone == VehicleAreaSeat.SEAT_ROW_1_LEFT) { 278 mCallbacks.get(i).onDriverSeatWarmerChange(level); 279 } else { 280 mCallbacks.get(i).onPassengerSeatWarmerChange(level); 281 } 282 } 283 } 284 } 285 } 286 handleAirCirculationUpdate(boolean airCirculationState)287 private void handleAirCirculationUpdate(boolean airCirculationState) { 288 boolean shouldPropagate 289 = mDataStore.shouldPropagateAirCirculationUpdate(airCirculationState); 290 if (Log.isLoggable(TAG, Log.DEBUG)) { 291 Log.d(TAG, "Air Circulation Update: " + airCirculationState + 292 " should propagate: " + shouldPropagate); 293 } 294 if (shouldPropagate) { 295 synchronized (mCallbacks) { 296 for (int i = 0; i < mCallbacks.size(); i++) { 297 mCallbacks.get(i).onAirCirculationChange(airCirculationState); 298 } 299 } 300 } 301 } 302 handleAutoModeUpdate(boolean autoModeState)303 private void handleAutoModeUpdate(boolean autoModeState) { 304 boolean shouldPropagate = mDataStore.shouldPropagateAutoModeUpdate(autoModeState); 305 if (Log.isLoggable(TAG, Log.DEBUG)) { 306 Log.d(TAG, "AutoMode Update, id: " + autoModeState + 307 " should propagate: " + shouldPropagate); 308 } 309 if (shouldPropagate) { 310 synchronized (mCallbacks) { 311 for (int i = 0; i < mCallbacks.size(); i++) { 312 mCallbacks.get(i).onAutoModeChange(autoModeState); 313 } 314 } 315 } 316 } 317 handleAcStateUpdate(boolean acState)318 private void handleAcStateUpdate(boolean acState) { 319 boolean shouldPropagate = mDataStore.shouldPropagateAcUpdate(acState); 320 if (Log.isLoggable(TAG, Log.DEBUG)) { 321 Log.d(TAG, "AC State Update, id: " + acState + 322 " should propagate: " + shouldPropagate); 323 } 324 if (shouldPropagate) { 325 synchronized (mCallbacks) { 326 for (int i = 0; i < mCallbacks.size(); i++) { 327 mCallbacks.get(i).onAcStateChange(acState); 328 } 329 } 330 } 331 } 332 handleFanPositionUpdate(int zone, int position)333 private void handleFanPositionUpdate(int zone, int position) { 334 int index = fanPositionToAirflowIndex(position); 335 boolean shouldPropagate = mDataStore.shouldPropagateFanPositionUpdate(zone, index); 336 if (Log.isLoggable(TAG, Log.DEBUG)) { 337 Log.d(TAG, "Fan Position Update, zone: " + zone + " position: " + position + 338 " should propagate: " + shouldPropagate); 339 } 340 if (shouldPropagate) { 341 synchronized (mCallbacks) { 342 for (int i = 0; i < mCallbacks.size(); i++) { 343 mCallbacks.get(i).onFanDirectionChange(position); 344 } 345 } 346 } 347 } 348 handleFanSpeedUpdate(int zone, int speed)349 private void handleFanSpeedUpdate(int zone, int speed) { 350 boolean shouldPropagate = mDataStore.shouldPropagateFanSpeedUpdate(zone, speed); 351 if (Log.isLoggable(TAG, Log.DEBUG)) { 352 Log.d(TAG, "Fan Speed Update, zone: " + zone + " speed: " + speed + 353 " should propagate: " + shouldPropagate); 354 } 355 if (shouldPropagate) { 356 synchronized (mCallbacks) { 357 for (int i = 0; i < mCallbacks.size(); i++) { 358 mCallbacks.get(i).onFanSpeedChange(speed); 359 } 360 } 361 } 362 } 363 handleTempUpdate(CarPropertyValue value)364 private void handleTempUpdate(CarPropertyValue value) { 365 final int zone = value.getAreaId(); 366 final float temp = (Float)value.getValue(); 367 final boolean available = value.getStatus() == CarPropertyValue.STATUS_AVAILABLE; 368 boolean shouldPropagate = mDataStore.shouldPropagateTempUpdate(zone, temp, available); 369 if (Log.isLoggable(TAG, Log.DEBUG)) { 370 Log.d(TAG, "Temp Update, zone: " + zone + " temp: " + temp + 371 "available: " + available + " should propagate: " + shouldPropagate); 372 } 373 if (shouldPropagate) { 374 int userTemperature = mPolicy.hardwareToUserTemp(temp); 375 synchronized (mCallbacks) { 376 for (int i = 0; i < mCallbacks.size(); i++) { 377 if (zone == VehicleAreaSeat.SEAT_ROW_1_LEFT) { 378 mCallbacks.get(i) 379 .onDriverTemperatureChange(value); 380 } else { 381 mCallbacks.get(i) 382 .onPassengerTemperatureChange(value); 383 } 384 } 385 } 386 } 387 } 388 handleDefrosterUpdate(int zone, boolean defrosterState)389 private void handleDefrosterUpdate(int zone, boolean defrosterState) { 390 boolean shouldPropagate = mDataStore.shouldPropagateDefrosterUpdate(zone, defrosterState); 391 if (Log.isLoggable(TAG, Log.DEBUG)) { 392 Log.d(TAG, "Defroster Update, zone: " + zone + " state: " + defrosterState + 393 " should propagate: " + shouldPropagate); 394 } 395 if (shouldPropagate) { 396 synchronized (mCallbacks) { 397 for (int i = 0; i < mCallbacks.size(); i++) { 398 if (zone == VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD) { 399 mCallbacks.get(i).onFrontDefrosterChange(defrosterState); 400 } else if (zone == VehicleAreaWindow.WINDOW_REAR_WINDSHIELD) { 401 mCallbacks.get(i).onRearDefrosterChange(defrosterState); 402 } 403 } 404 } 405 } 406 } 407 requestRefresh(final Runnable r, final Handler h)408 public void requestRefresh(final Runnable r, final Handler h) { 409 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 410 @Override 411 protected Void doInBackground(Void... unused) { 412 synchronized (mHvacManagerReady) { 413 while (mHvacManager == null) { 414 try { 415 mHvacManagerReady.wait(); 416 } catch (InterruptedException e) { 417 // We got interrupted so we might be shutting down. 418 return null; 419 } 420 } 421 } 422 fetchTemperature(DRIVER_ZONE_ID); 423 fetchTemperature(PASSENGER_ZONE_ID); 424 fetchFanSpeed(); 425 fetchDefrosterState(VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD); 426 fetchDefrosterState(VehicleAreaWindow.WINDOW_REAR_WINDSHIELD); 427 fetchAirflow(DRIVER_ZONE_ID); 428 fetchAirflow(PASSENGER_ZONE_ID); 429 fetchAcState(); 430 fetchAirCirculation(); 431 fetchHvacPowerState(); 432 return null; 433 } 434 435 @Override 436 protected void onPostExecute(Void unused) { 437 h.post(r); 438 } 439 }; 440 task.execute(); 441 } 442 getPolicy()443 public HvacPolicy getPolicy() { 444 return mPolicy; 445 } 446 isTemperatureControlAvailable(int zone)447 public boolean isTemperatureControlAvailable(int zone) { 448 if (mHvacManager != null) { 449 try { 450 return mHvacManager.isPropertyAvailable( 451 CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone); 452 } catch (android.car.CarNotConnectedException e) { 453 Log.e(TAG, "Car not connected in isTemperatureControlAvailable"); 454 } 455 } 456 457 return false; 458 } 459 isDriverTemperatureControlAvailable()460 public boolean isDriverTemperatureControlAvailable() { 461 return isTemperatureControlAvailable(DRIVER_ZONE_ID); 462 } 463 isPassengerTemperatureControlAvailable()464 public boolean isPassengerTemperatureControlAvailable() { 465 return isTemperatureControlAvailable(PASSENGER_ZONE_ID); 466 } 467 fetchTemperature(int zone)468 private void fetchTemperature(int zone) { 469 if (mHvacManager != null) { 470 try { 471 float value = mHvacManager.getFloatProperty( 472 CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone); 473 boolean available = mHvacManager.isPropertyAvailable( 474 CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone); 475 mDataStore.setTemperature(zone, value, available); 476 } catch (android.car.CarNotConnectedException e) { 477 Log.e(TAG, "Car not connected in fetchTemperature"); 478 } 479 } 480 } 481 getDriverTemperature()482 public int getDriverTemperature() { 483 return mPolicy.hardwareToUserTemp(mDataStore.getTemperature(DRIVER_ZONE_ID)); 484 } 485 getPassengerTemperature()486 public int getPassengerTemperature() { 487 return mPolicy.hardwareToUserTemp(mDataStore.getTemperature(PASSENGER_ZONE_ID)); 488 } 489 setDriverTemperature(int temperature)490 public void setDriverTemperature(int temperature) { 491 setTemperature(DRIVER_ZONE_ID, mPolicy.userToHardwareTemp(temperature)); 492 } 493 setPassengerTemperature(int temperature)494 public void setPassengerTemperature(int temperature) { 495 setTemperature(PASSENGER_ZONE_ID, mPolicy.userToHardwareTemp(temperature)); 496 } 497 setTemperature(final int zone, final float temperature)498 public void setTemperature(final int zone, final float temperature) { 499 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 500 protected Void doInBackground(Void... unused) { 501 if (mHvacManager != null) { 502 try { 503 mHvacManager.setFloatProperty( 504 CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone, temperature); 505 // if the set() succeeds, consider the property available 506 mDataStore.setTemperature(zone, temperature, true); 507 } catch (android.car.CarNotConnectedException e) { 508 Log.e(TAG, "Car not connected in setTemperature"); 509 } catch (Exception e) { 510 Log.e(TAG, "set temp failed", e); 511 } 512 } 513 return null; 514 } 515 }; 516 task.execute(); 517 } 518 setHvacPowerState(final boolean state)519 public void setHvacPowerState(final boolean state) { 520 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 521 protected Void doInBackground(Void... unused) { 522 if (mHvacManager != null) { 523 try { 524 mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_HVAC_POWER_ON, 525 SEAT_ALL, state); 526 // if the set() succeeds, consider the property available 527 mDataStore.setHvacPowerState(state); 528 } catch (android.car.CarNotConnectedException e) { 529 Log.e(TAG, "Car not connected in setHvacPowerState"); 530 } catch (Exception e) { 531 Log.e(TAG, "set power failed", e); 532 } 533 } 534 return null; 535 } 536 }; 537 task.execute(); 538 } 539 setDriverSeatWarmerLevel(int level)540 public void setDriverSeatWarmerLevel(int level) { 541 setSeatWarmerLevel(DRIVER_ZONE_ID, level); 542 } 543 setPassengerSeatWarmerLevel(int level)544 public void setPassengerSeatWarmerLevel(int level) { 545 setSeatWarmerLevel(PASSENGER_ZONE_ID, level); 546 } 547 setSeatWarmerLevel(final int zone, final int level)548 public void setSeatWarmerLevel(final int zone, final int level) { 549 mDataStore.setSeatWarmerLevel(zone, level); 550 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 551 protected Void doInBackground(Void... unused) { 552 if (mHvacManager != null) { 553 try { 554 mHvacManager.setIntProperty( 555 CarHvacManager.ID_ZONED_SEAT_TEMP, zone, level); 556 } catch (android.car.CarNotConnectedException e) { 557 Log.e(TAG, "Car not connected in setSeatWarmerLevel"); 558 } catch (Exception e) { 559 Log.e(TAG, "set seat warmer failed", e); 560 } 561 } 562 return null; 563 } 564 }; 565 task.execute(); 566 } 567 fetchFanSpeed()568 private void fetchFanSpeed() { 569 if (mHvacManager != null) { 570 int zone = SEAT_ALL; // Car specific workaround. 571 try { 572 mDataStore.setFanSpeed(mHvacManager.getIntProperty( 573 CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, zone)); 574 } catch (android.car.CarNotConnectedException e) { 575 Log.e(TAG, "Car not connected in fetchFanSpeed"); 576 } 577 } 578 } 579 getFanSpeed()580 public int getFanSpeed() { 581 return mDataStore.getFanSpeed(); 582 } 583 setFanSpeed(final int fanSpeed)584 public void setFanSpeed(final int fanSpeed) { 585 mDataStore.setFanSpeed(fanSpeed); 586 587 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 588 int newFanSpeed; 589 590 protected Void doInBackground(Void... unused) { 591 if (mHvacManager != null) { 592 int zone = SEAT_ALL; // Car specific workaround. 593 try { 594 if (Log.isLoggable(TAG, Log.DEBUG)) { 595 Log.d(TAG, "Setting fanspeed to: " + fanSpeed); 596 } 597 mHvacManager.setIntProperty( 598 CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, zone, fanSpeed); 599 600 newFanSpeed = mHvacManager.getIntProperty( 601 CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, zone); 602 } catch (android.car.CarNotConnectedException e) { 603 Log.e(TAG, "Car not connected in setFanSpeed"); 604 } 605 } 606 return null; 607 } 608 609 @Override 610 protected void onPostExecute(final Void result) { 611 Log.e(TAG, "postExecute new fanSpeed: " + newFanSpeed); 612 } 613 }; 614 task.execute(); 615 } 616 fetchDefrosterState(int zone)617 private void fetchDefrosterState(int zone) { 618 if (mHvacManager != null) { 619 try { 620 mDataStore.setDefrosterState(zone, mHvacManager.getBooleanProperty( 621 CarHvacManager.ID_WINDOW_DEFROSTER_ON, zone)); 622 } catch (android.car.CarNotConnectedException e) { 623 Log.e(TAG, "Car not connected in fetchDefrosterState"); 624 } 625 } 626 } 627 getFrontDefrosterState()628 public boolean getFrontDefrosterState() { 629 return mDataStore.getDefrosterState(VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD); 630 } 631 getRearDefrosterState()632 public boolean getRearDefrosterState() { 633 return mDataStore.getDefrosterState(VehicleAreaWindow.WINDOW_REAR_WINDSHIELD); 634 } 635 setFrontDefrosterState(boolean state)636 public void setFrontDefrosterState(boolean state) { 637 setDefrosterState(VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD, state); 638 } 639 setRearDefrosterState(boolean state)640 public void setRearDefrosterState(boolean state) { 641 setDefrosterState(VehicleAreaWindow.WINDOW_REAR_WINDSHIELD, state); 642 } 643 setDefrosterState(final int zone, final boolean state)644 public void setDefrosterState(final int zone, final boolean state) { 645 mDataStore.setDefrosterState(zone, state); 646 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 647 protected Void doInBackground(Void... unused) { 648 if (mHvacManager != null) { 649 try { 650 mHvacManager.setBooleanProperty( 651 CarHvacManager.ID_WINDOW_DEFROSTER_ON, zone, state); 652 } catch (android.car.CarNotConnectedException e) { 653 Log.e(TAG, "Car not connected in setDeforsterState"); 654 } 655 } 656 return null; 657 } 658 }; 659 task.execute(); 660 } 661 fetchAcState()662 private void fetchAcState() { 663 if (mHvacManager != null) { 664 try { 665 mDataStore.setAcState(mHvacManager.getBooleanProperty(CarHvacManager.ID_ZONED_AC_ON, 666 SEAT_ALL)); 667 } catch (android.car.CarNotConnectedException e) { 668 Log.e(TAG, "Car not connected in fetchAcState"); 669 } 670 } 671 } 672 getAcState()673 public boolean getAcState() { 674 return mDataStore.getAcState(); 675 } 676 setAcState(final boolean state)677 public void setAcState(final boolean state) { 678 mDataStore.setAcState(state); 679 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 680 protected Void doInBackground(Void... unused) { 681 if (mHvacManager != null) { 682 try { 683 mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_AC_ON, 684 SEAT_ALL, state); 685 } catch (android.car.CarNotConnectedException e) { 686 Log.e(TAG, "Car not connected in setAcState"); 687 } 688 } 689 return null; 690 } 691 }; 692 task.execute(); 693 } 694 fanPositionToAirflowIndex(int fanPosition)695 private int fanPositionToAirflowIndex(int fanPosition) { 696 for (int i = 0; i < AIRFLOW_STATES.length; i++) { 697 if (fanPosition == AIRFLOW_STATES[i]) { 698 return i; 699 } 700 } 701 Log.e(TAG, "Unknown fan position " + fanPosition + ". Returning default."); 702 return AIRFLOW_STATES[0]; 703 } 704 fetchAirflow(int zone)705 private void fetchAirflow(int zone) { 706 if (mHvacManager != null) { 707 zone = SEAT_ALL; // Car specific workaround. 708 try { 709 int val = mHvacManager.getIntProperty(CarHvacManager.ID_ZONED_FAN_DIRECTION, zone); 710 mDataStore.setAirflow(zone, fanPositionToAirflowIndex(val)); 711 } catch (android.car.CarNotConnectedException e) { 712 Log.e(TAG, "Car not connected in fetchAirFlow"); 713 } 714 } 715 } 716 getAirflowIndex(int zone)717 public int getAirflowIndex(int zone) { 718 return mDataStore.getAirflow(zone); 719 } 720 setAirflowIndex(final int zone, final int index)721 public void setAirflowIndex(final int zone, final int index) { 722 mDataStore.setAirflow(zone, index); 723 int override = SEAT_ALL; // Car specific workaround. 724 int val = AIRFLOW_STATES[index]; 725 setFanDirection(override, val); 726 } 727 setFanDirection(final int direction)728 public void setFanDirection(final int direction) { 729 mDataStore.setAirflow(SEAT_ALL, direction); 730 setFanDirection(SEAT_ALL, direction); 731 } 732 setFanDirection(final int zone, final int direction)733 private void setFanDirection(final int zone, final int direction) { 734 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 735 protected Void doInBackground(Void... unused) { 736 if (mHvacManager != null) { 737 try { 738 mHvacManager.setIntProperty( 739 CarHvacManager.ID_ZONED_FAN_DIRECTION, zone, direction); 740 } catch (android.car.CarNotConnectedException e) { 741 Log.e(TAG, "Car not connected in setAirflowIndex"); 742 } 743 } 744 return null; 745 } 746 }; 747 task.execute(); 748 } 749 750 fetchAirCirculation()751 private void fetchAirCirculation() { 752 if (mHvacManager != null) { 753 try { 754 mDataStore.setAirCirculationState(mHvacManager 755 .getBooleanProperty(CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON, 756 SEAT_ALL)); 757 } catch (android.car.CarNotConnectedException e) { 758 Log.e(TAG, "Car not connected in fetchAirCirculationState"); 759 } 760 } 761 } 762 getAirCirculationState()763 public boolean getAirCirculationState() { 764 return mDataStore.getAirCirculationState(); 765 } 766 setAirCirculation(final boolean state)767 public void setAirCirculation(final boolean state) { 768 mDataStore.setAirCirculationState(state); 769 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 770 protected Void doInBackground(Void... unused) { 771 if (mHvacManager != null) { 772 try { 773 mHvacManager.setBooleanProperty( 774 CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON, 775 SEAT_ALL, state); 776 } catch (android.car.CarNotConnectedException e) { 777 Log.e(TAG, "Car not connected in setAcState"); 778 } 779 } 780 return null; 781 } 782 }; 783 task.execute(); 784 } 785 getAutoModeState()786 public boolean getAutoModeState() { 787 return mDataStore.getAutoModeState(); 788 } 789 setAutoMode(final boolean state)790 public void setAutoMode(final boolean state) { 791 mDataStore.setAutoModeState(state); 792 final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() { 793 protected Void doInBackground(Void... unused) { 794 if (mHvacManager != null) { 795 try { 796 mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON, 797 SEAT_ALL, state); 798 } catch (android.car.CarNotConnectedException e) { 799 Log.e(TAG, "Car not connected in setAutoModeState"); 800 } 801 } 802 return null; 803 } 804 }; 805 task.execute(); 806 } 807 getHvacPowerState()808 public boolean getHvacPowerState() { 809 return mDataStore.getHvacPowerState(); 810 } 811 fetchHvacPowerState()812 private void fetchHvacPowerState() { 813 if (mHvacManager != null) { 814 try { 815 mDataStore.setHvacPowerState(mHvacManager.getBooleanProperty( 816 CarHvacManager.ID_ZONED_HVAC_POWER_ON, SEAT_ALL)); 817 } catch (android.car.CarNotConnectedException e) { 818 Log.e(TAG, "Car not connected in fetchHvacPowerState"); 819 } 820 } 821 } 822 } 823