1 /* 2 * Copyright (C) 2023 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.car.carlauncher.calmmode; 18 19 import android.app.Application; 20 import android.car.Car; 21 import android.car.VehicleAreaSeat; 22 import android.car.VehiclePropertyIds; 23 import android.car.VehicleUnit; 24 import android.car.hardware.CarPropertyValue; 25 import android.car.hardware.property.CarPropertyManager; 26 import android.icu.util.MeasureUnit; 27 import android.os.Build; 28 import android.util.Log; 29 30 import androidx.annotation.NonNull; 31 import androidx.annotation.Nullable; 32 import androidx.annotation.VisibleForTesting; 33 import androidx.lifecycle.AndroidViewModel; 34 import androidx.lifecycle.LiveData; 35 import androidx.lifecycle.MutableLiveData; 36 37 38 39 public class TemperatureViewModel extends AndroidViewModel 40 implements CarPropertyManager.CarPropertyEventCallback { 41 private static final boolean DEBUG = Build.isDebuggable(); 42 private static final String TAG = TemperatureViewModel.class.getSimpleName(); 43 private Car mCar; 44 private CarPropertyManager mPropertyManager; 45 private MutableLiveData<TemperatureData> mTemperatureData = new MutableLiveData<>(); 46 47 private boolean mIsTemperatureSet; 48 private float mValue; 49 private MeasureUnit mUnit; TemperatureViewModel(@onNull Application application)50 public TemperatureViewModel(@NonNull Application application) { 51 super(application); 52 mCar = Car.createCar(application); 53 mPropertyManager = mCar.getCarManager(CarPropertyManager.class); 54 // Listen for changes 55 mPropertyManager.registerCallback(this, VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS, 56 CarPropertyManager.SENSOR_RATE_ONCHANGE); 57 mPropertyManager.registerCallback(this, VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE, 58 CarPropertyManager.SENSOR_RATE_ONCHANGE); 59 60 } 61 62 @Override onCleared()63 protected void onCleared() { 64 super.onCleared(); 65 if (DEBUG) { 66 Log.v(TAG, "onCleared()"); 67 } 68 if (mCar != null && mCar.isConnected()) { 69 mCar.disconnect(); 70 mCar = null; 71 } 72 if (mPropertyManager != null) { 73 mPropertyManager.unregisterCallback(this, 74 VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS); 75 mPropertyManager.unregisterCallback(this, 76 VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE); 77 mPropertyManager = null; 78 } 79 } 80 81 /** 82 * @return CarPropertyValue for VehicleAreaSeat.SEAT_UNKNOWN or null if CarPropertyManager is 83 * not initialized 84 */ 85 @VisibleForTesting 86 @Nullable getCarPropertyValue(int propertyId)87 CarPropertyValue getCarPropertyValue(int propertyId) { 88 if (mPropertyManager == null) { 89 return null; 90 } 91 return mPropertyManager.getProperty(propertyId, mPropertyManager.getAreaId( 92 propertyId, VehicleAreaSeat.SEAT_UNKNOWN)); 93 } 94 95 @Override onChangeEvent(CarPropertyValue carPropertyValue)96 public void onChangeEvent(CarPropertyValue carPropertyValue) { 97 if (DEBUG) { 98 Log.v(TAG, "onChangeEvent(carPropertyValue=" + carPropertyValue + ")"); 99 } 100 if (carPropertyValue == null) { 101 return; 102 } 103 if (carPropertyValue.getPropertyId() == VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS) { 104 handleUnitChange(carPropertyValue); 105 } else if (carPropertyValue.getPropertyId() == VehiclePropertyIds.ENV_OUTSIDE_TEMPERATURE) { 106 handleValueChange(carPropertyValue); 107 } 108 } 109 110 @VisibleForTesting handleUnitChange(CarPropertyValue<Integer> newVehicleUnit)111 void handleUnitChange(CarPropertyValue<Integer> newVehicleUnit) { 112 if (newVehicleUnit.getValue() != VehicleUnit.FAHRENHEIT 113 && newVehicleUnit.getValue() != VehicleUnit.CELSIUS) { 114 if (DEBUG) { 115 Log.d(TAG, "handleUnitChange: Invalid temperature unit received"); 116 } 117 return; 118 } 119 MeasureUnit newMeasureUnit = 120 newVehicleUnit.getValue() == VehicleUnit.FAHRENHEIT 121 ? MeasureUnit.FAHRENHEIT : MeasureUnit.CELSIUS; 122 if (mUnit == newMeasureUnit) { 123 return; 124 } 125 // If temperature value has been set previously and unit has changed, 126 // convert value and post update 127 if (mIsTemperatureSet) { 128 TemperatureData temperatureData; 129 if (mUnit == MeasureUnit.FAHRENHEIT) { 130 temperatureData = new TemperatureData.Builder().setValueFahrenheit(mValue).build(); 131 temperatureData.convertToCelsius(); 132 } else { 133 temperatureData = new TemperatureData.Builder().setValueCelsius(mValue).build(); 134 temperatureData.convertToFahrenheit(); 135 } 136 mTemperatureData.setValue(temperatureData); 137 } 138 mUnit = newMeasureUnit; 139 } 140 141 @VisibleForTesting handleValueChange(CarPropertyValue<Float> newValue)142 void handleValueChange(CarPropertyValue<Float> newValue) { 143 if (mIsTemperatureSet && mValue == newValue.getValue()) { 144 return; 145 } 146 // Outside temperature is always received in celsius, assign default 147 if (mUnit == null) { 148 mUnit = MeasureUnit.CELSIUS; 149 } 150 TemperatureData temperatureData = 151 new TemperatureData.Builder().setValueCelsius(newValue.getValue()).build(); 152 if (mUnit != MeasureUnit.CELSIUS) { 153 temperatureData.convertToFahrenheit(); 154 } 155 mTemperatureData.setValue(temperatureData); 156 mValue = newValue.getValue(); 157 if (!mIsTemperatureSet) { 158 mIsTemperatureSet = true; 159 } 160 } 161 162 @Override onErrorEvent(int propertyId, int areaId)163 public void onErrorEvent(int propertyId, int areaId) { 164 if (DEBUG) { 165 Log.w(TAG, "onErrorEvent(propertyId=" + propertyId + ", areaId=" + areaId); 166 } 167 mTemperatureData.setValue(null); 168 } 169 getTemperatureData()170 public LiveData<TemperatureData> getTemperatureData() { 171 return mTemperatureData; 172 } 173 } 174