Add HVAC temp with buttons to nav bar

Created AdjustableTemperatureView class that implements the
TemperatureView interface to display temperature with buttons to
increment and decrement. Updated HvacController to only handle the
set temperature HVAC property. Removed uses of deprecated
CarHvacManager, using CarPropertyManager instead. Also modified and
updated the hvac tests.

UI changes:
- Add driver and passenger HVAC views to nav bar
- Use colored arrows with grey circle for hvac increase/decrease

Test: atest :carsysui-presubmit --include-subdir
Test: Manual - built on flame_car
Bug: 162598687
Change-Id: I39151884f2307e861d290de7ad39ea2ec0c256e8
This commit is contained in:
Julia Kawano
2020-08-21 21:37:47 +00:00
committed by Julia Kawano
parent 224c81c6da
commit 7f40cfb1f6
25 changed files with 945 additions and 355 deletions

View File

@@ -15,11 +15,11 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
android:viewportHeight="44"
android:width="44dp"
android:height="44dp">
<path
android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
android:fillColor="@color/car_nav_icon_fill_color" />
android:viewportHeight="44">
<path
android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
android:fillColor="@color/car_nav_icon_fill_color" />
</vector>

View File

@@ -15,10 +15,10 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
android:viewportHeight="44"
android:width="44dp"
android:height="44dp">
android:viewportHeight="44">
<path
android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
android:fillColor="@color/car_nav_icon_fill_color_selected" />

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
android:fillColor="@color/car_nav_icon_fill_color" />
</vector>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
android:fillColor="@color/car_nav_icon_fill_color_selected" />
</vector>

View File

@@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
@@ -14,38 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="37dp"
android:height="31dp"
android:viewportWidth="37"
android:viewportHeight="31">
<group
android:translateX="-4.000000"
android:translateY="-6.000000">
<group
android:translateX="5.000000"
android:translateY="5.000000">
<path
android:fillType="evenOdd"
android:strokeColor="#FAFAFA"
android:strokeWidth="3.5"
android:pathData="M0.320769938,6.07518051 C6.46754647,1.46509811 12.4222362,1.46509811
18.1848392,6.07518051 C23.9474422,10.6852629 29.3258717,10.4931761
34.3201276,5.49892021" />
<path
android:fillType="evenOdd"
android:strokeColor="#FAFAFA"
android:strokeWidth="3.5"
android:pathData="M0.320769938,17.0751805 C6.46754647,12.4650981 12.4222362,12.4650981
18.1848392,17.0751805 C23.9474422,21.6852629 29.3258717,21.4931761
34.3201276,16.4989202" />
<path
android:fillType="evenOdd"
android:strokeColor="#FAFAFA"
android:strokeWidth="3.5"
android:pathData="M0.320769938,28.0751805 C6.46754647,23.4650981 12.4222362,23.4650981
18.1848392,28.0751805 C23.9474422,32.6852629 29.3258717,32.4931761
34.3201276,27.4989202" />
</group>
</group>
</vector>
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
android:fillColor="@color/car_nav_icon_fill_color" />
</vector>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
android:fillColor="@color/car_nav_icon_fill_color_selected" />
</vector>

View File

@@ -15,10 +15,10 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="44"
android:viewportHeight="44"
android:width="44dp"
android:height="44dp">
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
android:viewportHeight="44">
<path
android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
android:fillColor="@color/car_nav_icon_fill_color" />

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
~ Copyright (C) 2020 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.
-->
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<item android:gravity="center"
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size">
<aapt:attr name="android:drawable">
<shape android:shape="oval">
<size
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"/>
<solid
android:color="#3C4043"/>
</shape>
</aapt:attr>
</item>
<item android:gravity="center"
android:width="48dp"
android:height="48dp">
<aapt:attr name="android:drawable">
<vector android:width="48dp"
android:height="48dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#8AB4F8"
android:pathData="M14,7l-5,5 5,5V7z"/>
</vector>
</aapt:attr>
</item>
<item>
<aapt:attr name="android:drawable">
<ripple android:color="?android:attr/colorControlHighlight"/>
</aapt:attr>
</item>
</layer-list>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
~ Copyright (C) 2020 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.
-->
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<item android:gravity="center"
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size">
<aapt:attr name="android:drawable">
<shape android:shape="oval">
<size
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"/>
<solid
android:color="#3C4043"/>
</shape>
</aapt:attr>
</item>
<item android:gravity="center"
android:width="48dp"
android:height="48dp">
<aapt:attr name="android:drawable">
<vector android:width="48dp"
android:height="48dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#F28B82"
android:pathData="M10,17l5,-5 -5,-5v10z"/>
</vector>
</aapt:attr>
</item>
<item>
<aapt:attr name="android:drawable">
<ripple android:color="?android:attr/colorControlHighlight"/>
</aapt:attr>
</item>
</layer-list>

View File

@@ -15,11 +15,11 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="44"
android:viewportHeight="44"
android:width="44dp"
android:height="44dp">
<path
android:width="@dimen/system_bar_icon_drawing_size"
android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
android:viewportHeight="44">
<path
android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z"
android:fillColor="@color/car_nav_icon_fill_color" />
</vector>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
~ Copyright (C) 2020 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingEnd="@dimen/hvac_container_padding"
android:paddingStart="@dimen/hvac_container_padding">
<ImageView
android:id="@+id/hvac_decrease_button"
android:layout_width="@dimen/hvac_temperature_button_size"
android:layout_height="@dimen/hvac_temperature_button_size"
android:scaleType="center"
android:src="@drawable/hvac_decrease_button"/>
<TextView
android:id="@+id/hvac_temperature_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="@dimen/hvac_temperature_text_size"
android:textColor="@color/system_bar_text_color"
android:paddingStart="@dimen/hvac_temperature_text_padding"
android:paddingEnd="@dimen/hvac_temperature_text_padding"
android:gravity="center"/>
<ImageView
android:id="@+id/hvac_increase_button"
android:layout_width="@dimen/hvac_temperature_button_size"
android:layout_height="@dimen/hvac_temperature_button_size"
android:scaleType="center"
android:src="@drawable/hvac_increase_button" />
</LinearLayout>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2018 The Android Open Source Project
~ Copyright (C) 2020 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.
@@ -12,7 +12,7 @@
~ 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
~ limitations under the License.
-->
<com.android.systemui.car.navigationbar.CarNavigationBarView
@@ -21,115 +21,115 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/system_bar_background"
android:orientation="vertical">
<!--The 20dp padding is the difference between the background selected icon size and the ripple
that was chosen, thus it's a hack to make it look pretty and not an official margin value-->
<LinearLayout
android:gravity="center"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/nav_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:layoutDirection="ltr"
android:paddingEnd="20dp"
android:paddingStart="20dp">
android:layoutDirection="ltr">
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/home"
style="@style/NavigationBarButton"
systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
systemui:icon="@drawable/car_ic_overview"
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
systemui:selectedIcon="@drawable/car_ic_overview_selected"
systemui:highlightWhenSelected="true"
/>
<Space
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"/>
android:layout_alignParentStart="true"
android:background="@null"
systemui:broadcast="true"
systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end">
<com.android.systemui.car.hvac.AdjustableTemperatureView
android:id="@+id/driver_hvac"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
systemui:hvacAreaId="49"
systemui:hvacTempFormat="%.0f\u00B0" />
</com.android.systemui.car.navigationbar.CarNavigationButton>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_weight="1"
android:gravity="center"
android:layoutDirection="ltr"
android:paddingEnd="@dimen/system_bar_button_group_padding"
android:paddingStart="@dimen/system_bar_button_group_padding">
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/home"
style="@style/NavigationBarButton"
systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
systemui:icon="@drawable/car_ic_home"
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
systemui:selectedIcon="@drawable/car_ic_home_selected"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/phone_nav"
style="@style/NavigationBarButton"
systemui:icon="@drawable/car_ic_phone"
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
systemui:packages="com.android.car.dialer"
systemui:selectedIcon="@drawable/car_ic_phone_selected"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/grid_nav"
style="@style/NavigationBarButton"
systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
systemui:icon="@drawable/car_ic_apps"
systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
systemui:selectedIcon="@drawable/car_ic_apps_selected"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/hvac"
style="@style/NavigationBarButton"
systemui:icon="@drawable/car_ic_hvac"
systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
systemui:selectedIcon="@drawable/car_ic_hvac_selected"
systemui:broadcast="true"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/notifications"
style="@style/NavigationBarButton"
systemui:icon="@drawable/car_ic_notification"
systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
<com.android.systemui.car.navigationbar.AssitantButton
android:id="@+id/assist"
style="@style/NavigationBarButton"
systemui:icon="@drawable/ic_mic_white"
systemui:useDefaultAppIconForRole="true"/>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/maps_nav"
style="@style/NavigationBarButton"
systemui:categories="android.intent.category.APP_MAPS"
systemui:icon="@drawable/car_ic_navigation"
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;launchFlags=0x14000000;end"
systemui:selectedIcon="@drawable/car_ic_navigation_selected"
systemui:highlightWhenSelected="true"
/>
<Space
android:layout_width="0dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"/>
android:layout_alignParentEnd="true"
android:background="@null"
systemui:broadcast="true"
systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end">
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/music_nav"
style="@style/NavigationBarButton"
systemui:categories="android.intent.category.APP_MUSIC"
systemui:icon="@drawable/car_ic_music"
systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
systemui:packages="com.android.car.media"
systemui:selectedIcon="@drawable/car_ic_music_selected"
systemui:highlightWhenSelected="true"
/>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/phone_nav"
style="@style/NavigationBarButton"
systemui:icon="@drawable/car_ic_phone"
systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
systemui:packages="com.android.car.dialer"
systemui:selectedIcon="@drawable/car_ic_phone_selected"
systemui:highlightWhenSelected="true"
/>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/grid_nav"
style="@style/NavigationBarButton"
systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
systemui:icon="@drawable/car_ic_apps"
systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
systemui:selectedIcon="@drawable/car_ic_apps_selected"
systemui:highlightWhenSelected="true"
/>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/notifications"
style="@style/NavigationBarButton"
systemui:icon="@drawable/car_ic_notification"
systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"
/>
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<com.android.systemui.car.navigationbar.AssitantButton
android:id="@+id/assist"
style="@style/NavigationBarButton"
systemui:icon="@drawable/ic_mic_white"
systemui:useDefaultAppIconForRole="true"
/>
</LinearLayout>
<com.android.systemui.car.hvac.AdjustableTemperatureView
android:id="@+id/passenger_hvac"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:gravity="center_vertical"
systemui:hvacAreaId="68"
systemui:hvacTempFormat="%.0f\u00B0" />
</com.android.systemui.car.navigationbar.CarNavigationButton>
</RelativeLayout>
<LinearLayout
android:id="@+id/lock_screen_nav_buttons"
@@ -142,5 +142,4 @@
android:paddingStart="@dimen/car_keyline_1"
android:visibility="gone"
/>
</com.android.systemui.car.navigationbar.CarNavigationBarView>

View File

@@ -55,10 +55,6 @@
android:minEms="4"
android:textAppearance="@style/TextAppearance.CarStatus"
systemui:hvacAreaId="49"
systemui:hvacMaxText="@string/hvac_max_text"
systemui:hvacMaxValue="@dimen/hvac_max_value"
systemui:hvacMinText="@string/hvac_min_text"
systemui:hvacMinValue="@dimen/hvac_min_value"
systemui:hvacPivotOffset="60dp"
systemui:hvacPropertyId="358614275"
systemui:hvacTempFormat="%.0f\u00B0"
@@ -133,10 +129,6 @@
android:minEms="4"
android:textAppearance="@style/TextAppearance.CarStatus"
systemui:hvacAreaId="68"
systemui:hvacMaxText="@string/hvac_max_text"
systemui:hvacMaxValue="@dimen/hvac_max_value"
systemui:hvacMinText="@string/hvac_min_text"
systemui:hvacMinValue="@dimen/hvac_min_value"
systemui:hvacPivotOffset="60dp"
systemui:hvacPropertyId="358614275"
systemui:hvacTempFormat="%.0f\u00B0"

View File

@@ -33,6 +33,7 @@
<!-- colors for status bar -->
<color name="system_bar_user_icon_color">#ffffff</color>
<color name="system_bar_text_color">#ffffff</color>
<color name="status_bar_background_color">#33000000</color>
<drawable name="system_bar_background">@color/status_bar_background_color</drawable>

View File

@@ -47,16 +47,22 @@
set here. See car_product overlay for car specific defaults-->
<dimen name="system_bar_user_icon_padding">16dp</dimen>
<dimen name="system_bar_icon_drawing_size_dark">36dp</dimen>
<dimen name="system_bar_icon_drawing_size">36dp</dimen>
<dimen name="system_bar_user_icon_drawing_size">36dp</dimen>
<dimen name="system_bar_button_group_padding">64dp</dimen>
<dimen name="system_bar_icon_drawing_size">44dp</dimen>
<!-- The amount by which to scale up the status bar icons. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.75</item>
<dimen name="car_primary_icon_size">@*android:dimen/car_primary_icon_size</dimen>
<dimen name="hvac_container_padding">16dp</dimen>
<dimen name="hvac_temperature_text_size">56sp</dimen>
<dimen name="hvac_temperature_text_padding">8dp</dimen>
<dimen name="hvac_temperature_button_size">76dp</dimen>
<!--These values represent MIN and MAX for hvac-->
<item name="hvac_min_value" format="float" type="dimen">0</item>
<item name="hvac_max_value" format="float" type="dimen">126</item>
<item name="hvac_min_value_celsius" format="float" type="dimen">0</item>
<item name="hvac_max_value_celsius" format="float" type="dimen">126</item>
<!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
quick settings header -->

View File

@@ -16,6 +16,8 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Format for HVAC temperature (No decimal and the degree symbol) -->
<string name="hvac_temperature_format" translatable="false">%.0f\u00B0</string>
<!-- String to represent lowest setting of an HVAC system [CHAR LIMIT=10]-->
<string name="hvac_min_text">Min</string>
<!-- String to represent largest setting of an HVAC system [CHAR LIMIT=10]-->

View File

@@ -34,17 +34,20 @@
<style name="TextAppearance.SystemBar.Username"
parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">@dimen/car_body3_size</item>
<item name="android:textColor">@*android:color/car_headline3</item>
<item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">@*android:dimen/car_body2_size</item>
<item name="android:textColor">@*android:color/car_grey_50</item>
<item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="NavigationBarButton">
<item name="android:layout_height">96dp</item>
<item name="android:layout_width">96dp</item>
<item name="android:layout_height">76dp</item>
<item name="android:layout_width">76dp</item>
<item name="android:layout_marginEnd">32dp</item>
<item name="android:padding">16dp</item>
<item name="android:gravity">center</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2020 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.systemui.car.hvac;
import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.R;
/**
* Displays temperature with a button to decrease and a button to increase on either side.
* Properties configured in the XML:
* hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
*/
public class AdjustableTemperatureView extends LinearLayout implements TemperatureView {
private HvacController mHvacController;
private float mCurrentTempC;
private TextView mTempTextView;
private boolean mDisplayInFahrenheit = false;
private final float mMinTempC;
private final float mMaxTempC;
private final int mAreaId;
private final String mTempFormat;
public AdjustableTemperatureView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
LayoutInflater.from(context).inflate(R.layout.adjustable_temperature_view, /* root= */this);
mTempFormat = getResources().getString(R.string.hvac_temperature_format);
mMinTempC = getResources().getFloat(R.dimen.hvac_min_value_celsius);
mMaxTempC = getResources().getFloat(R.dimen.hvac_max_value_celsius);
initializeButtons();
}
@Override
public void setHvacController(HvacController controller) {
mHvacController = controller;
}
@Override
public void setTemperatureView(float tempC) {
if (tempC > mMaxTempC || tempC < mMinTempC) {
return;
}
if (mTempTextView == null) {
mTempTextView = findViewById(R.id.hvac_temperature_text);
}
mTempTextView.setText(String.format(mTempFormat,
mDisplayInFahrenheit ? convertToFahrenheit(tempC) : tempC));
mCurrentTempC = tempC;
}
@Override
public void setDisplayInFahrenheit(boolean displayFahrenheit) {
mDisplayInFahrenheit = displayFahrenheit;
setTemperatureView(mCurrentTempC);
}
@Override
public int getAreaId() {
return mAreaId;
}
private void initializeButtons() {
findViewById(R.id.hvac_decrease_button).setOnClickListener(v -> {
float newTemp = mDisplayInFahrenheit ? convertToCelsius(
convertToFahrenheit(mCurrentTempC) - 1) : (mCurrentTempC - 1);
setTemperature(newTemp, mAreaId);
});
findViewById(R.id.hvac_increase_button).setOnClickListener(v -> {
float newTemp = mDisplayInFahrenheit ? convertToCelsius(
convertToFahrenheit(mCurrentTempC) + 1) : (mCurrentTempC + 1);
setTemperature(newTemp, mAreaId);
});
}
private void setTemperature(float tempC, int zone) {
if (tempC < mMaxTempC && tempC > mMinTempC && mHvacController != null) {
mHvacController.setTemperature(tempC, zone);
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.systemui.car.hvac;
import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -40,9 +42,7 @@ import com.android.systemui.R;
* Simple text display of HVAC properties, It is designed to show mTemperature and is configured in
* the XML.
* XML properties:
* hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
* hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
* hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
* hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
* hvacOrientaion = Example: left
*/
public class AnimatedTemperatureView extends FrameLayout implements TemperatureView {
@@ -84,7 +84,6 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
}
private final int mAreaId;
private final int mPropertyId;
private final int mPivotOffset;
private final int mGravity;
private final int mTextAppearanceRes;
@@ -100,12 +99,13 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
private final TemperatureTextAnimator mTextAnimator;
boolean mDisplayInFahrenheit = false;
private HvacController mHvacController;
public AnimatedTemperatureView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.AnimatedTemperatureView);
mAreaId = typedArray.getInt(R.styleable.AnimatedTemperatureView_hvacAreaId, -1);
mPropertyId = typedArray.getInt(R.styleable.AnimatedTemperatureView_hvacPropertyId, -1);
mPivotOffset =
typedArray.getDimensionPixelOffset(
R.styleable.AnimatedTemperatureView_hvacPivotOffset, 0);
@@ -115,11 +115,8 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
typedArray.getResourceId(R.styleable.AnimatedTemperatureView_android_textAppearance,
0);
mMinEms = typedArray.getInteger(R.styleable.AnimatedTemperatureView_android_minEms, 0);
mMinValue = typedArray.getFloat(R.styleable.AnimatedTemperatureView_hvacMinValue,
Float.NaN);
mMaxValue = typedArray.getFloat(R.styleable.AnimatedTemperatureView_hvacMaxValue,
Float.NaN);
mMinValue = getResources().getFloat(R.dimen.hvac_min_value_celsius);
mMaxValue = getResources().getFloat(R.dimen.hvac_max_value_celsius);
mPaddingRect =
new Rect(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
@@ -138,15 +135,10 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
mBackgroundAnimator = new TemperatureBackgroundAnimator(this, background);
String format = typedArray.getString(R.styleable.AnimatedTemperatureView_hvacTempFormat);
format = (format == null) ? "%.1f\u00B0" : format;
CharSequence minText = typedArray.getString(
R.styleable.AnimatedTemperatureView_hvacMinText);
CharSequence maxText = typedArray.getString(
R.styleable.AnimatedTemperatureView_hvacMaxText);
mTextAnimator = new TemperatureTextAnimator(this, textSwitcher, format, mPivotOffset,
minText, maxText);
mTextAnimator = new TemperatureTextAnimator(this, textSwitcher,
getResources().getString(R.string.hvac_temperature_format), mPivotOffset,
getResources().getString(R.string.hvac_min_text),
getResources().getString(R.string.hvac_max_text));
addView(background, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
@@ -186,13 +178,18 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
return textView;
}
@Override
public void setHvacController(HvacController controller) {
mHvacController = controller;
}
/**
* Formats the float for display
*
* @param temp - The current temp or NaN
*/
@Override
public void setTemp(float temp) {
public void setTemperatureView(float temp) {
if (mDisplayInFahrenheit) {
temp = convertToFahrenheit(temp);
}
@@ -252,15 +249,7 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
}
/**
* @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (358614275)
*/
@Override
public int getPropertyId() {
return mPropertyId;
}
/**
* @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
* @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
@Override
public int getAreaId() {
@@ -272,6 +261,5 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
super.onDetachedFromWindow();
mBackgroundAnimator.stopAnimations();
}
}

View File

@@ -18,12 +18,12 @@ package com.android.systemui.car.hvac;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import android.car.Car;
import android.car.VehicleUnit;
import android.car.hardware.CarPropertyValue;
import android.car.hardware.hvac.CarHvacManager;
import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
import android.car.hardware.property.CarPropertyManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -34,10 +34,8 @@ import com.android.systemui.dagger.SysUISingleton;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
@@ -54,49 +52,64 @@ public class HvacController {
private final CarServiceProvider mCarServiceProvider;
private final Set<TemperatureView> mRegisteredViews = new HashSet<>();
private CarHvacManager mHvacManager;
private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
private CarPropertyManager mCarPropertyManager;
private HashMap<Integer, List<TemperatureView>> mTempComponents = new HashMap<>();
/**
* Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
* match.
*/
private final CarHvacEventCallback mHardwareCallback = new CarHvacEventCallback() {
@Override
public void onChangeEvent(final CarPropertyValue val) {
try {
int areaId = val.getAreaId();
int propertyId = val.getPropertyId();
List<TemperatureView> temperatureViews = mTempComponents.get(
new HvacKey(propertyId, areaId));
if (temperatureViews != null && !temperatureViews.isEmpty()) {
float value = (float) val.getValue();
if (DEBUG) {
Log.d(TAG, "onChangeEvent: " + areaId + ":" + propertyId + ":" + value);
private final CarPropertyManager.CarPropertyEventCallback mHvacTemperatureSetCallback =
new CarPropertyManager.CarPropertyEventCallback() {
@Override
public void onChangeEvent(CarPropertyValue value) {
try {
int areaId = value.getAreaId();
List<TemperatureView> temperatureViews = mTempComponents.get(areaId);
if (temperatureViews != null && !temperatureViews.isEmpty()) {
float newTemp = (float) value.getValue();
if (DEBUG) {
Log.d(TAG, "onChangeEvent: " + areaId + ":" + value);
}
for (TemperatureView view : temperatureViews) {
view.setTemperatureView(newTemp);
}
}
} catch (Exception e) {
Log.e(TAG, "Failed handling hvac change event", e);
}
for (TemperatureView tempView : temperatureViews) {
tempView.setTemp(value);
}
} // else the data is not of interest
} catch (Exception e) {
// catch all so we don't take down the sysui if a new data type is
// introduced.
Log.e(TAG, "Failed handling hvac change event", e);
}
}
}
@Override
public void onErrorEvent(final int propertyId, final int zone) {
Log.d(TAG, "HVAC error event, propertyId: " + propertyId
+ " zone: " + zone);
}
};
@Override
public void onErrorEvent(int propId, int zone) {
Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
}
};
private final CarPropertyManager.CarPropertyEventCallback mTemperatureUnitChangeCallback =
new CarPropertyManager.CarPropertyEventCallback() {
@Override
public void onChangeEvent(CarPropertyValue value) {
if (!mRegisteredViews.isEmpty()) {
for (TemperatureView view : mRegisteredViews) {
view.setDisplayInFahrenheit(
value.getValue().equals(VehicleUnit.FAHRENHEIT));
}
}
}
@Override
public void onErrorEvent(int propId, int zone) {
Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
}
};
private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
car -> {
try {
mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
mHvacManager.registerCallback(mHardwareCallback);
mCarPropertyManager = (CarPropertyManager) car.getCarManager(
Car.PROPERTY_SERVICE);
mCarPropertyManager.registerCallback(mHvacTemperatureSetCallback,
HVAC_TEMPERATURE_SET, CarPropertyManager.SENSOR_RATE_ONCHANGE);
mCarPropertyManager.registerCallback(mTemperatureUnitChangeCallback,
HVAC_TEMPERATURE_DISPLAY_UNITS,
CarPropertyManager.SENSOR_RATE_ONCHANGE);
initComponents();
} catch (Exception e) {
Log.e(TAG, "Failed to correctly connect to HVAC", e);
@@ -109,8 +122,7 @@ public class HvacController {
}
/**
* Create connection to the Car service. Note: call backs from the Car service
* ({@link CarHvacManager}) will happen on the same thread this method was called from.
* Create connection to the Car service.
*/
public void connectToCarService() {
mCarServiceProvider.addListener(mCarServiceLifecycleListener);
@@ -124,21 +136,18 @@ public class HvacController {
return;
}
HvacKey hvacKey = new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId());
if (!mTempComponents.containsKey(hvacKey)) {
mTempComponents.put(hvacKey, new ArrayList<>());
int areaId = temperatureView.getAreaId();
if (!mTempComponents.containsKey(areaId)) {
mTempComponents.put(areaId, new ArrayList<>());
}
mTempComponents.get(hvacKey).add(temperatureView);
mTempComponents.get(areaId).add(temperatureView);
initComponent(temperatureView);
mRegisteredViews.add(temperatureView);
}
private void initComponents() {
Iterator<Map.Entry<HvacKey, List<TemperatureView>>> iterator =
mTempComponents.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<HvacKey, List<TemperatureView>> next = iterator.next();
for (Map.Entry<Integer, List<TemperatureView>> next : mTempComponents.entrySet()) {
List<TemperatureView> temperatureViews = next.getValue();
for (TemperatureView view : temperatureViews) {
initComponent(view);
@@ -147,29 +156,29 @@ public class HvacController {
}
private void initComponent(TemperatureView view) {
int id = view.getPropertyId();
int zone = view.getAreaId();
if (DEBUG) {
Log.d(TAG, "initComponent: " + zone + ":" + id);
Log.d(TAG, "initComponent: " + zone);
}
try {
if (mHvacManager != null
&& mHvacManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)) {
if (mHvacManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
if (mCarPropertyManager != null && mCarPropertyManager.isPropertyAvailable(
HVAC_TEMPERATURE_DISPLAY_UNITS, VEHICLE_AREA_TYPE_GLOBAL)) {
if (mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL) == VehicleUnit.FAHRENHEIT) {
view.setDisplayInFahrenheit(true);
}
}
if (mHvacManager == null || !mHvacManager.isPropertyAvailable(id, zone)) {
view.setTemp(Float.NaN);
if (mCarPropertyManager == null || !mCarPropertyManager.isPropertyAvailable(
HVAC_TEMPERATURE_SET, zone)) {
view.setTemperatureView(Float.NaN);
return;
}
view.setTemp(mHvacManager.getFloatProperty(id, zone));
view.setTemperatureView(
mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, zone));
view.setHvacController(this);
} catch (Exception e) {
view.setTemp(Float.NaN);
view.setTemperatureView(Float.NaN);
Log.e(TAG, "Failed to get value from hvac service", e);
}
}
@@ -199,30 +208,32 @@ public class HvacController {
}
/**
* Key for storing {@link TemperatureView}s in a hash map
* Set the temperature in Celsius of the specified zone
*/
private static class HvacKey {
int mPropertyId;
int mAreaId;
private HvacKey(int propertyId, int areaId) {
mPropertyId = propertyId;
mAreaId = areaId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HvacKey hvacKey = (HvacKey) o;
return mPropertyId == hvacKey.mPropertyId
&& mAreaId == hvacKey.mAreaId;
}
@Override
public int hashCode() {
return Objects.hash(mPropertyId, mAreaId);
public void setTemperature(float tempC, int zone) {
if (mCarPropertyManager != null) {
// Internally, all temperatures are represented in floating point Celsius
mCarPropertyManager.setFloatProperty(HVAC_TEMPERATURE_SET, zone, tempC);
}
}
/**
* Convert the given temperature in Celsius into Fahrenheit
*
* @param tempC - The temperature in Celsius
* @return Temperature in Fahrenheit.
*/
public static float convertToFahrenheit(float tempC) {
return (tempC * 9f / 5f) + 32;
}
/**
* Convert the given temperature in Fahrenheit to Celsius
*
* @param tempF - The temperature in Fahrenheit.
* @return Temperature in Celsius.
*/
public static float convertToCelsius(float tempF) {
return (float) ((tempF - 32) * 0.55555555556);
}
}

View File

@@ -16,6 +16,8 @@
package com.android.systemui.car.hvac;
import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -27,24 +29,25 @@ import com.android.systemui.R;
* Simple text display of HVAC properties, It is designed to show temperature and is configured in
* the XML.
* XML properties:
* hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
* hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
* hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
* hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
public class TemperatureTextView extends TextView implements TemperatureView {
private final int mAreaId;
private final int mPropertyId;
private final String mTempFormat;
private HvacController mHvacController;
private boolean mDisplayFahrenheit = false;
public TemperatureTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
mPropertyId = typedArray.getInt(R.styleable.TemperatureView_hvacPropertyId, -1);
String format = typedArray.getString(R.styleable.TemperatureView_hvacTempFormat);
mTempFormat = (format == null) ? "%.1f\u00B0" : format;
mTempFormat = getResources().getString(R.string.hvac_temperature_format);
}
@Override
public void setHvacController(HvacController controller) {
mHvacController = controller;
}
/**
@@ -53,7 +56,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
* @param temp - The current temp or NaN
*/
@Override
public void setTemp(float temp) {
public void setTemperatureView(float temp) {
if (Float.isNaN(temp)) {
setText("--");
return;
@@ -70,15 +73,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
}
/**
* @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
*/
@Override
public int getPropertyId() {
return mPropertyId;
}
/**
* @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
* @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
@Override
public int getAreaId() {

View File

@@ -17,15 +17,23 @@
package com.android.systemui.car.hvac;
/**
* Interface for Views that display temperature HVAC properties
* Interface for Views that display temperature HVAC properties.
*/
public interface TemperatureView {
/**
* Sets the {@link HvacController} to handle changes to HVAC properties. The View is only
* responsible for the UI to display temperature. It should not contain logic that makes direct
* changes to HVAC properties and instead use this {@link HvacController}.
*/
void setHvacController(HvacController controller);
/**
* Formats the float for display
*
* @param temp - The current temp in Celsius or NaN
*/
void setTemp(float temp);
void setTemperatureView(float temp);
/**
* Render the displayed temperature in Fahrenheit
@@ -35,22 +43,7 @@ public interface TemperatureView {
void setDisplayInFahrenheit(boolean displayFahrenheit);
/**
* Convert the given temperature in Celsius into Fahrenheit
*
* @param realTemp - The temperature in Celsius
* @return Temperature in Fahrenheit.
*/
default float convertToFahrenheit(float realTemp) {
return (realTemp * 9f / 5f) + 32;
}
/**
* @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
*/
int getPropertyId();
/**
* @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
* @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
int getAreaId();
}

View File

@@ -0,0 +1,174 @@
/*
* Copyright (C) 2020 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.systemui.car.hvac;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.car.Car;
import android.car.VehicleUnit;
import android.car.hardware.property.CarPropertyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class AdjustableTemperatureViewTest extends SysuiTestCase {
private static final float TEMP_CELSIUS = 22.0f;
private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
private AdjustableTemperatureView mAdjustableTemperatureView;
private HvacController mHvacController;
@Mock
private Car mCar;
@Mock
private CarPropertyManager mCarPropertyManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mCar.isConnected()).thenReturn(true);
when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
mHvacController = new HvacController(carServiceProvider);
mHvacController.connectToCarService();
mAdjustableTemperatureView = new AdjustableTemperatureView(getContext(), /* attrs= */ null);
mAdjustableTemperatureView.setHvacController(mHvacController);
}
@Test
public void addTemperatureViewToController_setsTemperatureView() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP_CELSIUS);
mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
assertEquals(tempText.getText(), String.format(mFormat, TEMP_CELSIUS));
}
@Test
public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP_CELSIUS);
when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
assertEquals(tempText.getText(), String.format(mFormat, convertToFahrenheit(TEMP_CELSIUS)));
}
@Test
public void adjustableViewIncreaseButton_setsTempWithCarPropertyManager() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP_CELSIUS);
mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
eq(TEMP_CELSIUS + 1));
}
@Test
public void adjustableViewDecreaseButton_setsTempWithCarPropertyManager() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP_CELSIUS);
mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
eq(TEMP_CELSIUS - 1));
}
@Test
public void adjustableViewIncreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP_CELSIUS);
when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) + 1)));
}
@Test
public void adjustableViewDecreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP_CELSIUS);
when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) - 1)));
}
}

View File

@@ -16,7 +16,13 @@
package com.android.systemui.car.hvac;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -24,7 +30,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.car.Car;
import android.car.hardware.hvac.CarHvacManager;
import android.car.VehicleUnit;
import android.car.hardware.property.CarPropertyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -46,92 +53,91 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class HvacControllerTest extends SysuiTestCase {
private static final int PROPERTY_ID = 1;
private static final int AREA_ID = 1;
private static final float VALUE = 72.0f;
private static final float TEMP = 72.0f;
private HvacController mHvacController;
private CarServiceProvider mCarServiceProvider;
@Mock
private Car mCar;
@Mock
private CarHvacManager mCarHvacManager;
private CarPropertyManager mCarPropertyManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mCar.isConnected()).thenReturn(true);
when(mCar.getCarManager(Car.HVAC_SERVICE)).thenReturn(mCarHvacManager);
when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
mCarServiceProvider = new CarServiceProvider(mContext, mCar);
mHvacController = new HvacController(mCarServiceProvider);
CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
mHvacController = new HvacController(carServiceProvider);
mHvacController.connectToCarService();
}
@Test
public void connectToCarService_registersCallback() {
verify(mCarHvacManager).registerCallback(any());
verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_SET), anyFloat());
verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_DISPLAY_UNITS),
anyFloat());
}
@Test
public void addTemperatureViewToController_usingTemperatureView_registersView() {
TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
verify(v).setTemp(VALUE);
verify(v).setTemperatureView(TEMP);
}
@Test
public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() {
TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
verify(v).setTemp(VALUE);
resetTemperatureView(v, PROPERTY_ID, AREA_ID);
verify(v).setTemperatureView(TEMP);
resetTemperatureView(v, AREA_ID);
mHvacController.addTemperatureViewToController(v);
verify(v, never()).setTemp(VALUE);
verify(v, never()).setTemperatureView(TEMP);
}
@Test
public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() {
TemperatureTextView v1 = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
TemperatureTextView v1 = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v1);
verify(v1).setTemp(VALUE);
verify(v1).setTemperatureView(TEMP);
TemperatureTextView v2 = setupMockTemperatureTextView(
PROPERTY_ID + 1,
AREA_ID + 1,
VALUE + 1);
TEMP + 1);
mHvacController.addTemperatureViewToController(v2);
verify(v2).setTemp(VALUE + 1);
verify(v2).setTemperatureView(TEMP + 1);
}
@Test
public void removeAllComponents_ableToRegisterSameView() {
TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
mHvacController.addTemperatureViewToController(v);
verify(v).setTemp(VALUE);
mHvacController.removeAllComponents();
resetTemperatureView(v, PROPERTY_ID, AREA_ID);
public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
verify(v).setTemp(VALUE);
verify(v).setDisplayInFahrenheit(true);
verify(v).setTemperatureView(TEMP);
}
private TemperatureTextView setupMockTemperatureTextView(int propertyId, int areaId,
float value) {
private TemperatureTextView setupMockTemperatureTextView(int areaId, float value) {
TemperatureTextView v = mock(TemperatureTextView.class);
resetTemperatureView(v, propertyId, areaId);
when(mCarHvacManager.isPropertyAvailable(propertyId, areaId)).thenReturn(true);
when(mCarHvacManager.getFloatProperty(propertyId, areaId)).thenReturn(value);
resetTemperatureView(v, areaId);
when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, areaId)).thenReturn(
true);
when(mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, areaId)).thenReturn(value);
return v;
}
private void resetTemperatureView(TemperatureTextView view, int propertyId, int areaId) {
private void resetTemperatureView(TemperatureTextView view, int areaId) {
reset(view);
when(view.getPropertyId()).thenReturn(propertyId);
when(view.getAreaId()).thenReturn(areaId);
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2020 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.systemui.car.hvac;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.car.Car;
import android.car.VehicleUnit;
import android.car.hardware.property.CarPropertyManager;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class TemperatureTextViewTest extends SysuiTestCase {
private static final float TEMP = 72.0f;
private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
private HvacController mHvacController;
private TemperatureTextView mTextView;
@Mock
private Context mContext;
@Mock
private Car mCar;
@Mock
private CarPropertyManager mCarPropertyManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mCar.isConnected()).thenReturn(true);
when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
mHvacController = new HvacController(carServiceProvider);
mHvacController.connectToCarService();
mTextView = new TemperatureTextView(getContext(), /* attrs= */ null);
}
@Test
public void addTemperatureViewToController_usingTemperatureView_registersView() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP);
mHvacController.addTemperatureViewToController(mTextView);
assertEquals(mTextView.getText(), String.format(mFormat, TEMP));
}
@Test
public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
TEMP);
when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
mHvacController.addTemperatureViewToController(mTextView);
assertEquals(mTextView.getText(), String.format(mFormat, convertToFahrenheit(TEMP)));
}
}