Merge Android Pie into master

Bug: 112104996
Change-Id: I75c47ad731d384a75130ecfffa4ebf6b50b66899
diff --git a/Android.mk b/Android.mk
index 5f91b42..76449fc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -33,9 +33,14 @@
 
 LOCAL_PRIVILEGED_MODULE := true
 
-LOCAL_STATIC_JAVA_LIBRARIES += jsr305
+LOCAL_JAVA_LIBRARIES += android.car
 
-LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES += jsr305 \
+    android.support.car
+
+LOCAL_STATIC_ANDROID_LIBRARIES += \
+    androidx.car_car \
+    androidx.legacy_legacy-support-v4
 
 LOCAL_USE_AAPT2 := true
 
@@ -43,9 +48,6 @@
 
 LOCAL_DEX_PREOPT := false
 
-include packages/apps/Car/libs/car-stream-ui-lib/car-stream-ui-lib.mk
-include packages/services/Car/car-support-lib/car-support.mk
-
 include $(BUILD_PACKAGE)
 
 endif
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 361e97a..81a688e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -21,10 +21,15 @@
         android:minSdkVersion="22"
         android:targetSdkVersion="23"/>
 
-    <uses-permission android:name="android.car.permission.CAR_HVAC" />
+    <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <!-- Required to use the TYPE_DISPLAY_OVERLAY layout param for the overlay hvac ui-->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+    <!-- Allow Hvac to go across all users-->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
+    <protected-broadcast android:name="android.car.intent.action.TOGGLE_HVAC_CONTROLS" />
 
     <application android:label="@string/hvac_label"
         android:icon="@drawable/ic_launcher_hvac"
diff --git a/res/drawable/ac_master_switch_off.png b/res/drawable/ac_master_switch_off.png
new file mode 100644
index 0000000..976985f
--- /dev/null
+++ b/res/drawable/ac_master_switch_off.png
Binary files differ
diff --git a/res/drawable/ac_master_switch_on.png b/res/drawable/ac_master_switch_on.png
new file mode 100644
index 0000000..ce9879d
--- /dev/null
+++ b/res/drawable/ac_master_switch_on.png
Binary files differ
diff --git a/res/drawable/ripple_background.xml b/res/drawable/ripple_background.xml
index 3bda80d..7bfa09a 100644
--- a/res/drawable/ripple_background.xml
+++ b/res/drawable/ripple_background.xml
@@ -16,5 +16,5 @@
 */
 -->
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        android:color="@color/car_card_ripple_light_color_background">
+        android:color="@color/car_card_ripple_background">
 </ripple>
diff --git a/res/layout/hvac_panel.xml b/res/layout/hvac_panel.xml
index b32c73d..3670099 100644
--- a/res/layout/hvac_panel.xml
+++ b/res/layout/hvac_panel.xml
@@ -109,6 +109,11 @@
                 android:translationY="@dimen/hvac_panel_row_animation_height_shift"

                 android:layout_marginTop="@dimen/hvac_panel_margin"

                 android:layout_marginBottom="@dimen/hvac_panel_row_margin">

+            <com.android.car.hvac.ui.ToggleButton

+                    android:id="@+id/hvac_master_switch"

+                    android:background="@drawable/hvac_panel_button_bg"

+                    android:layout_marginStart="@dimen/hvac_panel_margin"

+                    style="@style/HvacButton"/>

             <com.android.car.hvac.ui.SeatWarmerButton

                     android:id="@+id/left_seat_heater"

                     android:src="@drawable/ic_seat_heat_off"

diff --git a/res/layout/hvac_temperature_bar_overlay.xml b/res/layout/hvac_temperature_bar_overlay.xml
index c2df692..274a57c 100644
--- a/res/layout/hvac_temperature_bar_overlay.xml
+++ b/res/layout/hvac_temperature_bar_overlay.xml
@@ -44,7 +44,7 @@
     <FrameLayout
             xmlns:android="http://schemas.android.com/apk/res/android"
             android:id="@+id/temperature_bar"
-            android:layout_gravity="center_horizontal"
+            android:layout_gravity="center_horizontal|bottom"
             android:layout_width="@dimen/temperature_bar_width_collapsed"
             android:layout_height="@dimen/temperature_bar_collapsed_height"
             android:background="@drawable/temperature_bar_background">
diff --git a/res/layout/system_ui_observer.xml b/res/layout/system_ui_observer.xml
deleted file mode 100644
index 6b8d9c0..0000000
--- a/res/layout/system_ui_observer.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.android.car.hvac.ui.SystemUiObserver xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-</com.android.car.hvac.ui.SystemUiObserver>
-
diff --git a/res/values/config.xml b/res/values/config.xml
index f4d844d..e1aa19e 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -19,4 +19,8 @@
     <bool name="config_hardwareUsesCelsius">true</bool>
     <!-- This should really be configurable using settings but config will do for now. -->
     <bool name="config_userUsesCelsius">false</bool>
+    <!-- This is temporary flag instead of removing the functionality altogether as the system
+     ui is updated. It hides the semi-circle click targets/temp indicators that overlay
+     the system nav bar.-->
+    <bool name="config_showCollapsedBars">false</bool>
 </resources>
diff --git a/src/com/android/car/hvac/DataStore.java b/src/com/android/car/hvac/DataStore.java
index b6b071e..4a234e2 100644
--- a/src/com/android/car/hvac/DataStore.java
+++ b/src/com/android/car/hvac/DataStore.java
@@ -16,6 +16,7 @@
 package com.android.car.hvac;
 
 import android.os.SystemClock;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
@@ -35,6 +36,8 @@
 
     @GuardedBy("mTemperature")
     private SparseArray<Float> mTemperature = new SparseArray<Float>();
+    @GuardedBy("mTemperatureAvailable")
+    private SparseBooleanArray mTemperatureAvailable = new SparseBooleanArray();
     @GuardedBy("mFanSpeed")
     private Integer mFanSpeed = 0;
     @GuardedBy("mAirflow")
@@ -78,19 +81,27 @@
         }
     }
 
-    public void setTemperature(int zone, float temperature) {
+    public void setTemperature(int zone, float temperature, boolean available) {
         synchronized (mTemperature) {
-            mTemperature.put(zone, temperature);
-            mLastTemperatureSet.put(zone, SystemClock.uptimeMillis());
+            synchronized (mTemperatureAvailable) {
+                Log.d("HvacDataStore", "setTemperature(" + zone + ", " + temperature + ")");
+                mTemperature.put(zone, temperature);
+                mTemperatureAvailable.put(zone, available);
+                mLastTemperatureSet.put(zone, SystemClock.uptimeMillis());
+            }
         }
     }
 
-    public boolean shouldPropagateTempUpdate(int zone, float temperature) {
+    public boolean shouldPropagateTempUpdate(int zone, float temperature, boolean available) {
         synchronized (mTemperature) {
-            if (SystemClock.uptimeMillis() - mLastTemperatureSet.get(zone) < COALESCE_TIME_MS) {
-                return false;
+            synchronized (mTemperatureAvailable) {
+                if (SystemClock.uptimeMillis() - mLastTemperatureSet.get(zone) < COALESCE_TIME_MS) {
+                    if (available == mTemperatureAvailable.get(zone)) {
+                        return false;
+                    }
+                }
             }
-            mTemperature.put(zone, temperature);
+            setTemperature(zone, temperature, available);
         }
         return true;
     }
diff --git a/src/com/android/car/hvac/HvacController.java b/src/com/android/car/hvac/HvacController.java
index 5de3dc6..8c4324d 100644
--- a/src/com/android/car/hvac/HvacController.java
+++ b/src/com/android/car/hvac/HvacController.java
@@ -16,9 +16,8 @@
 package com.android.car.hvac;
 
 import android.app.Service;
-import android.car.VehicleSeat;
-import android.car.VehicleWindow;
-import android.car.VehicleZone;
+import android.car.VehicleAreaSeat;
+import android.car.VehicleAreaWindow;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.hvac.CarHvacManager;
@@ -42,14 +41,20 @@
 public class HvacController extends Service {
     private static final String DEMO_MODE_PROPERTY = "android.car.hvac.demo";
     private static final String TAG = "HvacController";
-    private static final int DRIVER_ZONE_ID = VehicleSeat.SEAT_ROW_1_LEFT;
-    private static final int PASSENGER_ZONE_ID = VehicleSeat.SEAT_ROW_1_RIGHT;
+    private static final int DRIVER_ZONE_ID = VehicleAreaSeat.SEAT_ROW_1_LEFT |
+            VehicleAreaSeat.SEAT_ROW_2_LEFT | VehicleAreaSeat.SEAT_ROW_2_CENTER;
+    private static final int PASSENGER_ZONE_ID = VehicleAreaSeat.SEAT_ROW_1_RIGHT |
+            VehicleAreaSeat.SEAT_ROW_2_RIGHT;
 
     public static final int[] AIRFLOW_STATES = new int[]{
-            CarHvacManager.FAN_POSITION_FACE,
-            CarHvacManager.FAN_POSITION_FLOOR,
-            CarHvacManager.FAN_POSITION_FACE_AND_FLOOR
+            CarHvacManager.FAN_DIRECTION_FACE,
+            CarHvacManager.FAN_DIRECTION_FLOOR,
+            (CarHvacManager.FAN_DIRECTION_FACE | CarHvacManager.FAN_DIRECTION_FLOOR)
     };
+    // Hardware specific value for the front seats
+    public static final int SEAT_ALL = VehicleAreaSeat.SEAT_ROW_1_LEFT |
+            VehicleAreaSeat.SEAT_ROW_1_RIGHT | VehicleAreaSeat.SEAT_ROW_2_LEFT |
+            VehicleAreaSeat.SEAT_ROW_2_CENTER | VehicleAreaSeat.SEAT_ROW_2_RIGHT;
 
     /**
      * Callback for receiving updates from the hvac manager. A Callback can be
@@ -57,10 +62,10 @@
      */
     public static abstract class Callback {
 
-        public void onPassengerTemperatureChange(float temp) {
+        public void onPassengerTemperatureChange(CarPropertyValue propValue) {
         }
 
-        public void onDriverTemperatureChange(float temp) {
+        public void onDriverTemperatureChange(CarPropertyValue propValue) {
         }
 
         public void onFanSpeedChange(int position) {
@@ -201,14 +206,14 @@
                         case CarHvacManager.ID_ZONED_AC_ON:
                             handleAcStateUpdate(getValue(val));
                             break;
-                        case CarHvacManager.ID_ZONED_FAN_POSITION:
+                        case CarHvacManager.ID_ZONED_FAN_DIRECTION:
                             handleFanPositionUpdate(areaId, getValue(val));
                             break;
                         case CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT:
                             handleFanSpeedUpdate(areaId, getValue(val));
                             break;
                         case CarHvacManager.ID_ZONED_TEMP_SETPOINT:
-                            handleTempUpdate(areaId, getValue(val));
+                            handleTempUpdate(val);
                             break;
                         case CarHvacManager.ID_WINDOW_DEFROSTER_ON:
                             handleDefrosterUpdate(areaId, getValue(val));
@@ -242,6 +247,10 @@
         return (E) propertyValue.getValue();
     }
 
+    public static boolean isAvailable(CarPropertyValue propertyValue) {
+        return propertyValue.getStatus() == CarPropertyValue.STATUS_AVAILABLE;
+    }
+
     void handleHvacPowerOn(boolean isOn) {
         boolean shouldPropagate = mDataStore.shouldPropagateHvacPowerUpdate(isOn);
         if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -265,7 +274,7 @@
         if (shouldPropagate) {
             synchronized (mCallbacks) {
                 for (int i = 0; i < mCallbacks.size(); i++) {
-                    if (zone == VehicleZone.ZONE_ROW_1_LEFT) {
+                    if (zone == VehicleAreaSeat.SEAT_ROW_1_LEFT) {
                         mCallbacks.get(i).onDriverSeatWarmerChange(level);
                     } else {
                         mCallbacks.get(i).onPassengerSeatWarmerChange(level);
@@ -352,22 +361,25 @@
         }
     }
 
-    private void handleTempUpdate(int zone, float temp) {
-        boolean shouldPropagate = mDataStore.shouldPropagateTempUpdate(zone, temp);
+    private void handleTempUpdate(CarPropertyValue value) {
+        final int zone = value.getAreaId();
+        final float temp = (Float)value.getValue();
+        final boolean available = value.getStatus() == CarPropertyValue.STATUS_AVAILABLE;
+        boolean shouldPropagate = mDataStore.shouldPropagateTempUpdate(zone, temp, available);
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "Temp Update, zone: " + zone + " temp: " + temp +
-                    " should propagate: " + shouldPropagate);
+                "available: " + available + " should propagate: " + shouldPropagate);
         }
         if (shouldPropagate) {
             int userTemperature =  mPolicy.hardwareToUserTemp(temp);
             synchronized (mCallbacks) {
                 for (int i = 0; i < mCallbacks.size(); i++) {
-                    if (zone == VehicleZone.ZONE_ROW_1_LEFT) {
+                    if (zone == VehicleAreaSeat.SEAT_ROW_1_LEFT) {
                         mCallbacks.get(i)
-                                .onDriverTemperatureChange(userTemperature);
+                                .onDriverTemperatureChange(value);
                     } else {
                         mCallbacks.get(i)
-                                .onPassengerTemperatureChange(userTemperature);
+                                .onPassengerTemperatureChange(value);
                     }
                 }
             }
@@ -383,9 +395,9 @@
         if (shouldPropagate) {
             synchronized (mCallbacks) {
                 for (int i = 0; i < mCallbacks.size(); i++) {
-                    if (zone == VehicleWindow.WINDOW_FRONT_WINDSHIELD) {
+                    if (zone == VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD) {
                         mCallbacks.get(i).onFrontDefrosterChange(defrosterState);
-                    } else if (zone == VehicleWindow.WINDOW_REAR_WINDSHIELD) {
+                    } else if (zone == VehicleAreaWindow.WINDOW_REAR_WINDSHIELD) {
                         mCallbacks.get(i).onRearDefrosterChange(defrosterState);
                     }
                 }
@@ -410,8 +422,8 @@
                 fetchTemperature(DRIVER_ZONE_ID);
                 fetchTemperature(PASSENGER_ZONE_ID);
                 fetchFanSpeed();
-                fetchDefrosterState(VehicleWindow.WINDOW_FRONT_WINDSHIELD);
-                fetchDefrosterState(VehicleWindow.WINDOW_REAR_WINDSHIELD);
+                fetchDefrosterState(VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD);
+                fetchDefrosterState(VehicleAreaWindow.WINDOW_REAR_WINDSHIELD);
                 fetchAirflow(DRIVER_ZONE_ID);
                 fetchAirflow(PASSENGER_ZONE_ID);
                 fetchAcState();
@@ -432,11 +444,35 @@
         return mPolicy;
     }
 
+    public boolean isTemperatureControlAvailable(int zone) {
+        if (mHvacManager != null) {
+            try {
+                return mHvacManager.isPropertyAvailable(
+                        CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone);
+            } catch (android.car.CarNotConnectedException e) {
+                Log.e(TAG, "Car not connected in isTemperatureControlAvailable");
+            }
+        }
+
+        return false;
+    }
+
+    public boolean isDriverTemperatureControlAvailable() {
+        return isTemperatureControlAvailable(DRIVER_ZONE_ID);
+    }
+
+    public boolean isPassengerTemperatureControlAvailable() {
+        return isTemperatureControlAvailable(PASSENGER_ZONE_ID);
+    }
+
     private void fetchTemperature(int zone) {
         if (mHvacManager != null) {
             try {
-                mDataStore.setTemperature(zone, mHvacManager.getFloatProperty(
-                        CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone));
+                float value = mHvacManager.getFloatProperty(
+                    CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone);
+                boolean available = mHvacManager.isPropertyAvailable(
+                    CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone);
+                mDataStore.setTemperature(zone, value, available);
             } catch (android.car.CarNotConnectedException e) {
                 Log.e(TAG, "Car not connected in fetchTemperature");
             }
@@ -460,15 +496,39 @@
     }
 
     public void setTemperature(final int zone, final float temperature) {
-        mDataStore.setTemperature(zone, temperature);
         final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
             protected Void doInBackground(Void... unused) {
                 if (mHvacManager != null) {
                     try {
                         mHvacManager.setFloatProperty(
                                 CarHvacManager.ID_ZONED_TEMP_SETPOINT, zone, temperature);
+                        // if the set() succeeds, consider the property available
+                        mDataStore.setTemperature(zone, temperature, true);
                     } catch (android.car.CarNotConnectedException e) {
                         Log.e(TAG, "Car not connected in setTemperature");
+                    } catch (Exception e) {
+                        Log.e(TAG, "set temp failed", e);
+                    }
+                }
+                return null;
+            }
+        };
+        task.execute();
+    }
+
+    public void setHvacPowerState(final boolean state) {
+        final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+            protected Void doInBackground(Void... unused) {
+                if (mHvacManager != null) {
+                    try {
+                        mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_HVAC_POWER_ON,
+                            SEAT_ALL, state);
+                        // if the set() succeeds, consider the property available
+                        mDataStore.setHvacPowerState(state);
+                    } catch (android.car.CarNotConnectedException e) {
+                        Log.e(TAG, "Car not connected in setHvacPowerState");
+                    } catch (Exception e) {
+                        Log.e(TAG, "set power failed", e);
                     }
                 }
                 return null;
@@ -495,6 +555,8 @@
                                 CarHvacManager.ID_ZONED_SEAT_TEMP, zone, level);
                     } catch (android.car.CarNotConnectedException e) {
                         Log.e(TAG, "Car not connected in setSeatWarmerLevel");
+                    } catch (Exception e) {
+                        Log.e(TAG, "set seat warmer failed", e);
                     }
                 }
                 return null;
@@ -505,7 +567,7 @@
 
     private void fetchFanSpeed() {
         if (mHvacManager != null) {
-            int zone = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
+            int zone = SEAT_ALL; // Car specific workaround.
             try {
                 mDataStore.setFanSpeed(mHvacManager.getIntProperty(
                         CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT, zone));
@@ -527,7 +589,7 @@
 
             protected Void doInBackground(Void... unused) {
                 if (mHvacManager != null) {
-                    int zone = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
+                    int zone = SEAT_ALL; // Car specific workaround.
                     try {
                         if (Log.isLoggable(TAG, Log.DEBUG)) {
                             Log.d(TAG, "Setting fanspeed to: " + fanSpeed);
@@ -564,19 +626,19 @@
     }
 
     public boolean getFrontDefrosterState() {
-        return mDataStore.getDefrosterState(VehicleWindow.WINDOW_FRONT_WINDSHIELD);
+        return mDataStore.getDefrosterState(VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD);
     }
 
     public boolean getRearDefrosterState() {
-        return mDataStore.getDefrosterState(VehicleWindow.WINDOW_REAR_WINDSHIELD);
+        return mDataStore.getDefrosterState(VehicleAreaWindow.WINDOW_REAR_WINDSHIELD);
     }
 
     public void setFrontDefrosterState(boolean state) {
-        setDefrosterState(VehicleWindow.WINDOW_FRONT_WINDSHIELD, state);
+        setDefrosterState(VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD, state);
     }
 
     public void setRearDefrosterState(boolean state) {
-        setDefrosterState(VehicleWindow.WINDOW_REAR_WINDSHIELD, state);
+        setDefrosterState(VehicleAreaWindow.WINDOW_REAR_WINDSHIELD, state);
     }
 
     public void setDefrosterState(final int zone, final boolean state) {
@@ -601,7 +663,7 @@
         if (mHvacManager != null) {
             try {
                 mDataStore.setAcState(mHvacManager.getBooleanProperty(CarHvacManager.ID_ZONED_AC_ON,
-                        VehicleZone.ZONE_ROW_1_ALL));
+                        SEAT_ALL));
             } catch (android.car.CarNotConnectedException e) {
                 Log.e(TAG, "Car not connected in fetchAcState");
             }
@@ -619,7 +681,7 @@
                 if (mHvacManager != null) {
                     try {
                         mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_AC_ON,
-                                VehicleZone.ZONE_ROW_1_ALL, state);
+                                SEAT_ALL, state);
                     } catch (android.car.CarNotConnectedException e) {
                         Log.e(TAG, "Car not connected in setAcState");
                     }
@@ -642,9 +704,9 @@
 
     private void fetchAirflow(int zone) {
         if (mHvacManager != null) {
-            zone = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
+            zone = SEAT_ALL; // Car specific workaround.
             try {
-                int val = mHvacManager.getIntProperty(CarHvacManager.ID_ZONED_FAN_POSITION, zone);
+                int val = mHvacManager.getIntProperty(CarHvacManager.ID_ZONED_FAN_DIRECTION, zone);
                 mDataStore.setAirflow(zone, fanPositionToAirflowIndex(val));
             } catch (android.car.CarNotConnectedException e) {
                 Log.e(TAG, "Car not connected in fetchAirFlow");
@@ -658,14 +720,14 @@
 
     public void setAirflowIndex(final int zone, final int index) {
         mDataStore.setAirflow(zone, index);
-        int override = VehicleZone.ZONE_ROW_1_ALL; // Car specific workaround.
+        int override = SEAT_ALL; // Car specific workaround.
         int val = AIRFLOW_STATES[index];
         setFanDirection(override, val);
     }
 
     public void setFanDirection(final int direction) {
-        mDataStore.setAirflow(VehicleZone.ZONE_ROW_1_ALL, direction);
-        setFanDirection(VehicleZone.ZONE_ROW_1_ALL, direction);
+        mDataStore.setAirflow(SEAT_ALL, direction);
+        setFanDirection(SEAT_ALL, direction);
     }
 
     private void setFanDirection(final int zone, final int direction) {
@@ -674,7 +736,7 @@
                 if (mHvacManager != null) {
                     try {
                         mHvacManager.setIntProperty(
-                                CarHvacManager.ID_ZONED_FAN_POSITION, zone, direction);
+                                CarHvacManager.ID_ZONED_FAN_DIRECTION, zone, direction);
                     } catch (android.car.CarNotConnectedException e) {
                         Log.e(TAG, "Car not connected in setAirflowIndex");
                     }
@@ -691,7 +753,7 @@
             try {
                 mDataStore.setAirCirculationState(mHvacManager
                         .getBooleanProperty(CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON,
-                                VehicleZone.ZONE_ROW_1_ALL));
+                                SEAT_ALL));
             } catch (android.car.CarNotConnectedException e) {
                 Log.e(TAG, "Car not connected in fetchAirCirculationState");
             }
@@ -710,7 +772,7 @@
                     try {
                         mHvacManager.setBooleanProperty(
                                 CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON,
-                                VehicleZone.ZONE_ROW_1_ALL, state);
+                                SEAT_ALL, state);
                     } catch (android.car.CarNotConnectedException e) {
                         Log.e(TAG, "Car not connected in setAcState");
                     }
@@ -732,7 +794,7 @@
                 if (mHvacManager != null) {
                     try {
                         mHvacManager.setBooleanProperty(CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON,
-                                VehicleZone.ZONE_ROW_1_ALL, state);
+                                SEAT_ALL, state);
                     } catch (android.car.CarNotConnectedException e) {
                         Log.e(TAG, "Car not connected in setAutoModeState");
                     }
@@ -751,7 +813,7 @@
         if (mHvacManager != null) {
             try {
                 mDataStore.setHvacPowerState(mHvacManager.getBooleanProperty(
-                        CarHvacManager.ID_ZONED_HVAC_POWER_ON, VehicleZone.ZONE_ROW_1_ALL));
+                        CarHvacManager.ID_ZONED_HVAC_POWER_ON, SEAT_ALL));
             } catch (android.car.CarNotConnectedException e) {
                 Log.e(TAG, "Car not connected in fetchHvacPowerState");
             }
diff --git a/src/com/android/car/hvac/HvacUiService.java b/src/com/android/car/hvac/HvacUiService.java
index 0478790..273375e 100644
--- a/src/com/android/car/hvac/HvacUiService.java
+++ b/src/com/android/car/hvac/HvacUiService.java
@@ -16,61 +16,71 @@
 package com.android.car.hvac;
 
 import android.app.Service;
+import android.car.Car;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.UserHandle;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.widget.LinearLayout;
+
 import com.android.car.hvac.controllers.HvacPanelController;
-import com.android.car.hvac.ui.SystemUiObserver;
 import com.android.car.hvac.ui.TemperatureBarOverlay;
 
 import java.util.ArrayList;
 import java.util.List;
 
+
 /**
  * Creates a sliding panel for HVAC controls and adds it to the window manager above SystemUI.
  */
 public class HvacUiService extends Service {
+    public static final String CAR_INTENT_ACTION_TOGGLE_HVAC_CONTROLS =
+            "android.car.intent.action.TOGGLE_HVAC_CONTROLS";
     private static final String TAG = "HvacUiService";
 
     private final List<View> mAddedViews = new ArrayList<>();
 
     private WindowManager mWindowManager;
 
-    private View mPanel;
     private View mContainer;
 
+    private int mNavBarHeight;
     private int mPanelCollapsedHeight;
     private int mPanelFullExpandedHeight;
     private int mScreenBottom;
     private int mScreenWidth;
+    // This is to compensate for the difference between where the y coordinate origin is and that
+    // of the actual bottom of the screen.
+    private int mInitialYOffset = 0;
+    private DisplayMetrics mDisplayMetrics;
 
     private int mTemperatureSideMargin;
     private int mTemperatureOverlayWidth;
     private int mTemperatureOverlayHeight;
-    private int mTemperatureBarCollapsedHeight;
 
     private HvacPanelController mHvacPanelController;
     private HvacController mHvacController;
 
-    private ViewGroup mDriverTemperatureBarTouchOverlay;
-    private ViewGroup mPassengerTemperatureBarTouchOverlay;
+    // we need both a expanded and collapsed version due to a rendering bug during window resize
+    // thus instead we swap between the collapsed window and the expanded one before/after they
+    // are needed.
     private TemperatureBarOverlay mDriverTemperatureBar;
     private TemperatureBarOverlay mPassengerTemperatureBar;
+    private TemperatureBarOverlay mDriverTemperatureBarCollapsed;
+    private TemperatureBarOverlay mPassengerTemperatureBarCollapsed;
 
-    private int mStatusBarHeight = -1;
 
     @Override
     public IBinder onBind(Intent intent) {
@@ -80,47 +90,108 @@
     @Override
     public void onCreate() {
         Resources res = getResources();
+        boolean showCollapsed = res.getBoolean(R.bool.config_showCollapsedBars);
         mPanelCollapsedHeight = res.getDimensionPixelSize(R.dimen.car_hvac_panel_collapsed_height);
         mPanelFullExpandedHeight
                 = res.getDimensionPixelSize(R.dimen.car_hvac_panel_full_expanded_height);
 
         mTemperatureSideMargin = res.getDimensionPixelSize(R.dimen.temperature_side_margin);
-        mTemperatureOverlayWidth = res.getDimensionPixelSize(R.dimen.temperature_bar_width_expanded);
+        mTemperatureOverlayWidth =
+                res.getDimensionPixelSize(R.dimen.temperature_bar_width_expanded);
         mTemperatureOverlayHeight
                 = res.getDimensionPixelSize(R.dimen.car_hvac_panel_full_expanded_height);
-        mTemperatureBarCollapsedHeight
-                = res.getDimensionPixelSize(R.dimen.temperature_bar_collapsed_height);
 
-        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
         mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
 
-        DisplayMetrics metrics = new DisplayMetrics();
-        mWindowManager.getDefaultDisplay().getRealMetrics(metrics);
-        mScreenBottom = metrics.heightPixels - getStatusBarHeight();
-        mScreenWidth = metrics.widthPixels;
+        mDisplayMetrics = new DisplayMetrics();
+        mWindowManager.getDefaultDisplay().getRealMetrics(mDisplayMetrics);
+        mScreenBottom = mDisplayMetrics.heightPixels;
+        mScreenWidth = mDisplayMetrics.widthPixels;
 
-        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
-                WindowManager.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.WRAP_CONTENT,
+        int identifier = res.getIdentifier("navigation_bar_height_car_mode", "dimen", "android");
+        mNavBarHeight = (identifier > 0 && showCollapsed) ?
+                res.getDimensionPixelSize(identifier) : 0;
+
+        WindowManager.LayoutParams testparams = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                         | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                 PixelFormat.TRANSLUCENT);
 
+        // There does not exist a way to get the current state of the system ui visibility from
+        // inside a Service thus we place something that's full screen and check it's final
+        // measurements as a hack to get that information. Once we have the initial state  we can
+        // safely just register for the change events from that point on.
+        View windowSizeTest = new View(this) {
+            @Override
+            protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+                boolean sysUIShowing = (mDisplayMetrics.heightPixels != bottom);
+                mInitialYOffset = (sysUIShowing) ? -mNavBarHeight : 0;
+                layoutHvacUi();
+                // we now have initial state so this empty view is not longer needed.
+                mWindowManager.removeView(this);
+                mAddedViews.remove(this);
+            }
+        };
+        addViewToWindowManagerAndTrack(windowSizeTest, testparams);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(CAR_INTENT_ACTION_TOGGLE_HVAC_CONTROLS);
+        // Register receiver such that any user with climate control permission can call it.
+        registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
+                Car.PERMISSION_CONTROL_CAR_CLIMATE, null);
+    }
+
+
+    /**
+     * Called after the mInitialYOffset is determined. This does a layout of all components needed
+     * for the HVAC UI. On start the all the windows need for the collapsed view are visible whereas
+     * the expanded view's windows are created and sized but are invisible.
+     */
+    private void layoutHvacUi() {
+        LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                        & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+                PixelFormat.TRANSLUCENT);
+
         params.packageName = this.getPackageName();
-        params.gravity = Gravity.TOP | Gravity.LEFT;
+        params.gravity = Gravity.BOTTOM | Gravity.LEFT;
 
         params.x = 0;
-        params.y = 0;
+        params.y = mInitialYOffset;
 
         params.width = mScreenWidth;
         params.height = mScreenBottom;
         params.setTitle("HVAC Container");
         disableAnimations(params);
+        // required of the sysui visiblity listener is not triggered.
+        params.hasSystemUiListeners = true;
 
         mContainer = inflater.inflate(R.layout.hvac_panel, null);
         mContainer.setLayoutParams(params);
+        mContainer.setOnSystemUiVisibilityChangeListener(visibility -> {
+            boolean systemUiVisible = (visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0;
+            int y = 0;
+            if (systemUiVisible) {
+                // when the system ui is visible the windowing systems coordinates start with
+                // 0 being above the system navigation bar. Therefore if we want to get the the
+                // actual bottom of the screen we need to set the y value to negative value of the
+                // navigation bar height.
+                y = -mNavBarHeight;
+            }
+            setYPosition(mDriverTemperatureBar, y);
+            setYPosition(mPassengerTemperatureBar, y);
+            setYPosition(mDriverTemperatureBarCollapsed, y);
+            setYPosition(mPassengerTemperatureBarCollapsed, y);
+            setYPosition(mContainer, y);
+        });
 
         // The top padding should be calculated on the screen height and the height of the
         // expanded hvac panel. The space defined by the padding is meant to be clickable for
@@ -129,41 +200,22 @@
         mContainer.setPadding(0, topPadding, 0, 0);
 
         mContainer.setFocusable(false);
-        mContainer.setClickable(false);
         mContainer.setFocusableInTouchMode(false);
 
-        mPanel = mContainer.findViewById(R.id.hvac_center_panel);
-        mPanel.getLayoutParams().height = mPanelCollapsedHeight;
+        View panel = mContainer.findViewById(R.id.hvac_center_panel);
+        panel.getLayoutParams().height = mPanelCollapsedHeight;
 
         addViewToWindowManagerAndTrack(mContainer, params);
 
         createTemperatureBars(inflater);
         mHvacPanelController = new HvacPanelController(this /* context */, mContainer,
                 mWindowManager, mDriverTemperatureBar, mPassengerTemperatureBar,
-                mDriverTemperatureBarTouchOverlay, mPassengerTemperatureBarTouchOverlay);
+                mDriverTemperatureBarCollapsed, mPassengerTemperatureBarCollapsed
+        );
         Intent bindIntent = new Intent(this /* context */, HvacController.class);
         if (!bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
             Log.e(TAG, "Failed to connect to HvacController.");
         }
-
-        params = new WindowManager.LayoutParams(
-                WindowManager.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
-                PixelFormat.TRANSLUCENT);
-        SystemUiObserver observer =
-                (SystemUiObserver) inflater.inflate(R.layout.system_ui_observer, null);
-        observer.setListener(visible -> {
-            adjustPosition(mDriverTemperatureBarTouchOverlay, visible);
-            adjustPosition(mPassengerTemperatureBarTouchOverlay, visible);
-            adjustPosition(mDriverTemperatureBar, visible);
-            adjustPosition(mPassengerTemperatureBar, visible);
-            adjustPosition(mContainer, visible);
-        });
-        addViewToWindowManagerAndTrack(observer, params);
     }
 
     private void addViewToWindowManagerAndTrack(View view, WindowManager.LayoutParams params) {
@@ -171,16 +223,21 @@
         mAddedViews.add(view);
     }
 
-    private void adjustPosition(View v, boolean systemUiVisible) {
+    private void setYPosition(View v, int y) {
         WindowManager.LayoutParams lp = (WindowManager.LayoutParams) v.getLayoutParams();
-        if (systemUiVisible) {
-            lp.y -= getStatusBarHeight();
-        } else {
-            lp.y += getStatusBarHeight();
-        }
+        lp.y = y;
         mWindowManager.updateViewLayout(v, lp);
     }
 
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if(action.equals(CAR_INTENT_ACTION_TOGGLE_HVAC_CONTROLS)){
+                mHvacPanelController.toggleHvacUi();
+            }
+        }
+    };
 
     @Override
     public void onDestroy() {
@@ -191,6 +248,7 @@
         if(mHvacController != null){
             unbindService(mServiceConnection);
         }
+        unregisterReceiver(mBroadcastReceiver);
     }
 
     private ServiceConnection mServiceConnection = new ServiceConnection() {
@@ -199,13 +257,10 @@
             mHvacController = ((HvacController.LocalBinder) service).getService();
             final Context context = HvacUiService.this;
 
-            final Runnable r = new Runnable() {
-                @Override
-                public void run() {
-                    // Once the hvac controller has refreshed its values from the vehicle,
-                    // bind all the values.
-                    mHvacPanelController.updateHvacController(mHvacController);
-                }
+            final Runnable r = () -> {
+                // Once the hvac controller has refreshed its values from the vehicle,
+                // bind all the values.
+                mHvacPanelController.updateHvacController(mHvacController);
             };
 
             if (mHvacController != null) {
@@ -221,7 +276,43 @@
         }
     };
 
-    private WindowManager.LayoutParams createClickableOverlayLayoutParam(String title) {
+    private void createTemperatureBars(LayoutInflater inflater) {
+        mDriverTemperatureBarCollapsed = createTemperatureBarOverlay(inflater,
+                "HVAC Driver Temp collapsed",
+                mNavBarHeight,
+                Gravity.BOTTOM | Gravity.LEFT);
+
+        mPassengerTemperatureBarCollapsed = createTemperatureBarOverlay(inflater,
+                "HVAC Passenger Temp collapsed",
+                mNavBarHeight,
+                Gravity.BOTTOM | Gravity.RIGHT);
+
+        mDriverTemperatureBar = createTemperatureBarOverlay(inflater,
+                "HVAC Driver Temp",
+                mTemperatureOverlayHeight,
+                Gravity.BOTTOM | Gravity.LEFT);
+
+        mPassengerTemperatureBar = createTemperatureBarOverlay(inflater,
+                "HVAC Passenger Temp",
+                mTemperatureOverlayHeight,
+                Gravity.BOTTOM | Gravity.RIGHT);
+    }
+
+    private TemperatureBarOverlay createTemperatureBarOverlay(LayoutInflater inflater,
+            String windowTitle, int windowHeight, int gravity) {
+        WindowManager.LayoutParams params = createTemperatureBarLayoutParams(
+                windowTitle, windowHeight, gravity);
+        TemperatureBarOverlay button = (TemperatureBarOverlay) inflater
+                .inflate(R.layout.hvac_temperature_bar_overlay, null);
+        button.setLayoutParams(params);
+        addViewToWindowManagerAndTrack(button, params);
+        return button;
+    }
+
+    // note the window manager does not copy the layout params but uses the supplied object thus
+    // you need a new copy for each window or change 1 can effect the others
+    private WindowManager.LayoutParams createTemperatureBarLayoutParams(String windowTitle,
+            int windowHeight, int gravity) {
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 WindowManager.LayoutParams.WRAP_CONTENT,
                 WindowManager.LayoutParams.WRAP_CONTENT,
@@ -229,69 +320,16 @@
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                         | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                 PixelFormat.TRANSLUCENT);
-        lp.setTitle(title);
+        lp.x = mTemperatureSideMargin;
+        lp.y = mInitialYOffset;
+        lp.width = mTemperatureOverlayWidth;
+        disableAnimations(lp);
+        lp.setTitle(windowTitle);
+        lp.height = windowHeight;
+        lp.gravity = gravity;
         return lp;
     }
 
-    private TemperatureBarOverlay createTemperatureBarOverlay(LayoutInflater inflater,
-            int gravity, String title) {
-        TemperatureBarOverlay button = (TemperatureBarOverlay) inflater
-                .inflate(R.layout.hvac_temperature_bar_overlay, null);
-
-        WindowManager.LayoutParams params = createClickableOverlayLayoutParam(title);
-        params.gravity = gravity;
-        params.x = mTemperatureSideMargin;
-        params.y = mScreenBottom - mTemperatureOverlayHeight;
-        params.width = mTemperatureOverlayWidth;
-        params.height = mTemperatureOverlayHeight;
-
-        disableAnimations(params);
-        button.setLayoutParams(params);
-        addViewToWindowManagerAndTrack(button, params);
-
-        return button;
-    }
-
-    /**
-     * Creates a touchable overlay in the dimensions of a collapsed {@link TemperatureBarOverlay}.
-     * @return a {@link ViewGroup} that was added to the {@link WindowManager}
-     */
-    private ViewGroup addTemperatureTouchOverlay(int gravity, String title) {
-        WindowManager.LayoutParams params = createClickableOverlayLayoutParam(title);
-        params.gravity = gravity;
-        params.x = mTemperatureSideMargin;
-        params.y = mScreenBottom - mTemperatureBarCollapsedHeight;
-        params.width = mTemperatureOverlayWidth;
-        params.height = mTemperatureBarCollapsedHeight;
-
-        ViewGroup overlay = new LinearLayout(this /* context */);
-        overlay.setLayoutParams(params);
-        addViewToWindowManagerAndTrack(overlay, params);
-        return overlay;
-    }
-
-    private void createTemperatureBars(LayoutInflater inflater) {
-        mDriverTemperatureBar
-                = createTemperatureBarOverlay(
-                        inflater, Gravity.TOP | Gravity.LEFT, "HVAC Driver Temp");
-        mPassengerTemperatureBar
-                = createTemperatureBarOverlay(
-                        inflater, Gravity.TOP | Gravity.RIGHT, "HVAC Passenger Temp");
-
-        // Create a transparent overlay that is the size of the collapsed temperature bar.
-        // It will receive touch events and trigger the expand/collapse of the panel. This is
-        // necessary since changing the height of the temperature bar overlay dynamically, causes
-        // a jank when WindowManager updates the view with a new height. This hack allows us
-        // to maintain the temperature bar overlay at constant (expanded) height and just
-        // update whether or not it is touchable/clickable.
-        mDriverTemperatureBarTouchOverlay
-                = addTemperatureTouchOverlay(
-                        Gravity.TOP | Gravity.LEFT, "HVAC Driver Touch Overlay");
-        mPassengerTemperatureBarTouchOverlay
-                = addTemperatureTouchOverlay(
-                        Gravity.TOP | Gravity.RIGHT, "HVAC Passenger Touch Overlay");
-    }
-
     /**
      * Disables animations when window manager updates a child view.
      */
@@ -303,19 +341,4 @@
             Log.e(TAG, "Error disabling animation");
         }
     }
-
-    private int getStatusBarHeight() {
-        // Cache the result to keep it fast.
-        if (mStatusBarHeight >= 0) {
-            return mStatusBarHeight;
-        }
-
-        int result = 0;
-        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
-        if (resourceId > 0) {
-            result = getResources().getDimensionPixelSize(resourceId);
-        }
-        mStatusBarHeight = result;
-        return result;
-    }
 }
diff --git a/src/com/android/car/hvac/LocalHvacPropertyService.java b/src/com/android/car/hvac/LocalHvacPropertyService.java
index 9d457c7..8be525c 100644
--- a/src/com/android/car/hvac/LocalHvacPropertyService.java
+++ b/src/com/android/car/hvac/LocalHvacPropertyService.java
@@ -15,9 +15,16 @@
  */
 package com.android.car.hvac;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import android.car.VehicleAreaSeat;
 import android.car.VehicleAreaType;
-import android.car.VehicleWindow;
-import android.car.VehicleZone;
+import android.car.VehicleAreaWindow;
 import android.car.hardware.CarPropertyConfig;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.hvac.CarHvacManager;
@@ -28,18 +35,14 @@
 import android.os.RemoteException;
 import android.util.Pair;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 /**
  * A local {@link ICarProperty} that is used to mock up data for HVAC.
  */
 public class LocalHvacPropertyService {
-    private static final int DRIVER_ZONE_ID = VehicleZone.ZONE_ROW_1_LEFT;
-    private static final int PASSENGER_ZONE_ID = VehicleZone.ZONE_ROW_1_RIGHT;
+    private static final int DRIVER_ZONE_ID = VehicleAreaSeat.SEAT_ROW_1_LEFT |
+            VehicleAreaSeat.SEAT_ROW_2_LEFT | VehicleAreaSeat.SEAT_ROW_2_CENTER;
+    private static final int PASSENGER_ZONE_ID = VehicleAreaSeat.SEAT_ROW_1_RIGHT |
+            VehicleAreaSeat.SEAT_ROW_2_RIGHT;
 
     private static final float MIN_TEMP = 16;
     private static final float MAX_TEMP = 32;
@@ -55,9 +58,13 @@
     private static final boolean DEFAULT_AC_ON = true;
     private static final boolean DEFAULT_AUTO_MODE = false;
     private static final int DEFAULT_FAN_SPEED = 3;
-    private static final int DEFAULT_FAN_POSITION = 2;
+    private static final int DEFAULT_FAN_DIRECTION = 2;
     private static final float DEFAULT_DRIVER_TEMP = 16;
     private static final float DEFAULT_PASSENGER_TEMP = 25;
+    // Hardware specific value for the front seats
+    public static final int SEAT_ALL = VehicleAreaSeat.SEAT_ROW_1_LEFT |
+            VehicleAreaSeat.SEAT_ROW_1_RIGHT | VehicleAreaSeat.SEAT_ROW_2_LEFT |
+            VehicleAreaSeat.SEAT_ROW_2_CENTER | VehicleAreaSeat.SEAT_ROW_2_RIGHT;
 
     private final List<CarPropertyConfig> mPropertyList;
     private final Map<Pair, Object> mProperties = new HashMap<>();
@@ -66,12 +73,12 @@
     public LocalHvacPropertyService() {
         CarPropertyConfig fanSpeedConfig = CarPropertyConfig.newBuilder(Integer.class,
                 CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT,
-                VehicleAreaType.VEHICLE_AREA_TYPE_ZONE)
+                VehicleAreaType.VEHICLE_AREA_TYPE_SEAT)
                 .addAreaConfig(DEFAULT_AREA_ID, MIN_FAN_SPEED, MAX_FAN_SPEED).build();
 
         CarPropertyConfig temperatureConfig = CarPropertyConfig.newBuilder(Float.class,
                 CarHvacManager.ID_ZONED_TEMP_SETPOINT,
-                VehicleAreaType.VEHICLE_AREA_TYPE_ZONE)
+                VehicleAreaType.VEHICLE_AREA_TYPE_SEAT)
                 .addAreaConfig(DEFAULT_AREA_ID, MIN_TEMP, MAX_TEMP).build();
 
         mPropertyList = new ArrayList<>(2);
@@ -81,12 +88,12 @@
 
     private final IBinder mCarPropertyService = new ICarProperty.Stub(){
         @Override
-        public void registerListener(ICarPropertyEventListener listener) throws RemoteException {
+        public void registerListener(int propId, float rate, ICarPropertyEventListener listener) throws RemoteException {
             mListeners.add(listener);
         }
 
         @Override
-        public void unregisterListener(ICarPropertyEventListener listener) throws RemoteException {
+        public void unregisterListener(int propId, ICarPropertyEventListener listener) throws RemoteException {
             mListeners.remove(listener);
         }
 
@@ -104,8 +111,9 @@
         public void setProperty(CarPropertyValue prop) throws RemoteException {
             mProperties.put(new Pair(prop.getPropertyId(), prop.getAreaId()), prop.getValue());
             for (ICarPropertyEventListener listener : mListeners) {
-                listener.onEvent(
-                        new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, prop));
+                LinkedList<CarPropertyEvent> l = new LinkedList<>();
+                l.add(new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, prop));
+                listener.onEvent(l);
             }
         }
     };
@@ -116,22 +124,22 @@
 
     private void setupDefaultValues() {
         mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_HVAC_POWER_ON,
-                VehicleZone.ZONE_ROW_1_ALL), DEFAULT_POWER_ON);
+                SEAT_ALL), DEFAULT_POWER_ON);
         mProperties.put(new Pair<>(CarHvacManager.ID_WINDOW_DEFROSTER_ON,
-                VehicleWindow.WINDOW_FRONT_WINDSHIELD), DEFAULT_DEFROSTER_ON);
+                VehicleAreaWindow.WINDOW_FRONT_WINDSHIELD), DEFAULT_DEFROSTER_ON);
         mProperties.put(new Pair<>(CarHvacManager.ID_WINDOW_DEFROSTER_ON,
-                VehicleWindow.WINDOW_REAR_WINDSHIELD), DEFAULT_DEFROSTER_ON);
+                VehicleAreaWindow.WINDOW_REAR_WINDSHIELD), DEFAULT_DEFROSTER_ON);
         mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_AIR_RECIRCULATION_ON,
-                VehicleZone.ZONE_ROW_1_ALL), DEFAULT_AIR_CIRCULATION_ON);
+                SEAT_ALL), DEFAULT_AIR_CIRCULATION_ON);
         mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_AC_ON,
-                VehicleZone.ZONE_ROW_1_ALL), DEFAULT_AC_ON);
+                SEAT_ALL), DEFAULT_AC_ON);
         mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_AUTOMATIC_MODE_ON,
-                VehicleZone.ZONE_ROW_1_ALL), DEFAULT_AUTO_MODE);
+                SEAT_ALL), DEFAULT_AUTO_MODE);
 
         mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_FAN_SPEED_SETPOINT,
-                VehicleZone.ZONE_ROW_1_ALL), DEFAULT_FAN_SPEED);
-        mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_FAN_POSITION,
-                VehicleZone.ZONE_ROW_1_ALL), DEFAULT_FAN_POSITION);
+                SEAT_ALL), DEFAULT_FAN_SPEED);
+        mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_FAN_DIRECTION,
+                SEAT_ALL), DEFAULT_FAN_DIRECTION);
 
         mProperties.put(new Pair<>(CarHvacManager.ID_ZONED_TEMP_SETPOINT,
                 DRIVER_ZONE_ID), DEFAULT_DRIVER_TEMP);
diff --git a/src/com/android/car/hvac/controllers/FanDirectionButtonsController.java b/src/com/android/car/hvac/controllers/FanDirectionButtonsController.java
index 9d7be0c..f0721b8 100644
--- a/src/com/android/car/hvac/controllers/FanDirectionButtonsController.java
+++ b/src/com/android/car/hvac/controllers/FanDirectionButtonsController.java
@@ -23,8 +23,8 @@
 
 /**
  * A controller to handle changes in the fan direction. Also maps fan directions specified
- * in the {@link FanDirectionButtons} to the {@link CarHvacManager}{@code #FAN_POSITION_*} constants
- * in the vehicle hardware.
+ * in the {@link FanDirectionButtons} to the {@link CarHvacManager}{@code #FAN_DIRECTION_*}
+ * constants in the vehicle hardware.
  */
 public class FanDirectionButtonsController {
     private final static int FAN_DIRECTION_COUNT = 4;
@@ -43,13 +43,13 @@
         // Note Car specific values are being used here, as not all cars have the floor
         // and defroster fan direction.
         mFanDirectionMap.put(FanDirectionButtons.FAN_DIRECTION_FACE,
-                CarHvacManager.FAN_POSITION_FACE);
+                CarHvacManager.FAN_DIRECTION_FACE);
         mFanDirectionMap.put(FanDirectionButtons.FAN_DIRECTION_FACE_FLOOR,
-                CarHvacManager.FAN_POSITION_FACE_AND_FLOOR);
+                (CarHvacManager.FAN_DIRECTION_FACE | CarHvacManager.FAN_DIRECTION_FLOOR));
         mFanDirectionMap.put(FanDirectionButtons.FAN_DIRECTION_FLOOR,
-                CarHvacManager.FAN_POSITION_FLOOR);
+                CarHvacManager.FAN_DIRECTION_FLOOR);
         mFanDirectionMap.put(FanDirectionButtons.FAN_DIRECTION_FLOOR_DEFROSTER,
-                CarHvacManager.FAN_POSITION_DEFROST_AND_FLOOR);
+                (CarHvacManager.FAN_DIRECTION_DEFROST | CarHvacManager.FAN_DIRECTION_FLOOR));
         mFanDirectionButtons.setFanDirectionClickListener(mListener);
     }
 
diff --git a/src/com/android/car/hvac/controllers/HvacPanelController.java b/src/com/android/car/hvac/controllers/HvacPanelController.java
index 771c2ed..dbc4cac 100644
--- a/src/com/android/car/hvac/controllers/HvacPanelController.java
+++ b/src/com/android/car/hvac/controllers/HvacPanelController.java
@@ -22,12 +22,14 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.IntDef;
+import android.os.Handler;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.ImageView;
+
+import androidx.annotation.IntDef;
+
 import com.android.car.hvac.HvacController;
 import com.android.car.hvac.R;
 import com.android.car.hvac.ui.FanDirectionButtons;
@@ -56,6 +58,19 @@
     private static final int STATE_COLLAPSED = 0;
     private static final int STATE_COLLAPSED_DIMMED = 1;
     private static final int STATE_FULL_EXPANDED = 2;
+    // Allows for delayed invocation of code. Thus we can control UI events to happen after
+    // others. Example: set something visible but do it after we've complete current UI updates.
+    private static Handler handler = new Handler();
+
+    // We have both a collapsed and expanded version of the overlays due to a bug
+    // that does not correctly rendering a window resize event. Thus we toggle the the visibility
+    // of the windows instead. A better solution would be a having separate views collapsed state
+    // since the it does not need the other elements but this works for now.
+    private TemperatureBarOverlay mDriverTemperatureBarCollapsed;
+    private TemperatureBarOverlay mPassengerTemperatureBarCollapsed;
+    private TemperatureBarOverlay mDriverTemperatureBarExpanded;
+    private TemperatureBarOverlay mPassengerTemperatureBarExpanded;
+    private final boolean mShowCollapsed;
 
     @IntDef({STATE_COLLAPSED,
             STATE_COLLAPSED_DIMMED,
@@ -70,15 +85,11 @@
     private View mPanel;
     private View mContainer;
 
-    private TemperatureBarOverlay mDriverTemperature;
-    private TemperatureBarOverlay mPassengerTemperature;
-
-    private ViewGroup mDriverTemperatureTouchOverlay;
-    private ViewGroup mPassengerTemperatureTouchOverlay;
-
     private SeatWarmerButton mDriverSeatWarmer;
     private SeatWarmerButton mPassengerSeatWarmer;
 
+    private ToggleButton mHvacPowerSwitch;
+
     private ToggleButton mAcButton;
     private ToggleButton mRecycleAirButton;
 
@@ -108,23 +119,29 @@
     private FanSpeedBarController mFanSpeedBarController;
     private FanDirectionButtonsController mFanDirectionButtonsController;
     private TemperatureController mTemperatureController;
+    private TemperatureController mTemperatureControllerCollapsed;
     private SeatWarmerController mSeatWarmerController;
 
     private boolean mInAnimation;
-    private boolean mHvacIsOn;
 
     // TODO: read from shared pref
     private boolean mAutoMode;
 
     public HvacPanelController(Context context, View container,
-            WindowManager windowManager, TemperatureBarOverlay driverTemperature,
-            TemperatureBarOverlay passengerTemperature, ViewGroup driverTemperatureBarTouchOverlay,
-            ViewGroup passengerTemperatureBarTouchOverlay) {
+            WindowManager windowManager,
+            TemperatureBarOverlay driverTemperatureExpanded,
+            TemperatureBarOverlay passengerTemperatureExpanded,
+            TemperatureBarOverlay driverTemperatureBarCollapsed,
+            TemperatureBarOverlay passengerTemperatureBarCollapsed) {
+        Resources res = context.getResources();
+        mShowCollapsed = res.getBoolean(R.bool.config_showCollapsedBars);
+
+        mDriverTemperatureBarCollapsed = driverTemperatureBarCollapsed;
+        mPassengerTemperatureBarCollapsed = passengerTemperatureBarCollapsed;
 
         mCurrentState = STATE_COLLAPSED;
         mWindowManager = windowManager;
 
-        Resources res = context.getResources();
         mPanelCollapsedHeight = res.getDimensionPixelSize(R.dimen.car_hvac_panel_collapsed_height);
         mPanelFullExpandedHeight
                 = res.getDimensionPixelSize(R.dimen.car_hvac_panel_full_expanded_height);
@@ -132,32 +149,28 @@
         mAutoOffDrawable = res.getDrawable(R.drawable.ic_auto_off);
         mAutoOnDrawable = res.getDrawable(R.drawable.ic_auto_on);
 
-        mDriverTemperature = driverTemperature;
-        mDriverTemperature.setBarOnClickListener(mPanelClickListener);
+        mDriverTemperatureBarExpanded = driverTemperatureExpanded;
+        mPassengerTemperatureBarExpanded = passengerTemperatureExpanded;
 
-        mPassengerTemperature = passengerTemperature;
-        mPassengerTemperature.setBarOnClickListener(mPanelClickListener);
+        mDriverTemperatureBarExpanded.setCloseButtonOnClickListener(mCollapseHvac);
+        mPassengerTemperatureBarExpanded.setCloseButtonOnClickListener(mCollapseHvac);
 
-        mDriverTemperature.setCloseButtonOnClickListener(mOpenCloseToggleListener);
-        mPassengerTemperature.setCloseButtonOnClickListener(mOpenCloseToggleListener);
+        // Initially the hvac panel is collapsed, hide the expanded version.
+        mDriverTemperatureBarExpanded.setVisibility(View.INVISIBLE);
+        mPassengerTemperatureBarExpanded.setVisibility(View.INVISIBLE);
 
-        // Initially the hvac panel is collapsed, disable touches on the overlay container.
-        disableTouchOnOverlay(mDriverTemperature);
-        disableTouchOnOverlay(mPassengerTemperature);
-
-        mDriverTemperatureTouchOverlay = driverTemperatureBarTouchOverlay;
-        mPassengerTemperatureTouchOverlay = passengerTemperatureBarTouchOverlay;
-
-        mDriverTemperatureTouchOverlay.setOnClickListener(mOpenCloseToggleListener);
-        mPassengerTemperatureTouchOverlay.setOnClickListener(mOpenCloseToggleListener);
+        mPassengerTemperatureBarCollapsed.setBarOnClickListener(mExpandHvac);
+        mDriverTemperatureBarCollapsed.setBarOnClickListener(mExpandHvac);
 
         mContainer = container;
         mContainer.setVisibility(View.INVISIBLE);
-        mContainer.setOnClickListener(mOpenCloseToggleListener);
+        mContainer.setOnClickListener(mCollapseHvac);
         mPanel = mContainer.findViewById(R.id.hvac_center_panel);
 
         mHvacFanControlBackground = mPanel.findViewById(R.id.fan_control_bg);
-        mPanel.setOnClickListener(mPanelClickListener);
+        // set clickable so that clicks are not forward to the mContainer. This way a miss click
+        // does not close the UI
+        mPanel.setClickable(true);
 
         // Set up top row buttons
         mPanelTopRow = (HvacPanelRow) mContainer.findViewById(R.id.top_row);
@@ -191,6 +204,16 @@
 
         mDriverSeatWarmer = (SeatWarmerButton) mContainer.findViewById(R.id.left_seat_heater);
         mPassengerSeatWarmer = (SeatWarmerButton) mContainer.findViewById(R.id.right_seat_heater);
+
+        mHvacPowerSwitch = (ToggleButton)mPanelBottomRow.findViewById(R.id.hvac_master_switch);
+        // TODO: this is not good UX design - just a placeholder
+        mHvacPowerSwitch.setToggleIcons(res.getDrawable(R.drawable.ac_master_switch_on),
+            res.getDrawable(R.drawable.ac_master_switch_off));
+
+        if (!mShowCollapsed) {
+            mDriverTemperatureBarCollapsed.setVisibility(View.INVISIBLE);
+            mPassengerTemperatureBarCollapsed.setVisibility(View.INVISIBLE);
+        }
     }
 
     public void updateHvacController(HvacController controller) {
@@ -200,8 +223,12 @@
         mFanSpeedBarController = new FanSpeedBarController(mFanSpeedBar, mHvacController);
         mFanDirectionButtonsController
                 = new FanDirectionButtonsController(mFanDirectionButtons, mHvacController);
-        mTemperatureController = new TemperatureController(mPassengerTemperature,
-                mDriverTemperature, mHvacController);
+        mTemperatureController = new TemperatureController(
+                mPassengerTemperatureBarExpanded,
+                mDriverTemperatureBarExpanded,
+                mPassengerTemperatureBarCollapsed,
+                mDriverTemperatureBarCollapsed,
+                mHvacController);
         mSeatWarmerController = new SeatWarmerController(mPassengerSeatWarmer,
                 mDriverSeatWarmer, mHvacController);
 
@@ -241,6 +268,9 @@
 
         setAutoMode(mHvacController.getAutoModeState());
 
+        mHvacPowerSwitch.setIsOn(mHvacController.getHvacPowerState());
+        mHvacPowerSwitch.setToggleListener(isOn -> mHvacController.setHvacPowerState(isOn));
+
         mHvacController.registerCallback(mToggleButtonCallbacks);
         mToggleButtonCallbacks.onHvacPowerChange(mHvacController.getHvacPowerState());
     }
@@ -272,19 +302,6 @@
             mAutoMode = isOn;
             setAutoMode(mAutoMode);
         }
-
-        @Override
-        public void onHvacPowerChange(boolean isOn) {
-            // When the HVAC Power is turned off, collapse the panel and fade the temperature
-            // bars. Also disable expanding the panel until power is back on.
-            mHvacIsOn = isOn;
-            if (!mHvacIsOn && mCurrentState == STATE_FULL_EXPANDED) {
-                transitionState(STATE_FULL_EXPANDED, STATE_COLLAPSED);
-            }
-
-            mDriverTemperature.setIsOn(mHvacIsOn);
-            mPassengerTemperature.setIsOn(mHvacIsOn);
-        }
     };
 
     /**
@@ -347,9 +364,9 @@
                 animationList.add(panelAlphaAnimator);
 
                 combineAnimationSet(animationList, listenerList,
-                        mDriverTemperature.getCollapseAnimations());
+                        mDriverTemperatureBarExpanded.getCollapseAnimations());
                 combineAnimationSet(animationList, listenerList,
-                        mPassengerTemperature.getCollapseAnimations());
+                        mPassengerTemperatureBarExpanded.getCollapseAnimations());
 
                 combineAnimationSet(animationList, listenerList,
                         mPanelTopRow.getCollapseAnimation(PANEL_ANIMATION_DELAY_MS,
@@ -376,9 +393,9 @@
 
                 animationList.add(heightAnimator);
                 combineAnimationSet(animationList, listenerList,
-                        mDriverTemperature.getExpandAnimatons());
+                        mDriverTemperatureBarExpanded.getExpandAnimatons());
                 combineAnimationSet(animationList, listenerList,
-                        mPassengerTemperature.getExpandAnimatons());
+                        mPassengerTemperatureBarExpanded.getExpandAnimatons());
 
                 // During expansion, the bottom panel animation should be delayed
                 combineAnimationSet(animationList, listenerList,
@@ -468,24 +485,6 @@
         mPanelTopRow.setAlpha(mTopPanelMaxAlpha);
     }
 
-    private View.OnClickListener mPanelClickListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (!mHvacIsOn) {
-                return;
-            }
-            switch (mCurrentState) {
-                case STATE_COLLAPSED:
-                    transitionState(STATE_COLLAPSED, STATE_FULL_EXPANDED);
-                    break;
-                case STATE_COLLAPSED_DIMMED:
-                    transitionState(mCurrentState, STATE_COLLAPSED);
-                    break;
-                default:
-            }
-        }
-    };
-
     private View.OnClickListener mAutoButtonClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
@@ -499,20 +498,39 @@
         }
     };
 
-    private View.OnClickListener mOpenCloseToggleListener = new View.OnClickListener() {
+     private View.OnClickListener mCollapseHvac = new View.OnClickListener() {
+         @Override
+         public void onClick(View v) {
+             if (mInAnimation) {
+                 return;
+             }
+             if (mCurrentState != STATE_COLLAPSED) {
+                 transitionState(mCurrentState, STATE_COLLAPSED);
+             }
+         }
+     };
+
+    public void toggleHvacUi() {
+        if(mCurrentState != STATE_COLLAPSED) {
+            mCollapseHvac.onClick(null);
+        } else {
+            mExpandHvac.onClick(null);
+        }
+    }
+
+    public View.OnClickListener mExpandHvac = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            if (!mHvacIsOn) {
+             if (mInAnimation) {
                 return;
             }
-            if (mCurrentState == STATE_FULL_EXPANDED) {
-                transitionState(mCurrentState, STATE_COLLAPSED);
-            } else if (mCurrentState == STATE_COLLAPSED) {
+            if (mCurrentState != STATE_FULL_EXPANDED) {
                 transitionState(mCurrentState, STATE_FULL_EXPANDED);
             }
         }
     };
 
+
     private ValueAnimator.AnimatorUpdateListener mHeightUpdateListener
             = new ValueAnimator.AnimatorUpdateListener() {
         @Override
@@ -541,32 +559,30 @@
         public void onTransitionStart() {
             mInAnimation = true;
             if (mEndState == STATE_FULL_EXPANDED) {
+                mPassengerTemperatureBarExpanded.setVisibility(View.VISIBLE);
+                mDriverTemperatureBarExpanded.setVisibility(View.VISIBLE);
+                if (mShowCollapsed) {
+                    mDriverTemperatureBarCollapsed.setVisibility(View.INVISIBLE);
+                    mPassengerTemperatureBarCollapsed.setVisibility(View.INVISIBLE);
+                }
                 mContainer.setAlpha(1);
                 mContainer.setVisibility(View.VISIBLE);
-            } else if (mStartState == STATE_FULL_EXPANDED) {
-                // Finished transitioning out of the fully expanded panel. Make the HVAC container
-                // and temperature bars not touchable so clicks on the screen bar are not intercepted.
-                disableTouchOnOverlay(mContainer);
-                disableTouchOnOverlay(mDriverTemperature);
-                disableTouchOnOverlay(mPassengerTemperature);
             }
         }
 
         public void onTransitionComplete() {
+            if (mEndState == STATE_COLLAPSED) {
+                if (mShowCollapsed) {
+                    mDriverTemperatureBarCollapsed.setVisibility(View.VISIBLE);
+                    mPassengerTemperatureBarCollapsed.setVisibility(View.VISIBLE);
+                }
+                handler.postAtFrontOfQueue(() -> {
+                    mDriverTemperatureBarExpanded.setVisibility(View.INVISIBLE);
+                    mPassengerTemperatureBarExpanded.setVisibility(View.INVISIBLE);
+                });
+            }
             if (mStartState == STATE_FULL_EXPANDED) {
                 mContainer.setVisibility(View.INVISIBLE);
-
-                enableTouchOnOverlay(mDriverTemperatureTouchOverlay);
-                enableTouchOnOverlay(mPassengerTemperatureTouchOverlay);
-            } else if (mEndState == STATE_FULL_EXPANDED) {
-                // Finished transitioning into the fully expanded HVAC panel, make the
-                // container and temperature bars touchable since it covers the screen.
-                enableTouchOnOverlay(mContainer);
-                enableTouchOnOverlay(mDriverTemperature);
-                enableTouchOnOverlay(mPassengerTemperature);
-
-                disableTouchOnOverlay(mDriverTemperatureTouchOverlay);
-                disableTouchOnOverlay(mPassengerTemperatureTouchOverlay);
             }
 
             // set new states
@@ -574,25 +590,4 @@
             mInAnimation = false;
         }
     }
-
-    private void disableTouchOnOverlay(View view) {
-        WindowManager.LayoutParams params
-                = (WindowManager.LayoutParams) view.getLayoutParams();
-        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-        mWindowManager.updateViewLayout(view, params);
-    }
-
-    private void enableTouchOnOverlay(View view) {
-        WindowManager.LayoutParams params
-                = (WindowManager.LayoutParams) view.getLayoutParams();
-        params.flags =
-                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                        & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-        mWindowManager.updateViewLayout(view, params);
-    }
-
 }
diff --git a/src/com/android/car/hvac/controllers/TemperatureController.java b/src/com/android/car/hvac/controllers/TemperatureController.java
index bb314d6..5c68468 100644
--- a/src/com/android/car/hvac/controllers/TemperatureController.java
+++ b/src/com/android/car/hvac/controllers/TemperatureController.java
@@ -15,6 +15,7 @@
  */
 package com.android.car.hvac.controllers;
 
+import android.car.hardware.CarPropertyValue;
 import com.android.car.hvac.HvacController;
 import com.android.car.hvac.ui.TemperatureBarOverlay;
 
@@ -22,33 +23,70 @@
  * A controller that handles temperature updates for the driver and passenger.
  */
 public class TemperatureController {
-    private final TemperatureBarOverlay mDriverTempBar;
-    private final TemperatureBarOverlay mPassengerTempBar;
+    private final TemperatureBarOverlay mDriverTempBarExpanded;
+    private final TemperatureBarOverlay mPassengerTempBarExpanded;
+    private final TemperatureBarOverlay mDriverTempBarCollapsed;
+    private final TemperatureBarOverlay mPassengerTempBarCollapsed;
     private final HvacController mHvacController;
 
-    public TemperatureController(TemperatureBarOverlay passengerTemperatureBar,
-            TemperatureBarOverlay driverTemperatureBar, HvacController controller) {
-        mDriverTempBar = driverTemperatureBar;
-        mPassengerTempBar = passengerTemperatureBar;
+    //TODO: builder pattern for clarity
+    public TemperatureController(TemperatureBarOverlay passengerTemperatureBarExpanded,
+            TemperatureBarOverlay driverTemperatureBarExpanded,
+            TemperatureBarOverlay passengerTemperatureBarCollapsed,
+            TemperatureBarOverlay driverTemperatureBarCollapsed,
+            HvacController controller) {
+        mDriverTempBarExpanded = driverTemperatureBarExpanded;
+        mPassengerTempBarExpanded = passengerTemperatureBarExpanded;
+        mPassengerTempBarCollapsed = passengerTemperatureBarCollapsed;
+        mDriverTempBarCollapsed = driverTemperatureBarCollapsed;
         mHvacController = controller;
 
         mHvacController.registerCallback(mCallback);
-        mDriverTempBar.setTemperatureChangeListener(mDriverTempClickListener);
-        mPassengerTempBar.setTemperatureChangeListener(mPassengerTempClickListener);
+        mDriverTempBarExpanded.setTemperatureChangeListener(mDriverTempClickListener);
+        mPassengerTempBarExpanded.setTemperatureChangeListener(mPassengerTempClickListener);
 
-        mDriverTempBar.setTemperature(mHvacController.getDriverTemperature());
-        mPassengerTempBar.setTemperature(mHvacController.getPassengerTemperature());
+        final boolean isDriverTempControlAvailable =
+                mHvacController.isDriverTemperatureControlAvailable();
+        mDriverTempBarExpanded.setAvailable(isDriverTempControlAvailable);
+        mDriverTempBarCollapsed.setAvailable(isDriverTempControlAvailable);
+        if (isDriverTempControlAvailable) {
+            mDriverTempBarExpanded.setTemperature(mHvacController.getDriverTemperature());
+            mDriverTempBarCollapsed.setTemperature(mHvacController.getDriverTemperature());
+        }
+
+        final boolean isPassengerTempControlAvailable =
+            mHvacController.isPassengerTemperatureControlAvailable();
+        mPassengerTempBarExpanded.setAvailable(isPassengerTempControlAvailable);
+        mPassengerTempBarCollapsed.setAvailable(isPassengerTempControlAvailable);
+        if (isPassengerTempControlAvailable) {
+            mPassengerTempBarExpanded.setTemperature(mHvacController.getPassengerTemperature());
+            mPassengerTempBarCollapsed.setTemperature(mHvacController.getPassengerTemperature());
+        }
     }
 
     private final HvacController.Callback mCallback = new HvacController.Callback() {
         @Override
-        public void onPassengerTemperatureChange(float temp) {
-            mPassengerTempBar.setTemperature((int) temp);
+        public void onPassengerTemperatureChange(CarPropertyValue value) {
+            final boolean available = value.getStatus() == CarPropertyValue.STATUS_AVAILABLE;
+            mPassengerTempBarExpanded.setAvailable(available);
+            mPassengerTempBarCollapsed.setAvailable(available);
+            if (available) {
+                final int temp = ((Float)value.getValue()).intValue();
+                mPassengerTempBarExpanded.setTemperature(temp);
+                mPassengerTempBarCollapsed.setTemperature(temp);
+            }
         }
 
         @Override
-        public void onDriverTemperatureChange(float temp) {
-            mDriverTempBar.setTemperature((int) temp);
+        public void onDriverTemperatureChange(CarPropertyValue value) {
+            final boolean available = value.getStatus() == CarPropertyValue.STATUS_AVAILABLE;
+            mDriverTempBarExpanded.setAvailable(available);
+            mDriverTempBarExpanded.setAvailable(available);
+            if (available) {
+                final int temp = ((Float)value.getValue()).intValue();
+                mDriverTempBarCollapsed.setTemperature(temp);
+                mDriverTempBarExpanded.setTemperature(temp);
+            }
         }
     };
 
@@ -57,6 +95,7 @@
                 @Override
                 public void onTemperatureChanged(int temperature) {
                     mHvacController.setPassengerTemperature(temperature);
+                    mPassengerTempBarCollapsed.setTemperature(temperature);
                 }
             };
 
@@ -65,6 +104,7 @@
                 @Override
                 public void onTemperatureChanged(int temperature) {
                     mHvacController.setDriverTemperature(temperature);
+                    mDriverTempBarCollapsed.setTemperature(temperature);
                 }
             };
 }
diff --git a/src/com/android/car/hvac/ui/FanDirectionButtons.java b/src/com/android/car/hvac/ui/FanDirectionButtons.java
index 6863e61..b07de9b 100644
--- a/src/com/android/car/hvac/ui/FanDirectionButtons.java
+++ b/src/com/android/car/hvac/ui/FanDirectionButtons.java
@@ -18,12 +18,14 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.IntDef;
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+
+import androidx.annotation.IntDef;
+
 import com.android.car.hvac.R;
 
 import java.util.HashMap;
diff --git a/src/com/android/car/hvac/ui/SeatWarmerButton.java b/src/com/android/car/hvac/ui/SeatWarmerButton.java
index 344e919..93ee76e 100644
--- a/src/com/android/car/hvac/ui/SeatWarmerButton.java
+++ b/src/com/android/car/hvac/ui/SeatWarmerButton.java
@@ -18,10 +18,12 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.IntDef;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ImageView;
+
+import androidx.annotation.IntDef;
+
 import com.android.car.hvac.R;
 
 /**
diff --git a/src/com/android/car/hvac/ui/SystemUiObserver.java b/src/com/android/car/hvac/ui/SystemUiObserver.java
deleted file mode 100644
index adddf12..0000000
--- a/src/com/android/car/hvac/ui/SystemUiObserver.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.hvac.ui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-
-/**
- * Mostly a hack. The system ui change methods on View or even the listeners don't get
- * called reliably, it seems like the framework is caching drawn views for performance
- * reasons. Instead we make this class which is a framelayout that must be match_parent
- * along both dimensions. This way we have this view that gets asked to be laid out
- * every time the screen size changes, which we can then use to compute whether the
- * system ui is visible or not.
- */
-public class SystemUiObserver extends FrameLayout {
-    private Listener mListener;
-    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
-    // Assuming that android always starts up with systemui visible.
-    private boolean mVisible = true;
-
-    {
-        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
-        wm.getDefaultDisplay().getRealMetrics(mDisplayMetrics);
-    }
-
-    public SystemUiObserver(Context context) {
-        super(context);
-    }
-
-    public SystemUiObserver(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public SystemUiObserver(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        boolean visible = !(bottom == mDisplayMetrics.heightPixels);
-        if (visible != mVisible && mListener != null) {
-            mListener.onSystemUiVisibilityChange(visible);
-        }
-        mVisible = visible;
-        super.onLayout(changed, left, top, right, bottom);
-    }
-
-    public void setListener(Listener listener) {
-        mListener = listener;
-    }
-
-    public interface Listener {
-        void onSystemUiVisibilityChange(boolean visible);
-    }
-}
diff --git a/src/com/android/car/hvac/ui/TemperatureBarOverlay.java b/src/com/android/car/hvac/ui/TemperatureBarOverlay.java
index 892ad6f..5d5e845 100644
--- a/src/com/android/car/hvac/ui/TemperatureBarOverlay.java
+++ b/src/com/android/car/hvac/ui/TemperatureBarOverlay.java
@@ -23,6 +23,7 @@
 import android.content.res.Resources;
 import android.graphics.drawable.GradientDrawable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -36,6 +37,7 @@
  * An expandable temperature control bar. Note this UI is meant to only support Fahrenheit.
  */
 public class TemperatureBarOverlay extends FrameLayout {
+
     /**
      * A listener that observes clicks on the temperature bar.
      */
@@ -56,8 +58,8 @@
     private static final float BUTTON_ALPHA_EXPANDED = 1.0f;
 
     private static final int DEFAULT_TEMPERATURE = 32;
-    private static final int MAX_TEMPERATURE = 85;
-    private static final int MIN_TEMPERATURE = 60;
+    private static final int MAX_TEMPERATURE = 256;
+    private static final int MIN_TEMPERATURE = 0;
 
     private String mInvalidTemperature;
 
@@ -106,17 +108,16 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
         Resources res = getResources();
 
         mCollapsedHeight = res.getDimensionPixelSize(R.dimen.temperature_bar_collapsed_height);
         mExpandedHeight = res.getDimensionPixelSize(R.dimen.temperature_bar_expanded_height);
         // Push the collapsed circle all the way down to the bottom of the screen and leave
         // half of it visible.
-        mCollapsedYShift
-                = res.getDimensionPixelSize(R.dimen.car_hvac_panel_full_expanded_height)
-                - (mCollapsedHeight / 2);
-        mExpandedYShift = res.getDimensionPixelSize(R.dimen.hvac_panel_row_margin);
+        mCollapsedYShift = (mCollapsedHeight / 2);
+        // center of expanded panel. The extra nudge of the mCollapsedYShift is to make up for
+        // the fact that the gravity is set to bottom.
+        mExpandedYShift = mCollapsedYShift - ((mExpandedHeight - mCollapsedHeight)/ 2);
 
         mCollapsedWidth = res.getDimensionPixelSize(R.dimen.temperature_bar_width_collapsed);
         mExpandedWidth = res.getDimensionPixelSize(R.dimen.temperature_bar_width_expanded);
@@ -131,12 +132,12 @@
 
         mOffColor = res.getColor(R.color.hvac_temperature_off_text_bg_color);
 
-        mIncreaseButton = (ImageView) findViewById(R.id.increase_button);
-        mDecreaseButton = (ImageView) findViewById(R.id.decrease_button);
+        mIncreaseButton = findViewById(R.id.increase_button);
+        mDecreaseButton = findViewById(R.id.decrease_button);
 
-        mFloatingText = (TextView) findViewById(R.id.floating_temperature_text);
-        mText = (TextView) findViewById(R.id.temperature_text);
-        mOffText = (TextView) findViewById(R.id.temperature_off_text);
+        mFloatingText = findViewById(R.id.floating_temperature_text);
+        mText = findViewById(R.id.temperature_text);
+        mOffText = findViewById(R.id.temperature_off_text);
 
         mTemperatureBar = findViewById(R.id.temperature_bar);
         mTemperatureBar.setTranslationY(mCollapsedYShift);
@@ -170,6 +171,7 @@
     public void setBarOnClickListener(OnClickListener l) {
         mFloatingText.setOnClickListener(l);
         mTemperatureBar.setOnClickListener(l);
+        setOnClickListener(l);
     }
 
     public void setCloseButtonOnClickListener(OnClickListener l) {
@@ -177,7 +179,7 @@
     }
 
     public AnimatorSet getExpandAnimatons() {
-        List<Animator> list = new ArrayList();
+        List<Animator> list = new ArrayList<>();
         AnimatorSet animation = new AnimatorSet();
         if (mIsOpen) {
             return animation;
@@ -189,12 +191,12 @@
         list.add(getAlphaAnimator(mFloatingText, true /* fade */,
                 TEXT_ALPHA_FADE_OUT_ANIMATION_TIME_MS));
 
-        ValueAnimator widthAnimator = new ValueAnimator().ofInt(mCollapsedWidth, mExpandedWidth)
+        ValueAnimator widthAnimator = ValueAnimator.ofInt(mCollapsedWidth, mExpandedWidth)
                 .setDuration(EXPAND_ANIMATION_TIME_MS);
         widthAnimator.addUpdateListener(mWidthUpdateListener);
         list.add(widthAnimator);
 
-        ValueAnimator heightAnimator = new ValueAnimator().ofInt(mCollapsedHeight,
+        ValueAnimator heightAnimator = ValueAnimator.ofInt(mCollapsedHeight,
                 mExpandedHeight)
                 .setDuration(EXPAND_ANIMATION_TIME_MS);
         heightAnimator.addUpdateListener(mHeightUpdateListener);
@@ -202,7 +204,7 @@
 
 
         ValueAnimator translationYAnimator
-                = new ValueAnimator().ofFloat(mCollapsedYShift, mExpandedYShift);
+                = ValueAnimator.ofFloat(mCollapsedYShift, mExpandedYShift);
         translationYAnimator.addUpdateListener(mTranslationYListener);
         list.add(translationYAnimator);
 
@@ -214,7 +216,7 @@
 
     public AnimatorSet getCollapseAnimations() {
 
-        List<Animator> list = new ArrayList();
+        List<Animator> list = new ArrayList<>();
         AnimatorSet animation = new AnimatorSet();
 
         if (!mIsOpen) {
@@ -230,18 +232,18 @@
 
         list.add(floatingTextAnimator);
 
-        ValueAnimator widthAnimator = new ValueAnimator().ofInt(mExpandedWidth, mCollapsedWidth)
+        ValueAnimator widthAnimator = ValueAnimator.ofInt(mExpandedWidth, mCollapsedWidth)
                 .setDuration(COLLAPSE_ANIMATION_TIME_MS);
         widthAnimator.addUpdateListener(mWidthUpdateListener);
         list.add(widthAnimator);
 
-        ValueAnimator heightAnimator = new ValueAnimator().ofInt(mExpandedHeight, mCollapsedHeight)
+        ValueAnimator heightAnimator = ValueAnimator.ofInt(mExpandedHeight, mCollapsedHeight)
                 .setDuration(COLLAPSE_ANIMATION_TIME_MS);
         heightAnimator.addUpdateListener(mHeightUpdateListener);
         list.add(heightAnimator);
 
         ValueAnimator translationYAnimator
-                = new ValueAnimator().ofFloat(mExpandedYShift, mCollapsedYShift);
+                = ValueAnimator.ofFloat(mExpandedYShift, mCollapsedYShift);
         translationYAnimator.addUpdateListener(mTranslationYListener);
         list.add(translationYAnimator);
 
@@ -288,6 +290,7 @@
         }
     };
 
+
     private void changeTemperatureColor(int startColor, int endColor) {
         if (endColor != startColor) {
             ValueAnimator animator = ValueAnimator.ofArgb(startColor, endColor);
@@ -302,24 +305,41 @@
     private final View.OnClickListener temperatureClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            int startColor = getTemperatureColor(mTemperature);
+            synchronized (this) {
+                if (!mIsOn) {
+                    Log.d("HvacTempBar", "setting temperature not available");
+                    return;
+                }
+                int startColor = getTemperatureColor(mTemperature);
 
-            if (v == mIncreaseButton && mTemperature < MAX_TEMPERATURE) {
-                mTemperature++;
-            } else if (v == mDecreaseButton && mTemperature > MIN_TEMPERATURE) {
-                mTemperature--;
-            }
-            int endColor = getTemperatureColor(mTemperature);
-            changeTemperatureColor(startColor, endColor);
+                if (v == mIncreaseButton && mTemperature < MAX_TEMPERATURE) {
+                    mTemperature++;
+                    Log.d("HvacTempBar", "increased temperature to " + mTemperature);
+                } else if (v == mDecreaseButton && mTemperature > MIN_TEMPERATURE) {
+                    mTemperature--;
+                    Log.d("HvacTempBar", "decreased temperature to " + mTemperature);
+                } else {
+                    Log.d("HvacTempBar", "key not recognized");
+                }
+                int endColor = getTemperatureColor(mTemperature);
+                changeTemperatureColor(startColor, endColor);
 
-            mText.setText(getContext().getString(R.string.hvac_temperature_template, mTemperature));
-            mFloatingText.setText(getContext()
+                mText.setText(
+                    getContext().getString(R.string.hvac_temperature_template, mTemperature));
+                mFloatingText.setText(getContext()
                     .getString(R.string.hvac_temperature_template, mTemperature));
-            mListener.onTemperatureChanged(mTemperature);
+                mListener.onTemperatureChanged(mTemperature);
+            }
         }
     };
 
+    public void setAvailable(boolean available) {
+        Log.d("HvacTempBar", "setAvailable(" + available + ")");
+        setIsOn(available);
+    }
+
     public void setTemperature(int temperature) {
+        Log.d("HvacTempBar", "setTemperature(" + temperature + ")");
         int startColor = getTemperatureColor(mTemperature);
         int endColor = getTemperatureColor(temperature);
         mTemperature = temperature;
@@ -331,14 +351,16 @@
             temperatureString = String.valueOf(mTemperature);
         }
 
-        mText.setText(getContext().getString(R.string.hvac_temperature_template,
+        synchronized (this) {
+            mText.setText(getContext().getString(R.string.hvac_temperature_template,
                 temperatureString));
-        mFloatingText.setText(getContext()
+            mFloatingText.setText(getContext()
                 .getString(R.string.hvac_temperature_template, temperatureString));
 
-        // Only animate the color if the button is currently enabled.
-        if (mIsOn) {
-            changeTemperatureColor(startColor, endColor);
+            // Only animate the color if the button is currently enabled.
+            if (mIsOn) {
+                changeTemperatureColor(startColor, endColor);
+            }
         }
     }
 
@@ -347,19 +369,22 @@
      * of the temperature.
      */
     public void setIsOn(boolean isOn) {
-        mIsOn = isOn;
-        GradientDrawable temperatureBall
+        synchronized (this) {
+            mIsOn = isOn;
+
+            GradientDrawable temperatureBall
                 = (GradientDrawable) mTemperatureBar.getBackground();
-        if (mIsOn) {
-            mFloatingText.setVisibility(VISIBLE);
-            mOffText.setVisibility(GONE);
-            temperatureBall.setColor(getTemperatureColor(mTemperature));
-            setAlpha(1.0f);
-        } else {
-            mOffText.setVisibility(VISIBLE);
-            mFloatingText.setVisibility(GONE);
-            temperatureBall.setColor(mOffColor);
-            setAlpha(.2f);
+            if (mIsOn) {
+                mFloatingText.setVisibility(VISIBLE);
+                mOffText.setVisibility(GONE);
+                temperatureBall.setColor(getTemperatureColor(mTemperature));
+                setAlpha(1.0f);
+            } else {
+                mOffText.setVisibility(VISIBLE);
+                mFloatingText.setVisibility(GONE);
+                temperatureBall.setColor(mOffColor);
+                setAlpha(.2f);
+            }
         }
     }
 
@@ -417,10 +442,6 @@
         }
     };
 
-    private ObjectAnimator getAlphaAnimator(View view, boolean fade) {
-        return getAlphaAnimator(view, fade, EXPAND_ANIMATION_TIME_MS);
-    }
-
     private ObjectAnimator getAlphaAnimator(View view, boolean fade, int duration) {
 
         float startingAlpha = BUTTON_ALPHA_COLLAPSED;