Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / multi_user / multi_user_window_manager_chromeos.cc
index 7529473..80e74bf 100644 (file)
@@ -4,11 +4,15 @@
 
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
 
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
+#include "apps/app_window.h"
+#include "apps/app_window_registry.h"
 #include "ash/ash_switches.h"
+#include "ash/desktop_background/user_wallpaper_delegate.h"
 #include "ash/multi_profile_uma.h"
+#include "ash/root_window_controller.h"
 #include "ash/session_state_delegate.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/shell_window_ids.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/login/wallpaper_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "ui/events/event.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/corewm/transient_window_manager.h"
+#include "ui/views/corewm/window_animations.h"
 #include "ui/views/corewm/window_util.h"
 
 namespace {
 
+// The animation time in milliseconds for a single window which is fading
+// in / out.
+static int kAnimationTimeMS = 100;
+
+// The animation time in millseconds for the fade in and / or out when switching
+// users.
+static int kUserFadeTimeMS = 110;
+
+// The animation time in ms for a window which get teleported to another screen.
+static int kTeleportAnimationTimeMS = 300;
+
 // Checks if a given event is a user event.
 bool IsUserEvent(ui::Event* e) {
   if (e) {
@@ -105,20 +123,19 @@ void RecordUMAForTransferredWindowType(aura::Window* window) {
     if (!g_browser_process->profile_manager())
       return;
     // If it is not a browser, it is probably be a V2 application. In that case
-    // one of the ShellWindowRegistries should know about it.
-    apps::ShellWindow* shell_window = NULL;
+    // one of the AppWindowRegistry instances should know about it.
+    apps::AppWindow* app_window = NULL;
     std::vector<Profile*> profiles =
         g_browser_process->profile_manager()->GetLoadedProfiles();
     for (std::vector<Profile*>::iterator it = profiles.begin();
-         it != profiles.end() && shell_window == NULL; it++) {
-      shell_window = apps::ShellWindowRegistry::Get(
-          *it)->GetShellWindowForNativeWindow(window);
+         it != profiles.end() && app_window == NULL;
+         it++) {
+      app_window = apps::AppWindowRegistry::Get(*it)
+                       ->GetAppWindowForNativeWindow(window);
     }
-    if (shell_window) {
-      if (shell_window->window_type() ==
-              apps::ShellWindow::WINDOW_TYPE_PANEL ||
-          shell_window->window_type() ==
-              apps::ShellWindow::WINDOW_TYPE_V1_PANEL) {
+    if (app_window) {
+      if (app_window->window_type() == apps::AppWindow::WINDOW_TYPE_PANEL ||
+          app_window->window_type() == apps::AppWindow::WINDOW_TYPE_V1_PANEL) {
         window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_PANEL;
       } else {
         window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_V2_APP;
@@ -132,6 +149,44 @@ void RecordUMAForTransferredWindowType(aura::Window* window) {
 
 namespace chrome {
 
+// A class to temporarily change the animation properties for a window.
+class AnimationSetter {
+ public:
+  AnimationSetter(aura::Window* window, int animation_time_in_ms)
+      : window_(window),
+        previous_animation_type_(
+            views::corewm::GetWindowVisibilityAnimationType(window_)),
+        previous_animation_time_(
+            views::corewm::GetWindowVisibilityAnimationDuration(*window_)) {
+    views::corewm::SetWindowVisibilityAnimationType(
+        window_,
+        views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
+    views::corewm::SetWindowVisibilityAnimationDuration(
+        window_,
+        base::TimeDelta::FromMilliseconds(animation_time_in_ms));
+  }
+
+  ~AnimationSetter() {
+    views::corewm::SetWindowVisibilityAnimationType(window_,
+                                                    previous_animation_type_);
+    views::corewm::SetWindowVisibilityAnimationDuration(
+        window_,
+        previous_animation_time_);
+  }
+
+ private:
+  // The window which gets used.
+  aura::Window* window_;
+
+  // Previous animation type.
+  const int previous_animation_type_;
+
+  // Previous animation time.
+  const base::TimeDelta previous_animation_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnimationSetter);
+};
+
 // logic while the user gets switched.
 class UserChangeActionDisabler {
  public:
@@ -154,22 +209,20 @@ class UserChangeActionDisabler {
 // When an app gets created, the window will be tagged for that user. Note
 // that the destruction does not need to be tracked here since the universal
 // window observer will take care of that.
-class AppObserver : public apps::ShellWindowRegistry::Observer {
+class AppObserver : public apps::AppWindowRegistry::Observer {
  public:
   explicit AppObserver(const std::string& user_id) : user_id_(user_id) {}
   virtual ~AppObserver() {}
 
-  // ShellWindowRegistry::Observer overrides:
-  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
-    aura::Window* window = shell_window->GetNativeWindow();
+  // AppWindowRegistry::Observer overrides:
+  virtual void OnAppWindowAdded(apps::AppWindow* app_window) OVERRIDE {
+    aura::Window* window = app_window->GetNativeWindow();
     DCHECK(window);
     MultiUserWindowManagerChromeOS::GetInstance()->SetWindowOwner(window,
                                                                   user_id_);
   }
-  virtual void OnShellWindowIconChanged(apps::ShellWindow* shell_window)
-      OVERRIDE {}
-  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window)
-      OVERRIDE {}
+  virtual void OnAppWindowIconChanged(apps::AppWindow* app_window) OVERRIDE {}
+  virtual void OnAppWindowRemoved(apps::AppWindow* app_window) OVERRIDE {}
 
  private:
   std::string user_id_;
@@ -181,8 +234,9 @@ MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
     const std::string& current_user_id)
     : current_user_id_(current_user_id),
       notification_blocker_(new MultiUserNotificationBlockerChromeOS(
-          message_center::MessageCenter::Get(), this)),
-      suppress_visibility_changes_(false) {
+          message_center::MessageCenter::Get(), this, current_user_id)),
+      suppress_visibility_changes_(false),
+      animations_disabled_(false) {
   // Add a session state observer to be able to monitor session changes.
   if (ash::Shell::HasInstance())
     ash::Shell::GetInstance()->session_state_delegate()->
@@ -201,21 +255,21 @@ MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
 
 MultiUserWindowManagerChromeOS::~MultiUserWindowManagerChromeOS() {
   // Remove all window observers.
-  WindowToEntryMap::iterator window_observer = window_to_entry_.begin();
-  while (window_observer != window_to_entry_.end()) {
-    OnWindowDestroyed(window_observer->first);
-    window_observer = window_to_entry_.begin();
+  WindowToEntryMap::iterator window = window_to_entry_.begin();
+  while (window != window_to_entry_.end()) {
+    OnWindowDestroyed(window->first);
+    window = window_to_entry_.begin();
   }
 
   // Remove all app observers.
-  UserIDToShellWindowObserver::iterator app_observer_iterator =
+  UserIDToAppWindowObserver::iterator app_observer_iterator =
       user_id_to_app_observer_.begin();
   while (app_observer_iterator != user_id_to_app_observer_.end()) {
     Profile* profile = multi_user_util::GetProfileFromUserID(
         app_observer_iterator->first);
     DCHECK(profile);
-    apps::ShellWindowRegistry::Get(profile)->RemoveObserver(
-        app_observer_iterator->second);
+    apps::AppWindowRegistry::Get(profile)
+        ->RemoveObserver(app_observer_iterator->second);
     delete app_observer_iterator->second;
     user_id_to_app_observer_.erase(app_observer_iterator);
     app_observer_iterator = user_id_to_app_observer_.begin();
@@ -242,7 +296,6 @@ void MultiUserWindowManagerChromeOS::SetWindowOwner(
 
   // Add observers to track state changes.
   window->AddObserver(this);
-  ash::wm::GetWindowState(window)->AddObserver(this);
   views::corewm::TransientWindowManager::Get(window)->AddObserver(this);
 
   // Check if this window was created due to a user interaction. If it was,
@@ -254,13 +307,11 @@ void MultiUserWindowManagerChromeOS::SetWindowOwner(
   // will add the children but not the owner to the transient children map.
   AddTransientOwnerRecursive(window, window);
 
-  // Right now only |notification_blocker_| needs to know when the list of
-  // owners may change.
-  // TODO(skuhne): replace this by observer when another one needs this event.
-  notification_blocker_->UpdateWindowOwners();
+  // Notify entry adding.
+  FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryAdded(window));
 
   if (!IsWindowOnDesktopOfUser(window, current_user_id_))
-    SetWindowVisibility(window, false);
+    SetWindowVisibility(window, false, 0);
 }
 
 const std::string& MultiUserWindowManagerChromeOS::GetWindowOwner(
@@ -273,42 +324,17 @@ const std::string& MultiUserWindowManagerChromeOS::GetWindowOwner(
 void MultiUserWindowManagerChromeOS::ShowWindowForUser(
     aura::Window* window,
     const std::string& user_id) {
-  // If there is either no owner, or the owner is the current user, no action
-  // is required.
-  const std::string& owner = GetWindowOwner(window);
-  if (owner.empty() ||
-      (owner == user_id && IsWindowOnDesktopOfUser(window, user_id)))
+  std::string previous_owner(GetUserPresentingWindow(window));
+  if (!ShowWindowForUserIntern(window, user_id))
     return;
-
-  bool minimized = ash::wm::GetWindowState(window)->IsMinimized();
-  // Check that we are not trying to transfer ownership of a minimized window.
-  if (user_id != owner && minimized)
+  // The window switched to a new desktop and we have to switch to that desktop,
+  // but only when it was on the visible desktop and the the target is not the
+  // visible desktop.
+  if (user_id == current_user_id_ || previous_owner != current_user_id_)
     return;
 
-  if (minimized) {
-    // If it is minimized it falls back to the original desktop.
-    ash::MultiProfileUMA::RecordTeleportAction(
-        ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_MINIMIZE);
-  } else {
-    // If the window was transferred without getting minimized, we should record
-    // the window type.
-    RecordUMAForTransferredWindowType(window);
-  }
-
-  WindowToEntryMap::iterator it = window_to_entry_.find(window);
-  it->second->set_show_for_user(user_id);
-
-  // Show the window if the added user is the current one.
-  if (user_id == current_user_id_) {
-    // Only show the window if it should be shown according to its state.
-    if (it->second->show())
-      SetWindowVisibility(window, true);
-  } else {
-    SetWindowVisibility(window, false);
-  }
-
-  // TODO(skuhne): replace this by observer when another one needs this event.
-  notification_blocker_->UpdateWindowOwners();
+  ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
+      user_id);
 }
 
 bool MultiUserWindowManagerChromeOS::AreWindowsSharedAmongUsers() {
@@ -353,16 +379,16 @@ void MultiUserWindowManagerChromeOS::AddUser(Profile* profile) {
     return;
 
   user_id_to_app_observer_[user_id] = new AppObserver(user_id);
-  apps::ShellWindowRegistry::Get(profile)->AddObserver(
-      user_id_to_app_observer_[user_id]);
+  apps::AppWindowRegistry::Get(profile)
+      ->AddObserver(user_id_to_app_observer_[user_id]);
 
   // Account all existing application windows of this user accordingly.
-  const apps::ShellWindowRegistry::ShellWindowList& shell_windows =
-      apps::ShellWindowRegistry::Get(profile)->shell_windows();
-  apps::ShellWindowRegistry::ShellWindowList::const_iterator it =
-      shell_windows.begin();
-  for (; it != shell_windows.end(); ++it)
-    user_id_to_app_observer_[user_id]->OnShellWindowAdded(*it);
+  const apps::AppWindowRegistry::AppWindowList& app_windows =
+      apps::AppWindowRegistry::Get(profile)->app_windows();
+  apps::AppWindowRegistry::AppWindowList::const_iterator it =
+      app_windows.begin();
+  for (; it != app_windows.end(); ++it)
+    user_id_to_app_observer_[user_id]->OnAppWindowAdded(*it);
 
   // Account all existing browser windows of this user accordingly.
   BrowserList* browser_list = BrowserList::GetInstance(HOST_DESKTOP_TYPE_ASH);
@@ -373,66 +399,41 @@ void MultiUserWindowManagerChromeOS::AddUser(Profile* profile) {
   }
 }
 
+void MultiUserWindowManagerChromeOS::AddObserver(Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void MultiUserWindowManagerChromeOS::RemoveObserver(Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void MultiUserWindowManagerChromeOS::ActiveUserChanged(
     const std::string& user_id) {
   DCHECK(user_id != current_user_id_);
-  std::string old_user = current_user_id_;
   current_user_id_ = user_id;
-  // Disable the window position manager and the MRU window tracker temporarily.
-  scoped_ptr<UserChangeActionDisabler> disabler(new UserChangeActionDisabler);
-
-  // We need to show/hide the windows in the same order as they were created in
-  // their parent window(s) to keep the layer / window hierarchy in sync. To
-  // achieve that we first collect all parent windows and then enumerate all
-  // windows in those parent windows and show or hide them accordingly.
-
-  // Create a list of all parent windows we have to check and their parents.
-  std::set<aura::Window*> parent_list;
-  for (WindowToEntryMap::iterator it = window_to_entry_.begin();
-       it != window_to_entry_.end(); ++it) {
-    aura::Window* parent = it->first->parent();
-    if (parent_list.find(parent) == parent_list.end())
-      parent_list.insert(parent);
-  }
-
-  // Traverse the found parent windows to handle their child windows in order of
-  // their appearance.
-  for (std::set<aura::Window*>::iterator it_parents = parent_list.begin();
-       it_parents != parent_list.end(); ++it_parents) {
-    const aura::Window::Windows window_list = (*it_parents)->children();
-    for (aura::Window::Windows::const_iterator it_window = window_list.begin();
-         it_window != window_list.end(); ++it_window) {
-      aura::Window* window = *it_window;
-      WindowToEntryMap::iterator it_map = window_to_entry_.find(window);
-      if (it_map != window_to_entry_.end()) {
-        bool should_be_visible = it_map->second->show_for_user() == user_id &&
-                                 it_map->second->show();
-        bool is_visible = window->IsVisible();
-        if (should_be_visible != is_visible)
-          SetWindowVisibility(window, should_be_visible);
-      }
-    }
-  }
-
-  // Finally we need to restore the previously active window.
-  ash::MruWindowTracker::WindowList mru_list =
-      ash::Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
-  if (mru_list.size()) {
-    aura::Window* window = mru_list[0];
-    ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
-    if (IsWindowOnDesktopOfUser(window, user_id) &&
-        !window_state->IsMinimized()) {
-      aura::client::ActivationClient* client =
-          aura::client::GetActivationClient(window->GetRootWindow());
-      // Several unit tests come here without an activation client.
-      if (client)
-        client->ActivateWindow(window);
-    }
+  // If there is an animation in progress finish the pending switch which also
+  // kills the timer (if there is one).
+  if (user_changed_animation_timer_.get())
+    TransitionUser(SHOW_NEW_USER);
+
+  // Start the animation by hiding the old user.
+  TransitionUser(HIDE_OLD_USER);
+
+  // If animations are disabled we immediately switch to the new user, otherwise
+  // we create a timer which will fade in the new user once the other user has
+  // been faded away.
+  if (animations_disabled_) {
+    TransitionUser(SHOW_NEW_USER);
+  } else {
+    user_changed_animation_timer_.reset(new base::Timer(
+        FROM_HERE,
+        base::TimeDelta::FromMilliseconds(kUserFadeTimeMS),
+        base::Bind(&MultiUserWindowManagerChromeOS::TransitionUser,
+                   base::Unretained(this),
+                   SHOW_NEW_USER),
+        false));
+    user_changed_animation_timer_->Reset();
   }
-
-  // This is called directly here to make sure notification_blocker will see the
-  // new window status.
-  notification_blocker_->ActiveUserChanged(user_id);
 }
 
 void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) {
@@ -442,13 +443,13 @@ void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) {
     RemoveTransientOwnerRecursive(window);
     return;
   }
-  ash::wm::GetWindowState(window)->RemoveObserver(this);
   views::corewm::TransientWindowManager::Get(window)->RemoveObserver(this);
   // Remove the window from the owners list.
   delete window_to_entry_[window];
   window_to_entry_.erase(window);
-  // TODO(skuhne): replace this by observer when another one needs this event.
-  notification_blocker_->UpdateWindowOwners();
+
+  // Notify entry change.
+  FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryRemoved(window));
 }
 
 void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanging(
@@ -482,13 +483,13 @@ void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanged(
 
   // Don't allow to make the window visible if it shouldn't be.
   if (visible && !IsWindowOnDesktopOfUser(window, current_user_id_)) {
-    SetWindowVisibility(window, false);
+    SetWindowVisibility(window, false, 0);
     return;
   }
   aura::Window* owned_parent = GetOwningWindowInTransientChain(window);
   if (owned_parent && owned_parent != window && visible &&
       !IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
-    SetWindowVisibility(window, false);
+    SetWindowVisibility(window, false, 0);
 }
 
 void MultiUserWindowManagerChromeOS::OnTransientChildAdded(
@@ -516,19 +517,6 @@ void MultiUserWindowManagerChromeOS::OnTransientChildRemoved(
     RemoveTransientOwnerRecursive(transient_window);
 }
 
-void MultiUserWindowManagerChromeOS::OnWindowShowTypeChanged(
-    ash::wm::WindowState* window_state,
-    ash::wm::WindowShowType old_type) {
-  if (!window_state->IsMinimized())
-    return;
-
-  aura::Window* window = window_state->window();
-  // If the window was shown on a different users desktop: move it back.
-  const std::string& owner = GetWindowOwner(window);
-  if (!IsWindowOnDesktopOfUser(window, owner))
-    ShowWindowForUser(window, owner);
-}
-
 void MultiUserWindowManagerChromeOS::Observe(
     int type,
     const content::NotificationSource& source,
@@ -537,6 +525,196 @@ void MultiUserWindowManagerChromeOS::Observe(
     AddBrowserWindow(content::Source<Browser>(source).ptr());
 }
 
+void MultiUserWindowManagerChromeOS::SetAnimationsForTest(bool disable) {
+  animations_disabled_ = disable;
+}
+
+bool MultiUserWindowManagerChromeOS::IsAnimationRunningForTest() {
+  return user_changed_animation_timer_.get() != NULL;
+}
+
+const std::string& MultiUserWindowManagerChromeOS::GetCurrentUserForTest() {
+  return current_user_id_;
+}
+
+bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern(
+    aura::Window* window,
+    const std::string& user_id) {
+  // If there is either no owner, or the owner is the current user, no action
+  // is required.
+  const std::string& owner = GetWindowOwner(window);
+  if (owner.empty() ||
+      (owner == user_id && IsWindowOnDesktopOfUser(window, user_id)))
+    return false;
+
+  bool minimized = ash::wm::GetWindowState(window)->IsMinimized();
+  // Check that we are not trying to transfer ownership of a minimized window.
+  if (user_id != owner && minimized)
+    return false;
+
+  if (minimized) {
+    // If it is minimized it falls back to the original desktop.
+    ash::MultiProfileUMA::RecordTeleportAction(
+        ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_MINIMIZE);
+  } else {
+    // If the window was transferred without getting minimized, we should record
+    // the window type.
+    RecordUMAForTransferredWindowType(window);
+  }
+
+  WindowToEntryMap::iterator it = window_to_entry_.find(window);
+  it->second->set_show_for_user(user_id);
+
+  // Show the window if the added user is the current one.
+  if (user_id == current_user_id_) {
+    // Only show the window if it should be shown according to its state.
+    if (it->second->show())
+      SetWindowVisibility(window, true, kTeleportAnimationTimeMS);
+  } else {
+    SetWindowVisibility(window, false, kTeleportAnimationTimeMS);
+  }
+
+  // Notify entry change.
+  FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryChanged(window));
+  return true;
+}
+
+void MultiUserWindowManagerChromeOS::TransitionUser(
+    MultiUserWindowManagerChromeOS::AnimationStep animation_step) {
+  TransitionWallpaper(animation_step);
+  TransitionUserShelf(animation_step);
+
+  // Disable the window position manager and the MRU window tracker temporarily.
+  scoped_ptr<UserChangeActionDisabler> disabler(new UserChangeActionDisabler);
+
+  // We need to show/hide the windows in the same order as they were created in
+  // their parent window(s) to keep the layer / window hierarchy in sync. To
+  // achieve that we first collect all parent windows and then enumerate all
+  // windows in those parent windows and show or hide them accordingly.
+
+  // Create a list of all parent windows we have to check and their parents.
+  std::set<aura::Window*> parent_list;
+  for (WindowToEntryMap::iterator it = window_to_entry_.begin();
+       it != window_to_entry_.end(); ++it) {
+    aura::Window* parent = it->first->parent();
+    if (parent_list.find(parent) == parent_list.end())
+      parent_list.insert(parent);
+  }
+
+  // Traverse the found parent windows to handle their child windows in order of
+  // their appearance.
+  for (std::set<aura::Window*>::iterator it_parents = parent_list.begin();
+       it_parents != parent_list.end(); ++it_parents) {
+    const aura::Window::Windows window_list = (*it_parents)->children();
+    for (aura::Window::Windows::const_iterator it_window = window_list.begin();
+         it_window != window_list.end(); ++it_window) {
+      aura::Window* window = *it_window;
+      WindowToEntryMap::iterator it_map = window_to_entry_.find(window);
+      if (it_map != window_to_entry_.end()) {
+        bool should_be_visible =
+            it_map->second->show_for_user() == current_user_id_ &&
+            it_map->second->show();
+        bool is_visible = window->IsVisible();
+        ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
+        if (animation_step == SHOW_NEW_USER &&
+            it_map->second->owner() == current_user_id_ &&
+            it_map->second->show_for_user() != current_user_id_ &&
+            window_state->IsMinimized()) {
+          // Pull back minimized visiting windows to the owners desktop.
+          ShowWindowForUserIntern(window, current_user_id_);
+          window_state->Unminimize();
+        } else if (should_be_visible != is_visible &&
+                   should_be_visible == (animation_step == SHOW_NEW_USER)) {
+          SetWindowVisibility(window, should_be_visible, kUserFadeTimeMS);
+        }
+      }
+    }
+  }
+
+  // Activation and real switch are happening after the other user gets shown.
+  if (animation_step == SHOW_NEW_USER) {
+    // Finally we need to restore the previously active window.
+    ash::MruWindowTracker::WindowList mru_list =
+        ash::Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
+    if (mru_list.size()) {
+      aura::Window* window = mru_list[0];
+      ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
+      if (IsWindowOnDesktopOfUser(window, current_user_id_) &&
+          !window_state->IsMinimized()) {
+        aura::client::ActivationClient* client =
+            aura::client::GetActivationClient(window->GetRootWindow());
+        // Several unit tests come here without an activation client.
+        if (client)
+          client->ActivateWindow(window);
+      }
+    }
+
+    // This is called directly here to make sure notification_blocker will see
+    // the new window status.
+    notification_blocker_->ActiveUserChanged(current_user_id_);
+
+    // We can reset the timer at this point.
+    // Note: The timer can be destroyed while it is performing its task.
+    user_changed_animation_timer_.reset();
+  }
+}
+
+void MultiUserWindowManagerChromeOS::TransitionWallpaper(
+    MultiUserWindowManagerChromeOS::AnimationStep animation_step) {
+  // Handle the wallpaper switch.
+  if (chromeos::WallpaperManager::Get()) {
+    ash::UserWallpaperDelegate* wallpaper_delegate =
+        ash::Shell::GetInstance()->user_wallpaper_delegate();
+    if (animation_step == HIDE_OLD_USER) {
+      // Set the wallpaper cross dissolve animation duration to our complete
+      // animation cycle for a fade in and fade out.
+      wallpaper_delegate->SetAnimationDurationOverride(2 * kUserFadeTimeMS);
+      chromeos::WallpaperManager::Get()->SetUserWallpaperDelayed(
+          current_user_id_);
+    } else {
+      // Revert the wallpaper cross dissolve animation duration back to the
+      // default.
+      wallpaper_delegate->SetAnimationDurationOverride(0);
+    }
+  }
+}
+
+void MultiUserWindowManagerChromeOS::TransitionUserShelf(
+    MultiUserWindowManagerChromeOS::AnimationStep animation_step) {
+  // The shelf animation duration override.
+  int duration_override = kUserFadeTimeMS;
+  // Handle the shelf order of items. This is done once the old user is hidden.
+  if (animation_step == SHOW_NEW_USER) {
+    // Some unit tests have no ChromeLauncherController.
+    if (ChromeLauncherController::instance())
+      ChromeLauncherController::instance()->ActiveUserChanged(current_user_id_);
+    // We kicked off the shelf animation in the command above. As such we can
+    // disable the override now again.
+    duration_override = 0;
+  }
+
+  if (animations_disabled_)
+    return;
+
+  ash::Shell::RootWindowControllerList controller =
+      ash::Shell::GetInstance()->GetAllRootWindowControllers();
+  for (ash::Shell::RootWindowControllerList::iterator it1 = controller.begin();
+       it1 != controller.end(); ++it1) {
+    (*it1)->GetShelfLayoutManager()->SetAnimationDurationOverride(
+        duration_override);
+  }
+
+  // For each root window hide the shelf.
+  if (animation_step == HIDE_OLD_USER) {
+    aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
+    for (aura::Window::Windows::const_iterator iter = root_windows.begin();
+         iter != root_windows.end(); ++iter) {
+      ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
+          ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN, *iter);
+    }
+  }
+}
+
 void MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser* browser) {
   // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
   // come here with no valid window.
@@ -547,7 +725,7 @@ void MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser* browser) {
 }
 
 void MultiUserWindowManagerChromeOS::SetWindowVisibility(
-    aura::Window* window, bool visible) {
+    aura::Window* window, bool visible, int animation_time_in_ms) {
   if (window->IsVisible() == visible)
     return;
 
@@ -581,26 +759,26 @@ void MultiUserWindowManagerChromeOS::SetWindowVisibility(
   base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
 
   if (visible) {
-    ShowWithTransientChildrenRecursive(window);
+    ShowWithTransientChildrenRecursive(window, animation_time_in_ms);
   } else {
     if (window->HasFocus())
       window->Blur();
-    window->Hide();
+    SetWindowVisible(window, false, animation_time_in_ms);
   }
 }
 
 void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
-    aura::Window* window) {
+    aura::Window* window, int animation_time_in_ms) {
   aura::Window::Windows::const_iterator it =
       views::corewm::GetTransientChildren(window).begin();
   for (; it != views::corewm::GetTransientChildren(window).end(); ++it)
-    ShowWithTransientChildrenRecursive(*it);
+    ShowWithTransientChildrenRecursive(*it, animation_time_in_ms);
 
   // We show all children which were not explicitly hidden.
   TransientWindowToVisibility::iterator it2 =
       transient_window_to_visibility_.find(window);
   if (it2 == transient_window_to_visibility_.end() || it2->second)
-    window->Show();
+    SetWindowVisible(window, true, animation_time_in_ms);
 }
 
 aura::Window* MultiUserWindowManagerChromeOS::GetOwningWindowInTransientChain(
@@ -642,7 +820,7 @@ void MultiUserWindowManagerChromeOS::AddTransientOwnerRecursive(
   // will hide recursively this and all children - but we have already collected
   // their initial view state.
   if (!IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
-    SetWindowVisibility(window, false);
+    SetWindowVisibility(window, false, kAnimationTimeMS);
 }
 
 void MultiUserWindowManagerChromeOS::RemoveTransientOwnerRecursive(
@@ -674,4 +852,22 @@ void MultiUserWindowManagerChromeOS::RemoveTransientOwnerRecursive(
   }
 }
 
+void MultiUserWindowManagerChromeOS::SetWindowVisible(
+    aura::Window* window,
+    bool visible,
+    int animation_time_in_ms) {
+  AnimationSetter animation_setter(
+      window,
+      animations_disabled_ ? 0 : animation_time_in_ms);
+
+  if (visible)
+    window->Show();
+  else
+    window->Hide();
+
+  // Make sure that animations have no influence on the window state after the
+  // call.
+  DCHECK_EQ(visible, window->IsVisible());
+}
+
 }  // namespace chrome