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_SPEED; 21 import static android.car.VehiclePropertyIds.HVAC_POWER_ON; 22 23 import android.car.hardware.CarPropertyValue; 24 import android.content.Context; 25 import android.content.res.Resources; 26 import android.graphics.Color; 27 import android.graphics.drawable.GradientDrawable; 28 import android.util.AttributeSet; 29 import android.widget.RelativeLayout; 30 import android.widget.TextView; 31 32 import com.android.systemui.R; 33 import com.android.systemui.car.hvac.HvacController; 34 import com.android.systemui.car.hvac.HvacPropertySetter; 35 import com.android.systemui.car.hvac.HvacView; 36 37 import java.util.ArrayList; 38 import java.util.List; 39 40 public class FanSpeedBar extends RelativeLayout implements HvacView { 41 42 private static final int BAR_SEGMENT_ANIMATION_DELAY_MS = 50; 43 private static final int BAR_SEGMENT_ANIMATION_PERIOD_MS = 100; 44 45 private HvacPropertySetter mHvacPropertySetter; 46 47 private int mHvacGlobalAreaId; 48 49 private int mButtonActiveTextColor; 50 private int mButtonInactiveTextColor; 51 52 private int mFanOffActiveBgColor; 53 private int mFanMaxActiveBgColor; 54 55 private float mCornerRadius; 56 57 private TextView mMaxButton; 58 private TextView mOffButton; 59 60 private FanSpeedBarSegment mFanSpeed1; 61 private FanSpeedBarSegment mFanSpeed2; 62 private FanSpeedBarSegment mFanSpeed3; 63 private FanSpeedBarSegment mFanSpeed4; 64 65 private boolean mPowerOn; 66 private boolean mAutoOn; 67 68 private float mOnAlpha; 69 private float mOffAlpha; 70 71 private final List<FanSpeedBarSegment> mFanSpeedButtons = new ArrayList<>(); 72 FanSpeedBar(Context context)73 public FanSpeedBar(Context context) { 74 super(context); 75 init(); 76 } 77 FanSpeedBar(Context context, AttributeSet attrs)78 public FanSpeedBar(Context context, AttributeSet attrs) { 79 super(context, attrs); 80 init(); 81 } 82 FanSpeedBar(Context context, AttributeSet attrs, int defStyleAttr)83 public FanSpeedBar(Context context, AttributeSet attrs, int defStyleAttr) { 84 super(context, attrs, defStyleAttr); 85 init(); 86 } 87 init()88 private void init() { 89 inflate(getContext(), R.layout.fan_speed, this); 90 91 Resources res = getContext().getResources(); 92 // The fanspeed bar is set as height 72dp to match min tap target size. However it is 93 // inset by fan speed inset to make it appear thinner. 94 int barHeight = res.getDimensionPixelSize(R.dimen.hvac_fan_speed_bar_height); 95 int insetHeight = res.getDimensionPixelSize(R.dimen.hvac_fan_speed_bar_vertical_inset); 96 mCornerRadius = (barHeight - 2 * insetHeight) / 2; 97 98 mFanOffActiveBgColor = res.getColor(R.color.hvac_fanspeed_off_active_bg); 99 100 mButtonActiveTextColor = res.getColor(R.color.hvac_fanspeed_off_active_text_color); 101 mButtonInactiveTextColor = res.getColor(R.color.hvac_fanspeed_off_inactive_text_color); 102 mFanMaxActiveBgColor = res.getColor(R.color.hvac_fanspeed_segment_color); 103 mHvacGlobalAreaId = res.getInteger(R.integer.hvac_global_area_id); 104 } 105 106 @Override setHvacPropertySetter(HvacPropertySetter hvacPropertySetter)107 public void setHvacPropertySetter(HvacPropertySetter hvacPropertySetter) { 108 mHvacPropertySetter = hvacPropertySetter; 109 } 110 111 @Override onPropertyChanged(CarPropertyValue value)112 public void onPropertyChanged(CarPropertyValue value) { 113 if (value.getPropertyId() == HVAC_FAN_SPEED) { 114 int level = (Integer) value.getValue(); 115 116 setOffAndMaxButtonsActiveState(level); 117 118 int fanSpeedCount = mFanSpeedButtons.size(); 119 int fanSpeedIndex = Math.min(level - 1, 4); 120 121 int delay = 0; 122 // Animate segments turning on when the fan speed is increased. 123 for (int i = 0; i < fanSpeedIndex; i++) { 124 FanSpeedBarSegment fanSpeedButton = mFanSpeedButtons.get(i); 125 if (!fanSpeedButton.isTurnedOn()) { 126 fanSpeedButton.playTurnOnAnimation(delay, BAR_SEGMENT_ANIMATION_PERIOD_MS); 127 delay += BAR_SEGMENT_ANIMATION_DELAY_MS; 128 } 129 } 130 131 delay = 0; 132 // Animate segments turning off when the fan speed is decreased. 133 for (int i = fanSpeedCount - 1; i >= fanSpeedIndex; i--) { 134 FanSpeedBarSegment fanSpeedButton = mFanSpeedButtons.get(i); 135 if (fanSpeedButton.isTurnedOn()) { 136 fanSpeedButton.playTurnOffAnimation(delay, BAR_SEGMENT_ANIMATION_PERIOD_MS); 137 delay += BAR_SEGMENT_ANIMATION_DELAY_MS; 138 } 139 } 140 141 return; 142 } 143 144 if (value.getPropertyId() == HVAC_POWER_ON) { 145 mPowerOn = (Boolean) value.getValue(); 146 } 147 148 if (value.getPropertyId() == HVAC_AUTO_ON) { 149 mAutoOn = (Boolean) value.getValue(); 150 } 151 152 updateViewPerAvailability(); 153 } 154 155 @Override getHvacPropertyToView()156 public @HvacController.HvacProperty Integer getHvacPropertyToView() { 157 return HVAC_FAN_SPEED; 158 } 159 160 @Override getAreaId()161 public @HvacController.AreaId Integer getAreaId() { 162 return mHvacGlobalAreaId; 163 } 164 165 @Override onFinishInflate()166 protected void onFinishInflate() { 167 super.onFinishInflate(); 168 169 mOnAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_on_alpha); 170 mOffAlpha = mContext.getResources().getFloat(R.dimen.hvac_turned_off_alpha); 171 172 mOffButton = (TextView) findViewById(R.id.fan_off); 173 mFanSpeed1 = (FanSpeedBarSegment) findViewById(R.id.fan_speed_1); 174 mFanSpeed2 = (FanSpeedBarSegment) findViewById(R.id.fan_speed_2); 175 mFanSpeed3 = (FanSpeedBarSegment) findViewById(R.id.fan_speed_3); 176 mFanSpeed4 = (FanSpeedBarSegment) findViewById(R.id.fan_speed_4); 177 mMaxButton = (TextView) findViewById(R.id.fan_max); 178 179 mFanSpeedButtons.add(mFanSpeed1); 180 mFanSpeedButtons.add(mFanSpeed2); 181 mFanSpeedButtons.add(mFanSpeed3); 182 mFanSpeedButtons.add(mFanSpeed4); 183 184 for (int i = 0; i < mFanSpeedButtons.size(); i++) { 185 mFanSpeedButtons.get(i).setOnClickListener( 186 getOnClickListener(/* fanSpeedLevel =*/ i + 2)); 187 } 188 189 mMaxButton.setOnClickListener(getOnClickListener(6)); 190 mOffButton.setOnClickListener(getOnClickListener(1)); 191 192 // Set the corner radius of the off/max button based on the height of the bar to get a 193 // pill-shaped border. 194 GradientDrawable offButtonBg = new GradientDrawable(); 195 offButtonBg.setCornerRadii(new float[]{mCornerRadius, mCornerRadius, 0, 0, 196 0, 0, mCornerRadius, mCornerRadius}); 197 mOffButton.setBackground(offButtonBg); 198 mOffButton.setTextColor(mButtonInactiveTextColor); 199 200 GradientDrawable maxButtonBg = new GradientDrawable(); 201 maxButtonBg.setCornerRadii(new float[]{0, 0, mCornerRadius, mCornerRadius, 202 mCornerRadius, mCornerRadius, 0, 0}); 203 mMaxButton.setBackground(maxButtonBg); 204 mMaxButton.setTextColor(mButtonInactiveTextColor); 205 } 206 207 @Override onHvacTemperatureUnitChanged(boolean usesFahrenheit)208 public void onHvacTemperatureUnitChanged(boolean usesFahrenheit) { 209 // no-op. 210 } 211 setOffAndMaxButtonsActiveState(int level)212 protected void setOffAndMaxButtonsActiveState(int level) { 213 setOffButtonActive(level == 1); 214 setMaxButtonActive(level == 6); 215 } 216 setMaxButtonActive(boolean active)217 private void setMaxButtonActive(boolean active) { 218 GradientDrawable background = (GradientDrawable) mMaxButton.getBackground(); 219 if (active) { 220 background.setColor(mFanMaxActiveBgColor); 221 mMaxButton.setTextColor(mButtonActiveTextColor); 222 } else { 223 background.setColor(Color.TRANSPARENT); 224 mMaxButton.setTextColor(mButtonInactiveTextColor); 225 } 226 } 227 setOffButtonActive(boolean active)228 private void setOffButtonActive(boolean active) { 229 GradientDrawable background = (GradientDrawable) mOffButton.getBackground(); 230 if (active) { 231 background.setColor(mFanOffActiveBgColor); 232 mOffButton.setTextColor(mButtonActiveTextColor); 233 } else { 234 background.setColor(Color.TRANSPARENT); 235 mOffButton.setTextColor(mButtonInactiveTextColor); 236 } 237 } 238 getOnClickListener(int fanSpeedLevel)239 private OnClickListener getOnClickListener(int fanSpeedLevel) { 240 return v -> { 241 if (shouldAllowControl()) { 242 mHvacPropertySetter.setHvacProperty(HVAC_FAN_SPEED, getAreaId(), fanSpeedLevel); 243 } 244 }; 245 } 246 247 private void updateViewPerAvailability() { 248 setAlpha(shouldAllowControl() ? mOnAlpha : mOffAlpha); 249 } 250 251 private boolean shouldAllowControl() { 252 return mPowerOn && !mAutoOn; 253 } 254 } 255