Added speed/duration to SessionStateAnimator, fixed call in SystemTrayDelegate
Exposed Grayscale/Brightness animation from WindowAnimations, used it in SessionStateAnimator.

BUG=139461


Review URL: https://chromiumcodereview.appspot.com/11360170

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167357 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ash/wm/session_state_animator.cc b/ash/wm/session_state_animator.cc
index b66384b..82f41f8 100644
--- a/ash/wm/session_state_animator.cc
+++ b/ash/wm/session_state_animator.cc
@@ -6,6 +6,7 @@
 
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
+#include "ash/wm/window_animations.h"
 #include "ash/wm/workspace/workspace_animations.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/root_window.h"
@@ -18,24 +19,6 @@
 
 namespace {
 
-// Amount of time taken to scale the snapshot of the screen down to a
-// slightly-smaller size once the user starts holding the power button.  Used
-// for both the pre-lock and pre-shutdown animations.
-const int kSlowCloseAnimMs = 400;
-
-// Amount of time taken to scale the snapshot of the screen back to its original
-// size when the button is released.
-const int kUndoSlowCloseAnimMs = 100;
-
-// Amount of time taken to scale the snapshot down to a point in the center of
-// the screen once the screen has been locked or we've been notified that the
-// system is shutting down.
-const int kFastCloseAnimMs = 150;
-
-// Amount of time taken to make the lock window fade in when the screen is
-// locked.
-const int kLockFadeInAnimMs = 200;
-
 // Slightly-smaller size that we scale the screen down to for the pre-lock and
 // pre-shutdown states.
 const float kSlowCloseSizeRatio = 0.95f;
@@ -68,6 +51,7 @@
 
 // Slowly shrinks |window| to a slightly-smaller size.
 void StartSlowCloseAnimationForWindow(aura::Window* window,
+                                      base::TimeDelta duration,
                                       ui::LayerAnimationObserver* observer) {
   ui::LayerAnimator* animator = window->layer()->GetAnimator();
   animator->set_preemption_strategy(
@@ -75,7 +59,7 @@
   ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
       ui::LayerAnimationElement::CreateTransformElement(
           GetSlowCloseTransform(),
-          base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs)));
+          duration));
   animator->StartAnimation(sequence);
   if (observer)
     sequence->AddObserver(observer);
@@ -84,6 +68,7 @@
 // Quickly undoes the effects of the slow-close animation on |window|.
 void StartUndoSlowCloseAnimationForWindow(
     aura::Window* window,
+    base::TimeDelta duration,
     ui::LayerAnimationObserver* observer) {
   ui::LayerAnimator* animator = window->layer()->GetAnimator();
   animator->set_preemption_strategy(
@@ -91,7 +76,7 @@
   ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
       ui::LayerAnimationElement::CreateTransformElement(
           gfx::Transform(),
-          base::TimeDelta::FromMilliseconds(kUndoSlowCloseAnimMs)));
+          duration));
   animator->StartAnimation(sequence);
   if (observer)
     sequence->AddObserver(observer);
@@ -100,6 +85,7 @@
 // Quickly shrinks |window| down to a point in the center of the screen and
 // fades it out to 0 opacity.
 void StartFastCloseAnimationForWindow(aura::Window* window,
+                                      base::TimeDelta duration,
                                       ui::LayerAnimationObserver* observer) {
   ui::LayerAnimator* animator = window->layer()->GetAnimator();
   animator->set_preemption_strategy(
@@ -107,41 +93,39 @@
   animator->StartAnimation(
       new ui::LayerAnimationSequence(
           ui::LayerAnimationElement::CreateTransformElement(
-              GetFastCloseTransform(),
-              base::TimeDelta::FromMilliseconds(kFastCloseAnimMs))));
+              GetFastCloseTransform(), duration)));
   ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
-      ui::LayerAnimationElement::CreateOpacityElement(
-         0.0, base::TimeDelta::FromMilliseconds(kFastCloseAnimMs)));
+      ui::LayerAnimationElement::CreateOpacityElement(0.0, duration));
   animator->StartAnimation(sequence);
   if (observer)
     sequence->AddObserver(observer);
 }
 
-// Fades |window| to |target_opacity| over |length| milliseconds.
+// Fades |window| to |target_opacity| over |duration|.
 void StartPartialFadeAnimation(aura::Window* window,
                                float target_opacity,
-                               base::TimeDelta length,
+                               base::TimeDelta duration,
                                ui::LayerAnimationObserver* observer) {
   ui::LayerAnimator* animator = window->layer()->GetAnimator();
   animator->set_preemption_strategy(
       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
   ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
       ui::LayerAnimationElement::CreateOpacityElement(
-          target_opacity, length));
+          target_opacity, duration));
   animator->StartAnimation(sequence);
   if (observer)
     sequence->AddObserver(observer);
 }
 
-// Fades |window| in to full opacity.
+// Fades |window| in to full opacity over |duration|.
 void FadeInWindow(aura::Window* window,
+                  base::TimeDelta duration,
                   ui::LayerAnimationObserver* observer) {
   ui::LayerAnimator* animator = window->layer()->GetAnimator();
   animator->set_preemption_strategy(
       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
   ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence(
-      ui::LayerAnimationElement::CreateOpacityElement(
-          1.0, base::TimeDelta::FromMilliseconds(kLockFadeInAnimMs)));
+      ui::LayerAnimationElement::CreateOpacityElement(1.0, duration));
   animator->StartAnimation(sequence);
   if (observer)
     sequence->AddObserver(observer);
@@ -165,7 +149,7 @@
 }
 
 void HideWindow(aura::Window* window,
-                base::TimeDelta length,
+                base::TimeDelta duration,
                 WorkspaceAnimationDirection direction,
                 ui::LayerAnimationObserver* observer) {
   WorkspaceAnimationDetails details;
@@ -173,7 +157,7 @@
   details.animate = true;
   details.animate_scale = true;
   details.animate_opacity = true;
-  details.duration = length;
+  details.duration = duration;
   HideWorkspace(window, details);
   // A bit of a dirty trick: we need to catch the end of the animation we don't
   // control. So we use two facts we know: which animator will be used and the
@@ -212,6 +196,27 @@
   window->layer()->GetAnimator()->ScheduleAnimation(sequence);
 }
 
+// Starts grayscale/brightness animation for |window| over |duration|. Target
+// value for both grayscale and brightness are specified by |target|.
+void StartGrayscaleBrightnessAnimationForWindow(
+    aura::Window* window,
+    float target,
+    base::TimeDelta duration,
+    ui::LayerAnimationObserver* observer) {
+  ui::LayerAnimator* animator = window->layer()->GetAnimator();
+
+  std::vector<ui::LayerAnimationSequence*> animations =
+      CreateBrightnessGrayscaleAnimationSequence(target, duration);
+
+  if (observer)
+    animations[0]->AddObserver(observer);
+
+  animator->set_preemption_strategy(
+      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+
+  animator->StartTogether(animations);
+}
+
 // Animation observer that will drop animated foreground once animation is
 // finished. It is used in when undoing shutdown animation.
 class CallbackAnimationObserver : public ui::LayerAnimationObserver {
@@ -308,6 +313,31 @@
 SessionStateAnimator::~SessionStateAnimator() {
 }
 
+base::TimeDelta SessionStateAnimator::GetDuration(AnimationSpeed speed) {
+  switch (speed) {
+    case ANIMATION_SPEED_IMMEDIATE:
+      return base::TimeDelta();
+    case ANIMATION_SPEED_UNDOABLE:
+      return base::TimeDelta::FromMilliseconds(400);
+    case ANIMATION_SPEED_REVERT:
+      return base::TimeDelta::FromMilliseconds(100);
+    case ANIMATION_SPEED_FAST:
+      return base::TimeDelta::FromMilliseconds(150);
+    case ANIMATION_SPEED_SHOW_LOCK_SCREEN:
+      return base::TimeDelta::FromMilliseconds(200);
+    case ANIMATION_SPEED_MOVE_WINDOWS:
+      return base::TimeDelta::FromMilliseconds(400);
+    case ANIMATION_SPEED_SHUTDOWN:
+      return base::TimeDelta::FromMilliseconds(1000);
+    case ANIMATION_SPEED_REVERT_SHUTDOWN:
+      return base::TimeDelta::FromMilliseconds(400);
+  }
+  // Satisfy compilers that do not understand that we will return from switch
+  // above anyway.
+  DCHECK(false) << "Unhandled animation speed " << speed;
+  return base::TimeDelta();
+}
+
 // Fills |containers| with the containers described by |container_mask|.
 void SessionStateAnimator::GetContainers(int container_mask,
                                          aura::Window::Windows* containers) {
@@ -363,12 +393,13 @@
 }
 
 void SessionStateAnimator::StartAnimation(int container_mask,
-                                          AnimationType type) {
+                                          AnimationType type,
+                                          AnimationSpeed speed) {
   aura::Window::Windows containers;
   GetContainers(container_mask, &containers);
   for (aura::Window::Windows::const_iterator it = containers.begin();
        it != containers.end(); ++it) {
-    RunAnimationForWindow(*it, type, NULL);
+    RunAnimationForWindow(*it, type, speed, NULL);
   }
 }
 
@@ -376,6 +407,7 @@
 void SessionStateAnimator::StartAnimationWithCallback(
     int container_mask,
     AnimationType type,
+    AnimationSpeed speed,
     base::Callback<void(void)>& callback) {
   aura::Window::Windows containers;
   GetContainers(container_mask, &containers);
@@ -383,74 +415,74 @@
        it != containers.end(); ++it) {
     ui::LayerAnimationObserver* observer =
         new CallbackAnimationObserver(callback);
-    RunAnimationForWindow(*it, type, observer);
+    RunAnimationForWindow(*it, type, speed, observer);
   }
 }
 
+void SessionStateAnimator::StartGlobalAnimation(AnimationType type,
+                                                AnimationSpeed speed) {
+  aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
+  RunAnimationForWindow(root_window, type, speed, NULL);
+}
+
 void SessionStateAnimator::RunAnimationForWindow(
     aura::Window* window,
     AnimationType type,
+    AnimationSpeed speed,
     ui::LayerAnimationObserver* observer) {
+  base::TimeDelta duration = GetDuration(speed);
+
   switch (type) {
     case ANIMATION_PARTIAL_CLOSE:
-      StartSlowCloseAnimationForWindow(window, observer);
+      StartSlowCloseAnimationForWindow(window, duration, observer);
       break;
     case ANIMATION_UNDO_PARTIAL_CLOSE:
-      StartUndoSlowCloseAnimationForWindow(window, observer);
+      StartUndoSlowCloseAnimationForWindow(window, duration, observer);
       break;
     case ANIMATION_FULL_CLOSE:
-      StartFastCloseAnimationForWindow(window, observer);
+      StartFastCloseAnimationForWindow(window, duration, observer);
       break;
     case ANIMATION_FADE_IN:
-      FadeInWindow(window, observer);
+      FadeInWindow(window, duration, observer);
       break;
     case ANIMATION_HIDE_IMMEDIATELY:
+      DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE);
       HideWindowImmediately(window, observer);
       break;
     case ANIMATION_RESTORE:
+      DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE);
       RestoreWindow(window, observer);
       break;
     case ANIMATION_LIFT:
-      HideWindow(window,
-          base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
-          WORKSPACE_ANIMATE_UP,
-          observer);
+      HideWindow(window, duration, WORKSPACE_ANIMATE_UP, observer);
       break;
     case ANIMATION_DROP:
-      ShowWindow(window,
-          base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
-          WORKSPACE_ANIMATE_DOWN,
-          observer);
+      ShowWindow(window, duration, WORKSPACE_ANIMATE_DOWN, observer);
       break;
     case ANIMATION_RAISE_TO_SCREEN:
-      ShowWindow(window,
-          base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
-          WORKSPACE_ANIMATE_UP,
-          observer);
+      ShowWindow(window, duration, WORKSPACE_ANIMATE_UP, observer);
       break;
     case ANIMATION_LOWER_BELOW_SCREEN:
-      HideWindow(window,
-          base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
-          WORKSPACE_ANIMATE_DOWN,
-          observer);
+      HideWindow(window, duration, WORKSPACE_ANIMATE_DOWN, observer);
       break;
     case ANIMATION_PARTIAL_FADE_IN:
-      StartPartialFadeAnimation(window, kPartialFadeRatio,
-          base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
-          observer);
+      StartPartialFadeAnimation(
+          window, kPartialFadeRatio, duration, observer);
       break;
     case ANIMATION_UNDO_PARTIAL_FADE_IN:
-      StartPartialFadeAnimation(window, 0.0,
-          base::TimeDelta::FromMilliseconds(kUndoSlowCloseAnimMs),
-          observer);
+      StartPartialFadeAnimation(window, 0.0, duration, observer);
       break;
     case ANIMATION_FULL_FADE_IN:
-      StartPartialFadeAnimation(window, 1.0,
-          base::TimeDelta::FromMilliseconds(kFastCloseAnimMs),
-          observer);
+      StartPartialFadeAnimation(window, 1.0, duration, observer);
       break;
-    default:
-      NOTREACHED() << "Unhandled animation type " << type;
+    case ANIMATION_GRAYSCALE_BRIGHTNESS:
+      StartGrayscaleBrightnessAnimationForWindow(
+          window, 1.0, duration, observer);
+      break;
+    case ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS:
+      StartGrayscaleBrightnessAnimationForWindow(
+          window, 0.0, duration, observer);
+      break;
   }
 }
 
diff --git a/ash/wm/session_state_animator.h b/ash/wm/session_state_animator.h
index 0c6013e..e46e2dfc 100644
--- a/ash/wm/session_state_animator.h
+++ b/ash/wm/session_state_animator.h
@@ -46,6 +46,32 @@
     ANIMATION_PARTIAL_FADE_IN,
     ANIMATION_UNDO_PARTIAL_FADE_IN,
     ANIMATION_FULL_FADE_IN,
+    ANIMATION_GRAYSCALE_BRIGHTNESS,
+    ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
+  };
+
+  // Constants for determining animation speed.
+  enum AnimationSpeed {
+    // Immediately change state.
+    ANIMATION_SPEED_IMMEDIATE = 0,
+    // Speed for animations associated with user action that can be undone.
+    // Used for pre-lock and pre-shutdown animations.
+    ANIMATION_SPEED_UNDOABLE,
+    // Speed for animation that reverts undoable action. Used for aborting
+    // pre-lock and pre-shutdown animations.
+    ANIMATION_SPEED_REVERT,
+    // Speed for user action that can not be undone, Used for lock and shutdown
+    // animations requested via menus/shortcuts and for animating remaining
+    // parts of partial lock/shutdown animations.
+    ANIMATION_SPEED_FAST,
+    // Speed for lock screen appearance in "old" animation set.
+    ANIMATION_SPEED_SHOW_LOCK_SCREEN,
+    // Speed for workspace-like animations in "new" animation set.
+    ANIMATION_SPEED_MOVE_WINDOWS,
+    // Speed for shutdown in "new" animation set.
+    ANIMATION_SPEED_SHUTDOWN,
+    // Speed for reverting shutdown in "new" animation set.
+    ANIMATION_SPEED_REVERT_SHUTDOWN,
   };
 
   // Specific containers or groups of containers that can be animated.
@@ -100,30 +126,42 @@
   SessionStateAnimator();
   virtual ~SessionStateAnimator();
 
+  // Reports animation duration for |speed|.
+  static base::TimeDelta GetDuration(AnimationSpeed speed);
+
+  // Fills |containers| with the containers included in |container_mask|.
+  static void GetContainers(int container_mask,
+                            aura::Window::Windows* containers);
+
   // Create |foreground_| layer if it doesn't already exist, but makes it
   // completely transparent.
   void CreateForeground();
   // Destroy |foreground_| when it is not needed anymore.
   void DropForeground();
 
-  // Apply animation |type| to all containers included in |container_mask|.
+  // Apply animation |type| to all containers included in |container_mask| with
+  // specified |speed|.
   void StartAnimation(int container_mask,
-                      AnimationType type);
+                      AnimationType type,
+                      AnimationSpeed speed);
 
-  // Apply animation |type| to all containers included in |container_mask| and
-  // call a |callback| at the end of the animation, if it is not null.
+  // Apply animation |type| to all containers included in |container_mask| with
+  // specified |speed| and call a |callback| at the end of the animation, if it
+  // is not null.
   void StartAnimationWithCallback(int container_mask,
                                   AnimationType type,
+                                  AnimationSpeed speed,
                                   base::Callback<void(void)>& callback);
 
-  // Fills |containers| with the containers included in |container_mask|.
-  void GetContainers(int container_mask,
-                     aura::Window::Windows* containers);
+  // Applies animation |type| whith specified |speed| to the root container.
+  void StartGlobalAnimation(AnimationType type,
+                            AnimationSpeed speed);
 
-  // Apply animation |type| to window |window| and add |observer| if it is not
-  // NULL to the last animation sequence.
+  // Apply animation |type| to window |window| with |speed| and add |observer|
+  // if it is not NULL to the last animation sequence.
   void RunAnimationForWindow(aura::Window* window,
                              AnimationType type,
+                             AnimationSpeed speed,
                              ui::LayerAnimationObserver* observer);
 
   // White foreground that is used during shutdown animation to "fade
diff --git a/ash/wm/session_state_controller.cc b/ash/wm/session_state_controller.cc
index 6de1351..ea12b8d 100644
--- a/ash/wm/session_state_controller.cc
+++ b/ash/wm/session_state_controller.cc
@@ -23,9 +23,6 @@
 const int SessionStateController::kShutdownTimeoutMs = 400;
 const int SessionStateController::kLockFailTimeoutMs = 4000;
 const int SessionStateController::kLockToShutdownTimeoutMs = 150;
-const int SessionStateController::kSlowCloseAnimMs = 400;
-const int SessionStateController::kUndoSlowCloseAnimMs = 100;
-const int SessionStateController::kFastCloseAnimMs = 150;
 const int SessionStateController::kShutdownRequestDelayMs = 50;
 
 SessionStateController::SessionStateController()
diff --git a/ash/wm/session_state_controller.h b/ash/wm/session_state_controller.h
index b0b3efe..53e28cd9 100644
--- a/ash/wm/session_state_controller.h
+++ b/ash/wm/session_state_controller.h
@@ -63,20 +63,6 @@
   // starting the pre-shutdown animation.
   static const int kLockToShutdownTimeoutMs;
 
-  // Amount of time taken to scale the snapshot of the screen down to a
-  // slightly-smaller size once the user starts holding the power button.  Used
-  // for both the pre-lock and pre-shutdown animations.
-  static const int kSlowCloseAnimMs;
-
-  // Amount of time taken to scale the snapshot of the screen back to its
-  // original size when the button is released.
-  static const int kUndoSlowCloseAnimMs;
-
-  // Amount of time taken to scale the snapshot down to a point in the center of
-  // the screen once the screen has been locked or we've been notified that the
-  // system is shutting down.
-  static const int kFastCloseAnimMs;
-
   // Additional time (beyond kFastCloseAnimMs) to wait after starting the
   // fast-close shutdown animation before actually requesting shutdown, to give
   // the animation time to finish.
diff --git a/ash/wm/session_state_controller_impl.cc b/ash/wm/session_state_controller_impl.cc
index 18e041d5f..9abb3b8b 100644
--- a/ash/wm/session_state_controller_impl.cc
+++ b/ash/wm/session_state_controller_impl.cc
@@ -55,7 +55,8 @@
     shell->cursor_manager()->ShowCursor(false);
     animator_->StartAnimation(
         internal::SessionStateAnimator::kAllContainersMask,
-        internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY);
+        internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
+        internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
   }
 }
 
@@ -68,7 +69,8 @@
   if (locked) {
     animator_->StartAnimation(
         internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
-        internal::SessionStateAnimator::ANIMATION_FADE_IN);
+        internal::SessionStateAnimator::ANIMATION_FADE_IN,
+        internal::SessionStateAnimator::ANIMATION_SPEED_SHOW_LOCK_SCREEN);
     lock_timer_.Stop();
     lock_fail_timer_.Stop();
 
@@ -81,7 +83,8 @@
         internal::SessionStateAnimator::DESKTOP_BACKGROUND |
         internal::SessionStateAnimator::LAUNCHER |
         internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
-        internal::SessionStateAnimator::ANIMATION_RESTORE);
+        internal::SessionStateAnimator::ANIMATION_RESTORE,
+        internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
   }
 }
 
@@ -91,22 +94,26 @@
 
   animator_->StartAnimation(
       internal::SessionStateAnimator::LAUNCHER,
-      internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY);
+      internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
+      internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
 
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_FULL_CLOSE);
+      internal::SessionStateAnimator::ANIMATION_FULL_CLOSE,
+      internal::SessionStateAnimator::ANIMATION_SPEED_FAST);
 
   // Hide the screen locker containers so we can make them fade in later.
   animator_->StartAnimation(
       internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY);
+      internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
+      internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
 }
 
 void SessionStateControllerImpl::StartLockAnimationAndLockImmediately() {
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE);
+      internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE,
+      internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
   OnLockTimeout();
 }
 
@@ -115,14 +122,16 @@
 
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE);
+      internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE,
+      internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
   StartLockTimer();
 }
 
 void SessionStateControllerImpl::StartShutdownAnimation() {
   animator_->StartAnimation(
       internal::SessionStateAnimator::kAllContainersMask,
-      internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE);
+      internal::SessionStateAnimator::ANIMATION_PARTIAL_CLOSE,
+      internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
 
   StartPreShutdownAnimationTimer();
 }
@@ -153,7 +162,8 @@
   shutdown_after_lock_ = false;
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE);
+      internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE,
+      internal::SessionStateAnimator::ANIMATION_SPEED_REVERT);
   lock_timer_.Stop();
 }
 
@@ -180,14 +190,17 @@
     // desktop background needs to be restored immediately.
     animator_->StartAnimation(
         internal::SessionStateAnimator::DESKTOP_BACKGROUND,
-        internal::SessionStateAnimator::ANIMATION_RESTORE);
+        internal::SessionStateAnimator::ANIMATION_RESTORE,
+        internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
     animator_->StartAnimation(
         internal::SessionStateAnimator::kAllLockScreenContainersMask,
-        internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE);
+        internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE,
+        internal::SessionStateAnimator::ANIMATION_SPEED_REVERT);
   } else {
     animator_->StartAnimation(
         internal::SessionStateAnimator::kAllContainersMask,
-        internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE);
+        internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE,
+        internal::SessionStateAnimator::ANIMATION_SPEED_REVERT);
   }
   pre_shutdown_timer_.Stop();
 }
@@ -212,14 +225,17 @@
     animator_->StartAnimation(
         internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS |
         internal::SessionStateAnimator::LAUNCHER,
-        internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY);
+        internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
+        internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
     animator_->StartAnimation(
         internal::SessionStateAnimator::kAllLockScreenContainersMask,
-        internal::SessionStateAnimator::ANIMATION_FULL_CLOSE);
+        internal::SessionStateAnimator::ANIMATION_FULL_CLOSE,
+        internal::SessionStateAnimator::ANIMATION_SPEED_FAST);
   } else {
     animator_->StartAnimation(
         internal::SessionStateAnimator::kAllContainersMask,
-        internal::SessionStateAnimator::ANIMATION_FULL_CLOSE);
+        internal::SessionStateAnimator::ANIMATION_FULL_CLOSE,
+        internal::SessionStateAnimator::ANIMATION_SPEED_FAST);
   }
   StartRealShutdownTimer();
 }
@@ -238,9 +254,11 @@
 
 void SessionStateControllerImpl::StartLockTimer() {
   lock_timer_.Stop();
-  lock_timer_.Start(FROM_HERE,
-                    base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
-                    this, &SessionStateControllerImpl::OnLockTimeout);
+  lock_timer_.Start(
+      FROM_HERE,
+      animator_->GetDuration(
+          internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE),
+      this, &SessionStateControllerImpl::OnLockTimeout);
 }
 
 void SessionStateControllerImpl::OnLockTimeout() {
@@ -257,7 +275,8 @@
   animator_->StartAnimation(
       internal::SessionStateAnimator::LAUNCHER |
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_RESTORE);
+      internal::SessionStateAnimator::ANIMATION_RESTORE,
+      internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
 }
 
 void SessionStateControllerImpl::StartLockToShutdownTimer() {
@@ -289,10 +308,14 @@
 }
 
 void SessionStateControllerImpl::StartRealShutdownTimer() {
+  base::TimeDelta duration =
+      base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
+  duration += animator_->GetDuration(
+      internal::SessionStateAnimator::ANIMATION_SPEED_FAST);
+
   real_shutdown_timer_.Start(
       FROM_HERE,
-      base::TimeDelta::FromMilliseconds(kFastCloseAnimMs +
-          kShutdownRequestDelayMs),
+      duration,
       this, &SessionStateControllerImpl::OnRealShutdownTimeout);
 }
 
diff --git a/ash/wm/session_state_controller_impl2.cc b/ash/wm/session_state_controller_impl2.cc
index ebbc3f3..c6456ad 100644
--- a/ash/wm/session_state_controller_impl2.cc
+++ b/ash/wm/session_state_controller_impl2.cc
@@ -55,10 +55,9 @@
     Shell* shell = ash::Shell::GetInstance();
     shell->env_filter()->set_cursor_hidden_by_filter(false);
     shell->cursor_manager()->ShowCursor(false);
-    animator_->CreateForeground();
-    animator_->StartAnimation(
-        internal::SessionStateAnimator::LOCK_SCREEN_SYSTEM_FOREGROUND,
-        internal::SessionStateAnimator::ANIMATION_FULL_FADE_IN);
+    animator_->StartGlobalAnimation(
+        internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
+        internal::SessionStateAnimator::ANIMATION_SPEED_FAST);
   }
 }
 
@@ -77,11 +76,13 @@
       animator_->StartAnimationWithCallback(
           internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
           internal::SessionStateAnimator::ANIMATION_DROP,
+          internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
           callback);
     } else {
       animator_->StartAnimationWithCallback(
           internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
           internal::SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN,
+          internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
           callback);
     }
     lock_timer_.Stop();
@@ -95,7 +96,8 @@
     animator_->StartAnimation(
         internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS |
         internal::SessionStateAnimator::LAUNCHER,
-        internal::SessionStateAnimator::ANIMATION_DROP);
+        internal::SessionStateAnimator::ANIMATION_DROP,
+        internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
   }
 }
 
@@ -118,19 +120,22 @@
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS |
       internal::SessionStateAnimator::LAUNCHER,
-      internal::SessionStateAnimator::ANIMATION_LIFT);
+      internal::SessionStateAnimator::ANIMATION_LIFT,
+      internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
 
   // Hide the screen locker containers so we can raise them later.
   animator_->StartAnimation(
       internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY);
+      internal::SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY,
+      internal::SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE);
 }
 
 void SessionStateControllerImpl2::StartLockAnimationAndLockImmediately() {
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS |
       internal::SessionStateAnimator::LAUNCHER,
-      internal::SessionStateAnimator::ANIMATION_LIFT);
+      internal::SessionStateAnimator::ANIMATION_LIFT,
+      internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
   OnLockTimeout();
 }
 
@@ -140,15 +145,15 @@
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS |
       internal::SessionStateAnimator::LAUNCHER,
-      internal::SessionStateAnimator::ANIMATION_LIFT);
+      internal::SessionStateAnimator::ANIMATION_LIFT,
+      internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE);
   StartLockTimer();
 }
 
 void SessionStateControllerImpl2::StartShutdownAnimation() {
-  animator_->CreateForeground();
-  animator_->StartAnimation(
-      internal::SessionStateAnimator::LOCK_SCREEN_SYSTEM_FOREGROUND,
-      internal::SessionStateAnimator::ANIMATION_PARTIAL_FADE_IN);
+  animator_->StartGlobalAnimation(
+      internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
+      internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
   StartPreShutdownAnimationTimer();
 }
 
@@ -179,7 +184,8 @@
   animator_->StartAnimation(
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS |
       internal::SessionStateAnimator::LAUNCHER,
-      internal::SessionStateAnimator::ANIMATION_DROP);
+      internal::SessionStateAnimator::ANIMATION_DROP,
+      internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
   lock_timer_.Stop();
 }
 
@@ -200,14 +206,9 @@
     shutdown_after_lock_ = false;
     return;
   }
-  animator_->CreateForeground();
-  base::Callback<void(void)> callback =
-      base::Bind(&internal::SessionStateAnimator::DropForeground,
-      base::Unretained(animator_.get()));
-  animator_->StartAnimationWithCallback(
-      internal::SessionStateAnimator::LOCK_SCREEN_SYSTEM_FOREGROUND,
-      internal::SessionStateAnimator::ANIMATION_UNDO_PARTIAL_FADE_IN,
-      callback);
+  animator_->StartGlobalAnimation(
+      internal::SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS,
+      internal::SessionStateAnimator::ANIMATION_SPEED_REVERT);
   pre_shutdown_timer_.Stop();
 }
 
@@ -224,10 +225,9 @@
   shell->env_filter()->set_cursor_hidden_by_filter(false);
   shell->cursor_manager()->ShowCursor(false);
 
-  animator_->CreateForeground();
-  animator_->StartAnimation(
-      internal::SessionStateAnimator::LOCK_SCREEN_SYSTEM_FOREGROUND,
-      internal::SessionStateAnimator::ANIMATION_FULL_FADE_IN);
+  animator_->StartGlobalAnimation(
+      internal::SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS,
+      internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
   StartRealShutdownTimer();
 }
 
@@ -245,9 +245,11 @@
 
 void SessionStateControllerImpl2::StartLockTimer() {
   lock_timer_.Stop();
-  lock_timer_.Start(FROM_HERE,
-                    base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
-                    this, &SessionStateControllerImpl2::OnLockTimeout);
+  lock_timer_.Start(
+      FROM_HERE,
+      animator_->GetDuration(
+          internal::SessionStateAnimator::ANIMATION_SPEED_UNDOABLE),
+      this, &SessionStateControllerImpl2::OnLockTimeout);
 }
 
 void SessionStateControllerImpl2::OnLockTimeout() {
@@ -264,7 +266,8 @@
   animator_->StartAnimation(
       internal::SessionStateAnimator::LAUNCHER |
       internal::SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS,
-      internal::SessionStateAnimator::ANIMATION_DROP);
+      internal::SessionStateAnimator::ANIMATION_DROP,
+      internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS);
 }
 
 void SessionStateControllerImpl2::StartLockToShutdownTimer() {
@@ -296,10 +299,13 @@
 }
 
 void SessionStateControllerImpl2::StartRealShutdownTimer() {
+  base::TimeDelta duration =
+      base::TimeDelta::FromMilliseconds(kShutdownRequestDelayMs);
+  duration += animator_->GetDuration(
+      internal::SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN);
   real_shutdown_timer_.Start(
       FROM_HERE,
-      base::TimeDelta::FromMilliseconds(kFastCloseAnimMs +
-          kShutdownRequestDelayMs),
+      duration,
       this, &SessionStateControllerImpl2::OnRealShutdownTimeout);
 }
 
@@ -324,11 +330,13 @@
     animator_->StartAnimationWithCallback(
         internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
         internal::SessionStateAnimator::ANIMATION_LIFT,
+        internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
         callback);
   } else {
     animator_->StartAnimationWithCallback(
         internal::SessionStateAnimator::LOCK_SCREEN_CONTAINERS,
         internal::SessionStateAnimator::ANIMATION_LOWER_BELOW_SCREEN,
+        internal::SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS,
         callback);
   }
 }
diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc
index 2c3c185..855c453 100644
--- a/ash/wm/window_animations.cc
+++ b/ash/wm/window_animations.cc
@@ -450,45 +450,18 @@
     window->layer()->SetVisible(true);
   }
 
-  int animation_duration = kBrightnessGrayscaleFadeDurationMs;
-  ui::Tween::Type animation_type = ui::Tween::EASE_OUT;
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          ash::switches::kAshBootAnimationFunction2)) {
-    animation_type = ui::Tween::EASE_OUT_2;
-  } else if (CommandLine::ForCurrentProcess()->HasSwitch(
-                  ash::switches::kAshBootAnimationFunction3)) {
-    animation_type = ui::Tween::EASE_OUT_3;
-  }
+  base::TimeDelta duration =
+      base::TimeDelta::FromMilliseconds(kBrightnessGrayscaleFadeDurationMs);
 
   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
-  settings.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(animation_duration));
+  settings.SetTransitionDuration(duration);
   if (!show)
     settings.AddObserver(new HidingWindowAnimationObserver(window));
 
-  scoped_ptr<ui::LayerAnimationSequence> brightness_sequence(
-      new ui::LayerAnimationSequence());
-  scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence(
-      new ui::LayerAnimationSequence());
-
-  scoped_ptr<ui::LayerAnimationElement> brightness_element(
-      ui::LayerAnimationElement::CreateBrightnessElement(
-          end_value,
-          base::TimeDelta::FromMilliseconds(animation_duration)));
-  brightness_element->set_tween_type(animation_type);
-  brightness_sequence->AddElement(brightness_element.release());
-
-  scoped_ptr<ui::LayerAnimationElement> grayscale_element(
-      ui::LayerAnimationElement::CreateGrayscaleElement(
-          end_value,
-          base::TimeDelta::FromMilliseconds(animation_duration)));
-  grayscale_element->set_tween_type(animation_type);
-  grayscale_sequence->AddElement(grayscale_element.release());
-
-   std::vector<ui::LayerAnimationSequence*> animations;
-   animations.push_back(brightness_sequence.release());
-   animations.push_back(grayscale_sequence.release());
-   window->layer()->GetAnimator()->ScheduleTogether(animations);
+   window->layer()->GetAnimator()->
+       ScheduleTogether(
+           internal::CreateBrightnessGrayscaleAnimationSequence(end_value,
+                                                                duration));
    if (!show) {
      window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
      window->layer()->SetVisible(false);
@@ -882,5 +855,40 @@
   }
 }
 
+std::vector<ui::LayerAnimationSequence*>
+CreateBrightnessGrayscaleAnimationSequence(float target_value,
+                                           base::TimeDelta duration) {
+  ui::Tween::Type animation_type = ui::Tween::EASE_OUT;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          ash::switches::kAshBootAnimationFunction2)) {
+    animation_type = ui::Tween::EASE_OUT_2;
+  } else if (CommandLine::ForCurrentProcess()->HasSwitch(
+                  ash::switches::kAshBootAnimationFunction3)) {
+    animation_type = ui::Tween::EASE_OUT_3;
+  }
+  scoped_ptr<ui::LayerAnimationSequence> brightness_sequence(
+      new ui::LayerAnimationSequence());
+  scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence(
+      new ui::LayerAnimationSequence());
+
+  scoped_ptr<ui::LayerAnimationElement> brightness_element(
+      ui::LayerAnimationElement::CreateBrightnessElement(
+          target_value, duration));
+  brightness_element->set_tween_type(animation_type);
+  brightness_sequence->AddElement(brightness_element.release());
+
+  scoped_ptr<ui::LayerAnimationElement> grayscale_element(
+      ui::LayerAnimationElement::CreateGrayscaleElement(
+          target_value, duration));
+  grayscale_element->set_tween_type(animation_type);
+  grayscale_sequence->AddElement(grayscale_element.release());
+
+  std::vector<ui::LayerAnimationSequence*> animations;
+  animations.push_back(brightness_sequence.release());
+  animations.push_back(grayscale_sequence.release());
+
+  return animations;
+}
+
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/wm/window_animations.h b/ash/wm/window_animations.h
index b7655e11..9179aac 100644
--- a/ash/wm/window_animations.h
+++ b/ash/wm/window_animations.h
@@ -5,6 +5,8 @@
 #ifndef ASH_WM_WINDOW_ANIMATIONS_H_
 #define ASH_WM_WINDOW_ANIMATIONS_H_
 
+#include <vector>
+
 #include "ash/ash_export.h"
 
 namespace aura {
@@ -19,6 +21,7 @@
 namespace ui {
 class ImplicitAnimationObserver;
 class Layer;
+class LayerAnimationSequence;
 }
 
 namespace ash {
@@ -96,6 +99,13 @@
 ASH_EXPORT bool AnimateOnChildWindowVisibilityChanged(aura::Window* window,
                                                       bool visible);
 
+// Creates vector of animation sequences that lasts for |duration| and changes
+// brightness and grayscale to |target_value|. Caller takes ownership of
+// returned LayerAnimationSequence objects.
+ASH_EXPORT std::vector<ui::LayerAnimationSequence*>
+CreateBrightnessGrayscaleAnimationSequence(float target_value,
+                                           base::TimeDelta duration);
+
 }  // namespace internal
 }  // namespace ash
 
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index 9ac78405..f84fe74 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -22,6 +22,7 @@
 #include "ash/system/user/update_observer.h"
 #include "ash/system/user/user_observer.h"
 #include "ash/volume_control_delegate.h"
+#include "ash/wm/session_state_controller.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/chromeos/chromeos_version.h"
@@ -353,9 +354,7 @@
   }
 
   virtual void ShutDown() OVERRIDE {
-    DBusThreadManager::Get()->GetPowerManagerClient()->RequestShutdown();
-    if (!base::chromeos::IsRunningOnChromeOS())
-      browser::AttemptUserExit();
+    ash::Shell::GetInstance()->session_state_controller()->RequestShutdown();
   }
 
   virtual void SignOut() OVERRIDE {
diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc
index a8d61a4..d49edc5 100644
--- a/ui/compositor/layer_animator.cc
+++ b/ui/compositor/layer_animator.cc
@@ -65,7 +65,8 @@
       transition_duration_(transition_duration),
       tween_type_(Tween::LINEAR),
       is_started_(false),
-      disable_timer_for_test_(false) {
+      disable_timer_for_test_(false),
+      adding_animations_(false) {
 }
 
 LayerAnimator::~LayerAnimator() {
@@ -231,6 +232,45 @@
   UpdateAnimationState();
 }
 
+void LayerAnimator::StartTogether(
+    const std::vector<LayerAnimationSequence*>& animations) {
+  scoped_refptr<LayerAnimator> retain(this);
+  if (preemption_strategy_ == IMMEDIATELY_SET_NEW_TARGET) {
+    std::vector<LayerAnimationSequence*>::const_iterator iter;
+    for (iter = animations.begin(); iter != animations.end(); ++iter) {
+      StartAnimation(*iter);
+    }
+    return;
+  }
+  adding_animations_ = true;
+
+  // Collect all the affected properties.
+  LayerAnimationElement::AnimatableProperties animated_properties;
+  std::vector<LayerAnimationSequence*>::const_iterator iter;
+  for (iter = animations.begin(); iter != animations.end(); ++iter) {
+    animated_properties.insert((*iter)->properties().begin(),
+                               (*iter)->properties().end());
+  }
+
+  // Starting a zero duration pause that affects all the animated properties
+  // will prevent any of the sequences from animating until there are no
+  // running animations that affect any of these properties, as well as
+  // handle preemption strategy.
+  StartAnimation(new LayerAnimationSequence(
+      LayerAnimationElement::CreatePauseElement(animated_properties,
+                                                base::TimeDelta())));
+
+  // These animations (provided they don't animate any common properties) will
+  // now animate together if trivially scheduled.
+  for (iter = animations.begin(); iter != animations.end(); ++iter) {
+    ScheduleAnimation(*iter);
+  }
+
+  adding_animations_ = false;
+  UpdateAnimationState();
+}
+
+
 void LayerAnimator::ScheduleTogether(
     const std::vector<LayerAnimationSequence*>& animations) {
   scoped_refptr<LayerAnimator> retain(this);
@@ -691,7 +731,7 @@
   // last_tick_time() from there to ensure animations started during the same
   // event complete at the same time.
   base::TimeTicks start_time;
-  if (is_animating())
+  if (is_animating() || adding_animations_)
     start_time = last_step_time_;
   else if (GetAnimationContainer()->is_running())
     start_time = GetAnimationContainer()->last_tick_time();
diff --git a/ui/compositor/layer_animator.h b/ui/compositor/layer_animator.h
index da2976a0..764be17 100644
--- a/ui/compositor/layer_animator.h
+++ b/ui/compositor/layer_animator.h
@@ -113,7 +113,12 @@
   // of this animation sequence.
   void ScheduleAnimation(LayerAnimationSequence* animation);
 
-  // Schedules the animations to be run together. Obviously will no work if
+  // Starts the animations to be run together. Obviously will not work if
+  // they animate any common properties. The animator takes ownership of the
+  // animation sequences. Takes PreemptionStrategy into account.
+  void StartTogether(const std::vector<LayerAnimationSequence*>& animations);
+
+  // Schedules the animations to be run together. Obviously will not work if
   // they animate any common properties. The animator takes ownership of the
   // animation sequences.
   void ScheduleTogether(const std::vector<LayerAnimationSequence*>& animations);
@@ -331,6 +336,10 @@
   // and allows for manual stepping.
   bool disable_timer_for_test_;
 
+  // Prevents timer adjustments in case when we start multiple animations
+  // with preemption strategies that discard previous animations.
+  bool adding_animations_;
+
   // This causes all animations to complete immediately.
   static bool disable_animations_for_test_;
 
diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc
index d1219a15..d73ca39 100644
--- a/ui/compositor/layer_animator_unittest.cc
+++ b/ui/compositor/layer_animator_unittest.cc
@@ -32,6 +32,22 @@
                             SkColorGetB(color));
 }
 
+// Creates vector with two LayerAnimationSequences, based on |first| and
+// |second| layer animation elements.
+std::vector<LayerAnimationSequence*> CreateMultiSequence(
+    LayerAnimationElement* first,
+    LayerAnimationElement* second) {
+  LayerAnimationSequence* first_sequence = new LayerAnimationSequence();
+  first_sequence->AddElement(first);
+  LayerAnimationSequence* second_sequence = new LayerAnimationSequence();
+  second_sequence->AddElement(second);
+
+  std::vector<ui::LayerAnimationSequence*> animations;
+  animations.push_back(first_sequence);
+  animations.push_back(second_sequence);
+  return animations;
+}
+
 class TestImplicitAnimationObserver : public ImplicitAnimationObserver {
  public:
   explicit TestImplicitAnimationObserver(bool notify_when_animator_destructed)
@@ -686,6 +702,249 @@
   EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
 }
 
+//-------------------------------------------------------
+// Preempt by immediately setting new target.
+TEST(LayerAnimatorTest, MultiPreemptBySettingNewTarget) {
+  scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
+  animator->set_disable_timer_for_test(true);
+  TestLayerAnimationDelegate delegate;
+  animator->SetDelegate(&delegate);
+
+  double start_opacity(0.0);
+  double target_opacity(1.0);
+  double start_brightness(0.1);
+  double target_brightness(0.9);
+
+  base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+  delegate.SetOpacityFromAnimation(start_opacity);
+  delegate.SetBrightnessFromAnimation(start_brightness);
+
+  animator->set_preemption_strategy(LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(target_brightness,
+                                                         delta)
+      ));
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(start_brightness,
+                                                         delta)
+      ));
+
+  EXPECT_FALSE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
+}
+
+// Preempt by animating to new target.
+TEST(LayerAnimatorTest, MultiPreemptByImmediatelyAnimatingToNewTarget) {
+  scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
+  AnimationContainerElement* element = animator.get();
+  animator->set_disable_timer_for_test(true);
+  TestLayerAnimationDelegate delegate;
+  animator->SetDelegate(&delegate);
+
+  double start_opacity(0.0);
+  double middle_opacity(0.5);
+  double target_opacity(1.0);
+
+  double start_brightness(0.1);
+  double middle_brightness(0.2);
+  double target_brightness(0.3);
+
+  base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+  delegate.SetOpacityFromAnimation(start_opacity);
+  delegate.SetBrightnessFromAnimation(start_brightness);
+
+  animator->set_preemption_strategy(
+      LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(target_brightness,
+                                                         delta)
+      ));
+
+  base::TimeTicks start_time = animator->last_step_time();
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(start_brightness,
+                                                         delta)));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(start_brightness,
+                                                         delta)));
+
+  EXPECT_TRUE(animator->is_animating());
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(),
+                  0.5 * (start_opacity + middle_opacity));
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(),
+                  0.5 * (start_brightness + middle_brightness));
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+
+  EXPECT_FALSE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
+}
+
+// Preempt by enqueuing the new animation.
+TEST(LayerAnimatorTest, MultiPreemptEnqueueNewAnimation) {
+  scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
+  AnimationContainerElement* element = animator.get();
+  animator->set_disable_timer_for_test(true);
+  TestLayerAnimationDelegate delegate;
+  animator->SetDelegate(&delegate);
+
+  double start_opacity(0.0);
+  double middle_opacity(0.5);
+  double target_opacity(1.0);
+
+  double start_brightness(0.1);
+  double middle_brightness(0.2);
+  double target_brightness(0.3);
+
+  base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+  delegate.SetOpacityFromAnimation(start_opacity);
+  delegate.SetBrightnessFromAnimation(start_brightness);
+
+  animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION);
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(target_brightness,
+                                                         delta)));
+
+  base::TimeTicks start_time = animator->last_step_time();
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(start_brightness,
+                                                         delta)));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
+
+  EXPECT_TRUE(animator->is_animating());
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+
+  EXPECT_FALSE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
+}
+
+// Start an animation when there are sequences waiting in the queue. In this
+// case, all pending and running animations should be finished, and the new
+// animation started.
+TEST(LayerAnimatorTest, MultiPreemptByReplacingQueuedAnimations) {
+  scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());
+  AnimationContainerElement* element = animator.get();
+  animator->set_disable_timer_for_test(true);
+  TestLayerAnimationDelegate delegate;
+  animator->SetDelegate(&delegate);
+
+  double start_opacity(0.0);
+  double middle_opacity(0.5);
+  double target_opacity(1.0);
+
+  double start_brightness(0.1);
+  double middle_brightness(0.2);
+  double target_brightness(0.3);
+
+  base::TimeDelta delta = base::TimeDelta::FromSeconds(1);
+
+  delegate.SetOpacityFromAnimation(start_opacity);
+  delegate.SetBrightnessFromAnimation(start_brightness);
+
+  animator->set_preemption_strategy(LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(target_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(target_brightness,
+                                                         delta)));
+
+  base::TimeTicks start_time = animator->last_step_time();
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(500));
+
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(middle_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(middle_brightness,
+                                                         delta)));
+
+  // Queue should now have two animations. Starting a third should replace the
+  // second.
+  animator->StartTogether(
+      CreateMultiSequence(
+          LayerAnimationElement::CreateOpacityElement(start_opacity, delta),
+          LayerAnimationElement::CreateBrightnessElement(start_brightness,
+                                                         delta)));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(1000));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), target_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), target_brightness);
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(1500));
+
+  EXPECT_TRUE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), middle_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), middle_brightness);
+
+  element->Step(start_time + base::TimeDelta::FromMilliseconds(2000));
+
+  EXPECT_FALSE(animator->is_animating());
+  EXPECT_FLOAT_EQ(delegate.GetOpacityForAnimation(), start_opacity);
+  EXPECT_FLOAT_EQ(delegate.GetBrightnessForAnimation(), start_brightness);
+}
+//-------------------------------------------------------
 // Test that cyclic sequences continue to animate.
 TEST(LayerAnimatorTest, CyclicSequences) {
   scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator());