• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         boolean shouldPropagate = mDataStore.shouldPropagateHvacPowerUpdate(isOn);
247         if (Log.isLoggable(TAG, Log.DEBUG)) {
248             Log.d(TAG, "Hvac Power On: " + isOn + " should propagate: " + shouldPropagate);
249         }
250         if (shouldPropagate) {
251             synchronized (mCallbacks) {
252                 for (int i = 0; i < mCallbacks.size(); i++) {
253                     mCallbacks.get(i).onHvacPowerChange(isOn);
254                 }
255             }
256         }
257     }
258 
handleSeatWarmerUpdate(int zone, int level)259     void handleSeatWarmerUpdate(int zone, int level) {
260         boolean shouldPropagate = mDataStore.shouldPropagateSeatWarmerLevelUpdate(zone, level);
261         if (Log.isLoggable(TAG, Log.DEBUG)) {
262             Log.d(TAG, "Seat Warmer Update, zone: " + zone + " level: " + level +
263                     " should propagate: " + shouldPropagate);
264         }
265         if (shouldPropagate) {
266             synchronized (mCallbacks) {
267                 for (int i = 0; i < mCallbacks.size(); i++) {
268                     if (zone == VehicleZone.ZONE_ROW_1_LEFT) {
269                         mCallbacks.get(i).onDriverSeatWarmerChange(level);
270                     } else {
271                         mCallbacks.get(i).onPassengerSeatWarmerChange(level);
272                     }
273                 }
274             }
275         }
276     }
277 
handleAirCirculationUpdate(boolean airCirculationState)278     private void handleAirCirculationUpdate(boolean airCirculationState) {
279         boolean shouldPropagate
280                 = mDataStore.shouldPropagateAirCirculationUpdate(airCirculationState);
281         if (Log.isLoggable(TAG, Log.DEBUG)) {
282             Log.d(TAG, "Air Circulation Update: " + airCirculationState +
283                     " should propagate: " + shouldPropagate);
284         }
285         if (shouldPropagate) {
286             synchronized (mCallbacks) {
287                 for (int i = 0; i < mCallbacks.size(); i++) {
288                     mCallbacks.get(i).onAirCirculationChange(airCirculationState);
289                 }
290             }
291         }
292     }
293 
handleAutoModeUpdate(boolean autoModeState)294     private void handleAutoModeUpdate(boolean autoModeState) {
295         boolean shouldPropagate = mDataStore.shouldPropagateAutoModeUpdate(autoModeState);
296         if (Log.isLoggable(TAG, Log.DEBUG)) {
297             Log.d(TAG, "AutoMode Update, id: " + autoModeState +
298                     " should propagate: " + shouldPropagate);
299         }
300         if (shouldPropagate) {
301             synchronized (mCallbacks) {
302                 for (int i = 0; i < mCallbacks.size(); i++) {
303                     mCallbacks.get(i).onAutoModeChange(autoModeState);
304                 }
305             }
306         }
307     }
308 
handleAcStateUpdate(boolean acState)309     private void handleAcStateUpdate(boolean acState) {
310         boolean shouldPropagate = mDataStore.shouldPropagateAcUpdate(acState);
311         if (Log.isLoggable(TAG, Log.DEBUG)) {
312             Log.d(TAG, "AC State Update, id: " + acState +
313                     " should propagate: " + shouldPropagate);
314         }
315         if (shouldPropagate) {
316             synchronized (mCallbacks) {
317                 for (int i = 0; i < mCallbacks.size(); i++) {
318                     mCallbacks.get(i).onAcStateChange(acState);
319                 }
320             }
321         }
322     }
323 
handleFanPositionUpdate(int zone, int position)324     private void handleFanPositionUpdate(int zone, int position) {
325         int index = fanPositionToAirflowIndex(position);
326         boolean shouldPropagate = mDataStore.shouldPropagateFanPositionUpdate(zone, index);
327         if (Log.isLoggable(TAG, Log.DEBUG)) {
328             Log.d(TAG, "Fan Position Update, zone: " + zone + " position: " + position +
329                     " should propagate: " + shouldPropagate);
330         }
331         if (shouldPropagate) {
332             synchronized (mCallbacks) {
333                 for (int i = 0; i < mCallbacks.size(); i++) {
334                     mCallbacks.get(i).onFanDirectionChange(position);
335                 }
336             }
337         }
338     }
339 
handleFanSpeedUpdate(int zone, int speed)340     private void handleFanSpeedUpdate(int zone, int speed) {
341         boolean shouldPropagate = mDataStore.shouldPropagateFanSpeedUpdate(zone, speed);
342         if (Log.isLoggable(TAG, Log.DEBUG)) {
343             Log.d(TAG, "Fan Speed Update, zone: " + zone + " speed: " + speed +
344                     " should propagate: " + shouldPropagate);
345         }
346         if (shouldPropagate) {
347             synchronized (mCallbacks) {
348                 for (int i = 0; i < mCallbacks.size(); i++) {
349                     mCallbacks.get(i).onFanSpeedChange(speed);
350                 }
351             }
352         }
353     }
354 
handleTempUpdate(int zone, float temp)355     private void handleTempUpdate(int zone, float temp) {
356         boolean shouldPropagate = mDataStore.shouldPropagateTempUpdate(zone, temp);
357         if (Log.isLoggable(TAG, Log.DEBUG)) {
358             Log.d(TAG, "Temp Update, zone: " + zone + " temp: " + temp +
359                     " should propagate: " + shouldPropagate);
360         }
361         if (shouldPropagate) {
362             int userTemperature =  mPolicy.hardwareToUserTemp(temp);
363             synchronized (mCallbacks) {
364                 for (int i = 0; i < mCallbacks.size(); i++) {
365                     if (zone == VehicleZone.ZONE_ROW_1_LEFT) {
366                         mCallbacks.get(i)
367                                 .onDriverTemperatureChange(userTemperature);
368                     } else {
369                         mCallbacks.get(i)
370                                 .onPassengerTemperatureChange(userTemperature);
371                     }
372                 }
373             }
374         }
375     }
376 
handleDefrosterUpdate(int zone, boolean defrosterState)377     private void handleDefrosterUpdate(int zone, boolean defrosterState) {
378         boolean shouldPropagate = mDataStore.shouldPropagateDefrosterUpdate(zone, defrosterState);
379         if (Log.isLoggable(TAG, Log.DEBUG)) {
380             Log.d(TAG, "Defroster Update, zone: " + zone + " state: " + defrosterState +
381                     " should propagate: " + shouldPropagate);
382         }
383         if (shouldPropagate) {
384             synchronized (mCallbacks) {
385                 for (int i = 0; i < mCallbacks.size(); i++) {
386                     if (zone == VehicleWindow.WINDOW_FRONT_WINDSHIELD) {
387                         mCallbacks.get(i).onFrontDefrosterChange(defrosterState);
388                     } else if (zone == VehicleWindow.WINDOW_REAR_WINDSHIELD) {
389                         mCallbacks.get(i).onRearDefrosterChange(defrosterState);
390                     }
391                 }
392             }
393         }
394     }
395 
requestRefresh(final Runnable r, final Handler h)396     public void requestRefresh(final Runnable r, final Handler h) {
397         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
398             @Override
399             protected Void doInBackground(Void... unused) {
400                 synchronized (mHvacManagerReady) {
401                     while (mHvacManager == null) {
402                         try {
403                             mHvacManagerReady.wait();
404                         } catch (InterruptedException e) {
405                             // We got interrupted so we might be shutting down.
406                             return null;
407                         }
408                     }
409                 }
410                 fetchTemperature(DRIVER_ZONE_ID);
411                 fetchTemperature(PASSENGER_ZONE_ID);
412                 fetchFanSpeed();
413                 fetchDefrosterState(VehicleWindow.WINDOW_FRONT_WINDSHIELD);
414                 fetchDefrosterState(VehicleWindow.WINDOW_REAR_WINDSHIELD);
415                 fetchAirflow(DRIVER_ZONE_ID);
416                 fetchAirflow(PASSENGER_ZONE_ID);
417                 fetchAcState();
418                 fetchAirCirculation();
419                 fetchHvacPowerState();
420                 return null;
421             }
422 
423             @Override
424             protected void onPostExecute(Void unused) {
425                 h.post(r);
426             }
427         };
428         task.execute();
429     }
430 
getPolicy()431     public HvacPolicy getPolicy() {
432         return mPolicy;
433     }
434 
fetchTemperature(int zone)435     private void fetchTemperature(int zone) {
436         if (mHvacManager != null) {
437             try {
438                 mDataStore.setTemperature(zone, mHvacManager.getFloatProperty(
439                         CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone));
440             } catch (android.car.CarNotConnectedException e) {
441                 Log.e(TAG, "Car not connected in fetchTemperature");
442             }
443         }
444     }
445 
getDriverTemperature()446     public int getDriverTemperature() {
447         return mPolicy.hardwareToUserTemp(mDataStore.getTemperature(DRIVER_ZONE_ID));
448     }
449 
getPassengerTemperature()450     public int getPassengerTemperature() {
451         return mPolicy.hardwareToUserTemp(mDataStore.getTemperature(PASSENGER_ZONE_ID));
452     }
453 
setDriverTemperature(int temperature)454     public void setDriverTemperature(int temperature) {
455         setTemperature(DRIVER_ZONE_ID, mPolicy.userToHardwareTemp(temperature));
456     }
457 
setPassengerTemperature(int temperature)458     public void setPassengerTemperature(int temperature) {
459         setTemperature(PASSENGER_ZONE_ID, mPolicy.userToHardwareTemp(temperature));
460     }
461 
setTemperature(final int zone, final float temperature)462     public void setTemperature(final int zone, final float temperature) {
463         mDataStore.setTemperature(zone, temperature);
464         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
465             protected Void doInBackground(Void... unused) {
466                 if (mHvacManager != null) {
467                     try {
468                         mHvacManager.setFloatProperty(
469                                 CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone, temperature);
470                     } catch (android.car.CarNotConnectedException e) {
471                         Log.e(TAG, "Car not connected in setTemperature");
472                     }
473                 }
474                 return null;
475             }
476         };
477         task.execute();
478     }
479 
setDriverSeatWarmerLevel(int level)480     public void setDriverSeatWarmerLevel(int level) {
481         setSeatWarmerLevel(DRIVER_ZONE_ID, level);
482     }
483 
setPassengerSeatWarmerLevel(int level)484     public void setPassengerSeatWarmerLevel(int level) {
485         setSeatWarmerLevel(PASSENGER_ZONE_ID, level);
486     }
487 
setSeatWarmerLevel(final int zone, final int level)488     public void setSeatWarmerLevel(final int zone, final int level) {
489         mDataStore.setSeatWarmerLevel(zone, level);
490         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
491             protected Void doInBackground(Void... unused) {
492                 if (mHvacManager != null) {
493                     try {
494                         mHvacManager.setIntProperty(
495                                 CarHvacManager.ID_ZONED_SEAT_TEMP, zone, level);
496                     } catch (android.car.CarNotConnectedException e) {
497                         Log.e(TAG, "Car not connected in setSeatWarmerLevel");
498                     }
499                 }
500                 return null;
501             }
502         };
503         task.execute();
504     }
505 
fetchFanSpeed()506     private void fetchFanSpeed() {
507         if (mHvacManager != null) {
508             int zone = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
509             try {
510                 mDataStore.setFanSpeed(mHvacManager.getIntProperty(
511                         CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, zone));
512             } catch (android.car.CarNotConnectedException e) {
513                 Log.e(TAG, "Car not connected in fetchFanSpeed");
514             }
515         }
516     }
517 
getFanSpeed()518     public int getFanSpeed() {
519         return mDataStore.getFanSpeed();
520     }
521 
setFanSpeed(final int fanSpeed)522     public void setFanSpeed(final int fanSpeed) {
523         mDataStore.setFanSpeed(fanSpeed);
524 
525         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
526             int newFanSpeed;
527 
528             protected Void doInBackground(Void... unused) {
529                 if (mHvacManager != null) {
530                     int zone = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
531                     try {
532                         if (Log.isLoggable(TAG, Log.DEBUG)) {
533                             Log.d(TAG, "Setting fanspeed to: " + fanSpeed);
534                         }
535                         mHvacManager.setIntProperty(
536                                 CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, zone, fanSpeed);
537 
538                         newFanSpeed = mHvacManager.getIntProperty(
539                                 CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, zone);
540                     } catch (android.car.CarNotConnectedException e) {
541                         Log.e(TAG, "Car not connected in setFanSpeed");
542                     }
543                 }
544                 return null;
545             }
546 
547             @Override
548             protected void onPostExecute(final Void result) {
549                 Log.e(TAG, "postExecute new fanSpeed: " + newFanSpeed);
550             }
551         };
552         task.execute();
553     }
554 
fetchDefrosterState(int zone)555     private void fetchDefrosterState(int zone) {
556         if (mHvacManager != null) {
557             try {
558                 mDataStore.setDefrosterState(zone, mHvacManager.getBooleanProperty(
559                         CarHvacManager.ID_WINDOW_DEFROSTER_ON, zone));
560             } catch (android.car.CarNotConnectedException e) {
561                 Log.e(TAG, "Car not connected in fetchDefrosterState");
562             }
563         }
564     }
565 
getFrontDefrosterState()566     public boolean getFrontDefrosterState() {
567         return mDataStore.getDefrosterState(VehicleWindow.WINDOW_FRONT_WINDSHIELD);
568     }
569 
getRearDefrosterState()570     public boolean getRearDefrosterState() {
571         return mDataStore.getDefrosterState(VehicleWindow.WINDOW_REAR_WINDSHIELD);
572     }
573 
setFrontDefrosterState(boolean state)574     public void setFrontDefrosterState(boolean state) {
575         setDefrosterState(VehicleWindow.WINDOW_FRONT_WINDSHIELD, state);
576     }
577 
setRearDefrosterState(boolean state)578     public void setRearDefrosterState(boolean state) {
579         setDefrosterState(VehicleWindow.WINDOW_REAR_WINDSHIELD, state);
580     }
581 
setDefrosterState(final int zone, final boolean state)582     public void setDefrosterState(final int zone, final boolean state) {
583         mDataStore.setDefrosterState(zone, state);
584         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
585             protected Void doInBackground(Void... unused) {
586                 if (mHvacManager != null) {
587                     try {
588                         mHvacManager.setBooleanProperty(
589                                 CarHvacManager.ID_WINDOW_DEFROSTER_ON, zone, state);
590                     } catch (android.car.CarNotConnectedException e) {
591                         Log.e(TAG, "Car not connected in setDeforsterState");
592                     }
593                 }
594                 return null;
595             }
596         };
597         task.execute();
598     }
599 
fetchAcState()600     private void fetchAcState() {
601         if (mHvacManager != null) {
602             try {
603                 mDataStore.setAcState(mHvacManager.getBooleanProperty(CarHvacManager.ID_ZONED_AC_ON,
604                         VehicleZone.ZONE_ROW_1_ALL));
605             } catch (android.car.CarNotConnectedException e) {
606                 Log.e(TAG, "Car not connected in fetchAcState");
607             }
608         }
609     }
610 
getAcState()611     public boolean getAcState() {
612         return mDataStore.getAcState();
613     }
614 
setAcState(final boolean state)615     public void setAcState(final boolean state) {
616         mDataStore.setAcState(state);
617         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
618             protected Void doInBackground(Void... unused) {
619                 if (mHvacManager != null) {
620                     try {
621                         mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_AC_ON,
622                                 VehicleZone.ZONE_ROW_1_ALL, state);
623                     } catch (android.car.CarNotConnectedException e) {
624                         Log.e(TAG, "Car not connected in setAcState");
625                     }
626                 }
627                 return null;
628             }
629         };
630         task.execute();
631     }
632 
fanPositionToAirflowIndex(int fanPosition)633     private int fanPositionToAirflowIndex(int fanPosition) {
634         for (int i = 0; i < AIRFLOW_STATES.length; i++) {
635             if (fanPosition == AIRFLOW_STATES[i]) {
636                 return i;
637             }
638         }
639         Log.e(TAG, "Unknown fan position " + fanPosition + ". Returning default.");
640         return AIRFLOW_STATES[0];
641     }
642 
fetchAirflow(int zone)643     private void fetchAirflow(int zone) {
644         if (mHvacManager != null) {
645             zone = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
646             try {
647                 int val = mHvacManager.getIntProperty(CarHvacManager.ID_ZONED_FAN_POSITION, zone);
648                 mDataStore.setAirflow(zone, fanPositionToAirflowIndex(val));
649             } catch (android.car.CarNotConnectedException e) {
650                 Log.e(TAG, "Car not connected in fetchAirFlow");
651             }
652         }
653     }
654 
getAirflowIndex(int zone)655     public int getAirflowIndex(int zone) {
656         return mDataStore.getAirflow(zone);
657     }
658 
setAirflowIndex(final int zone, final int index)659     public void setAirflowIndex(final int zone, final int index) {
660         mDataStore.setAirflow(zone, index);
661         int override = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
662         int val = AIRFLOW_STATES[index];
663         setFanDirection(override, val);
664     }
665 
setFanDirection(final int direction)666     public void setFanDirection(final int direction) {
667         mDataStore.setAirflow(VehicleZone.ZONE_ROW_1_ALL, direction);
668         setFanDirection(VehicleZone.ZONE_ROW_1_ALL, direction);
669     }
670 
setFanDirection(final int zone, final int direction)671     private void setFanDirection(final int zone, final int direction) {
672         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
673             protected Void doInBackground(Void... unused) {
674                 if (mHvacManager != null) {
675                     try {
676                         mHvacManager.setIntProperty(
677                                 CarHvacManager.ID_ZONED_FAN_POSITION, zone, direction);
678                     } catch (android.car.CarNotConnectedException e) {
679                         Log.e(TAG, "Car not connected in setAirflowIndex");
680                     }
681                 }
682                 return null;
683             }
684         };
685         task.execute();
686     }
687 
688 
fetchAirCirculation()689     private void fetchAirCirculation() {
690         if (mHvacManager != null) {
691             try {
692                 mDataStore.setAirCirculationState(mHvacManager
693                         .getBooleanProperty(CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON,
694                                 VehicleZone.ZONE_ROW_1_ALL));
695             } catch (android.car.CarNotConnectedException e) {
696                 Log.e(TAG, "Car not connected in fetchAirCirculationState");
697             }
698         }
699     }
700 
getAirCirculationState()701     public boolean getAirCirculationState() {
702         return mDataStore.getAirCirculationState();
703     }
704 
setAirCirculation(final boolean state)705     public void setAirCirculation(final boolean state) {
706         mDataStore.setAirCirculationState(state);
707         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
708             protected Void doInBackground(Void... unused) {
709                 if (mHvacManager != null) {
710                     try {
711                         mHvacManager.setBooleanProperty(
712                                 CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON,
713                                 VehicleZone.ZONE_ROW_1_ALL, state);
714                     } catch (android.car.CarNotConnectedException e) {
715                         Log.e(TAG, "Car not connected in setAcState");
716                     }
717                 }
718                 return null;
719             }
720         };
721         task.execute();
722     }
723 
getAutoModeState()724     public boolean getAutoModeState() {
725         return mDataStore.getAutoModeState();
726     }
727 
setAutoMode(final boolean state)728     public void setAutoMode(final boolean state) {
729         mDataStore.setAutoModeState(state);
730         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
731             protected Void doInBackground(Void... unused) {
732                 if (mHvacManager != null) {
733                     try {
734                         mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON,
735                                 VehicleZone.ZONE_ROW_1_ALL, state);
736                     } catch (android.car.CarNotConnectedException e) {
737                         Log.e(TAG, "Car not connected in setAutoModeState");
738                     }
739                 }
740                 return null;
741             }
742         };
743         task.execute();
744     }
745 
getHvacPowerState()746     public boolean getHvacPowerState() {
747         return mDataStore.getHvacPowerState();
748     }
749 
fetchHvacPowerState()750     private void fetchHvacPowerState() {
751         if (mHvacManager != null) {
752             try {
753                 mDataStore.setHvacPowerState(mHvacManager.getBooleanProperty(
754                         CarHvacManager.ID_ZONED_HVAC_POWER_ON, VehicleZone.ZONE_ROW_1_ALL));
755             } catch (android.car.CarNotConnectedException e) {
756                 Log.e(TAG, "Car not connected in fetchHvacPowerState");
757             }
758         }
759     }
760 }
761