1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/wm/core/window_animations.h" 6 7 #include <math.h> 8 9 #include <algorithm> 10 #include <vector> 11 12 #include "base/command_line.h" 13 #include "base/compiler_specific.h" 14 #include "base/logging.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/stl_util.h" 17 #include "base/time/time.h" 18 #include "ui/aura/client/aura_constants.h" 19 #include "ui/aura/window.h" 20 #include "ui/aura/window_delegate.h" 21 #include "ui/aura/window_observer.h" 22 #include "ui/aura/window_property.h" 23 #include "ui/compositor/compositor_observer.h" 24 #include "ui/compositor/layer.h" 25 #include "ui/compositor/layer_animation_observer.h" 26 #include "ui/compositor/layer_animation_sequence.h" 27 #include "ui/compositor/layer_animator.h" 28 #include "ui/compositor/layer_tree_owner.h" 29 #include "ui/compositor/scoped_animation_duration_scale_mode.h" 30 #include "ui/compositor/scoped_layer_animation_settings.h" 31 #include "ui/gfx/animation/animation.h" 32 #include "ui/gfx/interpolated_transform.h" 33 #include "ui/gfx/rect_conversions.h" 34 #include "ui/gfx/screen.h" 35 #include "ui/gfx/vector2d.h" 36 #include "ui/gfx/vector3d_f.h" 37 #include "ui/wm/core/window_util.h" 38 #include "ui/wm/core/wm_core_switches.h" 39 #include "ui/wm/public/animation_host.h" 40 41 DECLARE_WINDOW_PROPERTY_TYPE(int) 42 DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationType) 43 DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationTransition) 44 DECLARE_WINDOW_PROPERTY_TYPE(float) 45 DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(WM_EXPORT, bool) 46 47 namespace wm { 48 namespace { 49 const float kWindowAnimation_Vertical_TranslateY = 15.f; 50 51 // A base class for hiding animation observer which has two roles: 52 // 1) Notifies AnimationHost at the end of hiding animation. 53 // 2) Detaches the window's layers for hiding animation and deletes 54 // them upon completion of the animation. This is necessary to a) 55 // ensure that the animation continues in the event of the window being 56 // deleted, and b) to ensure that the animation is visible even if the 57 // window gets restacked below other windows when focus or activation 58 // changes. 59 // The subclass will determine when the animation is completed. 60 class HidingWindowAnimationObserverBase : public aura::WindowObserver { 61 public: 62 explicit HidingWindowAnimationObserverBase(aura::Window* window) 63 : window_(window) { 64 window_->AddObserver(this); 65 } 66 virtual ~HidingWindowAnimationObserverBase() { 67 if (window_) 68 window_->RemoveObserver(this); 69 } 70 71 // aura::WindowObserver: 72 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { 73 DCHECK_EQ(window, window_); 74 WindowInvalid(); 75 } 76 77 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE { 78 DCHECK_EQ(window, window_); 79 WindowInvalid(); 80 } 81 82 // Detach the current layers and create new layers for |window_|. 83 // Stack the original layers above |window_| and its transient 84 // children. If the window has transient children, the original 85 // layers will be moved above the top most transient child so that 86 // activation change does not put the window above the animating 87 // layer. 88 void DetachAndRecreateLayers() { 89 layer_owner_ = RecreateLayers(window_); 90 if (window_->parent()) { 91 const aura::Window::Windows& transient_children = 92 GetTransientChildren(window_); 93 aura::Window::Windows::const_iterator iter = 94 std::find(window_->parent()->children().begin(), 95 window_->parent()->children().end(), 96 window_); 97 DCHECK(iter != window_->parent()->children().end()); 98 aura::Window* topmost_transient_child = NULL; 99 for (++iter; iter != window_->parent()->children().end(); ++iter) { 100 if (std::find(transient_children.begin(), 101 transient_children.end(), 102 *iter) != transient_children.end()) { 103 topmost_transient_child = *iter; 104 } 105 } 106 if (topmost_transient_child) { 107 window_->parent()->layer()->StackAbove( 108 layer_owner_->root(), topmost_transient_child->layer()); 109 } 110 } 111 } 112 113 protected: 114 // Invoked when the hiding animation is completed. It will delete 115 // 'this', and no operation should be made on this object after this 116 // point. 117 void OnAnimationCompleted() { 118 // Window may have been destroyed by this point. 119 if (window_) { 120 aura::client::AnimationHost* animation_host = 121 aura::client::GetAnimationHost(window_); 122 if (animation_host) 123 animation_host->OnWindowHidingAnimationCompleted(); 124 window_->RemoveObserver(this); 125 } 126 delete this; 127 } 128 129 private: 130 // Invoked when the window is destroyed (or destroying). 131 void WindowInvalid() { 132 layer_owner_->root()->SuppressPaint(); 133 134 window_->RemoveObserver(this); 135 window_ = NULL; 136 } 137 138 aura::Window* window_; 139 140 // The owner of detached layers. 141 scoped_ptr<ui::LayerTreeOwner> layer_owner_; 142 143 DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserverBase); 144 }; 145 146 } // namespace 147 148 DEFINE_WINDOW_PROPERTY_KEY(int, 149 kWindowVisibilityAnimationTypeKey, 150 WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT); 151 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0); 152 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition, 153 kWindowVisibilityAnimationTransitionKey, 154 ANIMATE_BOTH); 155 DEFINE_WINDOW_PROPERTY_KEY(float, 156 kWindowVisibilityAnimationVerticalPositionKey, 157 kWindowAnimation_Vertical_TranslateY); 158 159 // A HidingWindowAnimationObserver that deletes observer and detached 160 // layers upon the completion of the implicit animation. 161 class ImplicitHidingWindowAnimationObserver 162 : public HidingWindowAnimationObserverBase, 163 public ui::ImplicitAnimationObserver { 164 public: 165 ImplicitHidingWindowAnimationObserver( 166 aura::Window* window, 167 ui::ScopedLayerAnimationSettings* settings); 168 virtual ~ImplicitHidingWindowAnimationObserver() {} 169 170 // ui::ImplicitAnimationObserver: 171 virtual void OnImplicitAnimationsCompleted() OVERRIDE; 172 173 private: 174 DISALLOW_COPY_AND_ASSIGN(ImplicitHidingWindowAnimationObserver); 175 }; 176 177 namespace { 178 179 const int kDefaultAnimationDurationForMenuMS = 150; 180 181 const float kWindowAnimation_HideOpacity = 0.f; 182 const float kWindowAnimation_ShowOpacity = 1.f; 183 const float kWindowAnimation_TranslateFactor = 0.5f; 184 const float kWindowAnimation_ScaleFactor = .95f; 185 186 const int kWindowAnimation_Rotate_DurationMS = 180; 187 const int kWindowAnimation_Rotate_OpacityDurationPercent = 90; 188 const float kWindowAnimation_Rotate_TranslateY = -20.f; 189 const float kWindowAnimation_Rotate_PerspectiveDepth = 500.f; 190 const float kWindowAnimation_Rotate_DegreesX = 5.f; 191 const float kWindowAnimation_Rotate_ScaleFactor = .99f; 192 193 const float kWindowAnimation_Bounce_Scale = 1.02f; 194 const int kWindowAnimation_Bounce_DurationMS = 180; 195 const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40; 196 197 base::TimeDelta GetWindowVisibilityAnimationDuration( 198 const aura::Window& window) { 199 int duration = 200 window.GetProperty(kWindowVisibilityAnimationDurationKey); 201 if (duration == 0 && window.type() == ui::wm::WINDOW_TYPE_MENU) { 202 return base::TimeDelta::FromMilliseconds( 203 kDefaultAnimationDurationForMenuMS); 204 } 205 return base::TimeDelta::FromInternalValue(duration); 206 } 207 208 // Gets/sets the WindowVisibilityAnimationType associated with a window. 209 // TODO(beng): redundant/fold into method on public api? 210 int GetWindowVisibilityAnimationType(aura::Window* window) { 211 int type = window->GetProperty(kWindowVisibilityAnimationTypeKey); 212 if (type == WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT) { 213 return (window->type() == ui::wm::WINDOW_TYPE_MENU || 214 window->type() == ui::wm::WINDOW_TYPE_TOOLTIP) 215 ? WINDOW_VISIBILITY_ANIMATION_TYPE_FADE 216 : WINDOW_VISIBILITY_ANIMATION_TYPE_DROP; 217 } 218 return type; 219 } 220 221 void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) { 222 const ui::Layer* root = layer; 223 while (root->parent()) 224 root = root->parent(); 225 layer->GetTargetTransformRelativeTo(root, transform); 226 } 227 228 gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer, 229 const gfx::Transform& transform) { 230 gfx::Transform in_world = transform; 231 GetTransformRelativeToRoot(layer, &in_world); 232 233 gfx::RectF transformed = layer->bounds(); 234 in_world.TransformRect(&transformed); 235 236 return gfx::ToEnclosingRect(transformed); 237 } 238 239 // Augment the host window so that the enclosing bounds of the full 240 // animation will fit inside of it. 241 void AugmentWindowSize(aura::Window* window, 242 const gfx::Transform& end_transform) { 243 aura::client::AnimationHost* animation_host = 244 aura::client::GetAnimationHost(window); 245 if (!animation_host) 246 return; 247 248 const gfx::Rect& world_at_start = window->bounds(); 249 gfx::Rect world_at_end = 250 GetLayerWorldBoundsAfterTransform(window->layer(), end_transform); 251 gfx::Rect union_in_window_space = 252 gfx::UnionRects(world_at_start, world_at_end); 253 254 // Calculate the top left and bottom right deltas to be added to the window 255 // bounds. 256 gfx::Vector2d top_left_delta(world_at_start.x() - union_in_window_space.x(), 257 world_at_start.y() - union_in_window_space.y()); 258 259 gfx::Vector2d bottom_right_delta( 260 union_in_window_space.x() + union_in_window_space.width() - 261 (world_at_start.x() + world_at_start.width()), 262 union_in_window_space.y() + union_in_window_space.height() - 263 (world_at_start.y() + world_at_start.height())); 264 265 DCHECK(top_left_delta.x() >= 0 && top_left_delta.y() >= 0 && 266 bottom_right_delta.x() >= 0 && bottom_right_delta.y() >= 0); 267 268 animation_host->SetHostTransitionOffsets(top_left_delta, bottom_right_delta); 269 } 270 271 // Shows a window using an animation, animating its opacity from 0.f to 1.f, 272 // its visibility to true, and its transform from |start_transform| to 273 // |end_transform|. 274 void AnimateShowWindowCommon(aura::Window* window, 275 const gfx::Transform& start_transform, 276 const gfx::Transform& end_transform) { 277 AugmentWindowSize(window, end_transform); 278 279 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 280 window->layer()->SetTransform(start_transform); 281 window->layer()->SetVisible(true); 282 283 { 284 // Property sets within this scope will be implicitly animated. 285 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); 286 base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); 287 if (duration.ToInternalValue() > 0) 288 settings.SetTransitionDuration(duration); 289 290 window->layer()->SetTransform(end_transform); 291 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); 292 } 293 } 294 295 // Hides a window using an animation, animating its opacity from 1.f to 0.f, 296 // its visibility to false, and its transform to |end_transform|. 297 void AnimateHideWindowCommon(aura::Window* window, 298 const gfx::Transform& end_transform) { 299 AugmentWindowSize(window, end_transform); 300 301 // Property sets within this scope will be implicitly animated. 302 ScopedHidingAnimationSettings hiding_settings(window); 303 base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); 304 if (duration.ToInternalValue() > 0) 305 hiding_settings.layer_animation_settings()->SetTransitionDuration(duration); 306 307 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 308 window->layer()->SetTransform(end_transform); 309 window->layer()->SetVisible(false); 310 } 311 312 static gfx::Transform GetScaleForWindow(aura::Window* window) { 313 gfx::Rect bounds = window->bounds(); 314 gfx::Transform scale = gfx::GetScaleTransform( 315 gfx::Point(kWindowAnimation_TranslateFactor * bounds.width(), 316 kWindowAnimation_TranslateFactor * bounds.height()), 317 kWindowAnimation_ScaleFactor); 318 return scale; 319 } 320 321 // Show/Hide windows using a shrink animation. 322 void AnimateShowWindow_Drop(aura::Window* window) { 323 AnimateShowWindowCommon(window, GetScaleForWindow(window), gfx::Transform()); 324 } 325 326 void AnimateHideWindow_Drop(aura::Window* window) { 327 AnimateHideWindowCommon(window, GetScaleForWindow(window)); 328 } 329 330 // Show/Hide windows using a vertical Glenimation. 331 void AnimateShowWindow_Vertical(aura::Window* window) { 332 gfx::Transform transform; 333 transform.Translate(0, window->GetProperty( 334 kWindowVisibilityAnimationVerticalPositionKey)); 335 AnimateShowWindowCommon(window, transform, gfx::Transform()); 336 } 337 338 void AnimateHideWindow_Vertical(aura::Window* window) { 339 gfx::Transform transform; 340 transform.Translate(0, window->GetProperty( 341 kWindowVisibilityAnimationVerticalPositionKey)); 342 AnimateHideWindowCommon(window, transform); 343 } 344 345 // Show/Hide windows using a fade. 346 void AnimateShowWindow_Fade(aura::Window* window) { 347 AnimateShowWindowCommon(window, gfx::Transform(), gfx::Transform()); 348 } 349 350 void AnimateHideWindow_Fade(aura::Window* window) { 351 AnimateHideWindowCommon(window, gfx::Transform()); 352 } 353 354 ui::LayerAnimationElement* CreateGrowShrinkElement( 355 aura::Window* window, bool grow) { 356 scoped_ptr<ui::InterpolatedTransform> scale(new ui::InterpolatedScale( 357 gfx::Point3F(kWindowAnimation_Bounce_Scale, 358 kWindowAnimation_Bounce_Scale, 359 1), 360 gfx::Point3F(1, 1, 1))); 361 scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( 362 new ui::InterpolatedTransformAboutPivot( 363 gfx::Point(window->bounds().width() * 0.5, 364 window->bounds().height() * 0.5), 365 scale.release())); 366 scale_about_pivot->SetReversed(grow); 367 scoped_ptr<ui::LayerAnimationElement> transition( 368 ui::LayerAnimationElement::CreateInterpolatedTransformElement( 369 scale_about_pivot.release(), 370 base::TimeDelta::FromMilliseconds( 371 kWindowAnimation_Bounce_DurationMS * 372 kWindowAnimation_Bounce_GrowShrinkDurationPercent / 100))); 373 transition->set_tween_type(grow ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN); 374 return transition.release(); 375 } 376 377 void AnimateBounce(aura::Window* window) { 378 ui::ScopedLayerAnimationSettings scoped_settings( 379 window->layer()->GetAnimator()); 380 scoped_settings.SetPreemptionStrategy( 381 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); 382 scoped_ptr<ui::LayerAnimationSequence> sequence( 383 new ui::LayerAnimationSequence); 384 sequence->AddElement(CreateGrowShrinkElement(window, true)); 385 sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement( 386 ui::LayerAnimationElement::BOUNDS, 387 base::TimeDelta::FromMilliseconds( 388 kWindowAnimation_Bounce_DurationMS * 389 (100 - 2 * kWindowAnimation_Bounce_GrowShrinkDurationPercent) / 390 100))); 391 sequence->AddElement(CreateGrowShrinkElement(window, false)); 392 window->layer()->GetAnimator()->StartAnimation(sequence.release()); 393 } 394 395 // A HidingWindowAnimationObserver that deletes observer and detached 396 // layers when the last_sequence has been completed or aborted. 397 class RotateHidingWindowAnimationObserver 398 : public HidingWindowAnimationObserverBase, 399 public ui::LayerAnimationObserver { 400 public: 401 explicit RotateHidingWindowAnimationObserver(aura::Window* window) 402 : HidingWindowAnimationObserverBase(window) {} 403 virtual ~RotateHidingWindowAnimationObserver() {} 404 405 // Destroys itself after |last_sequence| ends or is aborted. Does not take 406 // ownership of |last_sequence|, which should not be NULL. 407 void SetLastSequence(ui::LayerAnimationSequence* last_sequence) { 408 last_sequence->AddObserver(this); 409 } 410 411 // ui::LayerAnimationObserver: 412 virtual void OnLayerAnimationEnded( 413 ui::LayerAnimationSequence* sequence) OVERRIDE { 414 OnAnimationCompleted(); 415 } 416 virtual void OnLayerAnimationAborted( 417 ui::LayerAnimationSequence* sequence) OVERRIDE { 418 OnAnimationCompleted(); 419 } 420 virtual void OnLayerAnimationScheduled( 421 ui::LayerAnimationSequence* sequence) OVERRIDE {} 422 423 private: 424 DISALLOW_COPY_AND_ASSIGN(RotateHidingWindowAnimationObserver); 425 }; 426 427 void AddLayerAnimationsForRotate(aura::Window* window, bool show) { 428 if (show) 429 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 430 431 base::TimeDelta duration = base::TimeDelta::FromMilliseconds( 432 kWindowAnimation_Rotate_DurationMS); 433 434 RotateHidingWindowAnimationObserver* observer = NULL; 435 436 if (!show) { 437 observer = new RotateHidingWindowAnimationObserver(window); 438 window->layer()->GetAnimator()->SchedulePauseForProperties( 439 duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100, 440 ui::LayerAnimationElement::OPACITY); 441 } 442 scoped_ptr<ui::LayerAnimationElement> opacity( 443 ui::LayerAnimationElement::CreateOpacityElement( 444 show ? kWindowAnimation_ShowOpacity : kWindowAnimation_HideOpacity, 445 duration * kWindowAnimation_Rotate_OpacityDurationPercent / 100)); 446 opacity->set_tween_type(gfx::Tween::EASE_IN_OUT); 447 window->layer()->GetAnimator()->ScheduleAnimation( 448 new ui::LayerAnimationSequence(opacity.release())); 449 450 float xcenter = window->bounds().width() * 0.5; 451 452 gfx::Transform transform; 453 transform.Translate(xcenter, 0); 454 transform.ApplyPerspectiveDepth(kWindowAnimation_Rotate_PerspectiveDepth); 455 transform.Translate(-xcenter, 0); 456 scoped_ptr<ui::InterpolatedTransform> perspective( 457 new ui::InterpolatedConstantTransform(transform)); 458 459 scoped_ptr<ui::InterpolatedTransform> scale( 460 new ui::InterpolatedScale(1, kWindowAnimation_Rotate_ScaleFactor)); 461 scoped_ptr<ui::InterpolatedTransform> scale_about_pivot( 462 new ui::InterpolatedTransformAboutPivot( 463 gfx::Point(xcenter, kWindowAnimation_Rotate_TranslateY), 464 scale.release())); 465 466 scoped_ptr<ui::InterpolatedTransform> translation( 467 new ui::InterpolatedTranslation(gfx::Point(), gfx::Point( 468 0, kWindowAnimation_Rotate_TranslateY))); 469 470 scoped_ptr<ui::InterpolatedTransform> rotation( 471 new ui::InterpolatedAxisAngleRotation( 472 gfx::Vector3dF(1, 0, 0), 0, kWindowAnimation_Rotate_DegreesX)); 473 474 scale_about_pivot->SetChild(perspective.release()); 475 translation->SetChild(scale_about_pivot.release()); 476 rotation->SetChild(translation.release()); 477 rotation->SetReversed(show); 478 479 scoped_ptr<ui::LayerAnimationElement> transition( 480 ui::LayerAnimationElement::CreateInterpolatedTransformElement( 481 rotation.release(), duration)); 482 ui::LayerAnimationSequence* last_sequence = 483 new ui::LayerAnimationSequence(transition.release()); 484 window->layer()->GetAnimator()->ScheduleAnimation(last_sequence); 485 486 if (observer) { 487 observer->SetLastSequence(last_sequence); 488 observer->DetachAndRecreateLayers(); 489 } 490 } 491 492 void AnimateShowWindow_Rotate(aura::Window* window) { 493 AddLayerAnimationsForRotate(window, true); 494 } 495 496 void AnimateHideWindow_Rotate(aura::Window* window) { 497 AddLayerAnimationsForRotate(window, false); 498 } 499 500 bool AnimateShowWindow(aura::Window* window) { 501 if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { 502 if (HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { 503 // Since hide animation may have changed opacity and transform, 504 // reset them to show the window. 505 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity); 506 window->layer()->SetTransform(gfx::Transform()); 507 } 508 return false; 509 } 510 511 switch (GetWindowVisibilityAnimationType(window)) { 512 case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: 513 AnimateShowWindow_Drop(window); 514 return true; 515 case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: 516 AnimateShowWindow_Vertical(window); 517 return true; 518 case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: 519 AnimateShowWindow_Fade(window); 520 return true; 521 case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: 522 AnimateShowWindow_Rotate(window); 523 return true; 524 default: 525 return false; 526 } 527 } 528 529 bool AnimateHideWindow(aura::Window* window) { 530 if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) { 531 if (HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) { 532 // Since show animation may have changed opacity and transform, 533 // reset them, though the change should be hidden. 534 window->layer()->SetOpacity(kWindowAnimation_HideOpacity); 535 window->layer()->SetTransform(gfx::Transform()); 536 } 537 return false; 538 } 539 540 switch (GetWindowVisibilityAnimationType(window)) { 541 case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP: 542 AnimateHideWindow_Drop(window); 543 return true; 544 case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL: 545 AnimateHideWindow_Vertical(window); 546 return true; 547 case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE: 548 AnimateHideWindow_Fade(window); 549 return true; 550 case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE: 551 AnimateHideWindow_Rotate(window); 552 return true; 553 default: 554 return false; 555 } 556 } 557 558 } // namespace 559 560 //////////////////////////////////////////////////////////////////////////////// 561 // ImplicitHidingWindowAnimationObserver 562 563 ImplicitHidingWindowAnimationObserver::ImplicitHidingWindowAnimationObserver( 564 aura::Window* window, 565 ui::ScopedLayerAnimationSettings* settings) 566 : HidingWindowAnimationObserverBase(window) { 567 settings->AddObserver(this); 568 } 569 570 void ImplicitHidingWindowAnimationObserver::OnImplicitAnimationsCompleted() { 571 OnAnimationCompleted(); 572 } 573 574 //////////////////////////////////////////////////////////////////////////////// 575 // ScopedHidingAnimationSettings 576 577 ScopedHidingAnimationSettings::ScopedHidingAnimationSettings( 578 aura::Window* window) 579 : layer_animation_settings_(window->layer()->GetAnimator()), 580 observer_(new ImplicitHidingWindowAnimationObserver( 581 window, 582 &layer_animation_settings_)) { 583 } 584 585 ScopedHidingAnimationSettings::~ScopedHidingAnimationSettings() { 586 observer_->DetachAndRecreateLayers(); 587 } 588 589 //////////////////////////////////////////////////////////////////////////////// 590 // External interface 591 592 void SetWindowVisibilityAnimationType(aura::Window* window, int type) { 593 window->SetProperty(kWindowVisibilityAnimationTypeKey, type); 594 } 595 596 int GetWindowVisibilityAnimationType(aura::Window* window) { 597 return window->GetProperty(kWindowVisibilityAnimationTypeKey); 598 } 599 600 void SetWindowVisibilityAnimationTransition( 601 aura::Window* window, 602 WindowVisibilityAnimationTransition transition) { 603 window->SetProperty(kWindowVisibilityAnimationTransitionKey, transition); 604 } 605 606 bool HasWindowVisibilityAnimationTransition( 607 aura::Window* window, 608 WindowVisibilityAnimationTransition transition) { 609 WindowVisibilityAnimationTransition prop = window->GetProperty( 610 kWindowVisibilityAnimationTransitionKey); 611 return (prop & transition) != 0; 612 } 613 614 void SetWindowVisibilityAnimationDuration(aura::Window* window, 615 const base::TimeDelta& duration) { 616 window->SetProperty(kWindowVisibilityAnimationDurationKey, 617 static_cast<int>(duration.ToInternalValue())); 618 } 619 620 base::TimeDelta GetWindowVisibilityAnimationDuration( 621 const aura::Window& window) { 622 return base::TimeDelta::FromInternalValue( 623 window.GetProperty(kWindowVisibilityAnimationDurationKey)); 624 } 625 626 void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window, 627 float position) { 628 window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position); 629 } 630 631 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { 632 if (WindowAnimationsDisabled(window)) 633 return false; 634 if (visible) 635 return AnimateShowWindow(window); 636 // Don't start hiding the window again if it's already being hidden. 637 return window->layer()->GetTargetOpacity() != 0.0f && 638 AnimateHideWindow(window); 639 } 640 641 bool AnimateWindow(aura::Window* window, WindowAnimationType type) { 642 switch (type) { 643 case WINDOW_ANIMATION_TYPE_BOUNCE: 644 AnimateBounce(window); 645 return true; 646 default: 647 NOTREACHED(); 648 return false; 649 } 650 } 651 652 bool WindowAnimationsDisabled(aura::Window* window) { 653 // Individual windows can choose to skip animations. 654 if (window && window->GetProperty(aura::client::kAnimationsDisabledKey)) 655 return true; 656 657 // Animations can be disabled globally for testing. 658 if (CommandLine::ForCurrentProcess()->HasSwitch( 659 switches::kWindowAnimationsDisabled)) 660 return true; 661 662 // Tests of animations themselves should still run even if the machine is 663 // being accessed via Remote Desktop. 664 if (ui::ScopedAnimationDurationScaleMode::duration_scale_mode() == 665 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION) 666 return false; 667 668 // Let the user decide whether or not to play the animation. 669 return !gfx::Animation::ShouldRenderRichAnimation(); 670 } 671 672 } // namespace wm 673