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