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