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.
5 #include "ash/wm/session_state_animator.h"
8 #include "ash/shell_window_ids.h"
9 #include "ash/wm/window_animations.h"
10 #include "ui/aura/client/aura_constants.h"
11 #include "ui/aura/window_event_dispatcher.h"
12 #include "ui/compositor/layer_animation_observer.h"
13 #include "ui/compositor/layer_animation_sequence.h"
14 #include "ui/compositor/scoped_layer_animation_settings.h"
15 #include "ui/views/widget/widget.h"
20 // Slightly-smaller size that we scale the screen down to for the pre-lock and
21 // pre-shutdown states.
22 const float kSlowCloseSizeRatio
= 0.95f
;
24 // Maximum opacity of white layer when animating pre-shutdown state.
25 const float kPartialFadeRatio
= 0.3f
;
27 // Minimum size. Not zero as it causes numeric issues.
28 const float kMinimumScale
= 1e-4f
;
30 // Returns the transform that should be applied to containers for the slow-close
32 gfx::Transform
GetSlowCloseTransform() {
33 gfx::Size root_size
= Shell::GetPrimaryRootWindow()->bounds().size();
34 gfx::Transform transform
;
36 floor(0.5 * (1.0 - kSlowCloseSizeRatio
) * root_size
.width() + 0.5),
37 floor(0.5 * (1.0 - kSlowCloseSizeRatio
) * root_size
.height() + 0.5));
38 transform
.Scale(kSlowCloseSizeRatio
, kSlowCloseSizeRatio
);
42 // Returns the transform that should be applied to containers for the fast-close
44 gfx::Transform
GetFastCloseTransform() {
45 gfx::Size root_size
= Shell::GetPrimaryRootWindow()->bounds().size();
46 gfx::Transform transform
;
47 transform
.Translate(floor(0.5 * root_size
.width() + 0.5),
48 floor(0.5 * root_size
.height() + 0.5));
49 transform
.Scale(kMinimumScale
, kMinimumScale
);
53 // Slowly shrinks |window| to a slightly-smaller size.
54 void StartSlowCloseAnimationForWindow(aura::Window
* window
,
55 base::TimeDelta duration
,
56 ui::LayerAnimationObserver
* observer
) {
57 ui::LayerAnimator
* animator
= window
->layer()->GetAnimator();
58 animator
->set_preemption_strategy(
59 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
60 ui::LayerAnimationSequence
* sequence
= new ui::LayerAnimationSequence(
61 ui::LayerAnimationElement::CreateTransformElement(
62 GetSlowCloseTransform(),
65 sequence
->AddObserver(observer
);
66 animator
->StartAnimation(sequence
);
69 // Quickly undoes the effects of the slow-close animation on |window|.
70 void StartUndoSlowCloseAnimationForWindow(
72 base::TimeDelta duration
,
73 ui::LayerAnimationObserver
* observer
) {
74 ui::LayerAnimator
* animator
= window
->layer()->GetAnimator();
75 animator
->set_preemption_strategy(
76 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
77 ui::LayerAnimationSequence
* sequence
= new ui::LayerAnimationSequence(
78 ui::LayerAnimationElement::CreateTransformElement(
82 sequence
->AddObserver(observer
);
83 animator
->StartAnimation(sequence
);
86 // Quickly shrinks |window| down to a point in the center of the screen and
87 // fades it out to 0 opacity.
88 void StartFastCloseAnimationForWindow(aura::Window
* window
,
89 base::TimeDelta duration
,
90 ui::LayerAnimationObserver
* observer
) {
91 ui::LayerAnimator
* animator
= window
->layer()->GetAnimator();
92 animator
->set_preemption_strategy(
93 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
94 animator
->StartAnimation(
95 new ui::LayerAnimationSequence(
96 ui::LayerAnimationElement::CreateTransformElement(
97 GetFastCloseTransform(), duration
)));
98 ui::LayerAnimationSequence
* sequence
= new ui::LayerAnimationSequence(
99 ui::LayerAnimationElement::CreateOpacityElement(0.0, duration
));
101 sequence
->AddObserver(observer
);
102 animator
->StartAnimation(sequence
);
105 // Fades |window| to |target_opacity| over |duration|.
106 void StartPartialFadeAnimation(aura::Window
* window
,
107 float target_opacity
,
108 base::TimeDelta duration
,
109 ui::LayerAnimationObserver
* observer
) {
110 ui::LayerAnimator
* animator
= window
->layer()->GetAnimator();
111 animator
->set_preemption_strategy(
112 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
113 ui::LayerAnimationSequence
* sequence
= new ui::LayerAnimationSequence(
114 ui::LayerAnimationElement::CreateOpacityElement(
115 target_opacity
, duration
));
117 sequence
->AddObserver(observer
);
118 animator
->StartAnimation(sequence
);
121 // Fades |window| to |opacity| over |duration|.
122 void StartOpacityAnimationForWindow(aura::Window
* window
,
124 base::TimeDelta duration
,
125 ui::LayerAnimationObserver
* observer
) {
126 ui::LayerAnimator
* animator
= window
->layer()->GetAnimator();
127 animator
->set_preemption_strategy(
128 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
129 ui::LayerAnimationSequence
* sequence
= new ui::LayerAnimationSequence(
130 ui::LayerAnimationElement::CreateOpacityElement(opacity
, duration
));
132 sequence
->AddObserver(observer
);
133 animator
->StartAnimation(sequence
);
136 // Makes |window| fully transparent instantaneously.
137 void HideWindowImmediately(aura::Window
* window
,
138 ui::LayerAnimationObserver
* observer
) {
139 window
->layer()->SetOpacity(0.0);
141 observer
->OnLayerAnimationEnded(NULL
);
144 // Restores |window| to its original position and scale and full opacity
146 void RestoreWindow(aura::Window
* window
, ui::LayerAnimationObserver
* observer
) {
147 window
->layer()->SetTransform(gfx::Transform());
148 window
->layer()->SetOpacity(1.0);
150 observer
->OnLayerAnimationEnded(NULL
);
153 void HideWindow(aura::Window
* window
,
154 base::TimeDelta duration
,
156 ui::LayerAnimationObserver
* observer
) {
157 ui::Layer
* layer
= window
->layer();
158 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
160 settings
.SetPreemptionStrategy(
161 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
162 settings
.SetTransitionDuration(duration
);
164 settings
.SetTweenType(gfx::Tween::EASE_OUT
);
165 SetTransformForScaleAnimation(layer
,
166 above
? LAYER_SCALE_ANIMATION_ABOVE
: LAYER_SCALE_ANIMATION_BELOW
);
168 settings
.SetTweenType(gfx::Tween::EASE_IN_OUT
);
169 layer
->SetOpacity(0.0f
);
171 // After the animation completes snap the transform back to the identity,
172 // otherwise any one that asks for screen bounds gets a slightly scaled
174 settings
.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION
);
175 settings
.SetTransitionDuration(base::TimeDelta());
176 layer
->SetTransform(gfx::Transform());
178 // A bit of a dirty trick: we need to catch the end of the animation we don't
179 // control. So we use two facts we know: which animator will be used and the
180 // target opacity to add "Do nothing" animation sequence.
181 // Unfortunately, we can not just use empty LayerAnimationSequence, because
182 // it does not call NotifyEnded().
184 ui::LayerAnimationSequence
* sequence
= new ui::LayerAnimationSequence(
185 ui::LayerAnimationElement::CreateOpacityElement(
186 0.0, base::TimeDelta()));
187 sequence
->AddObserver(observer
);
188 layer
->GetAnimator()->ScheduleAnimation(sequence
);
192 // Animates |window| to identity transform and full opacity over |duration|.
193 void TransformWindowToBaseState(aura::Window
* window
,
194 base::TimeDelta duration
,
195 ui::LayerAnimationObserver
* observer
) {
196 ui::Layer
* layer
= window
->layer();
197 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
199 // Animate to target values.
200 settings
.SetPreemptionStrategy(
201 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
202 settings
.SetTransitionDuration(duration
);
204 settings
.SetTweenType(gfx::Tween::EASE_OUT
);
205 layer
->SetTransform(gfx::Transform());
207 settings
.SetTweenType(gfx::Tween::EASE_IN_OUT
);
208 layer
->SetOpacity(1.0f
);
210 // A bit of a dirty trick: we need to catch the end of the animation we don't
211 // control. So we use two facts we know: which animator will be used and the
212 // target opacity to add "Do nothing" animation sequence.
213 // Unfortunately, we can not just use empty LayerAnimationSequence, because
214 // it does not call NotifyEnded().
216 ui::LayerAnimationSequence
* sequence
= new ui::LayerAnimationSequence(
217 ui::LayerAnimationElement::CreateOpacityElement(
218 1.0, base::TimeDelta()));
219 sequence
->AddObserver(observer
);
220 layer
->GetAnimator()->ScheduleAnimation(sequence
);
224 void ShowWindow(aura::Window
* window
,
225 base::TimeDelta duration
,
227 ui::LayerAnimationObserver
* observer
) {
228 ui::Layer
* layer
= window
->layer();
229 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
231 // Set initial state of animation
232 settings
.SetPreemptionStrategy(
233 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
234 settings
.SetTransitionDuration(base::TimeDelta());
235 SetTransformForScaleAnimation(layer
,
236 above
? LAYER_SCALE_ANIMATION_ABOVE
: LAYER_SCALE_ANIMATION_BELOW
);
238 TransformWindowToBaseState(window
, duration
, observer
);
241 // Starts grayscale/brightness animation for |window| over |duration|. Target
242 // value for both grayscale and brightness are specified by |target|.
243 void StartGrayscaleBrightnessAnimationForWindow(
244 aura::Window
* window
,
246 base::TimeDelta duration
,
247 gfx::Tween::Type tween_type
,
248 ui::LayerAnimationObserver
* observer
) {
249 ui::LayerAnimator
* animator
= window
->layer()->GetAnimator();
251 scoped_ptr
<ui::LayerAnimationSequence
> brightness_sequence(
252 new ui::LayerAnimationSequence());
253 scoped_ptr
<ui::LayerAnimationSequence
> grayscale_sequence(
254 new ui::LayerAnimationSequence());
256 scoped_ptr
<ui::LayerAnimationElement
> brightness_element(
257 ui::LayerAnimationElement::CreateBrightnessElement(
259 brightness_element
->set_tween_type(tween_type
);
260 brightness_sequence
->AddElement(brightness_element
.release());
262 scoped_ptr
<ui::LayerAnimationElement
> grayscale_element(
263 ui::LayerAnimationElement::CreateGrayscaleElement(
265 grayscale_element
->set_tween_type(tween_type
);
266 grayscale_sequence
->AddElement(grayscale_element
.release());
268 std::vector
<ui::LayerAnimationSequence
*> animations
;
269 animations
.push_back(brightness_sequence
.release());
270 animations
.push_back(grayscale_sequence
.release());
273 animations
[0]->AddObserver(observer
);
275 animator
->set_preemption_strategy(
276 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
278 animator
->StartTogether(animations
);
281 // Animation observer that will drop animated foreground once animation is
282 // finished. It is used in when undoing shutdown animation.
283 class CallbackAnimationObserver
: public ui::LayerAnimationObserver
{
285 explicit CallbackAnimationObserver(base::Callback
<void(void)> &callback
)
286 : callback_(callback
) {
288 virtual ~CallbackAnimationObserver() {
292 // Overridden from ui::LayerAnimationObserver:
293 virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence
* seq
)
295 // Drop foreground once animation is over.
300 virtual void OnLayerAnimationAborted(ui::LayerAnimationSequence
* seq
)
302 // Drop foreground once animation is over.
307 virtual void OnLayerAnimationScheduled(ui::LayerAnimationSequence
* seq
)
310 base::Callback
<void(void)> callback_
;
312 DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver
);
316 bool IsLayerAnimated(ui::Layer
* layer
,
317 SessionStateAnimator::AnimationType type
) {
319 case SessionStateAnimator::ANIMATION_PARTIAL_CLOSE
:
320 if (layer
->GetTargetTransform() != GetSlowCloseTransform())
323 case SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE
:
324 if (layer
->GetTargetTransform() != gfx::Transform())
327 case SessionStateAnimator::ANIMATION_FULL_CLOSE
:
328 if (layer
->GetTargetTransform() != GetFastCloseTransform() ||
329 layer
->GetTargetOpacity() > 0.0001)
332 case SessionStateAnimator::ANIMATION_FADE_IN
:
333 if (layer
->GetTargetOpacity() < 0.9999)
336 case SessionStateAnimator::ANIMATION_FADE_OUT
:
337 if (layer
->GetTargetOpacity() > 0.0001)
340 case SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY
:
341 if (layer
->GetTargetOpacity() > 0.0001)
344 case SessionStateAnimator::ANIMATION_RESTORE
:
345 if (layer
->opacity() < 0.9999 || layer
->transform() != gfx::Transform())
348 case SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS
:
349 if ((layer
->GetTargetBrightness() < 0.9999) ||
350 (layer
->GetTargetGrayscale() < 0.9999))
353 case SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS
:
354 if ((layer
->GetTargetBrightness() > 0.0001) ||
355 (layer
->GetTargetGrayscale() > 0.0001))
358 case SessionStateAnimator::ANIMATION_DROP
:
359 case SessionStateAnimator::ANIMATION_UNDO_LIFT
:
360 //ToDo(antim) : check other effects
361 if (layer
->GetTargetOpacity() < 0.9999)
364 //ToDo(antim) : check other effects
365 case SessionStateAnimator::ANIMATION_LIFT
:
366 if (layer
->GetTargetOpacity() > 0.0001)
369 case SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN
:
370 //ToDo(antim) : check other effects
371 if (layer
->GetTargetOpacity() < 0.9999)
374 //ToDo(antim) : check other effects
375 case SessionStateAnimator::ANIMATION_LOWER_BELOW_SCREEN
:
376 if (layer
->GetTargetOpacity() > 0.0001)
380 NOTREACHED() << "Unhandled animation type " << type
;
388 bool SessionStateAnimator::TestApi::ContainersAreAnimated(
389 int container_mask
, AnimationType type
) const {
390 aura::Window::Windows containers
;
391 animator_
->GetContainers(container_mask
, &containers
);
392 for (aura::Window::Windows::const_iterator it
= containers
.begin();
393 it
!= containers
.end(); ++it
) {
394 aura::Window
* window
= *it
;
395 ui::Layer
* layer
= window
->layer();
396 if (!IsLayerAnimated(layer
, type
))
402 bool SessionStateAnimator::TestApi::RootWindowIsAnimated(AnimationType type
)
404 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
405 ui::Layer
* layer
= root_window
->layer();
406 return IsLayerAnimated(layer
, type
);
409 const int SessionStateAnimator::kAllLockScreenContainersMask
=
410 SessionStateAnimator::LOCK_SCREEN_BACKGROUND
|
411 SessionStateAnimator::LOCK_SCREEN_CONTAINERS
|
412 SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS
;
414 const int SessionStateAnimator::kAllContainersMask
=
415 SessionStateAnimator::kAllLockScreenContainersMask
|
416 SessionStateAnimator::DESKTOP_BACKGROUND
|
417 SessionStateAnimator::LAUNCHER
|
418 SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS
;
420 SessionStateAnimator::SessionStateAnimator() {
423 SessionStateAnimator::~SessionStateAnimator() {
426 base::TimeDelta
SessionStateAnimator::GetDuration(AnimationSpeed speed
) {
428 case ANIMATION_SPEED_IMMEDIATE
:
429 return base::TimeDelta();
430 case ANIMATION_SPEED_UNDOABLE
:
431 return base::TimeDelta::FromMilliseconds(400);
432 case ANIMATION_SPEED_REVERT
:
433 return base::TimeDelta::FromMilliseconds(150);
434 case ANIMATION_SPEED_FAST
:
435 return base::TimeDelta::FromMilliseconds(150);
436 case ANIMATION_SPEED_SHOW_LOCK_SCREEN
:
437 return base::TimeDelta::FromMilliseconds(200);
438 case ANIMATION_SPEED_MOVE_WINDOWS
:
439 return base::TimeDelta::FromMilliseconds(350);
440 case ANIMATION_SPEED_UNDO_MOVE_WINDOWS
:
441 return base::TimeDelta::FromMilliseconds(350);
442 case ANIMATION_SPEED_SHUTDOWN
:
443 return base::TimeDelta::FromMilliseconds(1000);
444 case ANIMATION_SPEED_REVERT_SHUTDOWN
:
445 return base::TimeDelta::FromMilliseconds(500);
447 // Satisfy compilers that do not understand that we will return from switch
449 DCHECK(false) << "Unhandled animation speed " << speed
;
450 return base::TimeDelta();
453 // Fills |containers| with the containers described by |container_mask|.
454 void SessionStateAnimator::GetContainers(int container_mask
,
455 aura::Window::Windows
* containers
) {
456 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
459 if (container_mask
& DESKTOP_BACKGROUND
) {
460 containers
->push_back(Shell::GetContainer(
461 root_window
, kShellWindowId_DesktopBackgroundContainer
));
463 if (container_mask
& LAUNCHER
) {
464 containers
->push_back(
465 Shell::GetContainer(root_window
, kShellWindowId_ShelfContainer
));
467 if (container_mask
& NON_LOCK_SCREEN_CONTAINERS
) {
468 // TODO(antrim): Figure out a way to eliminate a need to exclude launcher
470 aura::Window
* non_lock_screen_containers
= Shell::GetContainer(
471 root_window
, kShellWindowId_NonLockScreenContainersContainer
);
472 aura::Window::Windows children
= non_lock_screen_containers
->children();
474 for (aura::Window::Windows::const_iterator it
= children
.begin();
475 it
!= children
.end(); ++it
) {
476 aura::Window
* window
= *it
;
477 if (window
->id() == kShellWindowId_ShelfContainer
)
479 containers
->push_back(window
);
482 if (container_mask
& LOCK_SCREEN_BACKGROUND
) {
483 containers
->push_back(Shell::GetContainer(
484 root_window
, kShellWindowId_LockScreenBackgroundContainer
));
486 if (container_mask
& LOCK_SCREEN_CONTAINERS
) {
487 containers
->push_back(Shell::GetContainer(
488 root_window
, kShellWindowId_LockScreenContainersContainer
));
490 if (container_mask
& LOCK_SCREEN_RELATED_CONTAINERS
) {
491 containers
->push_back(Shell::GetContainer(
492 root_window
, kShellWindowId_LockScreenRelatedContainersContainer
));
496 void SessionStateAnimator::StartAnimation(int container_mask
,
498 AnimationSpeed speed
) {
499 aura::Window::Windows containers
;
500 GetContainers(container_mask
, &containers
);
501 for (aura::Window::Windows::const_iterator it
= containers
.begin();
502 it
!= containers
.end(); ++it
) {
503 RunAnimationForWindow(*it
, type
, speed
, NULL
);
507 void SessionStateAnimator::StartAnimationWithCallback(
510 AnimationSpeed speed
,
511 base::Callback
<void(void)>& callback
) {
512 aura::Window::Windows containers
;
513 GetContainers(container_mask
, &containers
);
514 for (aura::Window::Windows::const_iterator it
= containers
.begin();
515 it
!= containers
.end(); ++it
) {
516 ui::LayerAnimationObserver
* observer
=
517 new CallbackAnimationObserver(callback
);
518 RunAnimationForWindow(*it
, type
, speed
, observer
);
522 void SessionStateAnimator::StartAnimationWithObserver(
525 AnimationSpeed speed
,
526 ui::LayerAnimationObserver
* observer
) {
527 aura::Window::Windows containers
;
528 GetContainers(container_mask
, &containers
);
529 for (aura::Window::Windows::const_iterator it
= containers
.begin();
530 it
!= containers
.end(); ++it
) {
531 RunAnimationForWindow(*it
, type
, speed
, observer
);
535 void SessionStateAnimator::StartGlobalAnimation(AnimationType type
,
536 AnimationSpeed speed
) {
537 aura::Window
* root_window
= Shell::GetPrimaryRootWindow();
538 RunAnimationForWindow(root_window
, type
, speed
, NULL
);
541 void SessionStateAnimator::RunAnimationForWindow(
542 aura::Window
* window
,
544 AnimationSpeed speed
,
545 ui::LayerAnimationObserver
* observer
) {
546 base::TimeDelta duration
= GetDuration(speed
);
549 case ANIMATION_PARTIAL_CLOSE
:
550 StartSlowCloseAnimationForWindow(window
, duration
, observer
);
552 case ANIMATION_UNDO_PARTIAL_CLOSE
:
553 StartUndoSlowCloseAnimationForWindow(window
, duration
, observer
);
555 case ANIMATION_FULL_CLOSE
:
556 StartFastCloseAnimationForWindow(window
, duration
, observer
);
558 case ANIMATION_FADE_IN
:
559 StartOpacityAnimationForWindow(window
, 1.0, duration
, observer
);
561 case ANIMATION_FADE_OUT
:
562 StartOpacityAnimationForWindow(window
, 0.0, duration
, observer
);
564 case ANIMATION_HIDE_IMMEDIATELY
:
565 DCHECK_EQ(speed
, ANIMATION_SPEED_IMMEDIATE
);
566 HideWindowImmediately(window
, observer
);
568 case ANIMATION_RESTORE
:
569 DCHECK_EQ(speed
, ANIMATION_SPEED_IMMEDIATE
);
570 RestoreWindow(window
, observer
);
573 HideWindow(window
, duration
, true, observer
);
576 ShowWindow(window
, duration
, true, observer
);
578 case ANIMATION_UNDO_LIFT
:
579 TransformWindowToBaseState(window
, duration
, observer
);
581 case ANIMATION_RAISE_TO_SCREEN
:
582 ShowWindow(window
, duration
, false, observer
);
584 case ANIMATION_LOWER_BELOW_SCREEN
:
585 HideWindow(window
, duration
, false, observer
);
587 case ANIMATION_PARTIAL_FADE_IN
:
588 StartPartialFadeAnimation(
589 window
, kPartialFadeRatio
, duration
, observer
);
591 case ANIMATION_UNDO_PARTIAL_FADE_IN
:
592 StartPartialFadeAnimation(window
, 0.0, duration
, observer
);
594 case ANIMATION_FULL_FADE_IN
:
595 StartPartialFadeAnimation(window
, 1.0, duration
, observer
);
597 case ANIMATION_GRAYSCALE_BRIGHTNESS
:
598 StartGrayscaleBrightnessAnimationForWindow(
599 window
, 1.0, duration
, gfx::Tween::EASE_IN
, observer
);
601 case ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS
:
602 StartGrayscaleBrightnessAnimationForWindow(
603 window
, 0.0, duration
, gfx::Tween::EASE_IN_OUT
, observer
);