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 "ash/wm/session_state_animator_impl.h"
6
7#include <vector>
8
9#include "ash/shell.h"
10#include "ash/shell_window_ids.h"
11#include "ash/wm/window_animations.h"
12#include "ui/aura/client/aura_constants.h"
13#include "ui/aura/window_event_dispatcher.h"
14#include "ui/compositor/layer_animation_observer.h"
15#include "ui/compositor/layer_animation_sequence.h"
16#include "ui/compositor/scoped_layer_animation_settings.h"
17#include "ui/views/widget/widget.h"
18
19namespace ash {
20namespace {
21
22// Slightly-smaller size that we scale the screen down to for the pre-lock and
23// pre-shutdown states.
24const float kSlowCloseSizeRatio = 0.95f;
25
26// Maximum opacity of white layer when animating pre-shutdown state.
27const float kPartialFadeRatio = 0.3f;
28
29// Minimum size. Not zero as it causes numeric issues.
30const float kMinimumScale = 1e-4f;
31
32// Returns the primary root window's container.
33aura::Window* GetBackground() {
34  aura::Window* root_window = Shell::GetPrimaryRootWindow();
35  return Shell::GetContainer(root_window,
36                             kShellWindowId_DesktopBackgroundContainer);
37}
38
39// Returns the transform that should be applied to containers for the slow-close
40// animation.
41gfx::Transform GetSlowCloseTransform() {
42  gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size();
43  gfx::Transform transform;
44  transform.Translate(
45      floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.width() + 0.5),
46      floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.height() + 0.5));
47  transform.Scale(kSlowCloseSizeRatio, kSlowCloseSizeRatio);
48  return transform;
49}
50
51// Returns the transform that should be applied to containers for the fast-close
52// animation.
53gfx::Transform GetFastCloseTransform() {
54  gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size();
55  gfx::Transform transform;
56
57  transform.Translate(floor(0.5 * root_size.width() + 0.5),
58                      floor(0.5 * root_size.height() + 0.5));
59  transform.Scale(kMinimumScale, kMinimumScale);
60  return transform;
61}
62
63// Slowly shrinks |window| to a slightly-smaller size.
64void StartSlowCloseAnimationForWindow(aura::Window* window,
65                                      base::TimeDelta duration,
66                                      ui::LayerAnimationObserver* observer) {
67  ui::LayerAnimator* animator = window->layer()->GetAnimator();
68  animator->set_preemption_strategy(
69      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
70  ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
71      ui::LayerAnimationElement::CreateTransformElement(
72          GetSlowCloseTransform(),
73          duration));
74  if (observer)
75    sequence->AddObserver(observer);
76  animator->StartAnimation(sequence);
77}
78
79// Quickly undoes the effects of the slow-close animation on |window|.
80void StartUndoSlowCloseAnimationForWindow(
81    aura::Window* window,
82    base::TimeDelta duration,
83    ui::LayerAnimationObserver* observer) {
84  ui::LayerAnimator* animator = window->layer()->GetAnimator();
85  animator->set_preemption_strategy(
86      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
87  ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
88      ui::LayerAnimationElement::CreateTransformElement(
89          gfx::Transform(),
90          duration));
91  if (observer)
92    sequence->AddObserver(observer);
93  animator->StartAnimation(sequence);
94}
95
96// Quickly shrinks |window| down to a point in the center of the screen and
97// fades it out to 0 opacity.
98void StartFastCloseAnimationForWindow(aura::Window* window,
99                                      base::TimeDelta duration,
100                                      ui::LayerAnimationObserver* observer) {
101  ui::LayerAnimator* animator = window->layer()->GetAnimator();
102  animator->set_preemption_strategy(
103      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
104  animator->StartAnimation(
105      new ui::LayerAnimationSequence(
106          ui::LayerAnimationElement::CreateTransformElement(
107              GetFastCloseTransform(), duration)));
108  ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
109      ui::LayerAnimationElement::CreateOpacityElement(0.0, duration));
110  if (observer)
111    sequence->AddObserver(observer);
112  animator->StartAnimation(sequence);
113}
114
115// Fades |window| to |target_opacity| over |duration|.
116void StartPartialFadeAnimation(aura::Window* window,
117                               float target_opacity,
118                               base::TimeDelta duration,
119                               ui::LayerAnimationObserver* observer) {
120  ui::LayerAnimator* animator = window->layer()->GetAnimator();
121  animator->set_preemption_strategy(
122      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
123  ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
124      ui::LayerAnimationElement::CreateOpacityElement(
125          target_opacity, duration));
126  if (observer)
127    sequence->AddObserver(observer);
128  animator->StartAnimation(sequence);
129}
130
131// Fades |window| to |opacity| over |duration|.
132void StartOpacityAnimationForWindow(aura::Window* window,
133                                    float opacity,
134                                    base::TimeDelta duration,
135                                    ui::LayerAnimationObserver* observer) {
136  ui::LayerAnimator* animator = window->layer()->GetAnimator();
137  animator->set_preemption_strategy(
138      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
139  ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
140      ui::LayerAnimationElement::CreateOpacityElement(opacity, duration));
141  if (observer)
142    sequence->AddObserver(observer);
143  animator->StartAnimation(sequence);
144}
145
146// Makes |window| fully transparent instantaneously.
147void HideWindowImmediately(aura::Window* window,
148                           ui::LayerAnimationObserver* observer) {
149  window->layer()->SetOpacity(0.0);
150  if (observer)
151    observer->OnLayerAnimationEnded(NULL);
152}
153
154// Restores |window| to its original position and scale and full opacity
155// instantaneously.
156void RestoreWindow(aura::Window* window, ui::LayerAnimationObserver* observer) {
157  window->layer()->SetTransform(gfx::Transform());
158  window->layer()->SetOpacity(1.0);
159  if (observer)
160    observer->OnLayerAnimationEnded(NULL);
161}
162
163void HideWindow(aura::Window* window,
164                base::TimeDelta duration,
165                bool above,
166                ui::LayerAnimationObserver* observer) {
167  ui::Layer* layer = window->layer();
168  ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
169
170  settings.SetPreemptionStrategy(
171      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
172  settings.SetTransitionDuration(duration);
173
174  settings.SetTweenType(gfx::Tween::EASE_OUT);
175  SetTransformForScaleAnimation(layer,
176      above ? LAYER_SCALE_ANIMATION_ABOVE : LAYER_SCALE_ANIMATION_BELOW);
177
178  settings.SetTweenType(gfx::Tween::EASE_IN_OUT);
179  layer->SetOpacity(0.0f);
180
181  // After the animation completes snap the transform back to the identity,
182  // otherwise any one that asks for screen bounds gets a slightly scaled
183  // version.
184  settings.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION);
185  settings.SetTransitionDuration(base::TimeDelta());
186  layer->SetTransform(gfx::Transform());
187
188  // A bit of a dirty trick: we need to catch the end of the animation we don't
189  // control. So we use two facts we know: which animator will be used and the
190  // target opacity to add "Do nothing" animation sequence.
191  // Unfortunately, we can not just use empty LayerAnimationSequence, because
192  // it does not call NotifyEnded().
193  if (observer) {
194    ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
195        ui::LayerAnimationElement::CreateOpacityElement(
196            0.0, base::TimeDelta()));
197      sequence->AddObserver(observer);
198    layer->GetAnimator()->ScheduleAnimation(sequence);
199  }
200}
201
202// Animates |window| to identity transform and full opacity over |duration|.
203void TransformWindowToBaseState(aura::Window* window,
204                                base::TimeDelta duration,
205                                ui::LayerAnimationObserver* observer) {
206  ui::Layer* layer = window->layer();
207  ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
208
209  // Animate to target values.
210  settings.SetPreemptionStrategy(
211      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
212  settings.SetTransitionDuration(duration);
213
214  settings.SetTweenType(gfx::Tween::EASE_OUT);
215  layer->SetTransform(gfx::Transform());
216
217  settings.SetTweenType(gfx::Tween::EASE_IN_OUT);
218  layer->SetOpacity(1.0f);
219
220  // A bit of a dirty trick: we need to catch the end of the animation we don't
221  // control. So we use two facts we know: which animator will be used and the
222  // target opacity to add "Do nothing" animation sequence.
223  // Unfortunately, we can not just use empty LayerAnimationSequence, because
224  // it does not call NotifyEnded().
225  if (observer) {
226    ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
227        ui::LayerAnimationElement::CreateOpacityElement(
228            1.0, base::TimeDelta()));
229    sequence->AddObserver(observer);
230    layer->GetAnimator()->ScheduleAnimation(sequence);
231  }
232}
233
234void ShowWindow(aura::Window* window,
235                base::TimeDelta duration,
236                bool above,
237                ui::LayerAnimationObserver* observer) {
238  ui::Layer* layer = window->layer();
239  ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
240
241  // Set initial state of animation
242  settings.SetPreemptionStrategy(
243      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
244  settings.SetTransitionDuration(base::TimeDelta());
245  SetTransformForScaleAnimation(layer,
246      above ? LAYER_SCALE_ANIMATION_ABOVE : LAYER_SCALE_ANIMATION_BELOW);
247
248  TransformWindowToBaseState(window, duration, observer);
249}
250
251// Starts grayscale/brightness animation for |window| over |duration|. Target
252// value for both grayscale and brightness are specified by |target|.
253void StartGrayscaleBrightnessAnimationForWindow(
254    aura::Window* window,
255    float target,
256    base::TimeDelta duration,
257    gfx::Tween::Type tween_type,
258    ui::LayerAnimationObserver* observer) {
259  ui::LayerAnimator* animator = window->layer()->GetAnimator();
260
261  scoped_ptr<ui::LayerAnimationSequence> brightness_sequence(
262      new ui::LayerAnimationSequence());
263  scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence(
264      new ui::LayerAnimationSequence());
265
266  scoped_ptr<ui::LayerAnimationElement> brightness_element(
267      ui::LayerAnimationElement::CreateBrightnessElement(
268          target, duration));
269  brightness_element->set_tween_type(tween_type);
270  brightness_sequence->AddElement(brightness_element.release());
271
272  scoped_ptr<ui::LayerAnimationElement> grayscale_element(
273      ui::LayerAnimationElement::CreateGrayscaleElement(
274          target, duration));
275  grayscale_element->set_tween_type(tween_type);
276  grayscale_sequence->AddElement(grayscale_element.release());
277
278  std::vector<ui::LayerAnimationSequence*> animations;
279  animations.push_back(brightness_sequence.release());
280  animations.push_back(grayscale_sequence.release());
281
282  if (observer)
283    animations[0]->AddObserver(observer);
284
285  animator->set_preemption_strategy(
286      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
287
288  animator->StartTogether(animations);
289}
290
291// Animation observer that will drop animated foreground once animation is
292// finished. It is used in when undoing shutdown animation.
293class CallbackAnimationObserver : public ui::LayerAnimationObserver {
294 public:
295  explicit CallbackAnimationObserver(base::Closure callback)
296      : callback_(callback) {
297  }
298  virtual ~CallbackAnimationObserver() {
299  }
300
301 private:
302  // Overridden from ui::LayerAnimationObserver:
303  virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* seq)
304      OVERRIDE {
305    // Drop foreground once animation is over.
306    callback_.Run();
307    delete this;
308  }
309
310  virtual void OnLayerAnimationAborted(ui::LayerAnimationSequence* seq)
311      OVERRIDE {
312    // Drop foreground once animation is over.
313    callback_.Run();
314    delete this;
315  }
316
317  virtual void OnLayerAnimationScheduled(ui::LayerAnimationSequence* seq)
318      OVERRIDE {}
319
320  base::Closure callback_;
321
322  DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver);
323};
324
325
326bool IsLayerAnimated(ui::Layer* layer,
327                     SessionStateAnimator::AnimationType type) {
328  switch (type) {
329    case SessionStateAnimator::ANIMATION_PARTIAL_CLOSE:
330      if (layer->GetTargetTransform() != GetSlowCloseTransform())
331        return false;
332      break;
333    case SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE:
334      if (layer->GetTargetTransform() != gfx::Transform())
335        return false;
336      break;
337    case SessionStateAnimator::ANIMATION_FULL_CLOSE:
338      if (layer->GetTargetTransform() != GetFastCloseTransform() ||
339          layer->GetTargetOpacity() > 0.0001)
340        return false;
341      break;
342    case SessionStateAnimator::ANIMATION_FADE_IN:
343      if (layer->GetTargetOpacity() < 0.9999)
344        return false;
345      break;
346    case SessionStateAnimator::ANIMATION_FADE_OUT:
347      if (layer->GetTargetOpacity() > 0.0001)
348        return false;
349      break;
350    case SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY:
351      if (layer->GetTargetOpacity() > 0.0001)
352        return false;
353      break;
354    case SessionStateAnimator::ANIMATION_RESTORE:
355      if (layer->opacity() < 0.9999 || layer->transform() != gfx::Transform())
356        return false;
357      break;
358    case SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS:
359      if ((layer->GetTargetBrightness() < 0.9999) ||
360          (layer->GetTargetGrayscale() < 0.9999))
361        return false;
362      break;
363    case SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS:
364      if ((layer->GetTargetBrightness() > 0.0001) ||
365          (layer->GetTargetGrayscale() > 0.0001))
366        return false;
367      break;
368    case SessionStateAnimator::ANIMATION_DROP:
369    case SessionStateAnimator::ANIMATION_UNDO_LIFT:
370      //ToDo(antim) : check other effects
371      if (layer->GetTargetOpacity() < 0.9999)
372        return false;
373      break;
374      //ToDo(antim) : check other effects
375    case SessionStateAnimator::ANIMATION_LIFT:
376      if (layer->GetTargetOpacity() > 0.0001)
377        return false;
378      break;
379    case SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN:
380      //ToDo(antim) : check other effects
381      if (layer->GetTargetOpacity() < 0.9999)
382        return false;
383      break;
384      //ToDo(antim) : check other effects
385    case SessionStateAnimator::ANIMATION_LOWER_BELOW_SCREEN:
386      if (layer->GetTargetOpacity() > 0.0001)
387        return false;
388      break;
389    default:
390      NOTREACHED() << "Unhandled animation type " << type;
391      return false;
392  }
393  return true;
394}
395
396}  // namespace
397
398// This observer is intended to use in cases when some action has to be taken
399// once some animation successfully completes (i.e. it was not aborted).
400// Observer will count a number of sequences it is attached to, and a number of
401// finished sequences (either Ended or Aborted). Once these two numbers are
402// equal, observer will delete itself, calling callback passed to constructor if
403// there were no aborted animations.
404// This way it can be either used to wait for some animation to be finished in
405// multiple layers, to wait once a sequence of animations is finished in one
406// layer or the mixture of both.
407class SessionStateAnimatorImpl::AnimationSequence
408  : public SessionStateAnimator::AnimationSequence,
409    public ui::LayerAnimationObserver {
410 public:
411  explicit AnimationSequence(
412      SessionStateAnimatorImpl* animator,
413      base::Closure callback)
414      : SessionStateAnimator::AnimationSequence(callback),
415        animator_(animator),
416        sequences_attached_(0),
417        sequences_completed_(0) {
418  }
419
420  // SessionStateAnimator::AnimationSequence:
421  virtual void StartAnimation(
422      int container_mask,
423      SessionStateAnimator::AnimationType type,
424      SessionStateAnimator::AnimationSpeed speed) OVERRIDE {
425    animator_->StartAnimationInSequence(container_mask, type, speed, this);
426  }
427
428 private:
429  virtual ~AnimationSequence() {}
430
431  // ui::LayerAnimationObserver:
432  virtual void OnLayerAnimationEnded(
433      ui::LayerAnimationSequence* sequence) OVERRIDE {
434    sequences_completed_++;
435    if (sequences_completed_ == sequences_attached_)
436      OnAnimationCompleted();
437  }
438
439  virtual void OnLayerAnimationAborted(
440      ui::LayerAnimationSequence* sequence) OVERRIDE {
441    sequences_completed_++;
442    if (sequences_completed_ == sequences_attached_)
443      OnAnimationAborted();
444  }
445
446  virtual void OnLayerAnimationScheduled(
447      ui::LayerAnimationSequence* sequence) OVERRIDE {}
448
449  virtual void OnAttachedToSequence(
450      ui::LayerAnimationSequence* sequence) OVERRIDE {
451    LayerAnimationObserver::OnAttachedToSequence(sequence);
452    sequences_attached_++;
453  }
454
455  SessionStateAnimatorImpl* animator_;  // not owned
456
457  // Number of sequences this observer was attached to.
458  int sequences_attached_;
459
460  // Number of sequences either ended or aborted.
461  int sequences_completed_;
462
463  DISALLOW_COPY_AND_ASSIGN(AnimationSequence);
464};
465
466bool SessionStateAnimatorImpl::TestApi::ContainersAreAnimated(
467    int container_mask, AnimationType type) const {
468  aura::Window::Windows containers;
469  animator_->GetContainers(container_mask, &containers);
470  for (aura::Window::Windows::const_iterator it = containers.begin();
471       it != containers.end(); ++it) {
472    aura::Window* window = *it;
473    ui::Layer* layer = window->layer();
474    if (!IsLayerAnimated(layer, type))
475      return false;
476  }
477  return true;
478}
479
480bool SessionStateAnimatorImpl::TestApi::RootWindowIsAnimated(AnimationType type)
481    const {
482  aura::Window* root_window = Shell::GetPrimaryRootWindow();
483  ui::Layer* layer = root_window->layer();
484  return IsLayerAnimated(layer, type);
485}
486
487SessionStateAnimatorImpl::SessionStateAnimatorImpl() {
488}
489
490SessionStateAnimatorImpl::~SessionStateAnimatorImpl() {
491}
492
493// Fills |containers| with the containers described by |container_mask|.
494void SessionStateAnimatorImpl::GetContainers(int container_mask,
495    aura::Window::Windows* containers) {
496  aura::Window* root_window = Shell::GetPrimaryRootWindow();
497  containers->clear();
498
499  if (container_mask & ROOT_CONTAINER) {
500    containers->push_back(Shell::GetPrimaryRootWindow());
501  }
502
503  if (container_mask & DESKTOP_BACKGROUND) {
504    containers->push_back(Shell::GetContainer(
505        root_window, kShellWindowId_DesktopBackgroundContainer));
506  }
507  if (container_mask & LAUNCHER) {
508    containers->push_back(
509        Shell::GetContainer(root_window, kShellWindowId_ShelfContainer));
510  }
511  if (container_mask & NON_LOCK_SCREEN_CONTAINERS) {
512    // TODO(antrim): Figure out a way to eliminate a need to exclude launcher
513    // in such way.
514    aura::Window* non_lock_screen_containers = Shell::GetContainer(
515        root_window, kShellWindowId_NonLockScreenContainersContainer);
516    aura::Window::Windows children = non_lock_screen_containers->children();
517
518    for (aura::Window::Windows::const_iterator it = children.begin();
519         it != children.end(); ++it) {
520      aura::Window* window = *it;
521      if (window->id() == kShellWindowId_ShelfContainer)
522        continue;
523      containers->push_back(window);
524    }
525  }
526  if (container_mask & LOCK_SCREEN_BACKGROUND) {
527    containers->push_back(Shell::GetContainer(
528        root_window, kShellWindowId_LockScreenBackgroundContainer));
529  }
530  if (container_mask & LOCK_SCREEN_CONTAINERS) {
531    containers->push_back(Shell::GetContainer(
532        root_window, kShellWindowId_LockScreenContainersContainer));
533  }
534  if (container_mask & LOCK_SCREEN_RELATED_CONTAINERS) {
535    containers->push_back(Shell::GetContainer(
536        root_window, kShellWindowId_LockScreenRelatedContainersContainer));
537  }
538}
539
540void SessionStateAnimatorImpl::StartAnimation(int container_mask,
541                                              AnimationType type,
542                                              AnimationSpeed speed) {
543  aura::Window::Windows containers;
544  GetContainers(container_mask, &containers);
545  for (aura::Window::Windows::const_iterator it = containers.begin();
546       it != containers.end(); ++it) {
547    RunAnimationForWindow(*it, type, speed, NULL);
548  }
549}
550
551void SessionStateAnimatorImpl::StartAnimationWithCallback(
552    int container_mask,
553    AnimationType type,
554    AnimationSpeed speed,
555    base::Closure callback) {
556  aura::Window::Windows containers;
557  GetContainers(container_mask, &containers);
558  for (aura::Window::Windows::const_iterator it = containers.begin();
559       it != containers.end(); ++it) {
560    ui::LayerAnimationObserver* observer =
561        new CallbackAnimationObserver(callback);
562    RunAnimationForWindow(*it, type, speed, observer);
563  }
564}
565
566SessionStateAnimator::AnimationSequence*
567    SessionStateAnimatorImpl::BeginAnimationSequence(base::Closure callback) {
568  return new AnimationSequence(this, callback);
569}
570
571bool SessionStateAnimatorImpl::IsBackgroundHidden() const {
572  return !GetBackground()->IsVisible();
573}
574
575void SessionStateAnimatorImpl::ShowBackground() {
576  ui::ScopedLayerAnimationSettings settings(
577      GetBackground()->layer()->GetAnimator());
578  settings.SetTransitionDuration(base::TimeDelta());
579  GetBackground()->Show();
580}
581
582void SessionStateAnimatorImpl::HideBackground() {
583  ui::ScopedLayerAnimationSettings settings(
584      GetBackground()->layer()->GetAnimator());
585  settings.SetTransitionDuration(base::TimeDelta());
586  GetBackground()->Hide();
587}
588
589void SessionStateAnimatorImpl::StartAnimationInSequence(
590    int container_mask,
591    AnimationType type,
592    AnimationSpeed speed,
593    AnimationSequence* observer) {
594  aura::Window::Windows containers;
595  GetContainers(container_mask, &containers);
596  for (aura::Window::Windows::const_iterator it = containers.begin();
597       it != containers.end(); ++it) {
598    RunAnimationForWindow(*it, type, speed, observer);
599  }
600}
601
602void SessionStateAnimatorImpl::RunAnimationForWindow(
603    aura::Window* window,
604    AnimationType type,
605    AnimationSpeed speed,
606    ui::LayerAnimationObserver* observer) {
607  base::TimeDelta duration = GetDuration(speed);
608
609  switch (type) {
610    case ANIMATION_PARTIAL_CLOSE:
611      StartSlowCloseAnimationForWindow(window, duration, observer);
612      break;
613    case ANIMATION_UNDO_PARTIAL_CLOSE:
614      StartUndoSlowCloseAnimationForWindow(window, duration, observer);
615      break;
616    case ANIMATION_FULL_CLOSE:
617      StartFastCloseAnimationForWindow(window, duration, observer);
618      break;
619    case ANIMATION_FADE_IN:
620      StartOpacityAnimationForWindow(window, 1.0, duration, observer);
621      break;
622    case ANIMATION_FADE_OUT:
623      StartOpacityAnimationForWindow(window, 0.0, duration, observer);
624      break;
625    case ANIMATION_HIDE_IMMEDIATELY:
626      DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE);
627      HideWindowImmediately(window, observer);
628      break;
629    case ANIMATION_RESTORE:
630      DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE);
631      RestoreWindow(window, observer);
632      break;
633    case ANIMATION_LIFT:
634      HideWindow(window, duration, true, observer);
635      break;
636    case ANIMATION_DROP:
637      ShowWindow(window, duration, true, observer);
638      break;
639    case ANIMATION_UNDO_LIFT:
640      TransformWindowToBaseState(window, duration, observer);
641      break;
642    case ANIMATION_RAISE_TO_SCREEN:
643      ShowWindow(window, duration, false, observer);
644      break;
645    case ANIMATION_LOWER_BELOW_SCREEN:
646      HideWindow(window, duration, false, observer);
647      break;
648    case ANIMATION_PARTIAL_FADE_IN:
649      StartPartialFadeAnimation(
650          window, kPartialFadeRatio, duration, observer);
651      break;
652    case ANIMATION_UNDO_PARTIAL_FADE_IN:
653      StartPartialFadeAnimation(window, 0.0, duration, observer);
654      break;
655    case ANIMATION_FULL_FADE_IN:
656      StartPartialFadeAnimation(window, 1.0, duration, observer);
657      break;
658    case ANIMATION_GRAYSCALE_BRIGHTNESS:
659      StartGrayscaleBrightnessAnimationForWindow(
660          window, 1.0, duration, gfx::Tween::EASE_IN, observer);
661      break;
662    case ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS:
663      StartGrayscaleBrightnessAnimationForWindow(
664          window, 0.0, duration, gfx::Tween::EASE_IN_OUT, observer);
665      break;
666  }
667}
668
669}  // namespace ash
670