summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-28 23:21:31 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-28 23:21:31 +0000
commit5cc1b6590873a23e33a6a14ff8e992f3dba69679 (patch)
tree879aef806332971dd1349e01ad5d9de6aef1a172
parent18fe6adb58e43b891619a7e267ffe4d500f32d80 (diff)
downloadchromium_src-5cc1b6590873a23e33a6a14ff8e992f3dba69679.zip
chromium_src-5cc1b6590873a23e33a6a14ff8e992f3dba69679.tar.gz
chromium_src-5cc1b6590873a23e33a6a14ff8e992f3dba69679.tar.bz2
Creating multi profile animations for switching users and teleporting of windows.
This CL is adding window animations for the following multi profile related actions: - switching the user - teleporting of windows - window ownership changes The user switch animation is as follows: Time: -----> Screen: A X B - The desktop cross dissolves between A -> B - User A's windows fade out between A -> X - User B's windows get faded in between X -> B - User A's shelf gets hidden between A -> X - The user icon in the system tray as well as the shelf configuration changes at 'X'. - User B's shelf gets faded on between X -> B So at time X the user would see a half way cross dissolved desktop and shared windows (if there are any). Since there is no guarantee that there is an animation going from A -> X an additional timer was used to kick off the second animation portion. Further gotchas: - Animations of the individual shelf items were in the past incorrectly performed with another animator which produced a lag for some components (e.g. the activation bar lagged and / or there was a gap between icons in the tray and the screen border when playing the animation fast. - Wallpaper loading was so delayed that the animations started after all other animations were done. BUG=336639, 307279 Review URL: https://codereview.chromium.org/130983007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247517 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/default_user_wallpaper_delegate.cc8
-rw-r--r--ash/default_user_wallpaper_delegate.h3
-rw-r--r--ash/desktop_background/desktop_background_view.cc6
-rw-r--r--ash/desktop_background/user_wallpaper_delegate.h7
-rw-r--r--ash/shelf/shelf_layout_manager.cc14
-rw-r--r--ash/shelf/shelf_layout_manager.h7
-rw-r--r--ash/shelf/shelf_view.cc28
-rw-r--r--ash/system/tray/default_system_tray_delegate.cc3
-rw-r--r--ash/system/tray/default_system_tray_delegate.h1
-rw-r--r--ash/system/tray/system_tray_delegate.h5
-rw-r--r--chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc16
-rw-r--r--chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc2
-rw-r--r--chrome/browser/chromeos/login/wallpaper_manager.cc15
-rw-r--r--chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc20
-rw-r--r--chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc2
-rw-r--r--chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc313
-rw-r--r--chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h47
-rw-r--r--chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc46
-rw-r--r--chrome/browser/ui/ash/system_tray_delegate_chromeos.cc8
-rw-r--r--chrome/browser/ui/ash/system_tray_delegate_win.cc3
-rw-r--r--chrome/browser/ui/ash/user_wallpaper_delegate_win.cc10
-rw-r--r--ui/views/animation/bounds_animator.h3
-rw-r--r--ui/views/corewm/window_animations.cc17
-rw-r--r--ui/views/corewm/window_animations.h3
24 files changed, 485 insertions, 102 deletions
diff --git a/ash/default_user_wallpaper_delegate.cc b/ash/default_user_wallpaper_delegate.cc
index 168fc9d..5caddf0 100644
--- a/ash/default_user_wallpaper_delegate.cc
+++ b/ash/default_user_wallpaper_delegate.cc
@@ -13,6 +13,14 @@ int DefaultUserWallpaperDelegate::GetAnimationType() {
return views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE;
}
+int DefaultUserWallpaperDelegate::GetAnimationDurationOverride() {
+ return 0;
+}
+
+void DefaultUserWallpaperDelegate::SetAnimationDurationOverride(
+ int animation_duration_in_ms) {
+}
+
bool DefaultUserWallpaperDelegate::ShouldShowInitialAnimation() {
return false;
}
diff --git a/ash/default_user_wallpaper_delegate.h b/ash/default_user_wallpaper_delegate.h
index 2e22e30..9978738 100644
--- a/ash/default_user_wallpaper_delegate.h
+++ b/ash/default_user_wallpaper_delegate.h
@@ -19,6 +19,9 @@ class ASH_EXPORT DefaultUserWallpaperDelegate : public UserWallpaperDelegate {
// UserWallpaperDelegate overrides:
virtual int GetAnimationType() OVERRIDE;
+ virtual int GetAnimationDurationOverride() OVERRIDE;
+ virtual void SetAnimationDurationOverride(
+ int animation_duration_in_ms) OVERRIDE;
virtual bool ShouldShowInitialAnimation() OVERRIDE;
virtual void UpdateWallpaper() OVERRIDE;
virtual void InitializeWallpaper() OVERRIDE;
diff --git a/ash/desktop_background/desktop_background_view.cc b/ash/desktop_background/desktop_background_view.cc
index 6a7bf82..acf4e3b 100644
--- a/ash/desktop_background/desktop_background_view.cc
+++ b/ash/desktop_background/desktop_background_view.cc
@@ -207,6 +207,12 @@ views::Widget* CreateDesktopBackground(aura::Window* root_window,
Shell::GetInstance()->session_state_delegate()->NumberOfLoggedInUsers()) {
views::corewm::SetWindowVisibilityAnimationTransition(
desktop_widget->GetNativeView(), views::corewm::ANIMATE_SHOW);
+ int duration_override = wallpaper_delegate->GetAnimationDurationOverride();
+ if (duration_override) {
+ views::corewm::SetWindowVisibilityAnimationDuration(
+ desktop_widget->GetNativeView(),
+ base::TimeDelta::FromMilliseconds(duration_override));
+ }
} else {
// Disable animation if transition to login screen from an empty background.
views::corewm::SetWindowVisibilityAnimationTransition(
diff --git a/ash/desktop_background/user_wallpaper_delegate.h b/ash/desktop_background/user_wallpaper_delegate.h
index 440d284..e1e7f70 100644
--- a/ash/desktop_background/user_wallpaper_delegate.h
+++ b/ash/desktop_background/user_wallpaper_delegate.h
@@ -18,6 +18,13 @@ class ASH_EXPORT UserWallpaperDelegate {
// wallpaper.
virtual int GetAnimationType() = 0;
+ // Returns the wallpaper animation duration in ms. A value of 0 indicates
+ // that the default should be used.
+ virtual int GetAnimationDurationOverride() = 0;
+
+ // Sets wallpaper animation duration in ms. Pass 0 to use the default.
+ virtual void SetAnimationDurationOverride(int animation_duration_in_ms) = 0;
+
// Should the slower initial animation be shown (as opposed to the faster
// animation that's used e.g. when switching from one user's wallpaper to
// another's on the login screen)?
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 21fb0b3..b78cc15 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -207,7 +207,8 @@ ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf)
gesture_drag_status_(GESTURE_DRAG_NONE),
gesture_drag_amount_(0.f),
gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
- update_shelf_observer_(NULL) {
+ update_shelf_observer_(NULL),
+ duration_override_in_ms_(0) {
Shell::GetInstance()->AddShellObserver(this);
Shell::GetInstance()->lock_state_controller()->AddObserver(this);
aura::client::GetActivationClient(root_window_)->AddObserver(this);
@@ -498,6 +499,11 @@ void ShelfLayoutManager::CancelGestureDrag() {
gesture_drag_status_ = GESTURE_DRAG_NONE;
}
+void ShelfLayoutManager::SetAnimationDurationOverride(
+ int duration_override_in_ms) {
+ duration_override_in_ms_ = duration_override_in_ms;
+}
+
////////////////////////////////////////////////////////////////////////////////
// ShelfLayoutManager, aura::LayoutManager implementation:
@@ -660,13 +666,15 @@ void ShelfLayoutManager::UpdateBoundsAndOpacity(
ui::ScopedLayerAnimationSettings status_animation_setter(
GetLayer(shelf_->status_area_widget())->GetAnimator());
if (animate) {
+ int duration = duration_override_in_ms_ ? duration_override_in_ms_ :
+ kCrossFadeDurationMS;
shelf_animation_setter.SetTransitionDuration(
- base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
+ base::TimeDelta::FromMilliseconds(duration));
shelf_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
shelf_animation_setter.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
status_animation_setter.SetTransitionDuration(
- base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
+ base::TimeDelta::FromMilliseconds(duration));
status_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
status_animation_setter.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 18d6ba4..7a96c3a 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -167,6 +167,10 @@ class ASH_EXPORT ShelfLayoutManager :
void CompleteGestureDrag(const ui::GestureEvent& gesture);
void CancelGestureDrag();
+ // Set an animation duration override for the show / hide animation of the
+ // shelf. Specifying 0 leads to use the default.
+ void SetAnimationDurationOverride(int duration_override_in_ms);
+
// Overridden from aura::LayoutManager:
virtual void OnWindowResized() OVERRIDE;
virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
@@ -408,6 +412,9 @@ class ASH_EXPORT ShelfLayoutManager :
// The bounds of the dock.
gfx::Rect dock_bounds_;
+ // The show hide animation duration override or 0 for default.
+ int duration_override_in_ms_;
+
DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManager);
};
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index f3d840e..5796796 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -121,6 +121,28 @@ const float kDraggedImageOpacity = 0.5f;
namespace {
+// A class to temporarily disable a given bounds animator.
+class BoundsAnimatorDisabler {
+ public:
+ BoundsAnimatorDisabler(views::BoundsAnimator* bounds_animator)
+ : old_duration_(bounds_animator->GetAnimationDuration()),
+ bounds_animator_(bounds_animator) {
+ bounds_animator_->SetAnimationDuration(1);
+ }
+
+ ~BoundsAnimatorDisabler() {
+ bounds_animator_->SetAnimationDuration(old_duration_);
+ }
+
+ private:
+ // The previous animation duration.
+ int old_duration_;
+ // The bounds animator which gets used.
+ views::BoundsAnimator* bounds_animator_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoundsAnimatorDisabler);
+};
+
// The MenuModelAdapter gets slightly changed to adapt the menu appearance to
// our requirements.
class ShelfMenuModelAdapter : public views::MenuModelAdapter {
@@ -1490,6 +1512,12 @@ gfx::Size ShelfView::GetPreferredSize() {
}
void ShelfView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ // This bounds change is produced by the shelf movement and all content has
+ // to follow. Using an animation at that time would produce a time lag since
+ // the animation of the BoundsAnimator has itself a delay before it arrives
+ // at the required location. As such we tell the animator to go there
+ // immediately.
+ BoundsAnimatorDisabler disabler(bounds_animator_.get());
LayoutToIdealBounds();
FOR_EACH_OBSERVER(ShelfIconObserver, observers_,
OnShelfIconPositionsChanged());
diff --git a/ash/system/tray/default_system_tray_delegate.cc b/ash/system/tray/default_system_tray_delegate.cc
index ef51585d..382cbbc 100644
--- a/ash/system/tray/default_system_tray_delegate.cc
+++ b/ash/system/tray/default_system_tray_delegate.cc
@@ -276,4 +276,7 @@ int DefaultSystemTrayDelegate::GetSystemTrayMenuWidth() {
return 300;
}
+void DefaultSystemTrayDelegate::ActiveUserWasChanged() {
+}
+
} // namespace ash
diff --git a/ash/system/tray/default_system_tray_delegate.h b/ash/system/tray/default_system_tray_delegate.h
index f85b6ca..ee51893 100644
--- a/ash/system/tray/default_system_tray_delegate.h
+++ b/ash/system/tray/default_system_tray_delegate.h
@@ -88,6 +88,7 @@ class ASH_EXPORT DefaultSystemTrayDelegate : public SystemTrayDelegate {
virtual bool GetSessionLengthLimit(
base::TimeDelta* session_length_limit) OVERRIDE;
virtual int GetSystemTrayMenuWidth() OVERRIDE;
+ virtual void ActiveUserWasChanged() OVERRIDE;
private:
bool bluetooth_enabled_;
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index ee325dd..d12d764 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -314,6 +314,11 @@ class ASH_EXPORT SystemTrayDelegate {
// Get the system tray menu size in pixels (dependent on the language).
virtual int GetSystemTrayMenuWidth() = 0;
+
+ // The active user has been changed. This will be called when the UI is ready
+ // to be switched to the new user.
+ // Note: This will happen after SessionStateObserver::ActiveUserChanged fires.
+ virtual void ActiveUserWasChanged() = 0;
};
} // namespace ash
diff --git a/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc b/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc
index f931995..a4dcf449 100644
--- a/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc
+++ b/chrome/browser/chromeos/background/ash_user_wallpaper_delegate.cc
@@ -40,7 +40,9 @@ bool IsNormalWallpaperChange() {
class UserWallpaperDelegate : public ash::UserWallpaperDelegate {
public:
- UserWallpaperDelegate() : boot_animation_finished_(false) {
+ UserWallpaperDelegate()
+ : boot_animation_finished_(false),
+ animation_duration_override_in_ms_(0) {
}
virtual ~UserWallpaperDelegate() {
@@ -52,6 +54,15 @@ class UserWallpaperDelegate : public ash::UserWallpaperDelegate {
static_cast<int>(views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
}
+ virtual int GetAnimationDurationOverride() OVERRIDE {
+ return animation_duration_override_in_ms_;
+ }
+
+ virtual void SetAnimationDurationOverride(
+ int animation_duration_in_ms) OVERRIDE {
+ animation_duration_override_in_ms_ = animation_duration_in_ms;
+ }
+
virtual bool ShouldShowInitialAnimation() OVERRIDE {
if (IsNormalWallpaperChange() || boot_animation_finished_)
return false;
@@ -103,6 +114,9 @@ class UserWallpaperDelegate : public ash::UserWallpaperDelegate {
private:
bool boot_animation_finished_;
+ // The animation duration to show a new wallpaper if an animation is required.
+ int animation_duration_override_in_ms_;
+
DISALLOW_COPY_AND_ASSIGN(UserWallpaperDelegate);
};
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
index 1c88859..0ba13b7 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
@@ -229,6 +229,8 @@ void WallpaperPrivateApiMultiUserUnittest::SetUpMultiUserWindowManager(
new chrome::MultiUserWindowManagerChromeOS(active_user_id);
chrome::MultiUserWindowManager::SetInstanceForTest(
multi_user_window_manager_, mode);
+ // We do not want animations while the test is going on.
+ multi_user_window_manager_->SetAnimationsForTest(true);
EXPECT_TRUE(multi_user_window_manager_);
}
diff --git a/chrome/browser/chromeos/login/wallpaper_manager.cc b/chrome/browser/chromeos/login/wallpaper_manager.cc
index 1758d29..12394ad 100644
--- a/chrome/browser/chromeos/login/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/wallpaper_manager.cc
@@ -702,6 +702,9 @@ void WallpaperManager::SetUserWallpaperNow(const std::string& email) {
void WallpaperManager::ScheduleSetUserWallpaper(const std::string& email,
bool delayed) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Some unit tests come here without a UserManager.
+ if (!UserManager::IsInitialized())
+ return;
// There is no visible background in kiosk mode.
if (UserManager::Get()->IsLoggedInAsKioskApp())
return;
@@ -1033,7 +1036,9 @@ bool WallpaperManager::GetUserWallpaperInfo(const std::string& email,
WallpaperInfo* info){
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(email)) {
+ // Some unit tests come here with no browser local state attached.
+ if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(email) ||
+ !g_browser_process->local_state()) {
// Default to the values cached in memory.
*info = current_user_wallpaper_info_;
@@ -1193,10 +1198,12 @@ void WallpaperManager::OnWallpaperDecoded(
return;
}
- // Only cache user wallpaper at login screen.
- if (!UserManager::Get()->IsUserLoggedIn()) {
- wallpaper_cache_.insert(std::make_pair(email, wallpaper.image()));
+ // Only cache the user wallpaper at login screen and for multi profile users.
+ if (!UserManager::Get()->IsUserLoggedIn() ||
+ (UserManager::Get()->GetLoggedInUsers().size() > 1)) {
+ wallpaper_cache_[email] = wallpaper.image();
}
+
if (update_wallpaper) {
ash::Shell::GetInstance()->desktop_background_controller()->
SetCustomWallpaper(wallpaper.image(), layout);
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index c238e02..783533f 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -16,6 +16,7 @@
#include "ash/shelf/shelf_model.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
+#include "ash/system/tray/system_tray_delegate.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "base/prefs/scoped_user_pref_update.h"
@@ -87,7 +88,6 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/user_manager.h"
-#include "chrome/browser/chromeos/login/wallpaper_manager.h"
#include "chrome/browser/ui/ash/chrome_shell_delegate.h"
#include "chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h"
#include "chrome/browser/ui/ash/launcher/multi_profile_shell_window_launcher_controller.h"
@@ -243,7 +243,6 @@ class ChromeLauncherControllerUserSwitchObserverChromeOS
}
// chromeos::UserManager::UserSessionStateObserver overrides:
- virtual void ActiveUserChanged(const chromeos::User* active_user) OVERRIDE;
virtual void UserAddedToSession(const chromeos::User* added_user) OVERRIDE;
// content::NotificationObserver overrides:
@@ -269,17 +268,6 @@ class ChromeLauncherControllerUserSwitchObserverChromeOS
DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerUserSwitchObserverChromeOS);
};
-void ChromeLauncherControllerUserSwitchObserverChromeOS::ActiveUserChanged(
- const chromeos::User* active_user) {
- const std::string& user_email = active_user->email();
- // Forward the OS specific event to the ChromeLauncherController.
- controller_->ActiveUserChanged(user_email);
- // TODO(skuhne): At the moment the login screen does the wallpaper management
- // and wallpapers are not synchronized across multiple desktops.
- if (chromeos::WallpaperManager::Get())
- chromeos::WallpaperManager::Get()->SetUserWallpaperDelayed(user_email);
-}
-
void ChromeLauncherControllerUserSwitchObserverChromeOS::UserAddedToSession(
const chromeos::User* active_user) {
Profile* profile = multi_user_util::GetProfileFromUserID(
@@ -1167,6 +1155,8 @@ void ChromeLauncherController::ActiveUserChanged(
// Restore the order of running, but unpinned applications for the activated
// user.
RestoreUnpinnedRunningApplicationOrder(user_email);
+ // Inform the system tray of the change.
+ ash::Shell::GetInstance()->system_tray_delegate()->ActiveUserWasChanged();
}
void ChromeLauncherController::AdditionalUserAddedToSession(Profile* profile) {
@@ -1690,8 +1680,8 @@ void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs(
break;
case ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
// This one should not be a valid preference option for now. We only want
- // to completely hide it when we run app mode.
- NOTREACHED();
+ // to completely hide it when we run in app mode - or while we temporarily
+ // hide the shelf as part of an animation (e.g. the multi user change).
return;
}
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
index 03809e0..31c5692 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -37,6 +37,8 @@ class MultiUserNotificationBlockerChromeOSTest
shell_delegate->set_multi_profiles_enabled(true);
chrome::MultiUserWindowManager::CreateInstance();
+ // Disable any animations for the test.
+ GetMultiUserWindowManager()->SetAnimationsForTest(true);
GetMultiUserWindowManager()->notification_blocker_->AddObserver(this);
}
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index 7529473..7f30397 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -7,8 +7,12 @@
#include "apps/shell_window.h"
#include "apps/shell_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"
@@ -21,8 +25,10 @@
#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"
@@ -39,10 +45,22 @@
#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) {
@@ -132,6 +150,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:
@@ -182,7 +238,8 @@ MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
: current_user_id_(current_user_id),
notification_blocker_(new MultiUserNotificationBlockerChromeOS(
message_center::MessageCenter::Get(), this)),
- suppress_visibility_changes_(false) {
+ 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()->
@@ -260,7 +317,7 @@ void MultiUserWindowManagerChromeOS::SetWindowOwner(
notification_blocker_->UpdateWindowOwners();
if (!IsWindowOnDesktopOfUser(window, current_user_id_))
- SetWindowVisibility(window, false);
+ SetWindowVisibility(window, false, 0);
}
const std::string& MultiUserWindowManagerChromeOS::GetWindowOwner(
@@ -302,9 +359,9 @@ void MultiUserWindowManagerChromeOS::ShowWindowForUser(
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);
+ SetWindowVisibility(window, true, kTeleportAnimationTimeMS);
} else {
- SetWindowVisibility(window, false);
+ SetWindowVisibility(window, false, kTeleportAnimationTimeMS);
}
// TODO(skuhne): replace this by observer when another one needs this event.
@@ -376,63 +433,30 @@ void MultiUserWindowManagerChromeOS::AddUser(Profile* profile) {
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) {
@@ -482,13 +506,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(
@@ -537,6 +561,141 @@ 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;
+}
+
+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();
+ 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 +706,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 +740,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 +801,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 +833,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
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h
index 23ac686..7f004b2 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h
@@ -12,6 +12,7 @@
#include "ash/wm/window_state_observer.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
+#include "base/timer/timer.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -98,6 +99,12 @@ class MultiUserWindowManagerChromeOS
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
+ // Disable any animations for unit tests.
+ void SetAnimationsForTest(bool disable);
+
+ // Returns true when a user switch animation is running. For unit tests.
+ bool IsAnimationRunningForTest();
+
private:
friend class ::MultiUserNotificationBlockerChromeOSTest;
@@ -144,6 +151,24 @@ class MultiUserWindowManagerChromeOS
typedef std::map<std::string, AppObserver*> UserIDToShellWindowObserver;
typedef std::map<aura::Window*, bool> TransientWindowToVisibility;
+ // The animation step for the user change animation. First the old user gets
+ // hidden and then the new one gets presented.
+ enum AnimationStep {
+ HIDE_OLD_USER,
+ SHOW_NEW_USER
+ };
+
+ // Start the user change animation required for |animation_step|.
+ // Note that a call with SHOW_NEW_USER will finalize the animation and kill
+ // the timer (if there is one).
+ void TransitionUser(AnimationStep animtion_step);
+
+ // Start the user wallpaper animations.
+ void TransitionWallpaper(AnimationStep animtion_step);
+
+ // Start the user shelf animations.
+ void TransitionUserShelf(AnimationStep animtion_step);
+
// Add a browser window to the system so that the owner can be remembered.
void AddBrowserWindow(Browser* browser);
@@ -152,11 +177,17 @@ class MultiUserWindowManagerChromeOS
// distinguish state changes performed by this class vs. state changes
// performed by the others. Note furthermore that system modal dialogs will
// not get hidden. We will switch instead to the owners desktop.
- void SetWindowVisibility(aura::Window* window, bool visible);
+ // The |animation_time_in_ms| is the time the animation should take. Set to 0
+ // if it should get set instantly.
+ void SetWindowVisibility(aura::Window* window,
+ bool visible,
+ int animation_time_in_ms);
// Show the window and its transient children. However - if a transient child
// was turned invisible by some other operation, it will stay invisible.
- void ShowWithTransientChildrenRecursive(aura::Window* window);
+ // Use the given |animation_time_in_ms| for transitioning.
+ void ShowWithTransientChildrenRecursive(aura::Window* window,
+ int animation_time_in_ms);
// Find the first owned window in the chain.
// Returns NULL when the window itself is owned.
@@ -172,6 +203,11 @@ class MultiUserWindowManagerChromeOS
// unregistered.
void RemoveTransientOwnerRecursive(aura::Window* window);
+ // Animate a |window| to be |visible| in |animation_time_in_ms|.
+ void SetWindowVisible(aura::Window* window,
+ bool visible,
+ int aimation_time_in_ms);
+
// A lookup to see to which user the given window belongs to, where and if it
// should get shown.
WindowToEntryMap window_to_entry_;
@@ -201,6 +237,13 @@ class MultiUserWindowManagerChromeOS
// used is quite expensive.
static MultiProfileMode multi_user_mode_;
+ // A timer which watches to executes the second part of a "user changed"
+ // animation. Note that this timer exists only during such an animation.
+ scoped_ptr<base::Timer> user_changed_animation_timer_;
+
+ // If true, all animations will be suppressed.
+ bool animations_disabled_;
+
DISALLOW_COPY_AND_ASSIGN(MultiUserWindowManagerChromeOS);
};
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index dd48b960..207905e 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -12,6 +12,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
+#include "base/time/time.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
#include "chrome/common/chrome_switches.h"
@@ -40,6 +41,17 @@ class MultiUserWindowManagerChromeOSTest : public AshTestBase {
// Set up the test environment for this many windows.
void SetUpForThisManyWindows(int windows);
+ // Switch the user and wait until the animation is finished.
+ void SwitchUserAndWaitForAnimation(const std::string& user_id) {
+ multi_user_window_manager_->ActiveUserChanged(user_id);
+ base::TimeTicks now = base::TimeTicks::Now();
+ while (multi_user_window_manager_->IsAnimationRunningForTest()) {
+ // This should never take longer then a second.
+ ASSERT_GE(1000, (base::TimeTicks::Now() - now).InMilliseconds());
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+ }
+
// Return the window with the given index.
aura::Window* window(size_t index) {
DCHECK(index < window_.size());
@@ -107,6 +119,7 @@ void MultiUserWindowManagerChromeOSTest::SetUpForThisManyWindows(int windows) {
window_[i]->Show();
}
multi_user_window_manager_ = new chrome::MultiUserWindowManagerChromeOS("A");
+ multi_user_window_manager_->SetAnimationsForTest(true);
chrome::MultiUserWindowManager::SetInstanceForTest(multi_user_window_manager_,
chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
EXPECT_TRUE(multi_user_window_manager_);
@@ -644,5 +657,38 @@ TEST_F(MultiUserWindowManagerChromeOSTest,
EXPECT_EQ("b", session_state_delegate()->get_activated_user());
}
+// Test that using the full user switch animations are working as expected.
+TEST_F(MultiUserWindowManagerChromeOSTest, FullUserSwitchAnimationTests) {
+ SetUpForThisManyWindows(3);
+ // Turn the use of delays and animation on.
+ multi_user_window_manager()->SetAnimationsForTest(false);
+ // Set some owners and make sure we got what we asked for.
+ multi_user_window_manager()->SetWindowOwner(window(0), "A");
+ multi_user_window_manager()->SetWindowOwner(window(1), "B");
+ multi_user_window_manager()->SetWindowOwner(window(2), "C");
+ EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
+ EXPECT_EQ("A", GetOwnersOfVisibleWindowsAsString());
+
+ // Switch the user fore and back and see that the results are correct.
+ SwitchUserAndWaitForAnimation("B");
+
+ EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
+ EXPECT_EQ("B", GetOwnersOfVisibleWindowsAsString());
+
+ SwitchUserAndWaitForAnimation("A");
+
+ EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
+
+ // Switch the user quickly to another user and before the animation is done
+ // switch back and see that this works.
+ multi_user_window_manager()->ActiveUserChanged("B");
+ // Check that at this time we have nothing visible (in the middle of the
+ // animation).
+ EXPECT_EQ("H[A], H[B], H[C]", GetStatus());
+ // Check that after switching to C, C is fully visible.
+ SwitchUserAndWaitForAnimation("C");
+ EXPECT_EQ("H[A], H[B], S[C]", GetStatus());
+}
+
} // namespace test
} // namespace ash
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 80d59a2..ebdc893 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -903,6 +903,10 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
}
+ virtual void ActiveUserWasChanged() OVERRIDE {
+ GetSystemTrayNotifier()->NotifyUserUpdate();
+ }
+
private:
ash::SystemTray* GetPrimarySystemTray() {
return ash::Shell::GetInstance()->GetPrimarySystemTray();
@@ -1299,10 +1303,6 @@ class SystemTrayDelegate : public ash::SystemTrayDelegate,
}
// Overridden from ash::SessionStateObserver
- virtual void ActiveUserChanged(const std::string& user_id) OVERRIDE {
- GetSystemTrayNotifier()->NotifyUserUpdate();
- }
-
virtual void UserAddedToSession(const std::string& user_id) OVERRIDE {
GetSystemTrayNotifier()->NotifyUserAddedToSession();
}
diff --git a/chrome/browser/ui/ash/system_tray_delegate_win.cc b/chrome/browser/ui/ash/system_tray_delegate_win.cc
index eba5603..a8b8e4e 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_win.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_win.cc
@@ -273,6 +273,9 @@ class SystemTrayDelegateWin : public ash::SystemTrayDelegate,
IDS_SYSTEM_TRAY_MENU_BUBBLE_WIDTH_PIXELS);
}
+ virtual void ActiveUserWasChanged() OVERRIDE {
+ }
+
private:
ash::SystemTrayNotifier* GetSystemTrayNotifier() {
return ash::Shell::GetInstance()->system_tray_notifier();
diff --git a/chrome/browser/ui/ash/user_wallpaper_delegate_win.cc b/chrome/browser/ui/ash/user_wallpaper_delegate_win.cc
index 6c1a2ae..6a83c60 100644
--- a/chrome/browser/ui/ash/user_wallpaper_delegate_win.cc
+++ b/chrome/browser/ui/ash/user_wallpaper_delegate_win.cc
@@ -34,6 +34,16 @@ class UserWallpaperDelegate : public ash::UserWallpaperDelegate {
return true;
}
+ virtual int GetAnimationDurationOverride() OVERRIDE {
+ // Return 0 to select the default.
+ return 0;
+ }
+
+ virtual void SetAnimationDurationOverride(
+ int animation_duration_in_ms) OVERRIDE {
+ NOTIMPLEMENTED();
+ }
+
virtual void UpdateWallpaper() OVERRIDE {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
diff --git a/ui/views/animation/bounds_animator.h b/ui/views/animation/bounds_animator.h
index 1688dd5..d846b20 100644
--- a/ui/views/animation/bounds_animator.h
+++ b/ui/views/animation/bounds_animator.h
@@ -95,6 +95,9 @@ class VIEWS_EXPORT BoundsAnimator : public gfx::AnimationDelegate,
// milliseconds.
void SetAnimationDuration(int duration_ms);
+ // Gets the currently used animation duration.
+ int GetAnimationDuration() const { return animation_duration_ms_; }
+
// Sets the tween type for new animations. Default is EASE_OUT.
void set_tween_type(gfx::Tween::Type type) { tween_type_ = type; }
diff --git a/ui/views/corewm/window_animations.cc b/ui/views/corewm/window_animations.cc
index 1f90b40..e109c76 100644
--- a/ui/views/corewm/window_animations.cc
+++ b/ui/views/corewm/window_animations.cc
@@ -84,10 +84,11 @@ const float kWindowAnimation_Bounce_Scale = 1.02f;
const int kWindowAnimation_Bounce_DurationMS = 180;
const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40;
-base::TimeDelta GetWindowVisibilityAnimationDuration(aura::Window* window) {
+base::TimeDelta GetWindowVisibilityAnimationDuration(
+ const aura::Window& window) {
int duration =
- window->GetProperty(kWindowVisibilityAnimationDurationKey);
- if (duration == 0 && window->type() == ui::wm::WINDOW_TYPE_MENU) {
+ window.GetProperty(kWindowVisibilityAnimationDurationKey);
+ if (duration == 0 && window.type() == ui::wm::WINDOW_TYPE_MENU) {
return base::TimeDelta::FromMilliseconds(
kDefaultAnimationDurationForMenuMS);
}
@@ -255,7 +256,7 @@ void AnimateShowWindowCommon(aura::Window* window,
{
// Property sets within this scope will be implicitly animated.
ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
- base::TimeDelta duration = GetWindowVisibilityAnimationDuration(window);
+ base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
if (duration.ToInternalValue() > 0)
settings.SetTransitionDuration(duration);
@@ -275,7 +276,7 @@ void AnimateHideWindowCommon(aura::Window* window,
ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
settings.AddObserver(new HidingWindowAnimationObserver(window));
- base::TimeDelta duration = GetWindowVisibilityAnimationDuration(window);
+ base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
if (duration.ToInternalValue() > 0)
settings.SetTransitionDuration(duration);
@@ -528,6 +529,12 @@ void SetWindowVisibilityAnimationDuration(aura::Window* window,
static_cast<int>(duration.ToInternalValue()));
}
+base::TimeDelta GetWindowVisibilityAnimationDuration(
+ const aura::Window& window) {
+ return base::TimeDelta::FromInternalValue(
+ window.GetProperty(kWindowVisibilityAnimationDurationKey));
+}
+
void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window,
float position) {
window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position);
diff --git a/ui/views/corewm/window_animations.h b/ui/views/corewm/window_animations.h
index 996c215..f5728e6 100644
--- a/ui/views/corewm/window_animations.h
+++ b/ui/views/corewm/window_animations.h
@@ -74,6 +74,9 @@ VIEWS_EXPORT void SetWindowVisibilityAnimationDuration(
aura::Window* window,
const base::TimeDelta& duration);
+VIEWS_EXPORT base::TimeDelta GetWindowVisibilityAnimationDuration(
+ const aura::Window& window);
+
VIEWS_EXPORT void SetWindowVisibilityAnimationVerticalPosition(
aura::Window* window,
float position);