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.referenceui;
18 
19 import static android.car.VehiclePropertyIds.HVAC_AUTO_ON;
20 import static android.car.VehiclePropertyIds.HVAC_FAN_DIRECTION;
21 import static android.car.VehiclePropertyIds.HVAC_POWER_ON;
22 
23 import android.car.hardware.CarPropertyValue;
24 import android.content.Context;
25 import android.os.Build;
26 import android.util.AttributeSet;
27 import android.util.Log;
28 import android.widget.ImageView;
29 import android.widget.LinearLayout;
30 
31 import androidx.annotation.IntDef;
32 import androidx.annotation.Nullable;
33 
34 import com.android.systemui.R;
35 import com.android.systemui.car.hvac.HvacController;
36 import com.android.systemui.car.hvac.HvacPropertySetter;
37 import com.android.systemui.car.hvac.HvacView;
38 
39 import java.util.ArrayList;
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 
44 /**
45  * A group of buttons that allows users to select the fan direction. Only one button can be
46  * activated at a time.
47  */
48 public class FanDirectionButtons extends LinearLayout implements HvacView {
49 
50     /**
51      * NOTE: The integers below are not arbitrarily assigned and represent the corresponding values
52      * implemented in VHAL.
53      */
54     public static final int FAN_DIRECTION_FACE = 1;
55     public static final int FAN_DIRECTION_FACE_FLOOR = 3;
56     public static final int FAN_DIRECTION_FLOOR = 2;
57     public static final int FAN_DIRECTION_FLOOR_DEFROSTER = 6;
58     public static final int FAN_DIRECTION_COUNT = 4;
59 
60     private static final int INVALID_ID = -1;
61     private static final String TAG = FanDirectionButtons.class.getSimpleName();
62     private static final boolean DEBUG = Build.IS_ENG || Build.IS_USERDEBUG;
63 
64     @IntDef({FAN_DIRECTION_FACE, FAN_DIRECTION_FACE_FLOOR,
65             FAN_DIRECTION_FLOOR, FAN_DIRECTION_FLOOR_DEFROSTER})
66     public @interface FanDirection {
67     }
68 
69     /**
70      * A resource ID array for all fan direction buttons.
71      */
72     private static final int[] FAN_DIRECTION_BUTTON_IDS = {R.id.direction_face,
73             R.id.direction_face_and_floor, R.id.direction_floor, R.id.direction_defrost};
74 
75     private final List<ImageView> mButtons = new ArrayList<ImageView>();
76     private final List<Integer> mButtonDirections = new ArrayList<>();
77     private final Map<Integer, Integer> mButtonIndicesByDirection = new HashMap<>();
78 
79     private HvacPropertySetter mHvacPropertySetter;
80     private boolean mPowerOn;
81     private boolean mAutoOn;
82     private float mOnAlpha;
83     private float mOffAlpha;
84     private int mCurrentDirection = INVALID_ID;
85     private int mHvacGlobalAreaId;
86 
FanDirectionButtons(Context context)87     public FanDirectionButtons(Context context) {
88         super(context);
89         init();
90     }
91 
FanDirectionButtons(Context context, @Nullable AttributeSet attrs)92     public FanDirectionButtons(Context context, @Nullable AttributeSet attrs) {
93         super(context, attrs);
94         init();
95     }
96 
FanDirectionButtons(Context context, @Nullable AttributeSet attrs, int defStyleAttr)97     public FanDirectionButtons(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
98         super(context, attrs, defStyleAttr);
99         init();
100     }
101 
102     @Override
onFinishInflate()103     protected void onFinishInflate() {
104         super.onFinishInflate();
105 
106         mOnAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_on_alpha);
107         mOffAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_off_alpha);
108 
109         for (int i = 0; i < FAN_DIRECTION_COUNT; i++) {
110             ImageView button = (ImageView) findViewById(FAN_DIRECTION_BUTTON_IDS[i]);
111             int fanDirection = mButtonDirections.get(i);
112             button.setOnClickListener(v -> {
113                 if (!shouldAllowControl()) return;
114                 if (fanDirection != mCurrentDirection) {
115                     mHvacPropertySetter.setHvacProperty(HVAC_FAN_DIRECTION, getAreaId(),
116                             fanDirection);
117                 }
118             });
119             mButtons.add(button);
120         }
121     }
122 
123     @Override
setHvacPropertySetter(HvacPropertySetter hvacPropertySetter)124     public void setHvacPropertySetter(HvacPropertySetter hvacPropertySetter) {
125         mHvacPropertySetter = hvacPropertySetter;
126     }
127 
128     @Override
onPropertyChanged(CarPropertyValue value)129     public void onPropertyChanged(CarPropertyValue value) {
130         if (value.getPropertyId() == HVAC_FAN_DIRECTION) {
131             int newDirection = (Integer) value.getValue();
132             if (!mButtonDirections.contains(newDirection)) {
133                 if (DEBUG) {
134                     Log.w(TAG, "Button is not defined for direction: " + newDirection);
135                 }
136                 return;
137             }
138 
139             if (mCurrentDirection != INVALID_ID) {
140                 mButtons.get(mButtonIndicesByDirection.get(mCurrentDirection))
141                         .setSelected(false);
142             }
143             mCurrentDirection = newDirection;
144             mButtons.get(mButtonIndicesByDirection.get(mCurrentDirection))
145                     .setSelected(true);
146 
147             return;
148         }
149 
150         if (value.getPropertyId() == HVAC_POWER_ON) {
151             mPowerOn = (Boolean) value.getValue();
152         }
153 
154         if (value.getPropertyId() == HVAC_AUTO_ON) {
155             mAutoOn = (Boolean) value.getValue();
156         }
157 
158         updateViewPerAvailability();
159     }
160 
161     @Override
getHvacPropertyToView()162     public @HvacController.HvacProperty Integer getHvacPropertyToView() {
163         return HVAC_FAN_DIRECTION;
164     }
165 
166     @Override
getAreaId()167     public @HvacController.AreaId Integer getAreaId() {
168         return mHvacGlobalAreaId;
169     }
170 
171     @Override
onLocaleListChanged()172     public void onLocaleListChanged() {
173         // no-op.
174     }
175 
176     @Override
onHvacTemperatureUnitChanged(boolean usesFahrenheit)177     public void onHvacTemperatureUnitChanged(boolean usesFahrenheit) {
178         // no-op.
179     }
180 
init()181     private void init() {
182         inflate(getContext(), R.layout.fan_direction, this);
183         mHvacGlobalAreaId = getContext().getResources().getInteger(R.integer.hvac_global_area_id);
184         mButtonDirections.add(FAN_DIRECTION_FACE);
185         mButtonDirections.add(FAN_DIRECTION_FACE_FLOOR);
186         mButtonDirections.add(FAN_DIRECTION_FLOOR);
187         mButtonDirections.add(FAN_DIRECTION_FLOOR_DEFROSTER);
188 
189         mButtonIndicesByDirection.put(FAN_DIRECTION_FACE, 0);
190         mButtonIndicesByDirection.put(FAN_DIRECTION_FACE_FLOOR, 1);
191         mButtonIndicesByDirection.put(FAN_DIRECTION_FLOOR, 2);
192         mButtonIndicesByDirection.put(FAN_DIRECTION_FLOOR_DEFROSTER, 3);
193     }
194 
updateViewPerAvailability()195     private void updateViewPerAvailability() {
196         setAlpha(shouldAllowControl() ? mOnAlpha : mOffAlpha);
197     }
198 
shouldAllowControl()199     private boolean shouldAllowControl() {
200         return mPowerOn && !mAutoOn;
201     }
202 }
203