From 5cc1b6590873a23e33a6a14ff8e992f3dba69679 Mon Sep 17 00:00:00 2001 From: "skuhne@chromium.org" Date: Tue, 28 Jan 2014 23:21:31 +0000 Subject: 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 --- ash/default_user_wallpaper_delegate.cc | 8 + ash/default_user_wallpaper_delegate.h | 3 + ash/desktop_background/desktop_background_view.cc | 6 + ash/desktop_background/user_wallpaper_delegate.h | 7 + ash/shelf/shelf_layout_manager.cc | 14 +- ash/shelf/shelf_layout_manager.h | 7 + ash/shelf/shelf_view.cc | 28 ++ ash/system/tray/default_system_tray_delegate.cc | 3 + ash/system/tray/default_system_tray_delegate.h | 1 + ash/system/tray/system_tray_delegate.h | 5 + .../background/ash_user_wallpaper_delegate.cc | 16 +- .../extensions/wallpaper_private_api_unittest.cc | 2 + chrome/browser/chromeos/login/wallpaper_manager.cc | 15 +- .../ui/ash/launcher/chrome_launcher_controller.cc | 20 +- ..._user_notification_blocker_chromeos_unittest.cc | 2 + .../multi_user_window_manager_chromeos.cc | 313 ++++++++++++++++----- .../multi_user_window_manager_chromeos.h | 47 +++- .../multi_user_window_manager_chromeos_unittest.cc | 46 +++ .../ui/ash/system_tray_delegate_chromeos.cc | 8 +- chrome/browser/ui/ash/system_tray_delegate_win.cc | 3 + .../browser/ui/ash/user_wallpaper_delegate_win.cc | 10 + ui/views/animation/bounds_animator.h | 3 + ui/views/corewm/window_animations.cc | 17 +- ui/views/corewm/window_animations.h | 3 + 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(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 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 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::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(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 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 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::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 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 UserIDToShellWindowObserver; typedef std::map 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 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(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); -- cgit v1.1