Home | History | Annotate | Download | only in controllers
      1 /*
      2  * Copyright (c) 2016, 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 package com.android.car.hvac.controllers;
     17 
     18 import android.animation.Animator;
     19 import android.animation.AnimatorSet;
     20 import android.animation.ObjectAnimator;
     21 import android.animation.ValueAnimator;
     22 import android.content.Context;
     23 import android.content.res.Resources;
     24 import android.graphics.drawable.Drawable;
     25 import android.support.annotation.IntDef;
     26 import android.view.MotionEvent;
     27 import android.view.View;
     28 import android.view.ViewGroup;
     29 import android.view.WindowManager;
     30 import android.widget.ImageView;
     31 import com.android.car.hvac.HvacController;
     32 import com.android.car.hvac.R;
     33 import com.android.car.hvac.ui.FanDirectionButtons;
     34 import com.android.car.hvac.ui.FanSpeedBar;
     35 import com.android.car.hvac.ui.HvacPanelRow;
     36 import com.android.car.hvac.ui.SeatWarmerButton;
     37 import com.android.car.hvac.ui.TemperatureBarOverlay;
     38 import com.android.car.hvac.ui.ToggleButton;
     39 
     40 import java.util.ArrayList;
     41 import java.util.List;
     42 
     43 /**
     44  * A state machine to control transition from various HVAC UI layouts.
     45  */
     46 public class HvacPanelController {
     47     private static final int PANEL_ANIMATION_TIME_MS = 200;
     48     private static final int PANEL_COLLAPSE_ANIMATION_TIME_MS = 500;
     49 
     50     private static final int PANEL_ANIMATION_DELAY_MS = 100;
     51     private static final int PANEL_ANIMATION_LONG_DELAY_MS = 3 * PANEL_ANIMATION_DELAY_MS;
     52 
     53     private static final float DISABLED_BUTTON_ALPHA = 0.20f;
     54     private static final float ENABLED_BUTTON_ALPHA = 1.0f;
     55 
     56     private static final int STATE_COLLAPSED = 0;
     57     private static final int STATE_COLLAPSED_DIMMED = 1;
     58     private static final int STATE_FULL_EXPANDED = 2;
     59 
     60     @IntDef({STATE_COLLAPSED,
     61             STATE_COLLAPSED_DIMMED,
     62             STATE_FULL_EXPANDED})
     63     private @interface HvacPanelState {}
     64 
     65     private @HvacPanelState int mCurrentState;
     66 
     67     private int mPanelCollapsedHeight;
     68     private int mPanelFullExpandedHeight;
     69 
     70     private View mPanel;
     71     private View mContainer;
     72 
     73     private TemperatureBarOverlay mDriverTemperature;
     74     private TemperatureBarOverlay mPassengerTemperature;
     75 
     76     private ViewGroup mDriverTemperatureTouchOverlay;
     77     private ViewGroup mPassengerTemperatureTouchOverlay;
     78 
     79     private SeatWarmerButton mDriverSeatWarmer;
     80     private SeatWarmerButton mPassengerSeatWarmer;
     81 
     82     private ToggleButton mAcButton;
     83     private ToggleButton mRecycleAirButton;
     84 
     85     private ToggleButton mFrontDefrosterButton;
     86     private ToggleButton mRearDefrosterButton;
     87 
     88     private Drawable mAutoOnDrawable;
     89     private Drawable mAutoOffDrawable;
     90 
     91     private ImageView mAutoButton;
     92 
     93     private HvacPanelRow mPanelTopRow;
     94     private HvacPanelRow mPanelBottomRow;
     95 
     96     private FanSpeedBar mFanSpeedBar;
     97     private FanDirectionButtons mFanDirectionButtons;
     98 
     99     private float mTopPanelMaxAlpha = 1.0f;
    100 
    101     private WindowManager mWindowManager;
    102 
    103     private HvacPanelStateTransition mTransition;
    104 
    105     private View mHvacFanControlBackground;
    106 
    107     private HvacController mHvacController;
    108     private FanSpeedBarController mFanSpeedBarController;
    109     private FanDirectionButtonsController mFanDirectionButtonsController;
    110     private TemperatureController mTemperatureController;
    111     private SeatWarmerController mSeatWarmerController;
    112 
    113     private boolean mInAnimation;
    114     private boolean mHvacIsOn;
    115 
    116     // TODO: read from shared pref
    117     private boolean mAutoMode;
    118 
    119     public HvacPanelController(Context context, View container,
    120             WindowManager windowManager, TemperatureBarOverlay driverTemperature,
    121             TemperatureBarOverlay passengerTemperature, ViewGroup driverTemperatureBarTouchOverlay,
    122             ViewGroup passengerTemperatureBarTouchOverlay) {
    123 
    124         mCurrentState = STATE_COLLAPSED;
    125         mWindowManager = windowManager;
    126 
    127         Resources res = context.getResources();
    128         mPanelCollapsedHeight = res.getDimensionPixelSize(R.dimen.car_hvac_panel_collapsed_height);
    129         mPanelFullExpandedHeight
    130                 = res.getDimensionPixelSize(R.dimen.car_hvac_panel_full_expanded_height);
    131 
    132         mAutoOffDrawable = res.getDrawable(R.drawable.ic_auto_off);
    133         mAutoOnDrawable = res.getDrawable(R.drawable.ic_auto_on);
    134 
    135         mDriverTemperature = driverTemperature;
    136         mDriverTemperature.setBarOnClickListener(mPanelClickListener);
    137 
    138         mPassengerTemperature = passengerTemperature;
    139         mPassengerTemperature.setBarOnClickListener(mPanelClickListener);
    140 
    141         mDriverTemperature.setCloseButtonOnClickListener(mOpenCloseToggleListener);
    142         mPassengerTemperature.setCloseButtonOnClickListener(mOpenCloseToggleListener);
    143 
    144         // Initially the hvac panel is collapsed, disable touches on the overlay container.
    145         disableTouchOnOverlay(mDriverTemperature);
    146         disableTouchOnOverlay(mPassengerTemperature);
    147 
    148         mDriverTemperatureTouchOverlay = driverTemperatureBarTouchOverlay;
    149         mPassengerTemperatureTouchOverlay = passengerTemperatureBarTouchOverlay;
    150 
    151         mDriverTemperatureTouchOverlay.setOnClickListener(mOpenCloseToggleListener);
    152         mPassengerTemperatureTouchOverlay.setOnClickListener(mOpenCloseToggleListener);
    153 
    154         mContainer = container;
    155         mContainer.setVisibility(View.INVISIBLE);
    156         mContainer.setOnClickListener(mOpenCloseToggleListener);
    157         mPanel = mContainer.findViewById(R.id.hvac_center_panel);
    158 
    159         mHvacFanControlBackground = mPanel.findViewById(R.id.fan_control_bg);
    160         mPanel.setOnClickListener(mPanelClickListener);
    161 
    162         // Set up top row buttons
    163         mPanelTopRow = (HvacPanelRow) mContainer.findViewById(R.id.top_row);
    164 
    165         mAcButton = (ToggleButton) mPanelTopRow.findViewById(R.id.ac_button);
    166         mAcButton.setToggleIcons(res.getDrawable(R.drawable.ic_ac_on),
    167                 res.getDrawable(R.drawable.ic_ac_off));
    168 
    169         mRecycleAirButton = (ToggleButton) mPanelTopRow.findViewById(R.id.recycle_air_button);
    170 
    171         mRecycleAirButton.setToggleIcons(res.getDrawable(R.drawable.ic_recycle_air_on),
    172                 res.getDrawable(R.drawable.ic_recycle_air_off));
    173 
    174         // Setup bottom row buttons
    175         mPanelBottomRow = (HvacPanelRow) mContainer.findViewById(R.id.bottom_row);
    176 
    177         mAutoButton = (ImageView) mContainer.findViewById(R.id.auto_button);
    178         mAutoButton.setOnClickListener(mAutoButtonClickListener);
    179 
    180         mFrontDefrosterButton = (ToggleButton) mPanelBottomRow.findViewById(R.id.front_defroster);
    181         mRearDefrosterButton = (ToggleButton) mPanelBottomRow.findViewById(R.id.rear_defroster);
    182 
    183         mFrontDefrosterButton.setToggleIcons(res.getDrawable(R.drawable.ic_front_defroster_on),
    184                 res.getDrawable(R.drawable.ic_front_defroster_off));
    185 
    186         mRearDefrosterButton.setToggleIcons(res.getDrawable(R.drawable.ic_rear_defroster_on),
    187                 res.getDrawable(R.drawable.ic_rear_defroster_off));
    188 
    189         mFanSpeedBar = (FanSpeedBar) mContainer.findViewById(R.id.fan_speed_bar);
    190         mFanDirectionButtons = (FanDirectionButtons) mContainer.findViewById(R.id.fan_direction_buttons);
    191 
    192         mDriverSeatWarmer = (SeatWarmerButton) mContainer.findViewById(R.id.left_seat_heater);
    193         mPassengerSeatWarmer = (SeatWarmerButton) mContainer.findViewById(R.id.right_seat_heater);
    194     }
    195 
    196     public void updateHvacController(HvacController controller) {
    197         //TODO: handle disconnected HvacController.
    198         mHvacController = controller;
    199 
    200         mFanSpeedBarController = new FanSpeedBarController(mFanSpeedBar, mHvacController);
    201         mFanDirectionButtonsController
    202                 = new FanDirectionButtonsController(mFanDirectionButtons, mHvacController);
    203         mTemperatureController = new TemperatureController(mPassengerTemperature,
    204                 mDriverTemperature, mHvacController);
    205         mSeatWarmerController = new SeatWarmerController(mPassengerSeatWarmer,
    206                 mDriverSeatWarmer, mHvacController);
    207 
    208         // Toggle buttons do not need additional logic to map between hardware
    209         // and UI settings. Simply use a ToggleListener to handle clicks.
    210         mAcButton.setIsOn(mHvacController.getAcState());
    211         mAcButton.setToggleListener(new ToggleButton.ToggleListener() {
    212             @Override
    213             public void onToggled(boolean isOn) {
    214                 mHvacController.setAcState(isOn);
    215             }
    216         });
    217 
    218         mFrontDefrosterButton.setIsOn(mHvacController.getFrontDefrosterState());
    219         mFrontDefrosterButton.setToggleListener(new ToggleButton.ToggleListener() {
    220             @Override
    221             public void onToggled(boolean isOn) {
    222                 mHvacController.setFrontDefrosterState(isOn);
    223             }
    224         });
    225 
    226         mRearDefrosterButton.setIsOn(mHvacController.getRearDefrosterState());
    227         mRearDefrosterButton.setToggleListener(new ToggleButton.ToggleListener() {
    228             @Override
    229             public void onToggled(boolean isOn) {
    230                 mHvacController.setRearDefrosterState(isOn);
    231             }
    232         });
    233 
    234         mRecycleAirButton.setIsOn(mHvacController.getAirCirculationState());
    235         mRecycleAirButton.setToggleListener(new ToggleButton.ToggleListener() {
    236             @Override
    237             public void onToggled(boolean isOn) {
    238                 mHvacController.setAirCirculation(isOn);
    239             }
    240         });
    241 
    242         setAutoMode(mHvacController.getAutoModeState());
    243 
    244         mHvacController.registerCallback(mToggleButtonCallbacks);
    245         mToggleButtonCallbacks.onHvacPowerChange(mHvacController.getHvacPowerState());
    246     }
    247 
    248     private HvacController.Callback mToggleButtonCallbacks
    249             = new HvacController.Callback() {
    250         @Override
    251         public void onAirCirculationChange(boolean isOn) {
    252             mRecycleAirButton.setIsOn(isOn);
    253         }
    254 
    255         @Override
    256         public void onFrontDefrosterChange(boolean isOn) {
    257             mFrontDefrosterButton.setIsOn(isOn);
    258         }
    259 
    260         @Override
    261         public void onRearDefrosterChange(boolean isOn) {
    262             mRearDefrosterButton.setIsOn(isOn);
    263         }
    264 
    265         @Override
    266         public void onAcStateChange(boolean isOn) {
    267             mAcButton.setIsOn(isOn);
    268         }
    269 
    270         @Override
    271         public void onAutoModeChange(boolean isOn) {
    272             mAutoMode = isOn;
    273             setAutoMode(mAutoMode);
    274         }
    275 
    276         @Override
    277         public void onHvacPowerChange(boolean isOn) {
    278             // When the HVAC Power is turned off, collapse the panel and fade the temperature
    279             // bars. Also disable expanding the panel until power is back on.
    280             mHvacIsOn = isOn;
    281             if (!mHvacIsOn && mCurrentState == STATE_FULL_EXPANDED) {
    282                 transitionState(STATE_FULL_EXPANDED, STATE_COLLAPSED);
    283             }
    284 
    285             mDriverTemperature.setIsOn(mHvacIsOn);
    286             mPassengerTemperature.setIsOn(mHvacIsOn);
    287         }
    288     };
    289 
    290     /**
    291      * Take the listeners and animators from a {@link AnimatorSet} and merge them to the
    292      * input {@link Animator} and {@link android.animation.Animator.AnimatorListener} lists.
    293      */
    294     private void combineAnimationSet(List<Animator> animatorList,
    295             List<Animator.AnimatorListener> listenerList, AnimatorSet set) {
    296 
    297         ArrayList<Animator> list = set.getChildAnimations();
    298         if (list != null) {
    299             int size = list.size();
    300             for (int i = 0; i < size; i++) {
    301                 animatorList.add(list.get(i));
    302             }
    303         }
    304 
    305         ArrayList<Animator.AnimatorListener> listeners = set.getListeners();
    306         if (listeners != null) {
    307             int size = listeners.size();
    308             for (int i = 0; i < size; i++) {
    309                 listenerList.add(listeners.get(i));
    310             }
    311         }
    312     }
    313 
    314     /**
    315      * Play necessary animations between {@link HvacPanelState} transitions
    316      */
    317     private void transitionState(@HvacPanelState int startState, @HvacPanelState int endState) {
    318         if (startState == endState || mInAnimation) {
    319             return;
    320         }
    321 
    322         List<Animator> animationList = new ArrayList<>();
    323         List<Animator.AnimatorListener> listenerList = new ArrayList<>();
    324         ValueAnimator heightAnimator = getPanelHeightAnimator(startState, endState);
    325         mTransition = new HvacPanelStateTransition(startState, endState);
    326         ValueAnimator fanBgAlphaAnimator;
    327         switch (endState) {
    328             case STATE_COLLAPSED:
    329                 // Transition to collapsed state:
    330                 // 1. Collapse the temperature bars.
    331                 // 2. Collapse the top and bottom panel, staggered with a different delay.
    332                 // 3. Decrease height of the hvac center panel, but maintain container height.
    333                 // 4. Fade the background of the fan controls seperately to create staggered effect.
    334                 animationList.add(heightAnimator);
    335                 heightAnimator.setDuration(PANEL_COLLAPSE_ANIMATION_TIME_MS);
    336                 fanBgAlphaAnimator
    337                         = ObjectAnimator.ofFloat(mHvacFanControlBackground, View.ALPHA, 1, 0)
    338                         .setDuration(PANEL_COLLAPSE_ANIMATION_TIME_MS);
    339                 fanBgAlphaAnimator.setStartDelay(PANEL_ANIMATION_DELAY_MS);
    340                 animationList.add(fanBgAlphaAnimator);
    341 
    342                 ValueAnimator panelAlphaAnimator
    343                         = ObjectAnimator.ofFloat(mContainer, View.ALPHA, 1, 0);
    344                 panelAlphaAnimator.setDuration(200);
    345                 panelAlphaAnimator.setStartDelay(300);
    346 
    347                 animationList.add(panelAlphaAnimator);
    348 
    349                 combineAnimationSet(animationList, listenerList,
    350                         mDriverTemperature.getCollapseAnimations());
    351                 combineAnimationSet(animationList, listenerList,
    352                         mPassengerTemperature.getCollapseAnimations());
    353 
    354                 combineAnimationSet(animationList, listenerList,
    355                         mPanelTopRow.getCollapseAnimation(PANEL_ANIMATION_DELAY_MS,
    356                                 mTopPanelMaxAlpha));
    357                 combineAnimationSet(animationList, listenerList,
    358                         mPanelBottomRow.getCollapseAnimation(PANEL_ANIMATION_DELAY_MS,
    359                                 mTopPanelMaxAlpha));
    360                 break;
    361             case STATE_COLLAPSED_DIMMED:
    362                 // Hide the temperature numbers, open arrows and auto state button.
    363                 // TODO: determine if this section is still needed.
    364                 break;
    365             case STATE_FULL_EXPANDED:
    366                 // Transition to expaneded state:
    367                 // 1. Expand the temperature bars.
    368                 // 2. Expand the top and bottom panel, staggered with a different delay.
    369                 // 3. Increase height of the hvac center panel, but maintain container height.
    370                 // 4. Fade in fan control background in a staggered manner.
    371                 fanBgAlphaAnimator
    372                         = ObjectAnimator.ofFloat(mHvacFanControlBackground, View.ALPHA, 0, 1)
    373                         .setDuration(PANEL_ANIMATION_TIME_MS);
    374                 fanBgAlphaAnimator.setStartDelay(PANEL_ANIMATION_DELAY_MS);
    375                 animationList.add(fanBgAlphaAnimator);
    376 
    377                 animationList.add(heightAnimator);
    378                 combineAnimationSet(animationList, listenerList,
    379                         mDriverTemperature.getExpandAnimatons());
    380                 combineAnimationSet(animationList, listenerList,
    381                         mPassengerTemperature.getExpandAnimatons());
    382 
    383                 // During expansion, the bottom panel animation should be delayed
    384                 combineAnimationSet(animationList, listenerList,
    385                         mPanelTopRow.getExpandAnimation(PANEL_ANIMATION_DELAY_MS,
    386                                 mTopPanelMaxAlpha));
    387                 combineAnimationSet(animationList, listenerList,
    388                         mPanelBottomRow.getExpandAnimation(PANEL_ANIMATION_LONG_DELAY_MS, 1f));
    389                 break;
    390             default:
    391         }
    392 
    393         // If there are animations for the state change, play them all together and ensure
    394         // the animation listeners are attached.
    395         if (animationList.size() > 0) {
    396             AnimatorSet animatorSet = new AnimatorSet();
    397             animatorSet.playTogether(animationList);
    398             for (Animator.AnimatorListener listener : listenerList) {
    399                 animatorSet.addListener(listener);
    400             }
    401             animatorSet.addListener(mAnimatorListener);
    402             animatorSet.start();
    403         }
    404     }
    405 
    406     private AnimatorSet.AnimatorListener mAnimatorListener = new AnimatorSet.AnimatorListener() {
    407         @Override
    408         public void onAnimationStart(Animator animation) {
    409             mTransition.onTransitionStart();
    410         }
    411 
    412         @Override
    413         public void onAnimationEnd(Animator animation) {
    414             mTransition.onTransitionComplete();
    415         }
    416 
    417         @Override
    418         public void onAnimationCancel(Animator animation) {}
    419 
    420         @Override
    421         public void onAnimationRepeat(Animator animation) {}
    422     };
    423 
    424     private ValueAnimator getPanelHeightAnimator(@HvacPanelState int startState,
    425             @HvacPanelState int endState) {
    426         int startHeight = getStateHeight(startState);
    427         int endHeight = getStateHeight(endState);
    428         if (startHeight == endHeight) {
    429             return null;
    430         }
    431 
    432         ValueAnimator heightAnimator = new ValueAnimator().ofInt(startHeight, endHeight)
    433                 .setDuration(PANEL_ANIMATION_TIME_MS);
    434         heightAnimator.addUpdateListener(mHeightUpdateListener);
    435         return heightAnimator;
    436     }
    437 
    438     private int getStateHeight(@HvacPanelState int state) {
    439         switch (state) {
    440             case STATE_COLLAPSED:
    441             case STATE_COLLAPSED_DIMMED:
    442                 return mPanelCollapsedHeight;
    443             case STATE_FULL_EXPANDED:
    444                 return mPanelFullExpandedHeight;
    445             default:
    446                 throw new IllegalArgumentException("No height mapped to HVAC State: " + state);
    447         }
    448     }
    449 
    450     private void setAutoMode(boolean isOn) {
    451         if (isOn) {
    452             mPanelTopRow.setOnTouchListener(new View.OnTouchListener() {
    453                 @Override
    454                 public boolean onTouch(View v, MotionEvent event) {
    455                     return true;
    456                 }
    457             });
    458             mAutoMode = true;
    459             mPanelTopRow.disablePanel(true);
    460             mTopPanelMaxAlpha = DISABLED_BUTTON_ALPHA;
    461             mAutoButton.setImageDrawable(mAutoOnDrawable);
    462         } else {
    463             mPanelTopRow.disablePanel(false);
    464             mTopPanelMaxAlpha = ENABLED_BUTTON_ALPHA;
    465             mAutoButton.setImageDrawable(mAutoOffDrawable);
    466         }
    467         mHvacFanControlBackground.setAlpha(mTopPanelMaxAlpha);
    468         mPanelTopRow.setAlpha(mTopPanelMaxAlpha);
    469     }
    470 
    471     private View.OnClickListener mPanelClickListener = new View.OnClickListener() {
    472         @Override
    473         public void onClick(View v) {
    474             if (!mHvacIsOn) {
    475                 return;
    476             }
    477             switch (mCurrentState) {
    478                 case STATE_COLLAPSED:
    479                     transitionState(STATE_COLLAPSED, STATE_FULL_EXPANDED);
    480                     break;
    481                 case STATE_COLLAPSED_DIMMED:
    482                     transitionState(mCurrentState, STATE_COLLAPSED);
    483                     break;
    484                 default:
    485             }
    486         }
    487     };
    488 
    489     private View.OnClickListener mAutoButtonClickListener = new View.OnClickListener() {
    490         @Override
    491         public void onClick(View v) {
    492             if (mAutoMode) {
    493                 mAutoMode = false;
    494             } else {
    495                 mAutoMode = true;
    496             }
    497             mHvacController.setAutoMode(mAutoMode);
    498             setAutoMode(mAutoMode);
    499         }
    500     };
    501 
    502     private View.OnClickListener mOpenCloseToggleListener = new View.OnClickListener() {
    503         @Override
    504         public void onClick(View v) {
    505             if (!mHvacIsOn) {
    506                 return;
    507             }
    508             if (mCurrentState == STATE_FULL_EXPANDED) {
    509                 transitionState(mCurrentState, STATE_COLLAPSED);
    510             } else if (mCurrentState == STATE_COLLAPSED) {
    511                 transitionState(mCurrentState, STATE_FULL_EXPANDED);
    512             }
    513         }
    514     };
    515 
    516     private ValueAnimator.AnimatorUpdateListener mHeightUpdateListener
    517             = new ValueAnimator.AnimatorUpdateListener() {
    518         @Override
    519         public void onAnimationUpdate(ValueAnimator animation) {
    520             int height = (Integer) animation.getAnimatedValue();
    521             int currentHeight = mPanel.getLayoutParams().height;
    522             mPanel.getLayoutParams().height = height;
    523             mPanel.setTop(mPanel.getTop() + height - currentHeight);
    524             mPanel.requestLayout();
    525         }
    526     };
    527 
    528     /**
    529      * Handles the necessary setup/clean up before and after a state transition.
    530      */
    531     private class HvacPanelStateTransition {
    532         private @HvacPanelState int mEndState;
    533         private @HvacPanelState int mStartState;
    534 
    535         public HvacPanelStateTransition(@HvacPanelState int startState,
    536                 @HvacPanelState int endState) {
    537             mStartState = startState;
    538             mEndState = endState;
    539         }
    540 
    541         public void onTransitionStart() {
    542             mInAnimation = true;
    543             if (mEndState == STATE_FULL_EXPANDED) {
    544                 mContainer.setAlpha(1);
    545                 mContainer.setVisibility(View.VISIBLE);
    546             } else if (mStartState == STATE_FULL_EXPANDED) {
    547                 // Finished transitioning out of the fully expanded panel. Make the HVAC container
    548                 // and temperature bars not touchable so clicks on the screen bar are not intercepted.
    549                 disableTouchOnOverlay(mContainer);
    550                 disableTouchOnOverlay(mDriverTemperature);
    551                 disableTouchOnOverlay(mPassengerTemperature);
    552             }
    553         }
    554 
    555         public void onTransitionComplete() {
    556             if (mStartState == STATE_FULL_EXPANDED) {
    557                 mContainer.setVisibility(View.INVISIBLE);
    558 
    559                 enableTouchOnOverlay(mDriverTemperatureTouchOverlay);
    560                 enableTouchOnOverlay(mPassengerTemperatureTouchOverlay);
    561             } else if (mEndState == STATE_FULL_EXPANDED) {
    562                 // Finished transitioning into the fully expanded HVAC panel, make the
    563                 // container and temperature bars touchable since it covers the screen.
    564                 enableTouchOnOverlay(mContainer);
    565                 enableTouchOnOverlay(mDriverTemperature);
    566                 enableTouchOnOverlay(mPassengerTemperature);
    567 
    568                 disableTouchOnOverlay(mDriverTemperatureTouchOverlay);
    569                 disableTouchOnOverlay(mPassengerTemperatureTouchOverlay);
    570             }
    571 
    572             // set new states
    573             mCurrentState = mEndState;
    574             mInAnimation = false;
    575         }
    576     }
    577 
    578     private void disableTouchOnOverlay(View view) {
    579         WindowManager.LayoutParams params
    580                 = (WindowManager.LayoutParams) view.getLayoutParams();
    581         params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    582                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
    583                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
    584                 & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
    585         mWindowManager.updateViewLayout(view, params);
    586     }
    587 
    588     private void enableTouchOnOverlay(View view) {
    589         WindowManager.LayoutParams params
    590                 = (WindowManager.LayoutParams) view.getLayoutParams();
    591         params.flags =
    592                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    593                         | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
    594                         & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
    595         mWindowManager.updateViewLayout(view, params);
    596     }
    597 
    598 }
    599