Merge pi-dev-plus-aosp-without-vendor into stage-aosp-master
Bug: 79597307
Change-Id: Ief5c8ee079ba937e35c1d1e5df0e11600a2f8c68
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;