diff options
author | bruthig <bruthig@chromium.org> | 2014-09-12 16:48:06 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-12 23:53:51 +0000 |
commit | ca2e1496db635fb826949d54c72798fd56f7fcfd (patch) | |
tree | 7577d5939b474547e977e24d7e199e15c4ca50e6 | |
parent | 36f186d9260f10ab4b134987d369d0dd93f298ff (diff) | |
download | chromium_src-ca2e1496db635fb826949d54c72798fd56f7fcfd.zip chromium_src-ca2e1496db635fb826949d54c72798fd56f7fcfd.tar.gz chromium_src-ca2e1496db635fb826949d54c72798fd56f7fcfd.tar.bz2 |
- Moved screenshot shortcut handling from MaximizeModeController to PowerButtonController
- Added a command line switch to enable quick locking mode.
- Refactored SessionStateAnimator into an interface, implementation, and a test double so that all the LockStateControllerTests could be re-enabled.
- Re-enabled LockStateControllerTests.
BUG=371608, 167048, 162645
Review URL: https://codereview.chromium.org/326813004
Cr-Commit-Position: refs/heads/master@{#294696}
-rw-r--r-- | ash/ash.gyp | 4 | ||||
-rw-r--r-- | ash/ash_switches.cc | 4 | ||||
-rw-r--r-- | ash/ash_switches.h | 1 | ||||
-rw-r--r-- | ash/test/test_session_state_animator.cc | 304 | ||||
-rw-r--r-- | ash/test/test_session_state_animator.h | 166 | ||||
-rw-r--r-- | ash/wm/lock_state_controller.cc | 249 | ||||
-rw-r--r-- | ash/wm/lock_state_controller.h | 23 | ||||
-rw-r--r-- | ash/wm/lock_state_controller_unittest.cc | 611 | ||||
-rw-r--r-- | ash/wm/maximize_mode/maximize_mode_controller.cc | 46 | ||||
-rw-r--r-- | ash/wm/maximize_mode/maximize_mode_controller.h | 3 | ||||
-rw-r--r-- | ash/wm/maximize_mode/maximize_mode_controller_unittest.cc | 30 | ||||
-rw-r--r-- | ash/wm/power_button_controller.cc | 34 | ||||
-rw-r--r-- | ash/wm/power_button_controller.h | 28 | ||||
-rw-r--r-- | ash/wm/session_state_animator.cc | 574 | ||||
-rw-r--r-- | ash/wm/session_state_animator.h | 172 | ||||
-rw-r--r-- | ash/wm/session_state_animator_impl.cc | 669 | ||||
-rw-r--r-- | ash/wm/session_state_animator_impl.h | 88 | ||||
-rw-r--r-- | chrome/browser/chromeos/power/power_button_observer.cc | 7 |
18 files changed, 1831 insertions, 1182 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index 6480900..0dd433c 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -598,6 +598,8 @@ 'wm/screen_dimmer.h', 'wm/session_state_animator.cc', 'wm/session_state_animator.h', + 'wm/session_state_animator_impl.cc', + 'wm/session_state_animator_impl.h', 'wm/stacking_controller.cc', 'wm/stacking_controller.h', 'wm/status_area_layout_manager.cc', @@ -698,6 +700,8 @@ 'test/test_overlay_delegate.h', 'test/test_screenshot_delegate.cc', 'test/test_screenshot_delegate.h', + 'test/test_session_state_animator.cc', + 'test/test_session_state_animator.h', 'test/test_session_state_delegate.cc', 'test/test_session_state_delegate.h', 'test/test_shelf_delegate.cc', diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc index d37e73a..b79eae9 100644 --- a/ash/ash_switches.cc +++ b/ash/ash_switches.cc @@ -58,6 +58,10 @@ const char kAshEnableMagnifierKeyScroller[] = const char kAshDisableTextFilteringInOverviewMode[] = "ash-disable-text-filtering-in-overview-mode"; +// Enables quick, non-cancellable locking of the screen when in maximize mode. +const char kAshEnablePowerButtonQuickLock[] = + "ash-enable-power-button-quick-lock"; + // Enables software based mirroring. const char kAshEnableSoftwareMirroring[] = "ash-enable-software-mirroring"; diff --git a/ash/ash_switches.h b/ash/ash_switches.h index ad4c86c..42ba11d 100644 --- a/ash/ash_switches.h +++ b/ash/ash_switches.h @@ -30,6 +30,7 @@ ASH_EXPORT extern const char kAshDisableTouchExplorationMode[]; ASH_EXPORT extern const char kAshEnableMagnifierKeyScroller[]; #endif ASH_EXPORT extern const char kAshDisableTextFilteringInOverviewMode[]; +ASH_EXPORT extern const char kAshEnablePowerButtonQuickLock[]; ASH_EXPORT extern const char kAshEnableSoftwareMirroring[]; ASH_EXPORT extern const char kAshEnableSystemSounds[]; ASH_EXPORT extern const char kAshEnableTouchViewTesting[]; diff --git a/ash/test/test_session_state_animator.cc b/ash/test/test_session_state_animator.cc new file mode 100644 index 0000000..b1d5b47 --- /dev/null +++ b/ash/test/test_session_state_animator.cc @@ -0,0 +1,304 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/test/test_session_state_animator.h" + +#include <vector> + +#include "base/bind.h" + +namespace ash { +namespace test { + +namespace { +// A no-op callback that can be used when managing an animation that didn't +// actually have a callback given. +void DummyCallback() {} +} + +const SessionStateAnimator::Container + TestSessionStateAnimator::kAllContainers[] = { + SessionStateAnimator::DESKTOP_BACKGROUND, + SessionStateAnimator::LAUNCHER, + SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + SessionStateAnimator::LOCK_SCREEN_BACKGROUND, + SessionStateAnimator::LOCK_SCREEN_CONTAINERS, + SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS, + SessionStateAnimator::ROOT_CONTAINER + }; + +// A simple SessionStateAnimator::AnimationSequence that tracks the number of +// attached sequences. The callback will be invoked if all animations complete +// successfully. +class TestSessionStateAnimator::AnimationSequence + : public SessionStateAnimator::AnimationSequence { + public: + AnimationSequence(base::Closure callback, TestSessionStateAnimator* animator) + : SessionStateAnimator::AnimationSequence(callback), + sequence_count_(0), + sequence_aborted_(false), + animator_(animator) { + } + + virtual ~AnimationSequence() {} + + virtual void SequenceAttached() { + ++sequence_count_; + } + + // Notify the sequence that is has completed. + virtual void SequenceFinished(bool successfully) { + DCHECK_GT(sequence_count_, 0); + --sequence_count_; + sequence_aborted_ |= !successfully; + if (sequence_count_ == 0) { + if (sequence_aborted_) + OnAnimationAborted(); + else + OnAnimationCompleted(); + } + } + + // ash::SessionStateAnimator::AnimationSequence: + virtual void StartAnimation(int container_mask, + AnimationType type, + AnimationSpeed speed) OVERRIDE { + animator_->StartAnimationInSequence(container_mask, type, speed, this); + } + + private: + // Tracks the number of contained animations. + int sequence_count_; + + // True if the sequence was aborted. + bool sequence_aborted_; + + // The TestSessionAnimator that created this. Not owned. + TestSessionStateAnimator* animator_; + + DISALLOW_COPY_AND_ASSIGN(AnimationSequence); +}; + +TestSessionStateAnimator::ActiveAnimation::ActiveAnimation( + int animation_epoch, + base::TimeDelta duration, + SessionStateAnimator::Container container, + AnimationType type, + AnimationSpeed speed, + base::Closure success_callback, + base::Closure failed_callback) + : animation_epoch(animation_epoch), + remaining_duration(duration), + container(container), + type(type), + speed(speed), + success_callback(success_callback), + failed_callback(failed_callback) { +} + +TestSessionStateAnimator::ActiveAnimation::~ActiveAnimation() { +} + +TestSessionStateAnimator::TestSessionStateAnimator() + : last_animation_epoch_(0), + is_background_hidden_(false) { +} + +TestSessionStateAnimator::~TestSessionStateAnimator() { + CompleteAllAnimations(false); +} + +void TestSessionStateAnimator::ResetAnimationEpoch() { + CompleteAllAnimations(false); + last_animation_epoch_ = 0; +} + +void TestSessionStateAnimator::Advance(const base::TimeDelta& duration) { + for (ActiveAnimationsMap::iterator container_iter = + active_animations_.begin(); + container_iter != active_animations_.end(); + ++container_iter) { + AnimationList::iterator animation_iter = (*container_iter).second.begin(); + while (animation_iter != (*container_iter).second.end()) { + ActiveAnimation& active_animation = *animation_iter; + active_animation.remaining_duration -= duration; + if (active_animation.remaining_duration <= base::TimeDelta()) { + active_animation.success_callback.Run(); + animation_iter = (*container_iter).second.erase(animation_iter); + } else { + ++animation_iter; + } + } + } +} + +void TestSessionStateAnimator::CompleteAnimations(int animation_epoch, + bool completed_successfully) { + for (ActiveAnimationsMap::iterator container_iter = + active_animations_.begin(); + container_iter != active_animations_.end(); + ++container_iter) { + AnimationList::iterator animation_iter = (*container_iter).second.begin(); + while (animation_iter != (*container_iter).second.end()) { + ActiveAnimation active_animation = *animation_iter; + if (active_animation.animation_epoch <= animation_epoch) { + if (completed_successfully) + active_animation.success_callback.Run(); + else + active_animation.failed_callback.Run(); + animation_iter = (*container_iter).second.erase(animation_iter); + } else { + ++animation_iter; + } + } + } +} + +void TestSessionStateAnimator::CompleteAllAnimations( + bool completed_successfully) { + CompleteAnimations(last_animation_epoch_, completed_successfully); +} + +bool TestSessionStateAnimator::IsContainerAnimated( + SessionStateAnimator::Container container, + SessionStateAnimator::AnimationType type) const { + ActiveAnimationsMap::const_iterator container_iter = + active_animations_.find(container); + if (container_iter != active_animations_.end()) { + for (AnimationList::const_iterator animation_iter = + (*container_iter).second.begin(); + animation_iter != (*container_iter).second.end(); + ++animation_iter) { + const ActiveAnimation& active_animation = *animation_iter; + if (active_animation.type == type) + return true; + } + } + return false; +} + +bool TestSessionStateAnimator::AreContainersAnimated( + int container_mask, SessionStateAnimator::AnimationType type) const { + for (size_t i = 0; i < arraysize(kAllContainers); ++i) { + if (container_mask & kAllContainers[i] && + !IsContainerAnimated(kAllContainers[i], type)) { + return false; + } + } + return true; +} + +size_t TestSessionStateAnimator::GetAnimationCount() const { + size_t count = 0; + for (ActiveAnimationsMap::const_iterator container_iter = + active_animations_.begin(); + container_iter != active_animations_.end(); + ++container_iter) { + count += (*container_iter).second.size(); + } + return count; +} + +void TestSessionStateAnimator::StartAnimation(int container_mask, + AnimationType type, + AnimationSpeed speed) { + ++last_animation_epoch_; + for (size_t i = 0; i < arraysize(kAllContainers); ++i) { + if (container_mask & kAllContainers[i]) { + // Use a dummy no-op callback because one isn't required by the client + // but one is required when completing or aborting animations. + base::Closure callback = base::Bind(&DummyCallback); + AddAnimation(kAllContainers[i], type, speed, callback, callback); + } + } +} + +void TestSessionStateAnimator::StartAnimationWithCallback( + int container_mask, + AnimationType type, + AnimationSpeed speed, + base::Closure callback) { + ++last_animation_epoch_; + for (size_t i = 0; i < arraysize(kAllContainers); ++i) + if (container_mask & kAllContainers[i]) { + // ash::SessionStateAnimatorImpl invokes the callback whether or not the + // animation was completed successfully or not. + AddAnimation(kAllContainers[i], type, speed, callback, callback); + } +} + +ash::SessionStateAnimator::AnimationSequence* + TestSessionStateAnimator::BeginAnimationSequence(base::Closure callback) { + return new AnimationSequence(callback, this); +} + +bool TestSessionStateAnimator::IsBackgroundHidden() const { + return is_background_hidden_; +} + +void TestSessionStateAnimator::ShowBackground() { + is_background_hidden_ = false; +} + +void TestSessionStateAnimator::HideBackground() { + is_background_hidden_ = true; +} + +void TestSessionStateAnimator::StartAnimationInSequence( + int container_mask, + AnimationType type, + AnimationSpeed speed, + AnimationSequence* animation_sequence) { + ++last_animation_epoch_; + for (size_t i = 0; i < arraysize(kAllContainers); ++i) { + if (container_mask & kAllContainers[i]) { + base::Closure success_callback = + base::Bind(&AnimationSequence::SequenceFinished, + base::Unretained(animation_sequence), true); + base::Closure failed_callback = + base::Bind(&AnimationSequence::SequenceFinished, + base::Unretained(animation_sequence), false); + animation_sequence->SequenceAttached(); + AddAnimation(kAllContainers[i], type, speed, success_callback, + failed_callback); + } + } +} + +void TestSessionStateAnimator::AddAnimation( + SessionStateAnimator::Container container, + AnimationType type, + AnimationSpeed speed, + base::Closure success_callback, + base::Closure failed_callback) { + base::TimeDelta duration = GetDuration(speed); + ActiveAnimation active_animation(last_animation_epoch_, + duration, + container, + type, + speed, + success_callback, + failed_callback); + // This test double is limited to only have one animation active for a given + // container at a time. + AbortAnimation(container); + active_animations_[container].push_back(active_animation); +} + +void TestSessionStateAnimator::AbortAnimation( + SessionStateAnimator::Container container) { + ActiveAnimationsMap::iterator container_iter = + active_animations_.find(container); + if (container_iter != active_animations_.end()) { + AnimationList::iterator animation_iter = (*container_iter).second.begin(); + while (animation_iter != (*container_iter).second.end()) { + ActiveAnimation active_animation = *animation_iter; + active_animation.failed_callback.Run(); + animation_iter = (*container_iter).second.erase(animation_iter); + } + } +} + +} // namespace test +} // namespace ash diff --git a/ash/test/test_session_state_animator.h b/ash/test/test_session_state_animator.h new file mode 100644 index 0000000..d308010 --- /dev/null +++ b/ash/test/test_session_state_animator.h @@ -0,0 +1,166 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_TEST_TEST_SESSION_STATE_ANIMATOR_H_ +#define ASH_TEST_TEST_SESSION_STATE_ANIMATOR_H_ + +#include <map> +#include <vector> + +#include "ash/ash_export.h" +#include "ash/wm/session_state_animator.h" +#include "base/basictypes.h" +#include "base/time/time.h" + +namespace ash { +namespace test { + +// A SessionStateAnimator that offers control over the lifetime of active +// animations. +// NOTE: The TestSessionStateAnimator limits each +// SessionStateAnimator::Container to a single active animation at any one time. +// If a new animation is started on a container the existing one will be +// aborted. +class TestSessionStateAnimator : public SessionStateAnimator { + public: + TestSessionStateAnimator(); + virtual ~TestSessionStateAnimator(); + + int last_animation_epoch() { + return last_animation_epoch_; + } + + // Resets the current animation epoch back to 0 and aborts all currently + // active animations. + void ResetAnimationEpoch(); + + // Advances all contained animations by the specified |duration|. Any + // animations that will have completed after |duration| will have its + // callback called. + void Advance(const base::TimeDelta& duration); + + // Simulates running all of the contained animations to completion. Each + // contained AnimationSequence will have OnAnimationCompleted called if + // |completed_successfully| is true and OnAnimationAborted called if false. + void CompleteAnimations(int animation_epoch, bool completed_successfully); + + // Convenience method that calls CompleteAnimations with the last + // |animation_epoch|. In effect this will complete all animations. + // See CompleteAnimations for more documenation on |completed_succesffully|. + void CompleteAllAnimations(bool completed_successfully); + + // Returns true if there is an animation active with |type| for the given + // |container|. + bool IsContainerAnimated(SessionStateAnimator::Container container, + SessionStateAnimator::AnimationType type) const; + + // Returns true if there is an animation active with |type| for all the given + // containers specified by |container_mask|. + bool AreContainersAnimated(int container_mask, + SessionStateAnimator::AnimationType type) const; + + // Returns the number of active animations. + size_t GetAnimationCount() const; + + // ash::SessionStateAnimator: + virtual void StartAnimation(int container_mask, + AnimationType type, + AnimationSpeed speed) OVERRIDE; + virtual void StartAnimationWithCallback( + int container_mask, + AnimationType type, + AnimationSpeed speed, + base::Closure callback) OVERRIDE; + virtual AnimationSequence* BeginAnimationSequence( + base::Closure callback) OVERRIDE; + virtual bool IsBackgroundHidden() const OVERRIDE; + virtual void ShowBackground() OVERRIDE; + virtual void HideBackground() OVERRIDE; + + private: + class AnimationSequence; + friend class AnimationSequence; + + // Data structure to track the currently active animations and their + // callbacks. + struct ActiveAnimation { + ActiveAnimation( + int animation_epoch, + base::TimeDelta duration, + SessionStateAnimator::Container container, + AnimationType type, + AnimationSpeed speed, + base::Closure success_callback, + base::Closure failed_callback); + virtual ~ActiveAnimation(); + + // The time epoch that this animation was scheduled. + int animation_epoch; + + // The time remaining for this animation. + base::TimeDelta remaining_duration; + + // The container which is being animated. + SessionStateAnimator::Container container; + + // The animation type that is being done. + AnimationType type; + + // The speed at which the animation is being done. + AnimationSpeed speed; + + // The callback to be invoked upon a successful completion. + base::Closure success_callback; + + // The callback to be invoked upon an unsuccessful completion. + base::Closure failed_callback; + }; + + typedef std::vector<ActiveAnimation> AnimationList; + typedef std::map<SessionStateAnimator::Container, AnimationList> + ActiveAnimationsMap; + + // Starts an animation in the |animation_sequence| for each container + // specified by |container_mask| with the given |type| and |speed|. + virtual void StartAnimationInSequence( + int container_mask, + AnimationType type, + AnimationSpeed speed, + AnimationSequence* animation_sequence); + + // Adds a single animation to the currently active animations. If an + // animation is already active for the given |container| then it will be + // replaced by the new one. The existing animation will be aborted by calling + // OnAnimationAborted. + void AddAnimation(SessionStateAnimator::Container container, + AnimationType type, + AnimationSpeed speed, + base::Closure success_callback, + base::Closure failed_callback); + + // If an animation is currently active for the given |container| it will be + // aborted by invoking OnAnimationAborted and removed from the list of active + // animations. + void AbortAnimation(SessionStateAnimator::Container container); + + // Used for easy iteration over all the containers. + static const SessionStateAnimator::Container kAllContainers[]; + + // A map of currently active animations. + ActiveAnimationsMap active_animations_; + + // A time counter that tracks the last scheduled animation or animation + // sequence. + int last_animation_epoch_; + + // Tracks whether the background is hidden or not. + bool is_background_hidden_; + + DISALLOW_COPY_AND_ASSIGN(TestSessionStateAnimator); +}; + +} // namespace test +} // namespace ash + +#endif // ASH_TEST_TEST_SESSION_STATE_ANIMATOR_H_ diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc index ebb0698..a03a958 100644 --- a/ash/wm/lock_state_controller.cc +++ b/ash/wm/lock_state_controller.cc @@ -5,6 +5,7 @@ #include "ash/wm/lock_state_controller.h" #include <algorithm> +#include <string> #include "ash/accessibility_delegate.h" #include "ash/ash_switches.h" @@ -14,13 +15,12 @@ #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/wm/session_state_animator.h" +#include "ash/wm/session_state_animator_impl.h" #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/strings/string_util.h" #include "base/timer/timer.h" #include "ui/aura/window_tree_host.h" -#include "ui/compositor/layer_animation_sequence.h" -#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/views/controls/menu/menu_controller.h" #include "ui/wm/core/compound_event_filter.h" @@ -41,113 +41,6 @@ namespace { const int kMaxShutdownSoundDurationMs = 1500; #endif -aura::Window* GetBackground() { - aura::Window* root_window = Shell::GetPrimaryRootWindow(); - return Shell::GetContainer(root_window, - kShellWindowId_DesktopBackgroundContainer); -} - -bool IsBackgroundHidden() { - return !GetBackground()->IsVisible(); -} - -void ShowBackground() { - ui::ScopedLayerAnimationSettings settings( - GetBackground()->layer()->GetAnimator()); - settings.SetTransitionDuration(base::TimeDelta()); - GetBackground()->Show(); -} - -void HideBackground() { - ui::ScopedLayerAnimationSettings settings( - GetBackground()->layer()->GetAnimator()); - settings.SetTransitionDuration(base::TimeDelta()); - GetBackground()->Hide(); -} - -// This observer is intended to use in cases when some action has to be taken -// once some animation successfully completes (i.e. it was not aborted). -// Observer will count a number of sequences it is attached to, and a number of -// finished sequences (either Ended or Aborted). Once these two numbers are -// equal, observer will delete itself, calling callback passed to constructor if -// there were no aborted animations. -// This way it can be either used to wait for some animation to be finished in -// multiple layers, to wait once a sequence of animations is finished in one -// layer or the mixture of both. -class AnimationFinishedObserver : public ui::LayerAnimationObserver { - public: - explicit AnimationFinishedObserver(base::Closure &callback) - : callback_(callback), - sequences_attached_(0), - sequences_completed_(0), - paused_(false) { - } - - // Pauses observer: no checks will be made while paused. It can be used when - // a sequence has some immediate animations in the beginning, and for - // animations that can be tested with flag that makes all animations - // immediate. - void Pause() { - paused_ = true; - } - - // Unpauses observer. It does a check and calls callback if conditions are - // met. - void Unpause() { - if (!paused_) - return; - paused_ = false; - if (sequences_completed_ == sequences_attached_) { - callback_.Run(); - delete this; - } - } - - private: - virtual ~AnimationFinishedObserver() { - } - - // LayerAnimationObserver implementation - virtual void OnLayerAnimationEnded( - ui::LayerAnimationSequence* sequence) OVERRIDE { - sequences_completed_++; - if ((sequences_completed_ == sequences_attached_) && !paused_) { - callback_.Run(); - delete this; - } - } - - virtual void OnLayerAnimationAborted( - ui::LayerAnimationSequence* sequence) OVERRIDE { - sequences_completed_++; - if ((sequences_completed_ == sequences_attached_) && !paused_) - delete this; - } - - virtual void OnLayerAnimationScheduled( - ui::LayerAnimationSequence* sequence) OVERRIDE { - } - - virtual void OnAttachedToSequence( - ui::LayerAnimationSequence* sequence) OVERRIDE { - LayerAnimationObserver::OnAttachedToSequence(sequence); - sequences_attached_++; - } - - // Callback to be called. - base::Closure callback_; - - // Number of sequences this observer was attached to. - int sequences_attached_; - - // Number of sequences either ended or aborted. - int sequences_completed_; - - bool paused_; - - DISALLOW_COPY_AND_ASSIGN(AnimationFinishedObserver); -}; - } // namespace const int LockStateController::kLockTimeoutMs = 400; @@ -164,7 +57,7 @@ LockStateController::TestApi::~TestApi() { } LockStateController::LockStateController() - : animator_(new SessionStateAnimator()), + : animator_(new SessionStateAnimatorImpl()), login_status_(user::LOGGED_IN_NONE), system_is_locked_(false), shutting_down_(false), @@ -179,8 +72,9 @@ LockStateController::~LockStateController() { Shell::GetPrimaryRootWindow()->GetHost()->RemoveObserver(this); } -void LockStateController::SetDelegate(LockStateControllerDelegate* delegate) { - delegate_.reset(delegate); +void LockStateController::SetDelegate( + scoped_ptr<LockStateControllerDelegate> delegate) { + delegate_ = delegate.Pass(); } void LockStateController::AddObserver(LockStateObserver* observer) { @@ -209,9 +103,11 @@ void LockStateController::StartShutdownAnimation() { StartCancellableShutdownAnimation(); } -void LockStateController::StartLockAnimationAndLockImmediately() { +void LockStateController::StartLockAnimationAndLockImmediately( + bool shutdown_after_lock) { if (animating_lock_) return; + shutdown_after_lock_ = shutdown_after_lock; StartImmediatePreLockAnimation(true /* request_lock_on_completion */); } @@ -253,7 +149,8 @@ void LockStateController::CancelShutdownAnimation() { return; } - animator_->StartGlobalAnimation( + animator_->StartAnimation( + SessionStateAnimator::ROOT_CONTAINER, SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS, SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN); pre_shutdown_timer_.Stop(); @@ -277,7 +174,8 @@ void LockStateController::RequestShutdown() { shell->cursor_manager()->HideCursor(); shell->cursor_manager()->LockCursor(); - animator_->StartGlobalAnimation( + animator_->StartAnimation( + SessionStateAnimator::ROOT_CONTAINER, SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS, SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); StartRealShutdownTimer(true); @@ -314,7 +212,7 @@ void LockStateController::OnAppTerminating() { Shell* shell = ash::Shell::GetInstance(); shell->cursor_manager()->HideCursor(); shell->cursor_manager()->LockCursor(); - animator_->StartAnimation(SessionStateAnimator::kAllContainersMask, + animator_->StartAnimation(SessionStateAnimator::kAllNonRootContainersMask, SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); } @@ -418,7 +316,8 @@ void LockStateController::StartCancellableShutdownAnimation() { // Hide cursor, but let it reappear if the mouse moves. shell->cursor_manager()->HideCursor(); - animator_->StartGlobalAnimation( + animator_->StartAnimation( + SessionStateAnimator::ROOT_CONTAINER, SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS, SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); StartPreShutdownAnimationTimer(); @@ -434,29 +333,25 @@ void LockStateController::StartImmediatePreLockAnimation( base::Bind(&LockStateController::PreLockAnimationFinished, weak_ptr_factory_.GetWeakPtr(), request_lock_on_completion); - AnimationFinishedObserver* observer = - new AnimationFinishedObserver(next_animation_starter); - - observer->Pause(); + SessionStateAnimator::AnimationSequence* animation_sequence = + animator_->BeginAnimationSequence(next_animation_starter); - animator_->StartAnimationWithObserver( + animation_sequence->StartAnimation( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_LIFT, - SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, - observer); - animator_->StartAnimationWithObserver( + SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); + animation_sequence->StartAnimation( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_OUT, - SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, - observer); + SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); // Hide the screen locker containers so we can raise them later. animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); AnimateBackgroundAppearanceIfNecessary( - SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, observer); + SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, animation_sequence); - observer->Unpause(); + animation_sequence->EndSequence(); DispatchCancelMode(); FOR_EACH_OBSERVER(LockStateObserver, observers_, @@ -471,32 +366,28 @@ void LockStateController::StartCancellablePreLockAnimation() { base::Bind(&LockStateController::PreLockAnimationFinished, weak_ptr_factory_.GetWeakPtr(), true /* request_lock */); - AnimationFinishedObserver* observer = - new AnimationFinishedObserver(next_animation_starter); - - observer->Pause(); + SessionStateAnimator::AnimationSequence* animation_sequence = + animator_->BeginAnimationSequence(next_animation_starter); - animator_->StartAnimationWithObserver( + animation_sequence->StartAnimation( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_LIFT, - SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, - observer); - animator_->StartAnimationWithObserver( + SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); + animation_sequence->StartAnimation( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_OUT, - SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, - observer); + SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); // Hide the screen locker containers so we can raise them later. animator_->StartAnimation(SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); AnimateBackgroundAppearanceIfNecessary( - SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, observer); + SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, animation_sequence); DispatchCancelMode(); FOR_EACH_OBSERVER(LockStateObserver, observers_, OnLockStateEvent(LockStateObserver::EVENT_PRELOCK_ANIMATION_STARTED)); - observer->Unpause(); + animation_sequence->EndSequence(); } void LockStateController::CancelPreLockAnimation() { @@ -504,25 +395,22 @@ void LockStateController::CancelPreLockAnimation() { base::Closure next_animation_starter = base::Bind(&LockStateController::LockAnimationCancelled, weak_ptr_factory_.GetWeakPtr()); - AnimationFinishedObserver* observer = - new AnimationFinishedObserver(next_animation_starter); + SessionStateAnimator::AnimationSequence* animation_sequence = + animator_->BeginAnimationSequence(next_animation_starter); - observer->Pause(); - - animator_->StartAnimationWithObserver( + animation_sequence->StartAnimation( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_UNDO_LIFT, - SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, - observer); - animator_->StartAnimationWithObserver( + SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS); + animation_sequence->StartAnimation( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_IN, - SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, - observer); + SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS); AnimateBackgroundHidingIfNecessary( - SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, observer); + SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, + animation_sequence); - observer->Unpause(); + animation_sequence->EndSequence(); } void LockStateController::StartPostLockAnimation() { @@ -530,17 +418,14 @@ void LockStateController::StartPostLockAnimation() { base::Closure next_animation_starter = base::Bind(&LockStateController::PostLockAnimationFinished, weak_ptr_factory_.GetWeakPtr()); + SessionStateAnimator::AnimationSequence* animation_sequence = + animator_->BeginAnimationSequence(next_animation_starter); - AnimationFinishedObserver* observer = - new AnimationFinishedObserver(next_animation_starter); - - observer->Pause(); - animator_->StartAnimationWithObserver( + animation_sequence->StartAnimation( SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN, - SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, - observer); - observer->Unpause(); + SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); + animation_sequence->EndSequence(); } void LockStateController::StartUnlockAnimationBeforeUIDestroyed( @@ -558,25 +443,20 @@ void LockStateController::StartUnlockAnimationAfterUIDestroyed() { base::Closure next_animation_starter = base::Bind(&LockStateController::UnlockAnimationAfterUIDestroyedFinished, weak_ptr_factory_.GetWeakPtr()); + SessionStateAnimator::AnimationSequence* animation_sequence = + animator_->BeginAnimationSequence(next_animation_starter); - AnimationFinishedObserver* observer = - new AnimationFinishedObserver(next_animation_starter); - - observer->Pause(); - - animator_->StartAnimationWithObserver( + animation_sequence->StartAnimation( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_DROP, - SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, - observer); - animator_->StartAnimationWithObserver( + SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); + animation_sequence->StartAnimation( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_IN, - SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, - observer); + SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); AnimateBackgroundHidingIfNecessary( - SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, observer); - observer->Unpause(); + SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, animation_sequence); + animation_sequence->EndSequence(); } void LockStateController::LockAnimationCancelled() { @@ -642,14 +522,15 @@ void LockStateController::UnlockAnimationAfterUIDestroyedFinished() { void LockStateController::StoreUnlockedProperties() { if (!unlocked_properties_) { unlocked_properties_.reset(new UnlockedStateProperties()); - unlocked_properties_->background_is_hidden = IsBackgroundHidden(); + unlocked_properties_->background_is_hidden = + animator_->IsBackgroundHidden(); } if (unlocked_properties_->background_is_hidden) { // Hide background so that it can be animated later. animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND, SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY, SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); - ShowBackground(); + animator_->ShowBackground(); } } @@ -657,7 +538,7 @@ void LockStateController::RestoreUnlockedProperties() { if (!unlocked_properties_) return; if (unlocked_properties_->background_is_hidden) { - HideBackground(); + animator_->HideBackground(); // Restore background visibility. animator_->StartAnimation(SessionStateAnimator::DESKTOP_BACKGROUND, SessionStateAnimator::ANIMATION_FADE_IN, @@ -668,27 +549,25 @@ void LockStateController::RestoreUnlockedProperties() { void LockStateController::AnimateBackgroundAppearanceIfNecessary( SessionStateAnimator::AnimationSpeed speed, - ui::LayerAnimationObserver* observer) { + SessionStateAnimator::AnimationSequence* animation_sequence) { if (unlocked_properties_.get() && unlocked_properties_->background_is_hidden) { - animator_->StartAnimationWithObserver( + animation_sequence->StartAnimation( SessionStateAnimator::DESKTOP_BACKGROUND, SessionStateAnimator::ANIMATION_FADE_IN, - speed, - observer); + speed); } } void LockStateController::AnimateBackgroundHidingIfNecessary( SessionStateAnimator::AnimationSpeed speed, - ui::LayerAnimationObserver* observer) { + SessionStateAnimator::AnimationSequence* animation_sequence) { if (unlocked_properties_.get() && unlocked_properties_->background_is_hidden) { - animator_->StartAnimationWithObserver( + animation_sequence->StartAnimation( SessionStateAnimator::DESKTOP_BACKGROUND, SessionStateAnimator::ANIMATION_FADE_OUT, - speed, - observer); + speed); } } diff --git a/ash/wm/lock_state_controller.h b/ash/wm/lock_state_controller.h index b6d134f..ca16688 100644 --- a/ash/wm/lock_state_controller.h +++ b/ash/wm/lock_state_controller.h @@ -52,8 +52,8 @@ class ASH_EXPORT LockStateControllerDelegate { // Entry points: // * StartLockAnimation (bool shutdown after lock) - starts lock that can be // cancelled. -// * StartLockAnimationAndLockImmediately - starts uninterruptible lock -// animation. +// * StartLockAnimationAndLockImmediately (bool shutdown after lock) - starts +// uninterruptible lock animation. // This leads to call of either StartImmediatePreLockAnimation or // StartCancellablePreLockAnimation. Once they complete // PreLockAnimationFinished is called, and system lock is requested. @@ -135,6 +135,7 @@ class ASH_EXPORT LockStateController : public aura::WindowTreeHostObserver, controller_->OnRealShutdownTimeout(); controller_->real_shutdown_timer_.Stop(); } + private: LockStateController* controller_; // not owned @@ -144,8 +145,7 @@ class ASH_EXPORT LockStateController : public aura::WindowTreeHostObserver, LockStateController(); virtual ~LockStateController(); - // Takes ownership of |delegate|. - void SetDelegate(LockStateControllerDelegate* delegate); + void SetDelegate(scoped_ptr<LockStateControllerDelegate> delegate); void AddObserver(LockStateObserver* observer); void RemoveObserver(LockStateObserver* observer); @@ -160,9 +160,10 @@ class ASH_EXPORT LockStateController : public aura::WindowTreeHostObserver, // Starts shutting down (with slow animation) that can be cancelled. void StartShutdownAnimation(); - // Starts usual lock animation, but locks immediately. - // Unlike StartLockAnimation it does no lead to StartShutdownAnimation. - void StartLockAnimationAndLockImmediately(); + // Starts usual lock animation, but locks immediately. After locking and + // |kLockToShutdownTimeoutMs| StartShutdownAnimation() will be called unless + // CancelShutdownAnimation() is called, if |shutdown_after_lock| is true. + void StartLockAnimationAndLockImmediately(bool shutdown_after_lock); // Returns true if we have requested system to lock, but haven't received // confirmation yet. @@ -206,6 +207,10 @@ class ASH_EXPORT LockStateController : public aura::WindowTreeHostObserver, virtual void OnAppTerminating() OVERRIDE; virtual void OnLockStateChanged(bool locked) OVERRIDE; + void set_animator_for_test(SessionStateAnimator* animator) { + animator_.reset(animator); + } + private: friend class test::PowerButtonControllerTest; friend class test::LockStateControllerTest; @@ -266,12 +271,12 @@ class ASH_EXPORT LockStateController : public aura::WindowTreeHostObserver, // Fades in background layer with |speed| if it was hidden in unlocked state. void AnimateBackgroundAppearanceIfNecessary( ash::SessionStateAnimator::AnimationSpeed speed, - ui::LayerAnimationObserver* observer); + SessionStateAnimator::AnimationSequence* animation_sequence); // Fades out background layer with |speed| if it was hidden in unlocked state. void AnimateBackgroundHidingIfNecessary( ash::SessionStateAnimator::AnimationSpeed speed, - ui::LayerAnimationObserver* observer); + SessionStateAnimator::AnimationSequence* animation_sequence); scoped_ptr<SessionStateAnimator> animator_; diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc index 80db349..cca575f 100644 --- a/ash/wm/lock_state_controller_unittest.cc +++ b/ash/wm/lock_state_controller_unittest.cc @@ -4,26 +4,20 @@ #include "ash/wm/lock_state_controller.h" -#include "ash/ash_switches.h" #include "ash/session/session_state_delegate.h" #include "ash/shell.h" -#include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_lock_state_controller_delegate.h" +#include "ash/test/test_screenshot_delegate.h" +#include "ash/test/test_session_state_animator.h" #include "ash/test/test_shell_delegate.h" +#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/power_button_controller.h" #include "ash/wm/session_state_animator.h" -#include "base/command_line.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/time/time.h" -#include "ui/aura/env.h" -#include "ui/aura/test/test_window_delegate.h" -#include "ui/aura/window_event_dispatcher.h" -#include "ui/compositor/layer_animator.h" -#include "ui/compositor/scoped_animation_duration_scale_mode.h" -#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/events/test/event_generator.h" -#include "ui/gfx/rect.h" #include "ui/gfx/size.h" #if defined(OS_CHROMEOS) @@ -32,10 +26,6 @@ #include "ui/display/types/display_constants.h" #endif -#if defined(OS_WIN) -#include "base/win/windows_version.h" -#endif - namespace ash { namespace test { namespace { @@ -49,66 +39,35 @@ void CheckCalledCallback(bool* flag) { (*flag) = true; } -aura::Window* GetContainer(int container ) { - aura::Window* root_window = Shell::GetPrimaryRootWindow(); - return Shell::GetContainer(root_window, container); -} - -bool IsBackgroundHidden() { - return !GetContainer(kShellWindowId_DesktopBackgroundContainer)->IsVisible(); -} - -void HideBackground() { - ui::ScopedLayerAnimationSettings settings( - GetContainer(kShellWindowId_DesktopBackgroundContainer) - ->layer() - ->GetAnimator()); - settings.SetTransitionDuration(base::TimeDelta()); - GetContainer(kShellWindowId_DesktopBackgroundContainer)->Hide(); -} - -} // namespace +} // namespace class LockStateControllerTest : public AshTestBase { public: - LockStateControllerTest() : controller_(NULL), delegate_(NULL) {} + LockStateControllerTest() : power_button_controller_(NULL), + lock_state_controller_(NULL), + lock_state_controller_delegate_(NULL), + test_animator_(NULL) { + } virtual ~LockStateControllerTest() {} virtual void SetUp() OVERRIDE { AshTestBase::SetUp(); - // We would control animations in a fine way: - animation_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( - ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION)); - // TODO(antrim) : restore - // animator_helper_ = ui::test::CreateLayerAnimatorHelperForTest(); - - // Temporary disable animations so that observer is always called, and - // no leaks happen during tests. - animation_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( - ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); - // TODO(antrim): once there is a way to mock time and run animations, make - // sure that animations are finished even in simple tests. - - delegate_ = new TestLockStateControllerDelegate; - controller_ = Shell::GetInstance()->power_button_controller(); - lock_state_controller_ = static_cast<LockStateController*>( - Shell::GetInstance()->lock_state_controller()); - lock_state_controller_->SetDelegate(delegate_); // transfers ownership + scoped_ptr<LockStateControllerDelegate> lock_state_controller_delegate( + lock_state_controller_delegate_ = new TestLockStateControllerDelegate); + test_animator_ = new TestSessionStateAnimator; + + lock_state_controller_ = Shell::GetInstance()->lock_state_controller(); + lock_state_controller_->SetDelegate(lock_state_controller_delegate.Pass()); + lock_state_controller_->set_animator_for_test(test_animator_); + test_api_.reset(new LockStateController::TestApi(lock_state_controller_)); - animator_api_.reset( - new SessionStateAnimator::TestApi(lock_state_controller_-> - animator_.get())); - shell_delegate_ = reinterpret_cast<TestShellDelegate*>( - ash::Shell::GetInstance()->delegate()); + + power_button_controller_ = Shell::GetInstance()->power_button_controller(); session_state_delegate_ = Shell::GetInstance()->session_state_delegate(); - } - virtual void TearDown() { - // TODO(antrim) : restore - // animator_helper_->AdvanceUntilDone(); - window_.reset(); - AshTestBase::TearDown(); + shell_delegate_ = reinterpret_cast<TestShellDelegate*>( + ash::Shell::GetInstance()->delegate()); } protected: @@ -118,241 +77,260 @@ class LockStateControllerTest : public AshTestBase { } int NumShutdownRequests() { - return delegate_->num_shutdown_requests() + - shell_delegate_->num_exit_requests(); + return lock_state_controller_delegate_->num_shutdown_requests() + + shell_delegate_->num_exit_requests(); } void Advance(SessionStateAnimator::AnimationSpeed speed) { - // TODO (antrim) : restore - // animator_helper_->Advance(SessionStateAnimator::GetDuration(speed)); + test_animator_->Advance(test_animator_->GetDuration(speed)); } void AdvancePartially(SessionStateAnimator::AnimationSpeed speed, float factor) { -// TODO (antrim) : restore -// base::TimeDelta duration = SessionStateAnimator::GetDuration(speed); -// base::TimeDelta partial_duration = -// base::TimeDelta::FromInternalValue(duration.ToInternalValue() * factor); -// animator_helper_->Advance(partial_duration); + base::TimeDelta duration = test_animator_->GetDuration(speed); + base::TimeDelta partial_duration = + base::TimeDelta::FromInternalValue(duration.ToInternalValue() * factor); + test_animator_->Advance(partial_duration); } void ExpectPreLockAnimationStarted() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectPreLockAnimationStarted"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_LIFT)); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_OUT)); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); EXPECT_TRUE(test_api_->is_animating_lock()); } + void ExpectPreLockAnimationRunning() { + SCOPED_TRACE("Failure in ExpectPreLockAnimationRunning"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); + EXPECT_TRUE( + test_animator_->AreContainersAnimated( + SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, + SessionStateAnimator::ANIMATION_LIFT)); + EXPECT_TRUE( + test_animator_->AreContainersAnimated( + SessionStateAnimator::LAUNCHER, + SessionStateAnimator::ANIMATION_FADE_OUT)); + EXPECT_TRUE(test_api_->is_animating_lock()); + } + void ExpectPreLockAnimationCancel() { + SCOPED_TRACE("Failure in ExpectPreLockAnimationCancel"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, - SessionStateAnimator::ANIMATION_DROP)); + SessionStateAnimator::ANIMATION_UNDO_LIFT)); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_IN)); } void ExpectPreLockAnimationFinished() { - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); - EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + SCOPED_TRACE("Failure in ExpectPreLockAnimationFinished"); + EXPECT_FALSE( + test_animator_->AreContainersAnimated( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_LIFT)); - EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + EXPECT_FALSE( + test_animator_->AreContainersAnimated( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_OUT)); - EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + EXPECT_FALSE( + test_animator_->AreContainersAnimated( SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); } void ExpectPostLockAnimationStarted() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectPostLockAnimationStarted"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN)); } - void ExpectPastLockAnimationFinished() { - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); - EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + void ExpectPostLockAnimationFinished() { + SCOPED_TRACE("Failure in ExpectPostLockAnimationFinished"); + EXPECT_FALSE( + test_animator_->AreContainersAnimated( SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN)); } void ExpectUnlockBeforeUIDestroyedAnimationStarted() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectUnlockBeforeUIDestroyedAnimationStarted"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_LIFT)); } void ExpectUnlockBeforeUIDestroyedAnimationFinished() { - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); - EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + SCOPED_TRACE("Failure in ExpectUnlockBeforeUIDestroyedAnimationFinished"); + EXPECT_FALSE( + test_animator_->AreContainersAnimated( SessionStateAnimator::LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_LIFT)); } void ExpectUnlockAfterUIDestroyedAnimationStarted() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectUnlockAfterUIDestroyedAnimationStarted"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_DROP)); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_IN)); } void ExpectUnlockAfterUIDestroyedAnimationFinished() { - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); - EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + SCOPED_TRACE("Failure in ExpectUnlockAfterUIDestroyedAnimationFinished"); + EXPECT_EQ(0u, test_animator_->GetAnimationCount()); + EXPECT_FALSE( + test_animator_->AreContainersAnimated( SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, SessionStateAnimator::ANIMATION_DROP)); - EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + EXPECT_FALSE( + test_animator_->AreContainersAnimated( SessionStateAnimator::LAUNCHER, SessionStateAnimator::ANIMATION_FADE_IN)); } void ExpectShutdownAnimationStarted() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectShutdownAnimationStarted"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->RootWindowIsAnimated( + test_animator_->AreContainersAnimated( + SessionStateAnimator::ROOT_CONTAINER, SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS)); } - void ExpectShutdownAnimationFinished() { - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); - EXPECT_TRUE( - animator_api_->RootWindowIsAnimated( + void ExpectShutdownAnimationFinished() { + SCOPED_TRACE("Failure in ExpectShutdownAnimationFinished"); + EXPECT_EQ(0u, test_animator_->GetAnimationCount()); + EXPECT_FALSE( + test_animator_->AreContainersAnimated( + SessionStateAnimator::ROOT_CONTAINER, SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS)); } void ExpectShutdownAnimationCancel() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectShutdownAnimationCancel"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->RootWindowIsAnimated( + test_animator_->AreContainersAnimated( + SessionStateAnimator::ROOT_CONTAINER, SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS)); } void ExpectBackgroundIsShowing() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectBackgroundIsShowing"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::DESKTOP_BACKGROUND, SessionStateAnimator::ANIMATION_FADE_IN)); } void ExpectBackgroundIsHiding() { - //TODO (antrim) : restore EXPECT_TRUE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectBackgroundIsHiding"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( + test_animator_->AreContainersAnimated( SessionStateAnimator::DESKTOP_BACKGROUND, SessionStateAnimator::ANIMATION_FADE_OUT)); } + void ExpectRestoringBackgroundVisibility() { + SCOPED_TRACE("Failure in ExpectRestoringBackgroundVisibility"); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); + EXPECT_TRUE( + test_animator_->AreContainersAnimated( + SessionStateAnimator::DESKTOP_BACKGROUND, + SessionStateAnimator::ANIMATION_FADE_IN)); + } + void ExpectUnlockedState() { - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectUnlockedState"); + EXPECT_EQ(0u, test_animator_->GetAnimationCount()); EXPECT_FALSE(session_state_delegate_->IsScreenLocked()); - - aura::Window::Windows containers; - - SessionStateAnimator::GetContainers( - SessionStateAnimator::LAUNCHER | - SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS, - &containers); - for (aura::Window::Windows::const_iterator it = containers.begin(); - it != containers.end(); ++it) { - aura::Window* window = *it; - ui::Layer* layer = window->layer(); - EXPECT_EQ(1.0f, layer->opacity()); - EXPECT_EQ(0.0f, layer->layer_brightness()); - EXPECT_EQ(0.0f, layer->layer_saturation()); - EXPECT_EQ(gfx::Transform(), layer->transform()); - } } void ExpectLockedState() { - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); + SCOPED_TRACE("Failure in ExpectLockedState"); + EXPECT_EQ(0u, test_animator_->GetAnimationCount()); EXPECT_TRUE(session_state_delegate_->IsScreenLocked()); + } - aura::Window::Windows containers; - - SessionStateAnimator::GetContainers( - SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS | - SessionStateAnimator::LOCK_SCREEN_CONTAINERS, - &containers); - for (aura::Window::Windows::const_iterator it = containers.begin(); - it != containers.end(); ++it) { - aura::Window* window = *it; - ui::Layer* layer = window->layer(); - EXPECT_EQ(1.0f, layer->opacity()); - EXPECT_EQ(0.0f, layer->layer_brightness()); - EXPECT_EQ(0.0f, layer->layer_saturation()); - EXPECT_EQ(gfx::Transform(), layer->transform()); - } + void HideBackground() { + test_animator_->HideBackground(); } void PressPowerButton() { - controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); - //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); + power_button_controller_->OnPowerButtonEvent(true, base::TimeTicks::Now()); } void ReleasePowerButton() { - controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); - //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); + power_button_controller_->OnPowerButtonEvent(false, base::TimeTicks::Now()); } void PressLockButton() { - controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); + power_button_controller_->OnLockButtonEvent(true, base::TimeTicks::Now()); } void ReleaseLockButton() { - controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + power_button_controller_->OnLockButtonEvent(false, base::TimeTicks::Now()); + } + + void PressVolumeDown() { + GetEventGenerator().PressKey(ui::VKEY_VOLUME_DOWN, ui::EF_NONE); + } + + void ReleaseVolumeDown() { + GetEventGenerator().ReleaseKey(ui::VKEY_VOLUME_DOWN, ui::EF_NONE); } void SystemLocks() { lock_state_controller_->OnLockStateChanged(true); session_state_delegate_->LockScreen(); - //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); } void SuccessfulAuthentication(bool* call_flag) { base::Closure closure = base::Bind(&CheckCalledCallback, call_flag); lock_state_controller_->OnLockScreenHide(closure); - //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); } void SystemUnlocks() { lock_state_controller_->OnLockStateChanged(false); session_state_delegate_->UnlockScreen(); - //TODO (antrim) : restore animator_helper_->Advance(base::TimeDelta()); + } + + void EnableMaximizeMode(bool enable) { + Shell::GetInstance()->maximize_mode_controller()-> + EnableMaximizeModeWindowManager(enable); } void Initialize(bool legacy_button, user::LoginStatus status) { - controller_->set_has_legacy_power_button_for_test(legacy_button); + power_button_controller_->set_has_legacy_power_button_for_test( + legacy_button); lock_state_controller_->OnLoginStateChanged(status); SetUserLoggedIn(status != user::LOGGED_IN_NONE); if (status == user::LOGGED_IN_GUEST) @@ -360,32 +338,14 @@ class LockStateControllerTest : public AshTestBase { lock_state_controller_->OnLockStateChanged(false); } - void CreateWindowForLockscreen() { - window_.reset(new aura::Window(&window_delegate_)); - window_->SetBounds(gfx::Rect(0, 0, 100, 100)); - window_->SetType(ui::wm::WINDOW_TYPE_NORMAL); - window_->Init(aura::WINDOW_LAYER_TEXTURED); - window_->SetName("WINDOW"); - aura::Window* container = Shell::GetContainer( - Shell::GetPrimaryRootWindow(), kShellWindowId_LockScreenContainer); - ASSERT_TRUE(container); - container->AddChild(window_.get()); - window_->Show(); - } - - PowerButtonController* controller_; // not owned + PowerButtonController* power_button_controller_; // not owned LockStateController* lock_state_controller_; // not owned - TestLockStateControllerDelegate* delegate_; // not owned - TestShellDelegate* shell_delegate_; // not owned + TestLockStateControllerDelegate* + lock_state_controller_delegate_; // not owned + TestSessionStateAnimator* test_animator_; // not owned SessionStateDelegate* session_state_delegate_; // not owned - - aura::test::TestWindowDelegate window_delegate_; - scoped_ptr<aura::Window> window_; - scoped_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration_mode_; scoped_ptr<LockStateController::TestApi> test_api_; - scoped_ptr<SessionStateAnimator::TestApi> animator_api_; - // TODO(antrim) : restore -// scoped_ptr<ui::test::AnimationContainerTestHelper> animator_helper_; + TestShellDelegate* shell_delegate_; // not owned private: DISALLOW_COPY_AND_ASSIGN(LockStateControllerTest); @@ -395,8 +355,7 @@ class LockStateControllerTest : public AshTestBase { // correctly report power button releases. We should lock immediately the first // time the button is pressed and shut down when it's pressed from the locked // state. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_LegacyLockAndShutDown) { +TEST_F(LockStateControllerTest, LegacyLockAndShutDown) { Initialize(true, user::LOGGED_IN_USER); ExpectUnlockedState(); @@ -405,26 +364,23 @@ TEST_F(LockStateControllerTest, DISABLED_LegacyLockAndShutDown) { // power button get pressed. PressPowerButton(); - ExpectPreLockAnimationStarted(); - EXPECT_FALSE(test_api_->is_lock_cancellable()); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); - + ExpectPreLockAnimationStarted(); + test_animator_->CompleteAllAnimations(true); ExpectPreLockAnimationFinished(); - EXPECT_EQ(1, delegate_->num_lock_requests()); + + EXPECT_EQ(1, lock_state_controller_delegate_->num_lock_requests()); // Notify that we locked successfully. lock_state_controller_->OnStartingLock(); - // We had that animation already. - //TODO (antrim) : restore - // EXPECT_FALSE(animator_helper_->IsAnimating()); + EXPECT_EQ(0u, test_animator_->GetAnimationCount()); SystemLocks(); ExpectPostLockAnimationStarted(); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); - ExpectPastLockAnimationFinished(); + test_animator_->CompleteAllAnimations(true); + ExpectPostLockAnimationFinished(); // We shouldn't progress towards the shutdown state, however. EXPECT_FALSE(test_api_->lock_to_shutdown_timer_is_running()); @@ -510,8 +466,7 @@ TEST_F(LockStateControllerTest, ShutdownWhenNotLoggedIn) { } // Test that we lock the screen and deal with unlocking correctly. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_LockAndUnlock) { +TEST_F(LockStateControllerTest, LockAndUnlock) { Initialize(false, user::LOGGED_IN_USER); ExpectUnlockedState(); @@ -522,23 +477,23 @@ TEST_F(LockStateControllerTest, DISABLED_LockAndUnlock) { ExpectPreLockAnimationStarted(); EXPECT_TRUE(test_api_->is_lock_cancellable()); - EXPECT_EQ(0, delegate_->num_lock_requests()); + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); - Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); + test_animator_->CompleteAllAnimations(true); ExpectPreLockAnimationFinished(); - EXPECT_EQ(1, delegate_->num_lock_requests()); + EXPECT_EQ(1, lock_state_controller_delegate_->num_lock_requests()); // Notify that we locked successfully. lock_state_controller_->OnStartingLock(); // We had that animation already. - //TODO (antrim) : restore EXPECT_FALSE(animator_helper_->IsAnimating()); + EXPECT_EQ(0u, test_animator_->GetAnimationCount()); SystemLocks(); ExpectPostLockAnimationStarted(); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); - ExpectPastLockAnimationFinished(); + test_animator_->CompleteAllAnimations(true); + ExpectPostLockAnimationFinished(); // When we release the power button, the lock-to-shutdown timer should be // stopped. @@ -555,7 +510,7 @@ TEST_F(LockStateControllerTest, DISABLED_LockAndUnlock) { ExpectUnlockBeforeUIDestroyedAnimationStarted(); EXPECT_FALSE(called); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); + test_animator_->CompleteAllAnimations(true); ExpectUnlockBeforeUIDestroyedAnimationFinished(); EXPECT_TRUE(called); @@ -563,15 +518,14 @@ TEST_F(LockStateControllerTest, DISABLED_LockAndUnlock) { SystemUnlocks(); ExpectUnlockAfterUIDestroyedAnimationStarted(); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); + test_animator_->CompleteAllAnimations(true); ExpectUnlockAfterUIDestroyedAnimationFinished(); ExpectUnlockedState(); } // Test that we deal with cancelling lock correctly. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_LockAndCancel) { +TEST_F(LockStateControllerTest, LockAndCancel) { Initialize(false, user::LOGGED_IN_USER); ExpectUnlockedState(); @@ -586,28 +540,18 @@ TEST_F(LockStateControllerTest, DISABLED_LockAndCancel) { // forward only half way through AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); - gfx::Transform transform_before_button_released = - GetContainer(kShellWindowId_DefaultContainer)->layer()->transform(); - // Release the button before the lock timer fires. ReleasePowerButton(); ExpectPreLockAnimationCancel(); - gfx::Transform transform_after_button_released = - GetContainer(kShellWindowId_DefaultContainer)->layer()->transform(); - // Expect no flickering, animation should proceed from mid-state. - EXPECT_EQ(transform_before_button_released, transform_after_button_released); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); ExpectUnlockedState(); - EXPECT_EQ(0, delegate_->num_lock_requests()); + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); } // Test that we deal with cancelling lock correctly. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, - DISABLED_LockAndCancelAndLockAgain) { +TEST_F(LockStateControllerTest, LockAndCancelAndLockAgain) { Initialize(false, user::LOGGED_IN_USER); ExpectUnlockedState(); @@ -626,7 +570,8 @@ TEST_F(LockStateControllerTest, ReleasePowerButton(); ExpectPreLockAnimationCancel(); - AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS, 0.5f); + AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS, + 0.5f); PressPowerButton(); ExpectPreLockAnimationStarted(); @@ -634,17 +579,15 @@ TEST_F(LockStateControllerTest, AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.6f); - EXPECT_EQ(0, delegate_->num_lock_requests()); - ExpectPreLockAnimationStarted(); + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.6f); ExpectPreLockAnimationFinished(); - EXPECT_EQ(1, delegate_->num_lock_requests()); + EXPECT_EQ(1, lock_state_controller_delegate_->num_lock_requests()); } // Hold the power button down from the unlocked state to eventual shutdown. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_LockToShutdown) { +TEST_F(LockStateControllerTest, LockToShutdown) { Initialize(false, user::LOGGED_IN_USER); // Hold the power button and lock the screen. @@ -699,13 +642,11 @@ TEST_F(LockStateControllerTest, CancelLockToShutdown) { EXPECT_FALSE(test_api_->shutdown_timer_is_running()); } +// TODO(bruthig): Investigate why this hangs on Windows 8 and whether it can be +// safely enabled on OS_WIN. +#ifndef OS_WIN // Test that we handle the case where lock requests are ignored. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_Lock) { - // We require animations to have a duration for this test. - ui::ScopedAnimationDurationScaleMode normal_duration_mode( - ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); - +TEST_F(LockStateControllerTest, Lock) { Initialize(false, user::LOGGED_IN_USER); // Hold the power button and lock the screen. @@ -714,20 +655,16 @@ TEST_F(LockStateControllerTest, DISABLED_Lock) { Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); - EXPECT_EQ(1, delegate_->num_lock_requests()); + EXPECT_EQ(1, lock_state_controller_delegate_->num_lock_requests()); EXPECT_TRUE(test_api_->lock_fail_timer_is_running()); // We shouldn't start the lock-to-shutdown timer until the screen has actually // been locked and this was animated. EXPECT_FALSE(test_api_->lock_to_shutdown_timer_is_running()); - // Act as if the request timed out. We should restore the windows. - test_api_->trigger_lock_fail_timeout(); - - ExpectUnlockAfterUIDestroyedAnimationStarted(); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); - ExpectUnlockAfterUIDestroyedAnimationFinished(); - ExpectUnlockedState(); + // Act as if the request timed out. + EXPECT_DEATH(test_api_->trigger_lock_fail_timeout(), ""); } +#endif // Test the basic operation of the lock button (not logged in). TEST_F(LockStateControllerTest, LockButtonBasicNotLoggedIn) { @@ -737,7 +674,7 @@ TEST_F(LockStateControllerTest, LockButtonBasicNotLoggedIn) { PressLockButton(); EXPECT_FALSE(test_api_->is_animating_lock()); ReleaseLockButton(); - EXPECT_EQ(0, delegate_->num_lock_requests()); + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); } // Test the basic operation of the lock button (guest). @@ -748,12 +685,11 @@ TEST_F(LockStateControllerTest, LockButtonBasicGuest) { PressLockButton(); EXPECT_FALSE(test_api_->is_animating_lock()); ReleaseLockButton(); - EXPECT_EQ(0, delegate_->num_lock_requests()); + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); } // Test the basic operation of the lock button. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_LockButtonBasic) { +TEST_F(LockStateControllerTest, LockButtonBasic) { // If we're logged in as a regular user, we should start the lock timer and // the pre-lock animation. Initialize(false, user::LOGGED_IN_USER); @@ -768,14 +704,14 @@ TEST_F(LockStateControllerTest, DISABLED_LockButtonBasic) { Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); ExpectUnlockedState(); - EXPECT_EQ(0, delegate_->num_lock_requests()); + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); // Press the button again and let the lock timeout fire. We should request // that the screen be locked. PressLockButton(); ExpectPreLockAnimationStarted(); Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); - EXPECT_EQ(1, delegate_->num_lock_requests()); + EXPECT_EQ(1, lock_state_controller_delegate_->num_lock_requests()); // Pressing the lock button while we have a pending lock request shouldn't do // anything. @@ -793,30 +729,34 @@ TEST_F(LockStateControllerTest, DISABLED_LockButtonBasic) { ExpectPostLockAnimationStarted(); Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); - ExpectPastLockAnimationFinished(); + ExpectPostLockAnimationFinished(); PressLockButton(); ReleaseLockButton(); - ExpectPastLockAnimationFinished(); + ExpectPostLockAnimationFinished(); } // Test that the power button takes priority over the lock button. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, - DISABLED_PowerButtonPreemptsLockButton) { +TEST_F(LockStateControllerTest, PowerButtonPreemptsLockButton) { Initialize(false, user::LOGGED_IN_USER); // While the lock button is down, hold the power button. PressLockButton(); ExpectPreLockAnimationStarted(); + + AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.1f); + ExpectPreLockAnimationRunning(); + PressPowerButton(); - ExpectPreLockAnimationStarted(); + ExpectPreLockAnimationRunning(); - AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); + AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.1f); + ExpectPreLockAnimationRunning(); // The lock timer shouldn't be stopped when the lock button is released. ReleaseLockButton(); - ExpectPreLockAnimationStarted(); + ExpectPreLockAnimationRunning(); + ReleasePowerButton(); ExpectPreLockAnimationCancel(); @@ -826,14 +766,20 @@ TEST_F(LockStateControllerTest, // Now press the power button first and then the lock button. PressPowerButton(); ExpectPreLockAnimationStarted(); + + AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.1f); + PressLockButton(); - ExpectPreLockAnimationStarted(); + ExpectPreLockAnimationRunning(); - AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.5f); + AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.1f); // Releasing the power button should stop the lock timer. ReleasePowerButton(); ExpectPreLockAnimationCancel(); + + AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE, 0.1f); + ReleaseLockButton(); ExpectPreLockAnimationCancel(); } @@ -847,10 +793,10 @@ TEST_F(LockStateControllerTest, LockWithoutButton) { ExpectPreLockAnimationStarted(); EXPECT_FALSE(test_api_->is_lock_cancellable()); + EXPECT_LT(0u, test_animator_->GetAnimationCount()); - // TODO(antrim): After time-faking is fixed, let the pre-lock animation - // complete here and check that delegate_->num_lock_requests() is 0 to - // prevent http://crbug.com/172487 from regressing. + test_animator_->CompleteAllAnimations(true); + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); } // When we hear that the process is exiting but we haven't had a chance to @@ -860,8 +806,8 @@ TEST_F(LockStateControllerTest, ShutdownWithoutButton) { lock_state_controller_->OnAppTerminating(); EXPECT_TRUE( - animator_api_->ContainersAreAnimated( - SessionStateAnimator::kAllContainersMask, + test_animator_->AreContainersAnimated( + SessionStateAnimator::kAllNonRootContainersMask, SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY)); GenerateMouseMoveEvent(); EXPECT_FALSE(cursor_visible()); @@ -871,7 +817,6 @@ TEST_F(LockStateControllerTest, ShutdownWithoutButton) { // outside request to shut down (e.g. from the login or lock screen). TEST_F(LockStateControllerTest, RequestShutdownFromLoginScreen) { Initialize(false, user::LOGGED_IN_NONE); - CreateWindowForLockscreen(); lock_state_controller_->RequestShutdown(); @@ -891,9 +836,9 @@ TEST_F(LockStateControllerTest, RequestShutdownFromLockScreen) { Initialize(false, user::LOGGED_IN_USER); SystemLocks(); - CreateWindowForLockscreen(); + Advance(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN); - ExpectPastLockAnimationFinished(); + ExpectPostLockAnimationFinished(); lock_state_controller_->RequestShutdown(); @@ -909,9 +854,7 @@ TEST_F(LockStateControllerTest, RequestShutdownFromLockScreen) { EXPECT_EQ(1, NumShutdownRequests()); } -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, - DISABLED_RequestAndCancelShutdownFromLockScreen) { +TEST_F(LockStateControllerTest, RequestAndCancelShutdownFromLockScreen) { Initialize(false, user::LOGGED_IN_USER); SystemLocks(); @@ -927,9 +870,6 @@ TEST_F(LockStateControllerTest, AdvancePartially(SessionStateAnimator::ANIMATION_SPEED_SHUTDOWN, 0.5f); - float grayscale_before_button_release = - Shell::GetPrimaryRootWindow()->layer()->layer_grayscale(); - // Release the power button before the shutdown timer fires. ReleasePowerButton(); @@ -937,12 +877,7 @@ TEST_F(LockStateControllerTest, ExpectShutdownAnimationCancel(); - float grayscale_after_button_release = - Shell::GetPrimaryRootWindow()->layer()->layer_grayscale(); - // Expect no flickering in undo animation. - EXPECT_EQ(grayscale_before_button_release, grayscale_after_button_release); - - Advance(SessionStateAnimator::ANIMATION_SPEED_REVERT); + Advance(SessionStateAnimator::ANIMATION_SPEED_REVERT_SHUTDOWN); ExpectLockedState(); } @@ -952,14 +887,14 @@ TEST_F(LockStateControllerTest, IgnorePowerButtonIfScreenIsOff) { // When the screen brightness is at 0%, we shouldn't do anything in response // to power button presses. - controller_->OnScreenBrightnessChanged(0.0); + power_button_controller_->OnScreenBrightnessChanged(0.0); PressPowerButton(); EXPECT_FALSE(test_api_->is_animating_lock()); ReleasePowerButton(); // After increasing the brightness to 10%, we should start the timer like // usual. - controller_->OnScreenBrightnessChanged(10.0); + power_button_controller_->OnScreenBrightnessChanged(10.0); PressPowerButton(); EXPECT_TRUE(test_api_->is_animating_lock()); ReleasePowerButton(); @@ -988,12 +923,12 @@ TEST_F(LockStateControllerTest, HonorPowerButtonInDockedMode) { // When all of the displays are turned off (e.g. due to user inactivity), the // power button should be ignored. - controller_->OnScreenBrightnessChanged(0.0); + power_button_controller_->OnScreenBrightnessChanged(0.0); static_cast<ui::TestDisplaySnapshot*>(outputs[0].display) ->set_current_mode(NULL); static_cast<ui::TestDisplaySnapshot*>(outputs[1].display) ->set_current_mode(NULL); - controller_->OnDisplayModeChanged(outputs); + power_button_controller_->OnDisplayModeChanged(outputs); PressPowerButton(); EXPECT_FALSE(test_api_->is_animating_lock()); ReleasePowerButton(); @@ -1003,7 +938,7 @@ TEST_F(LockStateControllerTest, HonorPowerButtonInDockedMode) { // brightness to 0%), the power button should still be handled. static_cast<ui::TestDisplaySnapshot*>(outputs[1].display) ->set_current_mode(modes[0]); - controller_->OnDisplayModeChanged(outputs); + power_button_controller_->OnDisplayModeChanged(outputs); PressPowerButton(); EXPECT_TRUE(test_api_->is_animating_lock()); ReleasePowerButton(); @@ -1011,17 +946,14 @@ TEST_F(LockStateControllerTest, HonorPowerButtonInDockedMode) { #endif // Test that hidden background appears and revers correctly on lock/cancel. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockCancel) { +TEST_F(LockStateControllerTest, TestHiddenBackgroundLockCancel) { Initialize(false, user::LOGGED_IN_USER); HideBackground(); - EXPECT_TRUE(IsBackgroundHidden()); ExpectUnlockedState(); PressPowerButton(); ExpectPreLockAnimationStarted(); - EXPECT_FALSE(IsBackgroundHidden()); ExpectBackgroundIsShowing(); // Forward only half way through. @@ -1031,21 +963,23 @@ TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockCancel) { ReleasePowerButton(); ExpectPreLockAnimationCancel(); ExpectBackgroundIsHiding(); - EXPECT_FALSE(IsBackgroundHidden()); - Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); + Advance(SessionStateAnimator::ANIMATION_SPEED_UNDO_MOVE_WINDOWS); + + // When the CancelPrelockAnimation sequence finishes it queues up a + // restore background visibilty sequence when the background is hidden. + ExpectRestoringBackgroundVisibility(); + + Advance(SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); ExpectUnlockedState(); - EXPECT_TRUE(IsBackgroundHidden()); } // Test that hidden background appears and revers correctly on lock/unlock. -// TODO(antrim): Reenable this: http://crbug.com/167048 -TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockUnlock) { +TEST_F(LockStateControllerTest, TestHiddenBackgroundLockUnlock) { Initialize(false, user::LOGGED_IN_USER); HideBackground(); - EXPECT_TRUE(IsBackgroundHidden()); ExpectUnlockedState(); // Press the power button and check that the lock timer is started and that we @@ -1053,7 +987,6 @@ TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockUnlock) { PressPowerButton(); ExpectPreLockAnimationStarted(); - EXPECT_FALSE(IsBackgroundHidden()); ExpectBackgroundIsShowing(); Advance(SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); @@ -1066,7 +999,7 @@ TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockUnlock) { ExpectPostLockAnimationStarted(); Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); - ExpectPastLockAnimationFinished(); + ExpectPostLockAnimationFinished(); ExpectLockedState(); @@ -1080,14 +1013,104 @@ TEST_F(LockStateControllerTest, DISABLED_TestHiddenBackgroundLockUnlock) { ExpectUnlockAfterUIDestroyedAnimationStarted(); ExpectBackgroundIsHiding(); - EXPECT_FALSE(IsBackgroundHidden()); Advance(SessionStateAnimator::ANIMATION_SPEED_MOVE_WINDOWS); + + // When the StartUnlockAnimationAfterUIDestroyed sequence finishes it queues + // up a restore background visibilty sequence when the background is hidden. + ExpectRestoringBackgroundVisibility(); + + Advance(SessionStateAnimator::ANIMATION_SPEED_IMMEDIATE); + ExpectUnlockAfterUIDestroyedAnimationFinished(); - EXPECT_TRUE(IsBackgroundHidden()); ExpectUnlockedState(); } +TEST_F(LockStateControllerTest, Screenshot) { + test::TestScreenshotDelegate* delegate = GetScreenshotDelegate(); + delegate->set_can_take_screenshot(true); + + EnableMaximizeMode(false); + + // Screenshot handling should not be active when not in maximize mode. + ASSERT_EQ(0, delegate->handle_take_screenshot_count()); + PressVolumeDown(); + PressPowerButton(); + ReleasePowerButton(); + ReleaseVolumeDown(); + EXPECT_EQ(0, delegate->handle_take_screenshot_count()); + + EnableMaximizeMode(true); + + // Pressing power alone does not take a screenshot. + PressPowerButton(); + ReleasePowerButton(); + EXPECT_EQ(0, delegate->handle_take_screenshot_count()); + + // Press & release volume then pressing power does not take a screenshot. + ASSERT_EQ(0, delegate->handle_take_screenshot_count()); + PressVolumeDown(); + ReleaseVolumeDown(); + PressPowerButton(); + ReleasePowerButton(); + EXPECT_EQ(0, delegate->handle_take_screenshot_count()); + + // Pressing power and then volume does not take a screenshot. + ASSERT_EQ(0, delegate->handle_take_screenshot_count()); + PressPowerButton(); + ReleasePowerButton(); + PressVolumeDown(); + ReleaseVolumeDown(); + EXPECT_EQ(0, delegate->handle_take_screenshot_count()); + + // Holding volume down and pressing power takes a screenshot. + ASSERT_EQ(0, delegate->handle_take_screenshot_count()); + PressVolumeDown(); + PressPowerButton(); + ReleasePowerButton(); + ReleaseVolumeDown(); + EXPECT_EQ(1, delegate->handle_take_screenshot_count()); +} + +// Tests that a lock action is cancellable when quick lock is turned on and +// maximize mode is not active. +TEST_F(LockStateControllerTest, QuickLockWhileNotInMaximizeMode) { + Initialize(false, user::LOGGED_IN_USER); + power_button_controller_->set_enable_quick_lock_for_test(true); + EnableMaximizeMode(false); + + PressPowerButton(); + + ExpectPreLockAnimationStarted(); + EXPECT_TRUE(test_api_->is_animating_lock()); + EXPECT_TRUE(lock_state_controller_->CanCancelLockAnimation()); + + ReleasePowerButton(); + + EXPECT_EQ(0, lock_state_controller_delegate_->num_lock_requests()); +} + +// Tests that a lock action is not cancellable when quick lock is turned on and +// maximize mode is active. +TEST_F(LockStateControllerTest, QuickLockWhileInMaximizeMode) { + Initialize(false, user::LOGGED_IN_USER); + power_button_controller_->set_enable_quick_lock_for_test(true); + EnableMaximizeMode(true); + + PressPowerButton(); + + ExpectPreLockAnimationStarted(); + EXPECT_TRUE(test_api_->is_animating_lock()); + EXPECT_FALSE(lock_state_controller_->CanCancelLockAnimation()); + + ReleasePowerButton(); + + ExpectPreLockAnimationStarted(); + + test_animator_->CompleteAllAnimations(true); + EXPECT_EQ(1, lock_state_controller_delegate_->num_lock_requests()); +} + } // namespace test } // namespace ash diff --git a/ash/wm/maximize_mode/maximize_mode_controller.cc b/ash/wm/maximize_mode/maximize_mode_controller.cc index 663dcfc..dc78d28 100644 --- a/ash/wm/maximize_mode/maximize_mode_controller.cc +++ b/ash/wm/maximize_mode/maximize_mode_controller.cc @@ -19,7 +19,6 @@ #include "base/time/tick_clock.h" #include "ui/base/accelerators/accelerator.h" #include "ui/events/event.h" -#include "ui/events/event_handler.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/vector3d_f.h" @@ -113,47 +112,6 @@ float ClockwiseAngleBetweenVectorsInDegrees(const gfx::Vector3dF& base, return angle; } -#if defined(OS_CHROMEOS) - -// An event handler which listens for a volume down + power keypress and -// triggers a screenshot when this is seen. -class ScreenshotActionHandler : public ui::EventHandler { - public: - ScreenshotActionHandler(); - virtual ~ScreenshotActionHandler(); - - // ui::EventHandler: - virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE; - - private: - bool volume_down_pressed_; - - DISALLOW_COPY_AND_ASSIGN(ScreenshotActionHandler); -}; - -ScreenshotActionHandler::ScreenshotActionHandler() - : volume_down_pressed_(false) { - Shell::GetInstance()->PrependPreTargetHandler(this); -} - -ScreenshotActionHandler::~ScreenshotActionHandler() { - Shell::GetInstance()->RemovePreTargetHandler(this); -} - -void ScreenshotActionHandler::OnKeyEvent(ui::KeyEvent* event) { - if (event->key_code() == ui::VKEY_VOLUME_DOWN) { - volume_down_pressed_ = event->type() == ui::ET_KEY_PRESSED || - event->type() == ui::ET_TRANSLATED_KEY_PRESS; - } else if (volume_down_pressed_ && - event->key_code() == ui::VKEY_POWER && - event->type() == ui::ET_KEY_PRESSED) { - Shell::GetInstance()->accelerator_controller()->PerformAction( - ash::TAKE_SCREENSHOT, ui::Accelerator()); - } -} - -#endif // OS_CHROMEOS - } // namespace MaximizeModeController::MaximizeModeController() @@ -447,9 +405,6 @@ void MaximizeModeController::EnterMaximizeMode() { #if defined(USE_X11) event_blocker_.reset(new ScopedDisableInternalMouseAndKeyboardX11); #endif -#if defined(OS_CHROMEOS) - event_handler_.reset(new ScreenshotActionHandler); -#endif Shell::GetInstance()->display_controller()->AddObserver(this); } @@ -467,7 +422,6 @@ void MaximizeModeController::LeaveMaximizeMode() { SetRotationLocked(false); EnableMaximizeModeWindowManager(false); event_blocker_.reset(); - event_handler_.reset(); Shell::GetInstance()->display_controller()->RemoveObserver(this); } diff --git a/ash/wm/maximize_mode/maximize_mode_controller.h b/ash/wm/maximize_mode/maximize_mode_controller.h index 76199b7..d8fe9ca 100644 --- a/ash/wm/maximize_mode/maximize_mode_controller.h +++ b/ash/wm/maximize_mode/maximize_mode_controller.h @@ -175,9 +175,6 @@ class ASH_EXPORT MaximizeModeController // internal keyboard and touchpad. scoped_ptr<ScopedDisableInternalMouseAndKeyboard> event_blocker_; - // An event handler used to detect screenshot actions while in maximize mode. - scoped_ptr<ui::EventHandler> event_handler_; - // When true calls to OnAccelerometerUpdated will not rotate the display. bool rotation_locked_; diff --git a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc index 3996579..72e17af 100644 --- a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc +++ b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc @@ -12,8 +12,6 @@ #include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h" #include "ash/test/display_manager_test_api.h" -#include "ash/test/test_lock_state_controller_delegate.h" -#include "ash/test/test_screenshot_delegate.h" #include "ash/test/test_system_tray_delegate.h" #include "ash/test/test_volume_control_delegate.h" #include "base/test/simple_test_tick_clock.h" @@ -411,34 +409,6 @@ TEST_F(MaximizeModeControllerTest, RotationOnlyInMaximizeMode) { EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation()); } -#if defined(OS_CHROMEOS) -// Tests that a screenshot can be taken in maximize mode by holding volume down -// and pressing power. -TEST_F(MaximizeModeControllerTest, Screenshot) { - Shell::GetInstance()->lock_state_controller()->SetDelegate( - new test::TestLockStateControllerDelegate); - aura::Window* root = Shell::GetPrimaryRootWindow(); - ui::test::EventGenerator event_generator(root, root); - test::TestScreenshotDelegate* delegate = GetScreenshotDelegate(); - delegate->set_can_take_screenshot(true); - - // Open up 270 degrees. - OpenLidToAngle(270.0f); - ASSERT_TRUE(IsMaximizeModeStarted()); - - // Pressing power alone does not take a screenshot. - event_generator.PressKey(ui::VKEY_POWER, 0); - event_generator.ReleaseKey(ui::VKEY_POWER, 0); - EXPECT_EQ(0, delegate->handle_take_screenshot_count()); - - // Holding volume down and pressing power takes a screenshot. - event_generator.PressKey(ui::VKEY_VOLUME_DOWN, 0); - event_generator.PressKey(ui::VKEY_POWER, 0); - event_generator.ReleaseKey(ui::VKEY_POWER, 0); - EXPECT_EQ(1, delegate->handle_take_screenshot_count()); - event_generator.ReleaseKey(ui::VKEY_VOLUME_DOWN, 0); -} -#endif // OS_CHROMEOS TEST_F(MaximizeModeControllerTest, LaptopTest) { // Feeds in sample accelerometer data and verifies that there are no diff --git a/ash/wm/power_button_controller.cc b/ash/wm/power_button_controller.cc index 6e96c65..990e573 100644 --- a/ash/wm/power_button_controller.cc +++ b/ash/wm/power_button_controller.cc @@ -9,10 +9,12 @@ #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/wm/lock_state_controller.h" +#include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/session_state_animator.h" #include "base/command_line.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/display/types/chromeos/display_snapshot.h" +#include "ui/events/event_handler.h" #include "ui/wm/core/compound_event_filter.h" namespace ash { @@ -21,21 +23,26 @@ PowerButtonController::PowerButtonController( LockStateController* controller) : power_button_down_(false), lock_button_down_(false), + volume_down_pressed_(false), brightness_is_zero_(false), internal_display_off_and_external_display_on_(false), has_legacy_power_button_( CommandLine::ForCurrentProcess()->HasSwitch( switches::kAuraLegacyPowerButton)), + enable_quick_lock_(CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshEnablePowerButtonQuickLock)), controller_(controller) { #if defined(OS_CHROMEOS) Shell::GetInstance()->display_configurator()->AddObserver(this); #endif + Shell::GetInstance()->PrependPreTargetHandler(this); } PowerButtonController::~PowerButtonController() { #if defined(OS_CHROMEOS) Shell::GetInstance()->display_configurator()->RemoveObserver(this); #endif + Shell::GetInstance()->RemovePreTargetHandler(this); } void PowerButtonController::OnScreenBrightnessChanged(double percent) { @@ -55,6 +62,14 @@ void PowerButtonController::OnPowerButtonEvent( if (brightness_is_zero_ && !internal_display_off_and_external_display_on_) return; + if (volume_down_pressed_ && down && + Shell::GetInstance()->maximize_mode_controller()-> + IsMaximizeModeWindowManagerEnabled()) { + Shell::GetInstance()->accelerator_controller()->PerformAction( + ash::TAKE_SCREENSHOT, ui::Accelerator()); + return; + } + const SessionStateDelegate* session_state_delegate = Shell::GetInstance()->session_state_delegate(); if (has_legacy_power_button_) { @@ -65,7 +80,7 @@ void PowerButtonController::OnPowerButtonEvent( if (session_state_delegate->CanLockScreen() && !session_state_delegate->IsScreenLocked() && !controller_->LockRequested()) { - controller_->StartLockAnimationAndLockImmediately(); + controller_->StartLockAnimationAndLockImmediately(false); } else { controller_->RequestShutdown(); } @@ -78,7 +93,11 @@ void PowerButtonController::OnPowerButtonEvent( if (session_state_delegate->CanLockScreen() && !session_state_delegate->IsScreenLocked()) { - controller_->StartLockAnimation(true); + if (Shell::GetInstance()->maximize_mode_controller()-> + IsMaximizeModeWindowManagerEnabled() && enable_quick_lock_) + controller_->StartLockAnimationAndLockImmediately(true); + else + controller_->StartLockAnimation(true); } else { controller_->StartShutdownAnimation(); } @@ -104,9 +123,7 @@ void PowerButtonController::OnLockButtonEvent( return; } - // Give the power button precedence over the lock button (we don't expect both - // buttons to be present, so this is just making sure that we don't do - // something completely stupid if that assumption changes later). + // Give the power button precedence over the lock button. if (power_button_down_) return; @@ -116,6 +133,13 @@ void PowerButtonController::OnLockButtonEvent( controller_->CancelLockAnimation(); } +void PowerButtonController::OnKeyEvent(ui::KeyEvent* event) { + if (event->key_code() == ui::VKEY_VOLUME_DOWN) { + volume_down_pressed_ = event->type() == ui::ET_KEY_PRESSED || + event->type() == ui::ET_TRANSLATED_KEY_PRESS; + } +} + #if defined(OS_CHROMEOS) void PowerButtonController::OnDisplayModeChanged( const ui::DisplayConfigurator::DisplayStateList& display_states) { diff --git a/ash/wm/power_button_controller.h b/ash/wm/power_button_controller.h index f178014..6511a5f 100644 --- a/ash/wm/power_button_controller.h +++ b/ash/wm/power_button_controller.h @@ -5,9 +5,13 @@ #ifndef ASH_WM_POWER_BUTTON_CONTROLLER_H_ #define ASH_WM_POWER_BUTTON_CONTROLLER_H_ +#include "ash/accelerators/accelerator_controller.h" +#include "ash/accelerators/accelerator_table.h" #include "ash/ash_export.h" #include "ash/wm/session_state_animator.h" #include "base/basictypes.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/events/event_handler.h" #if defined(OS_CHROMEOS) #include "ui/display/chromeos/display_configurator.h" @@ -30,13 +34,14 @@ class PowerButtonControllerTest; class LockStateController; -// Displays onscreen animations and locks or suspends the system in response to -// the power button being pressed or released. -class ASH_EXPORT PowerButtonController +// Handles power & lock button events which may result in the locking or +// shutting down of the system as well as taking screen shots while in maximize +// mode. +class ASH_EXPORT PowerButtonController : ui::EventHandler // TODO(derat): Remove these ifdefs after DisplayConfigurator becomes // cross-platform. #if defined(OS_CHROMEOS) - : public ui::DisplayConfigurator::Observer + , public ui::DisplayConfigurator::Observer #endif { public: @@ -47,6 +52,10 @@ class ASH_EXPORT PowerButtonController has_legacy_power_button_ = legacy; } + void set_enable_quick_lock_for_test(bool enable_quick_lock) { + enable_quick_lock_ = enable_quick_lock; + } + // Called when the current screen brightness changes. void OnScreenBrightnessChanged(double percent); @@ -54,6 +63,9 @@ class ASH_EXPORT PowerButtonController void OnPowerButtonEvent(bool down, const base::TimeTicks& timestamp); void OnLockButtonEvent(bool down, const base::TimeTicks& timestamp); + // ui::EventHandler: + virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE; + #if defined(OS_CHROMEOS) // Overriden from ui::DisplayConfigurator::Observer: virtual void OnDisplayModeChanged( @@ -67,6 +79,9 @@ class ASH_EXPORT PowerButtonController bool power_button_down_; bool lock_button_down_; + // True when the volume down button is being held down. + bool volume_down_pressed_; + // Has the screen brightness been reduced to 0%? bool brightness_is_zero_; @@ -79,7 +94,10 @@ class ASH_EXPORT PowerButtonController // that misreports power button releases? bool has_legacy_power_button_; - LockStateController* controller_; // Not owned. + // Enables quick, non-cancellable locking of the screen when in maximize mode. + bool enable_quick_lock_; + + LockStateController* controller_; // Not owned. DISALLOW_COPY_AND_ASSIGN(PowerButtonController); }; diff --git a/ash/wm/session_state_animator.cc b/ash/wm/session_state_animator.cc index 9900275..009f88e 100644 --- a/ash/wm/session_state_animator.cc +++ b/ash/wm/session_state_animator.cc @@ -15,415 +15,62 @@ #include "ui/views/widget/widget.h" namespace ash { -namespace { -// Slightly-smaller size that we scale the screen down to for the pre-lock and -// pre-shutdown states. -const float kSlowCloseSizeRatio = 0.95f; - -// Maximum opacity of white layer when animating pre-shutdown state. -const float kPartialFadeRatio = 0.3f; - -// Minimum size. Not zero as it causes numeric issues. -const float kMinimumScale = 1e-4f; - -// Returns the transform that should be applied to containers for the slow-close -// animation. -gfx::Transform GetSlowCloseTransform() { - gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size(); - gfx::Transform transform; - transform.Translate( - floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.width() + 0.5), - floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.height() + 0.5)); - transform.Scale(kSlowCloseSizeRatio, kSlowCloseSizeRatio); - return transform; -} - -// Returns the transform that should be applied to containers for the fast-close -// animation. -gfx::Transform GetFastCloseTransform() { - gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size(); - gfx::Transform transform; - transform.Translate(floor(0.5 * root_size.width() + 0.5), - floor(0.5 * root_size.height() + 0.5)); - transform.Scale(kMinimumScale, kMinimumScale); - return transform; -} - -// Slowly shrinks |window| to a slightly-smaller size. -void StartSlowCloseAnimationForWindow(aura::Window* window, - base::TimeDelta duration, - ui::LayerAnimationObserver* observer) { - ui::LayerAnimator* animator = window->layer()->GetAnimator(); - animator->set_preemption_strategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateTransformElement( - GetSlowCloseTransform(), - duration)); - if (observer) - sequence->AddObserver(observer); - animator->StartAnimation(sequence); -} - -// Quickly undoes the effects of the slow-close animation on |window|. -void StartUndoSlowCloseAnimationForWindow( - aura::Window* window, - base::TimeDelta duration, - ui::LayerAnimationObserver* observer) { - ui::LayerAnimator* animator = window->layer()->GetAnimator(); - animator->set_preemption_strategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateTransformElement( - gfx::Transform(), - duration)); - if (observer) - sequence->AddObserver(observer); - animator->StartAnimation(sequence); -} +const int SessionStateAnimator::kAllLockScreenContainersMask = + SessionStateAnimator::LOCK_SCREEN_BACKGROUND | + SessionStateAnimator::LOCK_SCREEN_CONTAINERS | + SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS; -// Quickly shrinks |window| down to a point in the center of the screen and -// fades it out to 0 opacity. -void StartFastCloseAnimationForWindow(aura::Window* window, - base::TimeDelta duration, - ui::LayerAnimationObserver* observer) { - ui::LayerAnimator* animator = window->layer()->GetAnimator(); - animator->set_preemption_strategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - animator->StartAnimation( - new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateTransformElement( - GetFastCloseTransform(), duration))); - ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateOpacityElement(0.0, duration)); - if (observer) - sequence->AddObserver(observer); - animator->StartAnimation(sequence); -} +const int SessionStateAnimator::kAllNonRootContainersMask = + SessionStateAnimator::kAllLockScreenContainersMask | + SessionStateAnimator::DESKTOP_BACKGROUND | + SessionStateAnimator::LAUNCHER | + SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS; -// Fades |window| to |target_opacity| over |duration|. -void StartPartialFadeAnimation(aura::Window* window, - float target_opacity, - base::TimeDelta duration, - ui::LayerAnimationObserver* observer) { - ui::LayerAnimator* animator = window->layer()->GetAnimator(); - animator->set_preemption_strategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateOpacityElement( - target_opacity, duration)); - if (observer) - sequence->AddObserver(observer); - animator->StartAnimation(sequence); +SessionStateAnimator::AnimationSequence::AnimationSequence( + base::Closure callback) + : sequence_ended_(false), + animation_completed_(false), + invoke_callback_(false), + callback_(callback) { } -// Fades |window| to |opacity| over |duration|. -void StartOpacityAnimationForWindow(aura::Window* window, - float opacity, - base::TimeDelta duration, - ui::LayerAnimationObserver* observer) { - ui::LayerAnimator* animator = window->layer()->GetAnimator(); - animator->set_preemption_strategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateOpacityElement(opacity, duration)); - if (observer) - sequence->AddObserver(observer); - animator->StartAnimation(sequence); +SessionStateAnimator::AnimationSequence::~AnimationSequence() { } -// Makes |window| fully transparent instantaneously. -void HideWindowImmediately(aura::Window* window, - ui::LayerAnimationObserver* observer) { - window->layer()->SetOpacity(0.0); - if (observer) - observer->OnLayerAnimationEnded(NULL); +void SessionStateAnimator::AnimationSequence::EndSequence() { + sequence_ended_ = true; + CleanupIfSequenceCompleted(); } -// Restores |window| to its original position and scale and full opacity -// instantaneously. -void RestoreWindow(aura::Window* window, ui::LayerAnimationObserver* observer) { - window->layer()->SetTransform(gfx::Transform()); - window->layer()->SetOpacity(1.0); - if (observer) - observer->OnLayerAnimationEnded(NULL); +void SessionStateAnimator::AnimationSequence::OnAnimationCompleted() { + animation_completed_ = true; + invoke_callback_ = true; + CleanupIfSequenceCompleted(); } -void HideWindow(aura::Window* window, - base::TimeDelta duration, - bool above, - ui::LayerAnimationObserver* observer) { - ui::Layer* layer = window->layer(); - ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); - - settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - settings.SetTransitionDuration(duration); - - settings.SetTweenType(gfx::Tween::EASE_OUT); - SetTransformForScaleAnimation(layer, - above ? LAYER_SCALE_ANIMATION_ABOVE : LAYER_SCALE_ANIMATION_BELOW); - - settings.SetTweenType(gfx::Tween::EASE_IN_OUT); - layer->SetOpacity(0.0f); - - // After the animation completes snap the transform back to the identity, - // otherwise any one that asks for screen bounds gets a slightly scaled - // version. - settings.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION); - settings.SetTransitionDuration(base::TimeDelta()); - layer->SetTransform(gfx::Transform()); - - // A bit of a dirty trick: we need to catch the end of the animation we don't - // control. So we use two facts we know: which animator will be used and the - // target opacity to add "Do nothing" animation sequence. - // Unfortunately, we can not just use empty LayerAnimationSequence, because - // it does not call NotifyEnded(). - if (observer) { - ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateOpacityElement( - 0.0, base::TimeDelta())); - sequence->AddObserver(observer); - layer->GetAnimator()->ScheduleAnimation(sequence); - } +void SessionStateAnimator::AnimationSequence::OnAnimationAborted() { + animation_completed_ = true; + invoke_callback_ = false; + CleanupIfSequenceCompleted(); } -// Animates |window| to identity transform and full opacity over |duration|. -void TransformWindowToBaseState(aura::Window* window, - base::TimeDelta duration, - ui::LayerAnimationObserver* observer) { - ui::Layer* layer = window->layer(); - ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); - - // Animate to target values. - settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - settings.SetTransitionDuration(duration); - - settings.SetTweenType(gfx::Tween::EASE_OUT); - layer->SetTransform(gfx::Transform()); - - settings.SetTweenType(gfx::Tween::EASE_IN_OUT); - layer->SetOpacity(1.0f); - - // A bit of a dirty trick: we need to catch the end of the animation we don't - // control. So we use two facts we know: which animator will be used and the - // target opacity to add "Do nothing" animation sequence. - // Unfortunately, we can not just use empty LayerAnimationSequence, because - // it does not call NotifyEnded(). - if (observer) { - ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( - ui::LayerAnimationElement::CreateOpacityElement( - 1.0, base::TimeDelta())); - sequence->AddObserver(observer); - layer->GetAnimator()->ScheduleAnimation(sequence); - } -} - -void ShowWindow(aura::Window* window, - base::TimeDelta duration, - bool above, - ui::LayerAnimationObserver* observer) { - ui::Layer* layer = window->layer(); - ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); - - // Set initial state of animation - settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - settings.SetTransitionDuration(base::TimeDelta()); - SetTransformForScaleAnimation(layer, - above ? LAYER_SCALE_ANIMATION_ABOVE : LAYER_SCALE_ANIMATION_BELOW); - - TransformWindowToBaseState(window, duration, observer); -} - -// Starts grayscale/brightness animation for |window| over |duration|. Target -// value for both grayscale and brightness are specified by |target|. -void StartGrayscaleBrightnessAnimationForWindow( - aura::Window* window, - float target, - base::TimeDelta duration, - gfx::Tween::Type tween_type, - ui::LayerAnimationObserver* observer) { - ui::LayerAnimator* animator = window->layer()->GetAnimator(); - - scoped_ptr<ui::LayerAnimationSequence> brightness_sequence( - new ui::LayerAnimationSequence()); - scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence( - new ui::LayerAnimationSequence()); - - scoped_ptr<ui::LayerAnimationElement> brightness_element( - ui::LayerAnimationElement::CreateBrightnessElement( - target, duration)); - brightness_element->set_tween_type(tween_type); - brightness_sequence->AddElement(brightness_element.release()); - - scoped_ptr<ui::LayerAnimationElement> grayscale_element( - ui::LayerAnimationElement::CreateGrayscaleElement( - target, duration)); - grayscale_element->set_tween_type(tween_type); - grayscale_sequence->AddElement(grayscale_element.release()); - - std::vector<ui::LayerAnimationSequence*> animations; - animations.push_back(brightness_sequence.release()); - animations.push_back(grayscale_sequence.release()); - - if (observer) - animations[0]->AddObserver(observer); - - animator->set_preemption_strategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - - animator->StartTogether(animations); -} - -// Animation observer that will drop animated foreground once animation is -// finished. It is used in when undoing shutdown animation. -class CallbackAnimationObserver : public ui::LayerAnimationObserver { - public: - explicit CallbackAnimationObserver(base::Callback<void(void)> &callback) - : callback_(callback) { - } - virtual ~CallbackAnimationObserver() { - } - - private: - // Overridden from ui::LayerAnimationObserver: - virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* seq) - OVERRIDE { - // Drop foreground once animation is over. - callback_.Run(); - delete this; - } - - virtual void OnLayerAnimationAborted(ui::LayerAnimationSequence* seq) - OVERRIDE { - // Drop foreground once animation is over. - callback_.Run(); +void SessionStateAnimator::AnimationSequence::CleanupIfSequenceCompleted() { + if (sequence_ended_ && animation_completed_) { + if (invoke_callback_) + callback_.Run(); delete this; } - - virtual void OnLayerAnimationScheduled(ui::LayerAnimationSequence* seq) - OVERRIDE {} - - base::Callback<void(void)> callback_; - - DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver); -}; - - -bool IsLayerAnimated(ui::Layer* layer, - SessionStateAnimator::AnimationType type) { - switch (type) { - case SessionStateAnimator::ANIMATION_PARTIAL_CLOSE: - if (layer->GetTargetTransform() != GetSlowCloseTransform()) - return false; - break; - case SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE: - if (layer->GetTargetTransform() != gfx::Transform()) - return false; - break; - case SessionStateAnimator::ANIMATION_FULL_CLOSE: - if (layer->GetTargetTransform() != GetFastCloseTransform() || - layer->GetTargetOpacity() > 0.0001) - return false; - break; - case SessionStateAnimator::ANIMATION_FADE_IN: - if (layer->GetTargetOpacity() < 0.9999) - return false; - break; - case SessionStateAnimator::ANIMATION_FADE_OUT: - if (layer->GetTargetOpacity() > 0.0001) - return false; - break; - case SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY: - if (layer->GetTargetOpacity() > 0.0001) - return false; - break; - case SessionStateAnimator::ANIMATION_RESTORE: - if (layer->opacity() < 0.9999 || layer->transform() != gfx::Transform()) - return false; - break; - case SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS: - if ((layer->GetTargetBrightness() < 0.9999) || - (layer->GetTargetGrayscale() < 0.9999)) - return false; - break; - case SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS: - if ((layer->GetTargetBrightness() > 0.0001) || - (layer->GetTargetGrayscale() > 0.0001)) - return false; - break; - case SessionStateAnimator::ANIMATION_DROP: - case SessionStateAnimator::ANIMATION_UNDO_LIFT: - //ToDo(antim) : check other effects - if (layer->GetTargetOpacity() < 0.9999) - return false; - break; - //ToDo(antim) : check other effects - case SessionStateAnimator::ANIMATION_LIFT: - if (layer->GetTargetOpacity() > 0.0001) - return false; - break; - case SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN: - //ToDo(antim) : check other effects - if (layer->GetTargetOpacity() < 0.9999) - return false; - break; - //ToDo(antim) : check other effects - case SessionStateAnimator::ANIMATION_LOWER_BELOW_SCREEN: - if (layer->GetTargetOpacity() > 0.0001) - return false; - break; - default: - NOTREACHED() << "Unhandled animation type " << type; - return false; - } - return true; -} - -} // namespace - -bool SessionStateAnimator::TestApi::ContainersAreAnimated( - int container_mask, AnimationType type) const { - aura::Window::Windows containers; - animator_->GetContainers(container_mask, &containers); - for (aura::Window::Windows::const_iterator it = containers.begin(); - it != containers.end(); ++it) { - aura::Window* window = *it; - ui::Layer* layer = window->layer(); - if (!IsLayerAnimated(layer, type)) - return false; - } - return true; } -bool SessionStateAnimator::TestApi::RootWindowIsAnimated(AnimationType type) - const { - aura::Window* root_window = Shell::GetPrimaryRootWindow(); - ui::Layer* layer = root_window->layer(); - return IsLayerAnimated(layer, type); -} - -const int SessionStateAnimator::kAllLockScreenContainersMask = - SessionStateAnimator::LOCK_SCREEN_BACKGROUND | - SessionStateAnimator::LOCK_SCREEN_CONTAINERS | - SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS; - -const int SessionStateAnimator::kAllContainersMask = - SessionStateAnimator::kAllLockScreenContainersMask | - SessionStateAnimator::DESKTOP_BACKGROUND | - SessionStateAnimator::LAUNCHER | - SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS; - SessionStateAnimator::SessionStateAnimator() { } SessionStateAnimator::~SessionStateAnimator() { } -base::TimeDelta SessionStateAnimator::GetDuration(AnimationSpeed speed) { +base::TimeDelta SessionStateAnimator::GetDuration( + SessionStateAnimator::AnimationSpeed speed) { switch (speed) { case ANIMATION_SPEED_IMMEDIATE: return base::TimeDelta(); @@ -450,159 +97,4 @@ base::TimeDelta SessionStateAnimator::GetDuration(AnimationSpeed speed) { return base::TimeDelta(); } -// Fills |containers| with the containers described by |container_mask|. -void SessionStateAnimator::GetContainers(int container_mask, - aura::Window::Windows* containers) { - aura::Window* root_window = Shell::GetPrimaryRootWindow(); - containers->clear(); - - if (container_mask & DESKTOP_BACKGROUND) { - containers->push_back(Shell::GetContainer( - root_window, kShellWindowId_DesktopBackgroundContainer)); - } - if (container_mask & LAUNCHER) { - containers->push_back( - Shell::GetContainer(root_window, kShellWindowId_ShelfContainer)); - } - if (container_mask & NON_LOCK_SCREEN_CONTAINERS) { - // TODO(antrim): Figure out a way to eliminate a need to exclude launcher - // in such way. - aura::Window* non_lock_screen_containers = Shell::GetContainer( - root_window, kShellWindowId_NonLockScreenContainersContainer); - aura::Window::Windows children = non_lock_screen_containers->children(); - - for (aura::Window::Windows::const_iterator it = children.begin(); - it != children.end(); ++it) { - aura::Window* window = *it; - if (window->id() == kShellWindowId_ShelfContainer) - continue; - containers->push_back(window); - } - } - if (container_mask & LOCK_SCREEN_BACKGROUND) { - containers->push_back(Shell::GetContainer( - root_window, kShellWindowId_LockScreenBackgroundContainer)); - } - if (container_mask & LOCK_SCREEN_CONTAINERS) { - containers->push_back(Shell::GetContainer( - root_window, kShellWindowId_LockScreenContainersContainer)); - } - if (container_mask & LOCK_SCREEN_RELATED_CONTAINERS) { - containers->push_back(Shell::GetContainer( - root_window, kShellWindowId_LockScreenRelatedContainersContainer)); - } -} - -void SessionStateAnimator::StartAnimation(int container_mask, - AnimationType type, - AnimationSpeed speed) { - aura::Window::Windows containers; - GetContainers(container_mask, &containers); - for (aura::Window::Windows::const_iterator it = containers.begin(); - it != containers.end(); ++it) { - RunAnimationForWindow(*it, type, speed, NULL); - } -} - -void SessionStateAnimator::StartAnimationWithCallback( - int container_mask, - AnimationType type, - AnimationSpeed speed, - base::Callback<void(void)>& callback) { - aura::Window::Windows containers; - GetContainers(container_mask, &containers); - for (aura::Window::Windows::const_iterator it = containers.begin(); - it != containers.end(); ++it) { - ui::LayerAnimationObserver* observer = - new CallbackAnimationObserver(callback); - RunAnimationForWindow(*it, type, speed, observer); - } -} - -void SessionStateAnimator::StartAnimationWithObserver( - int container_mask, - AnimationType type, - AnimationSpeed speed, - ui::LayerAnimationObserver* observer) { - aura::Window::Windows containers; - GetContainers(container_mask, &containers); - for (aura::Window::Windows::const_iterator it = containers.begin(); - it != containers.end(); ++it) { - RunAnimationForWindow(*it, type, speed, observer); - } -} - -void SessionStateAnimator::StartGlobalAnimation(AnimationType type, - AnimationSpeed speed) { - aura::Window* root_window = Shell::GetPrimaryRootWindow(); - RunAnimationForWindow(root_window, type, speed, NULL); -} - -void SessionStateAnimator::RunAnimationForWindow( - aura::Window* window, - AnimationType type, - AnimationSpeed speed, - ui::LayerAnimationObserver* observer) { - base::TimeDelta duration = GetDuration(speed); - - switch (type) { - case ANIMATION_PARTIAL_CLOSE: - StartSlowCloseAnimationForWindow(window, duration, observer); - break; - case ANIMATION_UNDO_PARTIAL_CLOSE: - StartUndoSlowCloseAnimationForWindow(window, duration, observer); - break; - case ANIMATION_FULL_CLOSE: - StartFastCloseAnimationForWindow(window, duration, observer); - break; - case ANIMATION_FADE_IN: - StartOpacityAnimationForWindow(window, 1.0, duration, observer); - break; - case ANIMATION_FADE_OUT: - StartOpacityAnimationForWindow(window, 0.0, duration, observer); - break; - case ANIMATION_HIDE_IMMEDIATELY: - DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE); - HideWindowImmediately(window, observer); - break; - case ANIMATION_RESTORE: - DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE); - RestoreWindow(window, observer); - break; - case ANIMATION_LIFT: - HideWindow(window, duration, true, observer); - break; - case ANIMATION_DROP: - ShowWindow(window, duration, true, observer); - break; - case ANIMATION_UNDO_LIFT: - TransformWindowToBaseState(window, duration, observer); - break; - case ANIMATION_RAISE_TO_SCREEN: - ShowWindow(window, duration, false, observer); - break; - case ANIMATION_LOWER_BELOW_SCREEN: - HideWindow(window, duration, false, observer); - break; - case ANIMATION_PARTIAL_FADE_IN: - StartPartialFadeAnimation( - window, kPartialFadeRatio, duration, observer); - break; - case ANIMATION_UNDO_PARTIAL_FADE_IN: - StartPartialFadeAnimation(window, 0.0, duration, observer); - break; - case ANIMATION_FULL_FADE_IN: - StartPartialFadeAnimation(window, 1.0, duration, observer); - break; - case ANIMATION_GRAYSCALE_BRIGHTNESS: - StartGrayscaleBrightnessAnimationForWindow( - window, 1.0, duration, gfx::Tween::EASE_IN, observer); - break; - case ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS: - StartGrayscaleBrightnessAnimationForWindow( - window, 0.0, duration, gfx::Tween::EASE_IN_OUT, observer); - break; - } -} - } // namespace ash diff --git a/ash/wm/session_state_animator.h b/ash/wm/session_state_animator.h index a9e43db4..b293b47 100644 --- a/ash/wm/session_state_animator.h +++ b/ash/wm/session_state_animator.h @@ -7,19 +7,8 @@ #include "ash/ash_export.h" #include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/timer/timer.h" -#include "ui/aura/window.h" -#include "ui/compositor/layer_animation_observer.h" - -namespace gfx { -class Rect; -class Size; -} - -namespace ui { -class Layer; -} +#include "base/callback.h" +#include "base/time/time.h" namespace ash { @@ -98,78 +87,135 @@ class ASH_EXPORT SessionStateAnimator { // Multiple system layers belong here like status, menu, tooltip // and overlay layers. LOCK_SCREEN_RELATED_CONTAINERS = 1 << 5, + + // The primary root window. + ROOT_CONTAINER = 1 << 6, }; - // Helper class used by tests to access internal state. - class ASH_EXPORT TestApi { + // A bitfield mask including LOCK_SCREEN_WALLPAPER, + // LOCK_SCREEN_CONTAINERS, and LOCK_SCREEN_RELATED_CONTAINERS. + static const int kAllLockScreenContainersMask; + + // A bitfield mask of all containers except the ROOT_CONTAINER. + static const int kAllNonRootContainersMask; + + // The AnimationSequence groups together multiple animations and invokes a + // callback once all contained animations are completed successfully. + // Subclasses of AnimationSequence should call one of OnAnimationCompleted or + // OnAnimationAborted once and behaviour is undefined if called multiple + // times. + // AnimationSequences will destroy themselves once EndSquence and one of + // OnAnimationCompleted or OnAnimationAborted has been called. + // + // Typical usage: + // AnimationSequence* animation_sequence = + // session_state_animator->BeginAnimationSequence(some_callback); + // animation_sequence->StartAnimation( + // SessionStateAnimator::LAUNCHER, + // SessionStateAnimator::ANIMATION_FADE_IN, + // SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); + // animation_sequence->StartAnimation( + // SessionStateAnimator::LAUNCHER, + // SessionStateAnimator::ANIMATION_FADE_IN, + // SessionStateAnimator::ANIMATION_SPEED_UNDOABLE); + // animation_sequence->EndSequence(); + // // some_callback won't be called until here even if the animations + // // were completed before the EndSequence call. + // + class ASH_EXPORT AnimationSequence { public: - explicit TestApi(SessionStateAnimator* animator) - : animator_(animator) {} + virtual ~AnimationSequence(); + + // Apply animation |type| to all containers included in |container_mask| + // with specified |speed|. + virtual void StartAnimation(int container_mask, + AnimationType type, + AnimationSpeed speed) = 0; + + // Ends the animation sequence and enables the callback to be invoked + // when the animation sequence has completed. No more animations should be + // started after EndSequence is called because the AnimationSequenceObserver + // may have destroyed itself. + // NOTE: Clients of AnimationSequence should not access it after EndSequence + // has been called. + virtual void EndSequence(); + + protected: + // AnimationSequence should not be instantiated directly, only through + // subclasses. + explicit AnimationSequence(base::Closure callback); + + // Subclasses should call this when the contained animations completed + // successfully. + // NOTE: This should NOT be accessed after OnAnimationCompleted has been + // called. + virtual void OnAnimationCompleted(); + + // Subclasses should call this when the contained animations did NOT + // complete successfully. + // NOTE: This should NOT be accessed after OnAnimationAborted has been + // called. + virtual void OnAnimationAborted(); - // Returns true if containers of a given |container_mask| - // were last animated with |type| (probably; the analysis is fairly ad-hoc). - // |container_mask| is a bitfield of a Container. - bool ContainersAreAnimated(int container_mask, AnimationType type) const; + private: + // Destroys this and calls the callback if the contained animations + // completed successfully. + void CleanupIfSequenceCompleted(); - // Returns true if root window was last animated with |type| (probably; - // the analysis is fairly ad-hoc). - bool RootWindowIsAnimated(AnimationType type) const; + // Tracks whether the sequence has ended. + bool sequence_ended_; - private: - SessionStateAnimator* animator_; // not owned + // Track whether the contained animations have completed or not, both + // successfully and unsuccessfully. + bool animation_completed_; - DISALLOW_COPY_AND_ASSIGN(TestApi); - }; + // Flag to specify whether the callback should be invoked once the sequence + // has completed. + bool invoke_callback_; - // A bitfield mask including LOCK_SCREEN_WALLPAPER, - // LOCK_SCREEN_CONTAINERS, and LOCK_SCREEN_RELATED_CONTAINERS. - const static int kAllLockScreenContainersMask; + // Callback to be called. + base::Closure callback_; - // A bitfield mask of all containers. - const static int kAllContainersMask; + DISALLOW_COPY_AND_ASSIGN(AnimationSequence); + }; SessionStateAnimator(); virtual ~SessionStateAnimator(); // Reports animation duration for |speed|. - static base::TimeDelta GetDuration(AnimationSpeed speed); - - // Fills |containers| with the containers included in |container_mask|. - static void GetContainers(int container_mask, - aura::Window::Windows* containers); + virtual base::TimeDelta GetDuration(AnimationSpeed speed); // Apply animation |type| to all containers included in |container_mask| with // specified |speed|. - void StartAnimation(int container_mask, - AnimationType type, - AnimationSpeed speed); + virtual void StartAnimation(int container_mask, + AnimationType type, + AnimationSpeed speed) = 0; // Apply animation |type| to all containers included in |container_mask| with // specified |speed| and call a |callback| at the end of the animation, if it // is not null. - void StartAnimationWithCallback(int container_mask, - AnimationType type, - AnimationSpeed speed, - base::Callback<void(void)>& callback); - -// Apply animation |type| to all containers included in |container_mask| with -// specified |speed| and add |observer| to all animations. - void StartAnimationWithObserver(int container_mask, - AnimationType type, - AnimationSpeed speed, - ui::LayerAnimationObserver* observer); - - // Applies animation |type| whith specified |speed| to the root container. - void StartGlobalAnimation(AnimationType type, - AnimationSpeed speed); - - // Apply animation |type| to window |window| with |speed| and add |observer| - // if it is not NULL to the last animation sequence. - void RunAnimationForWindow(aura::Window* window, - AnimationType type, - AnimationSpeed speed, - ui::LayerAnimationObserver* observer); + virtual void StartAnimationWithCallback( + int container_mask, + AnimationType type, + AnimationSpeed speed, + base::Closure callback) = 0; + + // Begins an animation sequence. Use this when you need to be notified when + // a group of animations are completed. See AnimationSequence documentation + // for more details. + virtual AnimationSequence* BeginAnimationSequence( + base::Closure callback) = 0; + + // Retruns true if the background is hidden. + virtual bool IsBackgroundHidden() const = 0; + + // Shows the background immediately. + virtual void ShowBackground() = 0; + + // Hides the background immediately. + virtual void HideBackground() = 0; + private: DISALLOW_COPY_AND_ASSIGN(SessionStateAnimator); }; diff --git a/ash/wm/session_state_animator_impl.cc b/ash/wm/session_state_animator_impl.cc new file mode 100644 index 0000000..4fb0d7b --- /dev/null +++ b/ash/wm/session_state_animator_impl.cc @@ -0,0 +1,669 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/wm/session_state_animator_impl.h" + +#include <vector> + +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/wm/window_animations.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window_event_dispatcher.h" +#include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/layer_animation_sequence.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace { + +// Slightly-smaller size that we scale the screen down to for the pre-lock and +// pre-shutdown states. +const float kSlowCloseSizeRatio = 0.95f; + +// Maximum opacity of white layer when animating pre-shutdown state. +const float kPartialFadeRatio = 0.3f; + +// Minimum size. Not zero as it causes numeric issues. +const float kMinimumScale = 1e-4f; + +// Returns the primary root window's container. +aura::Window* GetBackground() { + aura::Window* root_window = Shell::GetPrimaryRootWindow(); + return Shell::GetContainer(root_window, + kShellWindowId_DesktopBackgroundContainer); +} + +// Returns the transform that should be applied to containers for the slow-close +// animation. +gfx::Transform GetSlowCloseTransform() { + gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size(); + gfx::Transform transform; + transform.Translate( + floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.width() + 0.5), + floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.height() + 0.5)); + transform.Scale(kSlowCloseSizeRatio, kSlowCloseSizeRatio); + return transform; +} + +// Returns the transform that should be applied to containers for the fast-close +// animation. +gfx::Transform GetFastCloseTransform() { + gfx::Size root_size = Shell::GetPrimaryRootWindow()->bounds().size(); + gfx::Transform transform; + + transform.Translate(floor(0.5 * root_size.width() + 0.5), + floor(0.5 * root_size.height() + 0.5)); + transform.Scale(kMinimumScale, kMinimumScale); + return transform; +} + +// Slowly shrinks |window| to a slightly-smaller size. +void StartSlowCloseAnimationForWindow(aura::Window* window, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer) { + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->set_preemption_strategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateTransformElement( + GetSlowCloseTransform(), + duration)); + if (observer) + sequence->AddObserver(observer); + animator->StartAnimation(sequence); +} + +// Quickly undoes the effects of the slow-close animation on |window|. +void StartUndoSlowCloseAnimationForWindow( + aura::Window* window, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer) { + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->set_preemption_strategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateTransformElement( + gfx::Transform(), + duration)); + if (observer) + sequence->AddObserver(observer); + animator->StartAnimation(sequence); +} + +// Quickly shrinks |window| down to a point in the center of the screen and +// fades it out to 0 opacity. +void StartFastCloseAnimationForWindow(aura::Window* window, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer) { + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->set_preemption_strategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + animator->StartAnimation( + new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateTransformElement( + GetFastCloseTransform(), duration))); + ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateOpacityElement(0.0, duration)); + if (observer) + sequence->AddObserver(observer); + animator->StartAnimation(sequence); +} + +// Fades |window| to |target_opacity| over |duration|. +void StartPartialFadeAnimation(aura::Window* window, + float target_opacity, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer) { + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->set_preemption_strategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateOpacityElement( + target_opacity, duration)); + if (observer) + sequence->AddObserver(observer); + animator->StartAnimation(sequence); +} + +// Fades |window| to |opacity| over |duration|. +void StartOpacityAnimationForWindow(aura::Window* window, + float opacity, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer) { + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + animator->set_preemption_strategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateOpacityElement(opacity, duration)); + if (observer) + sequence->AddObserver(observer); + animator->StartAnimation(sequence); +} + +// Makes |window| fully transparent instantaneously. +void HideWindowImmediately(aura::Window* window, + ui::LayerAnimationObserver* observer) { + window->layer()->SetOpacity(0.0); + if (observer) + observer->OnLayerAnimationEnded(NULL); +} + +// Restores |window| to its original position and scale and full opacity +// instantaneously. +void RestoreWindow(aura::Window* window, ui::LayerAnimationObserver* observer) { + window->layer()->SetTransform(gfx::Transform()); + window->layer()->SetOpacity(1.0); + if (observer) + observer->OnLayerAnimationEnded(NULL); +} + +void HideWindow(aura::Window* window, + base::TimeDelta duration, + bool above, + ui::LayerAnimationObserver* observer) { + ui::Layer* layer = window->layer(); + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); + + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + settings.SetTransitionDuration(duration); + + settings.SetTweenType(gfx::Tween::EASE_OUT); + SetTransformForScaleAnimation(layer, + above ? LAYER_SCALE_ANIMATION_ABOVE : LAYER_SCALE_ANIMATION_BELOW); + + settings.SetTweenType(gfx::Tween::EASE_IN_OUT); + layer->SetOpacity(0.0f); + + // After the animation completes snap the transform back to the identity, + // otherwise any one that asks for screen bounds gets a slightly scaled + // version. + settings.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION); + settings.SetTransitionDuration(base::TimeDelta()); + layer->SetTransform(gfx::Transform()); + + // A bit of a dirty trick: we need to catch the end of the animation we don't + // control. So we use two facts we know: which animator will be used and the + // target opacity to add "Do nothing" animation sequence. + // Unfortunately, we can not just use empty LayerAnimationSequence, because + // it does not call NotifyEnded(). + if (observer) { + ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateOpacityElement( + 0.0, base::TimeDelta())); + sequence->AddObserver(observer); + layer->GetAnimator()->ScheduleAnimation(sequence); + } +} + +// Animates |window| to identity transform and full opacity over |duration|. +void TransformWindowToBaseState(aura::Window* window, + base::TimeDelta duration, + ui::LayerAnimationObserver* observer) { + ui::Layer* layer = window->layer(); + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); + + // Animate to target values. + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + settings.SetTransitionDuration(duration); + + settings.SetTweenType(gfx::Tween::EASE_OUT); + layer->SetTransform(gfx::Transform()); + + settings.SetTweenType(gfx::Tween::EASE_IN_OUT); + layer->SetOpacity(1.0f); + + // A bit of a dirty trick: we need to catch the end of the animation we don't + // control. So we use two facts we know: which animator will be used and the + // target opacity to add "Do nothing" animation sequence. + // Unfortunately, we can not just use empty LayerAnimationSequence, because + // it does not call NotifyEnded(). + if (observer) { + ui::LayerAnimationSequence* sequence = new ui::LayerAnimationSequence( + ui::LayerAnimationElement::CreateOpacityElement( + 1.0, base::TimeDelta())); + sequence->AddObserver(observer); + layer->GetAnimator()->ScheduleAnimation(sequence); + } +} + +void ShowWindow(aura::Window* window, + base::TimeDelta duration, + bool above, + ui::LayerAnimationObserver* observer) { + ui::Layer* layer = window->layer(); + ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); + + // Set initial state of animation + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + settings.SetTransitionDuration(base::TimeDelta()); + SetTransformForScaleAnimation(layer, + above ? LAYER_SCALE_ANIMATION_ABOVE : LAYER_SCALE_ANIMATION_BELOW); + + TransformWindowToBaseState(window, duration, observer); +} + +// Starts grayscale/brightness animation for |window| over |duration|. Target +// value for both grayscale and brightness are specified by |target|. +void StartGrayscaleBrightnessAnimationForWindow( + aura::Window* window, + float target, + base::TimeDelta duration, + gfx::Tween::Type tween_type, + ui::LayerAnimationObserver* observer) { + ui::LayerAnimator* animator = window->layer()->GetAnimator(); + + scoped_ptr<ui::LayerAnimationSequence> brightness_sequence( + new ui::LayerAnimationSequence()); + scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence( + new ui::LayerAnimationSequence()); + + scoped_ptr<ui::LayerAnimationElement> brightness_element( + ui::LayerAnimationElement::CreateBrightnessElement( + target, duration)); + brightness_element->set_tween_type(tween_type); + brightness_sequence->AddElement(brightness_element.release()); + + scoped_ptr<ui::LayerAnimationElement> grayscale_element( + ui::LayerAnimationElement::CreateGrayscaleElement( + target, duration)); + grayscale_element->set_tween_type(tween_type); + grayscale_sequence->AddElement(grayscale_element.release()); + + std::vector<ui::LayerAnimationSequence*> animations; + animations.push_back(brightness_sequence.release()); + animations.push_back(grayscale_sequence.release()); + + if (observer) + animations[0]->AddObserver(observer); + + animator->set_preemption_strategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + + animator->StartTogether(animations); +} + +// Animation observer that will drop animated foreground once animation is +// finished. It is used in when undoing shutdown animation. +class CallbackAnimationObserver : public ui::LayerAnimationObserver { + public: + explicit CallbackAnimationObserver(base::Closure callback) + : callback_(callback) { + } + virtual ~CallbackAnimationObserver() { + } + + private: + // Overridden from ui::LayerAnimationObserver: + virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* seq) + OVERRIDE { + // Drop foreground once animation is over. + callback_.Run(); + delete this; + } + + virtual void OnLayerAnimationAborted(ui::LayerAnimationSequence* seq) + OVERRIDE { + // Drop foreground once animation is over. + callback_.Run(); + delete this; + } + + virtual void OnLayerAnimationScheduled(ui::LayerAnimationSequence* seq) + OVERRIDE {} + + base::Closure callback_; + + DISALLOW_COPY_AND_ASSIGN(CallbackAnimationObserver); +}; + + +bool IsLayerAnimated(ui::Layer* layer, + SessionStateAnimator::AnimationType type) { + switch (type) { + case SessionStateAnimator::ANIMATION_PARTIAL_CLOSE: + if (layer->GetTargetTransform() != GetSlowCloseTransform()) + return false; + break; + case SessionStateAnimator::ANIMATION_UNDO_PARTIAL_CLOSE: + if (layer->GetTargetTransform() != gfx::Transform()) + return false; + break; + case SessionStateAnimator::ANIMATION_FULL_CLOSE: + if (layer->GetTargetTransform() != GetFastCloseTransform() || + layer->GetTargetOpacity() > 0.0001) + return false; + break; + case SessionStateAnimator::ANIMATION_FADE_IN: + if (layer->GetTargetOpacity() < 0.9999) + return false; + break; + case SessionStateAnimator::ANIMATION_FADE_OUT: + if (layer->GetTargetOpacity() > 0.0001) + return false; + break; + case SessionStateAnimator::ANIMATION_HIDE_IMMEDIATELY: + if (layer->GetTargetOpacity() > 0.0001) + return false; + break; + case SessionStateAnimator::ANIMATION_RESTORE: + if (layer->opacity() < 0.9999 || layer->transform() != gfx::Transform()) + return false; + break; + case SessionStateAnimator::ANIMATION_GRAYSCALE_BRIGHTNESS: + if ((layer->GetTargetBrightness() < 0.9999) || + (layer->GetTargetGrayscale() < 0.9999)) + return false; + break; + case SessionStateAnimator::ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS: + if ((layer->GetTargetBrightness() > 0.0001) || + (layer->GetTargetGrayscale() > 0.0001)) + return false; + break; + case SessionStateAnimator::ANIMATION_DROP: + case SessionStateAnimator::ANIMATION_UNDO_LIFT: + //ToDo(antim) : check other effects + if (layer->GetTargetOpacity() < 0.9999) + return false; + break; + //ToDo(antim) : check other effects + case SessionStateAnimator::ANIMATION_LIFT: + if (layer->GetTargetOpacity() > 0.0001) + return false; + break; + case SessionStateAnimator::ANIMATION_RAISE_TO_SCREEN: + //ToDo(antim) : check other effects + if (layer->GetTargetOpacity() < 0.9999) + return false; + break; + //ToDo(antim) : check other effects + case SessionStateAnimator::ANIMATION_LOWER_BELOW_SCREEN: + if (layer->GetTargetOpacity() > 0.0001) + return false; + break; + default: + NOTREACHED() << "Unhandled animation type " << type; + return false; + } + return true; +} + +} // namespace + +// This observer is intended to use in cases when some action has to be taken +// once some animation successfully completes (i.e. it was not aborted). +// Observer will count a number of sequences it is attached to, and a number of +// finished sequences (either Ended or Aborted). Once these two numbers are +// equal, observer will delete itself, calling callback passed to constructor if +// there were no aborted animations. +// This way it can be either used to wait for some animation to be finished in +// multiple layers, to wait once a sequence of animations is finished in one +// layer or the mixture of both. +class SessionStateAnimatorImpl::AnimationSequence + : public SessionStateAnimator::AnimationSequence, + public ui::LayerAnimationObserver { + public: + explicit AnimationSequence( + SessionStateAnimatorImpl* animator, + base::Closure callback) + : SessionStateAnimator::AnimationSequence(callback), + animator_(animator), + sequences_attached_(0), + sequences_completed_(0) { + } + + // SessionStateAnimator::AnimationSequence: + virtual void StartAnimation( + int container_mask, + SessionStateAnimator::AnimationType type, + SessionStateAnimator::AnimationSpeed speed) OVERRIDE { + animator_->StartAnimationInSequence(container_mask, type, speed, this); + } + + private: + virtual ~AnimationSequence() {} + + // ui::LayerAnimationObserver: + virtual void OnLayerAnimationEnded( + ui::LayerAnimationSequence* sequence) OVERRIDE { + sequences_completed_++; + if (sequences_completed_ == sequences_attached_) + OnAnimationCompleted(); + } + + virtual void OnLayerAnimationAborted( + ui::LayerAnimationSequence* sequence) OVERRIDE { + sequences_completed_++; + if (sequences_completed_ == sequences_attached_) + OnAnimationAborted(); + } + + virtual void OnLayerAnimationScheduled( + ui::LayerAnimationSequence* sequence) OVERRIDE {} + + virtual void OnAttachedToSequence( + ui::LayerAnimationSequence* sequence) OVERRIDE { + LayerAnimationObserver::OnAttachedToSequence(sequence); + sequences_attached_++; + } + + SessionStateAnimatorImpl* animator_; // not owned + + // Number of sequences this observer was attached to. + int sequences_attached_; + + // Number of sequences either ended or aborted. + int sequences_completed_; + + DISALLOW_COPY_AND_ASSIGN(AnimationSequence); +}; + +bool SessionStateAnimatorImpl::TestApi::ContainersAreAnimated( + int container_mask, AnimationType type) const { + aura::Window::Windows containers; + animator_->GetContainers(container_mask, &containers); + for (aura::Window::Windows::const_iterator it = containers.begin(); + it != containers.end(); ++it) { + aura::Window* window = *it; + ui::Layer* layer = window->layer(); + if (!IsLayerAnimated(layer, type)) + return false; + } + return true; +} + +bool SessionStateAnimatorImpl::TestApi::RootWindowIsAnimated(AnimationType type) + const { + aura::Window* root_window = Shell::GetPrimaryRootWindow(); + ui::Layer* layer = root_window->layer(); + return IsLayerAnimated(layer, type); +} + +SessionStateAnimatorImpl::SessionStateAnimatorImpl() { +} + +SessionStateAnimatorImpl::~SessionStateAnimatorImpl() { +} + +// Fills |containers| with the containers described by |container_mask|. +void SessionStateAnimatorImpl::GetContainers(int container_mask, + aura::Window::Windows* containers) { + aura::Window* root_window = Shell::GetPrimaryRootWindow(); + containers->clear(); + + if (container_mask & ROOT_CONTAINER) { + containers->push_back(Shell::GetPrimaryRootWindow()); + } + + if (container_mask & DESKTOP_BACKGROUND) { + containers->push_back(Shell::GetContainer( + root_window, kShellWindowId_DesktopBackgroundContainer)); + } + if (container_mask & LAUNCHER) { + containers->push_back( + Shell::GetContainer(root_window, kShellWindowId_ShelfContainer)); + } + if (container_mask & NON_LOCK_SCREEN_CONTAINERS) { + // TODO(antrim): Figure out a way to eliminate a need to exclude launcher + // in such way. + aura::Window* non_lock_screen_containers = Shell::GetContainer( + root_window, kShellWindowId_NonLockScreenContainersContainer); + aura::Window::Windows children = non_lock_screen_containers->children(); + + for (aura::Window::Windows::const_iterator it = children.begin(); + it != children.end(); ++it) { + aura::Window* window = *it; + if (window->id() == kShellWindowId_ShelfContainer) + continue; + containers->push_back(window); + } + } + if (container_mask & LOCK_SCREEN_BACKGROUND) { + containers->push_back(Shell::GetContainer( + root_window, kShellWindowId_LockScreenBackgroundContainer)); + } + if (container_mask & LOCK_SCREEN_CONTAINERS) { + containers->push_back(Shell::GetContainer( + root_window, kShellWindowId_LockScreenContainersContainer)); + } + if (container_mask & LOCK_SCREEN_RELATED_CONTAINERS) { + containers->push_back(Shell::GetContainer( + root_window, kShellWindowId_LockScreenRelatedContainersContainer)); + } +} + +void SessionStateAnimatorImpl::StartAnimation(int container_mask, + AnimationType type, + AnimationSpeed speed) { + aura::Window::Windows containers; + GetContainers(container_mask, &containers); + for (aura::Window::Windows::const_iterator it = containers.begin(); + it != containers.end(); ++it) { + RunAnimationForWindow(*it, type, speed, NULL); + } +} + +void SessionStateAnimatorImpl::StartAnimationWithCallback( + int container_mask, + AnimationType type, + AnimationSpeed speed, + base::Closure callback) { + aura::Window::Windows containers; + GetContainers(container_mask, &containers); + for (aura::Window::Windows::const_iterator it = containers.begin(); + it != containers.end(); ++it) { + ui::LayerAnimationObserver* observer = + new CallbackAnimationObserver(callback); + RunAnimationForWindow(*it, type, speed, observer); + } +} + +SessionStateAnimator::AnimationSequence* + SessionStateAnimatorImpl::BeginAnimationSequence(base::Closure callback) { + return new AnimationSequence(this, callback); +} + +bool SessionStateAnimatorImpl::IsBackgroundHidden() const { + return !GetBackground()->IsVisible(); +} + +void SessionStateAnimatorImpl::ShowBackground() { + ui::ScopedLayerAnimationSettings settings( + GetBackground()->layer()->GetAnimator()); + settings.SetTransitionDuration(base::TimeDelta()); + GetBackground()->Show(); +} + +void SessionStateAnimatorImpl::HideBackground() { + ui::ScopedLayerAnimationSettings settings( + GetBackground()->layer()->GetAnimator()); + settings.SetTransitionDuration(base::TimeDelta()); + GetBackground()->Hide(); +} + +void SessionStateAnimatorImpl::StartAnimationInSequence( + int container_mask, + AnimationType type, + AnimationSpeed speed, + AnimationSequence* observer) { + aura::Window::Windows containers; + GetContainers(container_mask, &containers); + for (aura::Window::Windows::const_iterator it = containers.begin(); + it != containers.end(); ++it) { + RunAnimationForWindow(*it, type, speed, observer); + } +} + +void SessionStateAnimatorImpl::RunAnimationForWindow( + aura::Window* window, + AnimationType type, + AnimationSpeed speed, + ui::LayerAnimationObserver* observer) { + base::TimeDelta duration = GetDuration(speed); + + switch (type) { + case ANIMATION_PARTIAL_CLOSE: + StartSlowCloseAnimationForWindow(window, duration, observer); + break; + case ANIMATION_UNDO_PARTIAL_CLOSE: + StartUndoSlowCloseAnimationForWindow(window, duration, observer); + break; + case ANIMATION_FULL_CLOSE: + StartFastCloseAnimationForWindow(window, duration, observer); + break; + case ANIMATION_FADE_IN: + StartOpacityAnimationForWindow(window, 1.0, duration, observer); + break; + case ANIMATION_FADE_OUT: + StartOpacityAnimationForWindow(window, 0.0, duration, observer); + break; + case ANIMATION_HIDE_IMMEDIATELY: + DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE); + HideWindowImmediately(window, observer); + break; + case ANIMATION_RESTORE: + DCHECK_EQ(speed, ANIMATION_SPEED_IMMEDIATE); + RestoreWindow(window, observer); + break; + case ANIMATION_LIFT: + HideWindow(window, duration, true, observer); + break; + case ANIMATION_DROP: + ShowWindow(window, duration, true, observer); + break; + case ANIMATION_UNDO_LIFT: + TransformWindowToBaseState(window, duration, observer); + break; + case ANIMATION_RAISE_TO_SCREEN: + ShowWindow(window, duration, false, observer); + break; + case ANIMATION_LOWER_BELOW_SCREEN: + HideWindow(window, duration, false, observer); + break; + case ANIMATION_PARTIAL_FADE_IN: + StartPartialFadeAnimation( + window, kPartialFadeRatio, duration, observer); + break; + case ANIMATION_UNDO_PARTIAL_FADE_IN: + StartPartialFadeAnimation(window, 0.0, duration, observer); + break; + case ANIMATION_FULL_FADE_IN: + StartPartialFadeAnimation(window, 1.0, duration, observer); + break; + case ANIMATION_GRAYSCALE_BRIGHTNESS: + StartGrayscaleBrightnessAnimationForWindow( + window, 1.0, duration, gfx::Tween::EASE_IN, observer); + break; + case ANIMATION_UNDO_GRAYSCALE_BRIGHTNESS: + StartGrayscaleBrightnessAnimationForWindow( + window, 0.0, duration, gfx::Tween::EASE_IN_OUT, observer); + break; + } +} + +} // namespace ash diff --git a/ash/wm/session_state_animator_impl.h b/ash/wm/session_state_animator_impl.h new file mode 100644 index 0000000..bad7103 --- /dev/null +++ b/ash/wm/session_state_animator_impl.h @@ -0,0 +1,88 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_WM_SESSION_STATE_ANIMATOR_IMPL_H_ +#define ASH_WM_SESSION_STATE_ANIMATOR_IMPL_H_ + +#include "ash/ash_export.h" +#include "ash/wm/session_state_animator.h" +#include "base/basictypes.h" +#include "ui/aura/window.h" + +namespace ui { +class LayerAnimationObserver; +} + +namespace ash { + +// Displays onscreen animations for session state changes (lock/unlock, sign +// out, shut down). +class ASH_EXPORT SessionStateAnimatorImpl : public SessionStateAnimator { + public: + // Helper class used by tests to access internal state. + class ASH_EXPORT TestApi { + public: + explicit TestApi(SessionStateAnimatorImpl* animator) + : animator_(animator) {} + + // Returns true if containers of a given |container_mask| + // were last animated with |type| (probably; the analysis is fairly ad-hoc). + // |container_mask| is a bitfield of a Container. + bool ContainersAreAnimated(int container_mask, + SessionStateAnimator::AnimationType type) const; + + // Returns true if root window was last animated with |type| (probably; + // the analysis is fairly ad-hoc). + bool RootWindowIsAnimated(SessionStateAnimator::AnimationType type) const; + + private: + SessionStateAnimatorImpl* animator_; // not owned + + DISALLOW_COPY_AND_ASSIGN(TestApi); + }; + + SessionStateAnimatorImpl(); + virtual ~SessionStateAnimatorImpl(); + + // Fills |containers| with the containers included in |container_mask|. + static void GetContainers(int container_mask, + aura::Window::Windows* containers); + + // ash::SessionStateAnimator: + virtual void StartAnimation(int container_mask, + AnimationType type, + AnimationSpeed speed) OVERRIDE; + virtual void StartAnimationWithCallback( + int container_mask, + AnimationType type, + AnimationSpeed speed, + base::Closure callback) OVERRIDE; + virtual AnimationSequence* BeginAnimationSequence( + base::Closure callback) OVERRIDE; + virtual bool IsBackgroundHidden() const OVERRIDE; + virtual void ShowBackground() OVERRIDE; + virtual void HideBackground() OVERRIDE; + + private: + class AnimationSequence; + friend class AnimationSequence; + + virtual void StartAnimationInSequence(int container_mask, + AnimationType type, + AnimationSpeed speed, + AnimationSequence* observer); + + // Apply animation |type| to window |window| with |speed| and add |observer| + // if it is not NULL to the last animation sequence. + void RunAnimationForWindow(aura::Window* window, + SessionStateAnimator::AnimationType type, + SessionStateAnimator::AnimationSpeed speed, + ui::LayerAnimationObserver* observer); + + DISALLOW_COPY_AND_ASSIGN(SessionStateAnimatorImpl); +}; + +} // namespace ash + +#endif // ASH_WM_SESSION_STATE_ANIMATOR_IMPL_H_ diff --git a/chrome/browser/chromeos/power/power_button_observer.cc b/chrome/browser/chromeos/power/power_button_observer.cc index 8a74cae..e7a2718 100644 --- a/chrome/browser/chromeos/power/power_button_observer.cc +++ b/chrome/browser/chromeos/power/power_button_observer.cc @@ -15,6 +15,10 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "content/public/browser/notification_service.h" +namespace ash { +class LockStateControllerDelegate; +} + namespace chromeos { namespace { @@ -30,7 +34,8 @@ ash::user::LoginStatus GetCurrentLoginStatus() { PowerButtonObserver::PowerButtonObserver() { ash::Shell::GetInstance()->lock_state_controller()-> - SetDelegate(new SessionStateControllerDelegateChromeos); + SetDelegate(scoped_ptr<ash::LockStateControllerDelegate>( + new SessionStateControllerDelegateChromeos)); registrar_.Add( this, |