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