• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.car.hvac;
18 
19 import static android.car.VehiclePropertyIds.HVAC_SEAT_TEMPERATURE;
20 
21 import android.car.VehiclePropertyIds;
22 import android.car.hardware.CarPropertyConfig;
23 import android.car.hardware.CarPropertyValue;
24 import android.car.hardware.property.AreaIdConfig;
25 import android.content.Context;
26 import android.content.res.TypedArray;
27 import android.graphics.drawable.Drawable;
28 import android.os.Build;
29 import android.util.AttributeSet;
30 import android.util.Log;
31 import android.util.SparseArray;
32 import android.widget.ImageButton;
33 
34 import androidx.annotation.ArrayRes;
35 
36 import com.android.systemui.R;
37 
38 /**
39  * An image button that allows for multiple seat heating/cooling states based on
40  * {@link R.integer.hvac_seat_heat_level_count}.
41  */
42 public class SeatTemperatureLevelButton extends ImageButton implements HvacView {
43     private static final boolean DEBUG = Build.IS_ENG || Build.IS_USERDEBUG;
44     private static final String TAG = "SeatTemperatureLevelButton";
45 
46     private static final int INVALID_ID = -1;
47     private static final int HEATING = 1;
48     private static final int COOLING = -1;
49 
50     private final SparseArray<Drawable> mIcons = new SparseArray<>();
51 
52     private int mAreaId;
53     private HvacPropertySetter mHvacPropertySetter;
54     private Drawable mCurrentIcon;
55     private int mCurrentLevel = -1;
56     private int mTotalLevelCount;
57     private int mTemperatureLevelType;
58 
SeatTemperatureLevelButton(Context context)59     public SeatTemperatureLevelButton(Context context) {
60         super(context);
61     }
62 
SeatTemperatureLevelButton(Context context, AttributeSet attrs)63     public SeatTemperatureLevelButton(Context context, AttributeSet attrs) {
64         super(context, attrs);
65         parseAttributes(attrs);
66     }
67 
SeatTemperatureLevelButton(Context context, AttributeSet attrs, int defStyleAttr)68     public SeatTemperatureLevelButton(Context context, AttributeSet attrs, int defStyleAttr) {
69         super(context, attrs, defStyleAttr);
70         parseAttributes(attrs);
71     }
72 
73     @Override
onFinishInflate()74     public void onFinishInflate() {
75         super.onFinishInflate();
76         setOnClickListener(v -> {
77             if (mHvacPropertySetter == null) {
78                 return;
79             }
80 
81             int newLevel = mTemperatureLevelType * (mCurrentLevel + 1) % (mTotalLevelCount + 1);
82             if (DEBUG) {
83                 Log.d(TAG, "setOnClickListener: new seat temperature level: " + newLevel);
84             }
85             mHvacPropertySetter.setHvacProperty(getHvacPropertyToView(), mAreaId, newLevel);
86         });
87         setOnLongClickListener(v -> {
88             if (mHvacPropertySetter == null) {
89                 return false;
90             }
91 
92             int newLevel = mTemperatureLevelType * (mCurrentLevel == 0 ? mTotalLevelCount : 0);
93             if (DEBUG) {
94                 Log.d(TAG, "setOnLongClickListener: new seat temperature level: " + newLevel);
95             }
96             mHvacPropertySetter.setHvacProperty(getHvacPropertyToView(), mAreaId, newLevel);
97             return true;
98         });
99         updateIcon();
100     }
101 
102     @Override
setHvacPropertySetter(HvacPropertySetter hvacPropertySetter)103     public void setHvacPropertySetter(HvacPropertySetter hvacPropertySetter) {
104         mHvacPropertySetter = hvacPropertySetter;
105     }
106 
107     @Override
setConfigInfo(CarPropertyConfig<?> carPropertyConfig)108     public void setConfigInfo(CarPropertyConfig<?> carPropertyConfig) {
109         AreaIdConfig<Integer> areaIdConfig = (AreaIdConfig<Integer>)
110                 carPropertyConfig.getAreaIdConfig(mAreaId);
111         // The number of seat temperature levels cannot exceed the number of icons that represent
112         // the levels.
113         mTotalLevelCount = Math.min(areaIdConfig.getMaxValue(), mIcons.size());
114     }
115 
116     @Override
onPropertyChanged(CarPropertyValue value)117     public void onPropertyChanged(CarPropertyValue value) {
118         if (value == null) {
119             if (DEBUG) {
120                 Log.d(TAG, "onPropertyChanged: received null value");
121             }
122             return;
123         }
124 
125         if (DEBUG) {
126             Log.d(TAG, "onPropertyChanged: property ID: "
127                     + VehiclePropertyIds.toString(value.getPropertyId()));
128             Log.d(TAG, "onPropertyChanged: area ID: 0x" + Integer.toHexString(value.getAreaId()));
129             Log.d(TAG, "onPropertyChanged: value: " + value.getValue());
130         }
131 
132         if (value.getPropertyId() == getHvacPropertyToView() && value.getAreaId() == getAreaId()) {
133             mCurrentLevel = (int) value.getValue();
134             if (mTemperatureLevelType == COOLING && mCurrentLevel > 0) {
135                 mCurrentLevel = 0;
136             } else if (mTemperatureLevelType == HEATING && mCurrentLevel < 0) {
137                 mCurrentLevel = 0;
138             }
139 
140             mCurrentLevel = Math.abs(mCurrentLevel);
141 
142             mCurrentIcon = mIcons.get(mCurrentLevel);
143             updateIcon();
144         }
145     }
146 
147     @Override
getHvacPropertyToView()148     public @HvacController.HvacProperty Integer getHvacPropertyToView() {
149         return HVAC_SEAT_TEMPERATURE;
150     }
151 
152     @Override
getAreaId()153     public @HvacController.AreaId Integer getAreaId() {
154         return mAreaId;
155     }
156 
updateIcon()157     private void updateIcon() {
158         mContext.getMainThreadHandler().post(() -> {
159             setSelected(mCurrentLevel != 0);
160             setImageDrawable(mCurrentIcon);
161         });
162     }
163 
parseAttributes(AttributeSet attrs)164     private void parseAttributes(AttributeSet attrs) {
165         mIcons.clear();
166 
167         mTotalLevelCount = mContext.getResources().getInteger(R.integer.hvac_seat_heat_level_count);
168 
169         TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.HvacView);
170         mAreaId = typedArray.getInt(R.styleable.HvacView_hvacAreaId, INVALID_ID);
171         typedArray.recycle();
172 
173         typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.SeatTemperatureLevelButton);
174         mTemperatureLevelType = typedArray.getInt(
175                 R.styleable.SeatTemperatureLevelButton_seatTemperatureType, HEATING);
176 
177         @ArrayRes int drawableListRes = typedArray.getResourceId(
178                 R.styleable.SeatTemperatureLevelButton_seatTemperatureIconDrawableList,
179                 R.array.hvac_heated_seat_default_icons);
180 
181         TypedArray seatTemperatureIcons = mContext.getResources().obtainTypedArray(drawableListRes);
182         if (seatTemperatureIcons.length() != mTotalLevelCount) {
183             throw new IllegalArgumentException(
184                     "R.styeable.SeatHeatLevelButton_seatHeaterIconDrawableList should have the "
185                             + "same length as R.integer.hvac_seat_heat_level_count");
186         }
187 
188         int[] drawableIds = new int[seatTemperatureIcons.length()];
189         for (int i = 0; i < mTotalLevelCount; i++) {
190             drawableIds[i] = seatTemperatureIcons.getResourceId(i, 0);
191             mIcons.set(i, mContext.getResources().getDrawable(drawableIds[i], mContext.getTheme()));
192         }
193         typedArray.recycle();
194         seatTemperatureIcons.recycle();
195     }
196 }
197