10eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer/*
20eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * Copyright (c) 2016, The Android Open Source Project
30eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer *
40eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License");
50eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * you may not use this file except in compliance with the License.
60eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * You may obtain a copy of the License at
70eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer *
80eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer *     http://www.apache.org/licenses/LICENSE-2.0
90eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer *
100eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * Unless required by applicable law or agreed to in writing, software
110eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS,
120eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * See the License for the specific language governing permissions and
140eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * limitations under the License.
150eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer */
160eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerpackage com.android.car.hvac;
170eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
180eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerimport android.os.SystemClock;
199e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granataimport android.util.Log;
200eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerimport android.util.SparseArray;
210eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerimport android.util.SparseBooleanArray;
220eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerimport android.util.SparseIntArray;
230eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerimport android.util.SparseLongArray;
240eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
250eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerimport java.util.concurrent.TimeUnit;
260eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerimport javax.annotation.concurrent.GuardedBy;
270eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
280eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer/**
290eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * The hvac unit can be controller from two places, the ui and the hardware buttons. Each of these
300eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * request updates to the current state from different threads. Moreover, there can be conditions
310eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * where the hvac could send spurious updates so this class routes everything through and coalesces
320eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer * them, keeping the application's view of the world sane.
330eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer */
340eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyerpublic class DataStore {
350eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private static final long COALESCE_TIME_MS = TimeUnit.SECONDS.toMillis(2);
360eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
370eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mTemperature")
380eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseArray<Float> mTemperature = new SparseArray<Float>();
399e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata    @GuardedBy("mTemperatureAvailable")
409e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata    private SparseBooleanArray mTemperatureAvailable = new SparseBooleanArray();
410eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mFanSpeed")
420eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private Integer mFanSpeed = 0;
430eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAirflow")
440eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseIntArray mAirflow = new SparseIntArray();
450eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mDefrosterState")
460eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseBooleanArray mDefrosterState = new SparseBooleanArray();
470eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAcState")
480eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private Boolean mAcState = false;
490eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mSeatWarmerLevel")
500eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseIntArray mSeatWarmerLevel = new SparseIntArray();
510eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAirCirculationState")
520eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private Boolean mAirCirculationState = false;
530eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAutoModeState")
540eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private Boolean mAutoModeState = false;
550eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mHvacPowerState")
560eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private Boolean mHvacPowerState = false;
570eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
580eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mTemperature")
590eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseLongArray mLastTemperatureSet = new SparseLongArray();
600eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mFanSpeed")
610eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private long mLastFanSpeedSet;
620eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAirflow")
630eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseLongArray mLastAirflowSet = new SparseLongArray();
640eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mDefrosterState")
650eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseLongArray mLastDefrosterSet = new SparseLongArray();
660eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAcState")
670eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private long mLastAcSet;
680eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mSeatWarmerLevel")
690eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private SparseLongArray mLastSeatWarmerLevel = new SparseLongArray();
700eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAirCirculationState")
710eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private long mAirCirculationLastSet;
720eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mAutoModeState")
730eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private long mAutoModeLastSet;
740eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    @GuardedBy("mHvacPowerState")
750eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    private long mHvacPowerLastSet;
760eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
770eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
780eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public float getTemperature(int zone) {
790eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mTemperature) {
800eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mTemperature.get(zone);
810eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
820eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
830eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
849e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata    public void setTemperature(int zone, float temperature, boolean available) {
850eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mTemperature) {
869e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata            synchronized (mTemperatureAvailable) {
879e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                Log.d("HvacDataStore", "setTemperature(" + zone + ", " + temperature + ")");
889e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                mTemperature.put(zone, temperature);
899e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                mTemperatureAvailable.put(zone, available);
909e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                mLastTemperatureSet.put(zone, SystemClock.uptimeMillis());
919e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata            }
920eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
930eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
940eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
959e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata    public boolean shouldPropagateTempUpdate(int zone, float temperature, boolean available) {
960eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mTemperature) {
979e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata            synchronized (mTemperatureAvailable) {
989e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                if (SystemClock.uptimeMillis() - mLastTemperatureSet.get(zone) < COALESCE_TIME_MS) {
999e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                    if (available == mTemperatureAvailable.get(zone)) {
1009e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                        return false;
1019e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                    }
1029e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata                }
1030eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
1049e5e6b74668dd7e5143eca428ab61bec6033f57bEnrico Granata            setTemperature(zone, temperature, available);
1050eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1060eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
1070eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1080eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1090eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean getDefrosterState(int zone) {
1100eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mDefrosterState) {
1110eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mDefrosterState.get(zone);
1120eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1130eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1140eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1150eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setDefrosterState(int zone, boolean state) {
1160eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mDefrosterState) {
1170eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mDefrosterState.put(zone, state);
1180eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mLastDefrosterSet.put(zone, SystemClock.uptimeMillis());
1190eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1200eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1210eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1220eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateDefrosterUpdate(int zone, boolean defrosterState) {
1230eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mDefrosterState) {
1240eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mLastDefrosterSet.get(zone) < COALESCE_TIME_MS) {
1250eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
1260eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
1270eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mDefrosterState.put(zone, defrosterState);
1280eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1290eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
1300eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1310eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1320eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public int getFanSpeed() {
1330eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mFanSpeed) {
1340eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mFanSpeed;
1350eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1360eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1370eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1380eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setFanSpeed(int speed) {
1390eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mFanSpeed) {
1400eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mFanSpeed = speed;
1410eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mLastFanSpeedSet = SystemClock.uptimeMillis();
1420eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1430eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1440eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1450eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateFanSpeedUpdate(int zone, int speed) {
1460eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        // TODO: We ignore fan speed zones for now because we dont have a multi zone car.
1470eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mFanSpeed) {
1480eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mLastFanSpeedSet < COALESCE_TIME_MS) {
1490eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
1500eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
1510eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mFanSpeed = speed;
1520eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1530eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
1540eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1550eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1560eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean getAcState() {
1570eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAcState) {
1580eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mAcState;
1590eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1600eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1610eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1620eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setAcState(boolean acState) {
1630eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAcState) {
1640eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAcState = acState;
1650eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mLastAcSet = SystemClock.uptimeMillis();
1660eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1670eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1680eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1690eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateAcUpdate(boolean acState) {
1700eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAcState) {
1710eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mLastAcSet < COALESCE_TIME_MS) {
1720eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
1730eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
1740eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAcState = acState;
1750eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1760eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
1770eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1780eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1790eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public int getAirflow(int zone) {
1800eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAirflow) {
1810eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mAirflow.get(zone);
1820eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1830eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1840eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1850eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setAirflow(int zone, int index) {
1860eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAirflow) {
1870eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAirflow.put(zone, index);
1880eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mLastAirflowSet.put(zone, SystemClock.uptimeMillis());
1890eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1900eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
1910eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
1920eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateFanPositionUpdate(int zone, int index) {
1930eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAirflow) {
1940eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mLastAirflowSet.get(zone) < COALESCE_TIME_MS) {
1950eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
1960eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
1970eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAirflow.put(zone, index);
1980eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
1990eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
2000eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2010eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2020eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public float getSeatWarmerLevel(int zone) {
2030eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mSeatWarmerLevel) {
2040eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mSeatWarmerLevel.get(zone);
2050eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2060eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2070eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2080eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setSeatWarmerLevel(int zone, int level) {
2090eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mSeatWarmerLevel) {
2100eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mSeatWarmerLevel.put(zone, level);
2110eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mLastSeatWarmerLevel.put(zone, SystemClock.uptimeMillis());
2120eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2130eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2140eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2150eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateSeatWarmerLevelUpdate(int zone, int level) {
2160eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mSeatWarmerLevel) {
2170eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mLastSeatWarmerLevel.get(zone) < COALESCE_TIME_MS) {
2180eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
2190eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
2200eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mSeatWarmerLevel.put(zone, level);
2210eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2220eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
2230eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2240eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2250eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean getAirCirculationState() {
2260eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAirCirculationState) {
2270eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mAirCirculationState;
2280eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2290eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2300eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2310eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setAirCirculationState(boolean airCirculationState) {
2320eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAirCirculationState) {
2330eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAirCirculationState = airCirculationState;
2340eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAirCirculationLastSet = SystemClock.uptimeMillis();
2350eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2360eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2370eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2380eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateAirCirculationUpdate(boolean airCirculationState) {
2390eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAirCirculationState) {
2400eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mAirCirculationLastSet < COALESCE_TIME_MS) {
2410eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
2420eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
2430eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAcState = airCirculationState;
2440eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2450eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
2460eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2470eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2480eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean getAutoModeState() {
2490eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAutoModeState) {
2500eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mAutoModeState;
2510eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2520eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2530eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2540eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setAutoModeState(boolean autoModeState) {
2550eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAutoModeState) {
2560eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAutoModeState = autoModeState;
2570eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAutoModeLastSet = SystemClock.uptimeMillis();
2580eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2590eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2600eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2610eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateAutoModeUpdate(boolean autoModeState) {
2620eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mAutoModeState) {
2630eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mAutoModeLastSet < COALESCE_TIME_MS) {
2640eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
2650eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
2660eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mAcState = autoModeState;
2670eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2680eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
2690eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2700eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2710eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean getHvacPowerState() {
2720eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mHvacPowerState) {
2730eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            return mHvacPowerState;
2740eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2750eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2760eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2770eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public void setHvacPowerState(boolean hvacPowerState) {
2780eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mHvacPowerState) {
2790eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mHvacPowerState = hvacPowerState;
2800eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mHvacPowerLastSet = SystemClock.uptimeMillis();
2810eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2820eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2830eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer
2840eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    public boolean shouldPropagateHvacPowerUpdate(boolean hvacPowerState) {
2850eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        synchronized (mHvacPowerState) {
2860eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            if (SystemClock.uptimeMillis() - mHvacPowerLastSet < COALESCE_TIME_MS) {
2870eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer                return false;
2880eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            }
2890eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer            mHvacPowerState = hvacPowerState;
2900eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        }
2910eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer        return true;
2920eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer    }
2930eecb13879c6f0abaf3d4c64fd19941777200eaeRakesh Iyer}
294