Skip to content

Commit

Permalink
Changes sequence of docked animations when evicting windows from dock…
Browse files Browse the repository at this point in the history
…. Windows that are restored into docked area are slid from below rather than from above as before. Additionally minimizing animation for the windows that no longer fit in the dock is slowed down in hopes of making it less confusing.

To allow this a new ScopedLayerAnimationSettings::LockTransitionDuration method is introduced which locks the current animation transition duration until the ScopedLayerAnimationSettings object that invoked it goes out of scope.

BUG=323188
TEST=ash_unittests --gtest_filter=WindowAnimationsTest.LockAnimationDuration

Review URL: https://codereview.chromium.org/82573002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238212 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
varkha@chromium.org committed Dec 2, 2013
1 parent dd3e22f commit fbc9448
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 16 deletions.
18 changes: 13 additions & 5 deletions ash/wm/dock/docked_window_layout_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ const int DockedWindowLayoutManager::kMinDockGap = 2;
const int DockedWindowLayoutManager::kIdealWidth = 250;
const int kMinimumHeight = 250;
const int kSlideDurationMs = 120;
const int kFadeDurationMs = 720;
const int kFadeDurationMs = 60;
const int kMinimizeDurationMs = 720;

namespace {

Expand Down Expand Up @@ -654,10 +655,17 @@ void DockedWindowLayoutManager::MaybeMinimizeChildrenExcept(
if (window == child || !IsUsedByLayout(window))
continue;
int room_needed = GetWindowHeightCloseTo(window, 0) + kMinDockGap;
if (available_room > room_needed)
if (available_room > room_needed) {
available_room -= room_needed;
else
} else {
// Slow down minimizing animations. Lock duration so that it is not
// overridden by other ScopedLayerAnimationSettings down the stack.
ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
settings.SetTransitionDuration(
base::TimeDelta::FromMilliseconds(kMinimizeDurationMs));
settings.LockTransitionDuration();
wm::GetWindowState(window)->Minimize();
}
}
}

Expand All @@ -674,7 +682,7 @@ void DockedWindowLayoutManager::RestoreDockedWindow(
wm::WindowState* window_state) {
aura::Window* window = window_state->window();
DCHECK(!IsPopupOrTransient(window));
// Always place restored window at the top shuffling the other windows down.
// Always place restored window at the bottom shuffling the other windows up.
// TODO(varkha): add a separate container for docked windows to keep track
// of ordering.
gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(
Expand All @@ -688,7 +696,7 @@ void DockedWindowLayoutManager::RestoreDockedWindow(
return;
}
gfx::Rect bounds(window->bounds());
bounds.set_y(work_area.y() - bounds.height());
bounds.set_y(work_area.bottom());
window->SetBounds(bounds);
window->Show();
MaybeMinimizeChildrenExcept(window);
Expand Down
8 changes: 6 additions & 2 deletions ash/wm/window_animations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ void AddLayerAnimationsForMinimize(aura::Window* window, bool show) {

rotation_about_pivot->SetReversed(show);

base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
kLayerAnimationsForMinimizeDurationMS);
base::TimeDelta duration = window->layer()->GetAnimator()->
GetTransitionDuration();

scoped_ptr<ui::LayerAnimationElement> transition(
ui::LayerAnimationElement::CreateInterpolatedTransformElement(
Expand Down Expand Up @@ -136,6 +136,10 @@ void AddLayerAnimationsForMinimize(aura::Window* window, bool show) {
void AnimateShowWindow_Minimize(aura::Window* window) {
window->layer()->set_delegate(window);
window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
kLayerAnimationsForMinimizeDurationMS);
settings.SetTransitionDuration(duration);
AddLayerAnimationsForMinimize(window, true);

// Now that the window has been restored, we need to clear its animation style
Expand Down
106 changes: 106 additions & 0 deletions ash/wm/window_animations_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@

#include "ash/shell_window_ids.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/window_state.h"
#include "ash/wm/workspace_controller.h"
#include "base/time/time.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.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/gfx/animation/animation_container_element.h"

using aura::Window;
Expand All @@ -33,6 +36,37 @@ class WindowAnimationsTest : public ash::test::AshTestBase {
DISALLOW_COPY_AND_ASSIGN(WindowAnimationsTest);
};

// Listens to animation scheduled notifications. Remembers the transition
// duration of the first sequence.
class MinimizeAnimationObserver : public ui::LayerAnimationObserver {
public:
explicit MinimizeAnimationObserver(ui::LayerAnimator* animator)
: animator_(animator) {
animator_->AddObserver(this);
// RemoveObserver is called when the first animation is scheduled and so
// there should be no need for now to remove it in destructor.
};
base::TimeDelta duration() { return duration_; }

protected:
// ui::LayerAnimationObserver:
virtual void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) OVERRIDE {
duration_ = animator_->GetTransitionDuration();
animator_->RemoveObserver(this);
}
virtual void OnLayerAnimationEnded(
ui::LayerAnimationSequence* sequence) OVERRIDE {}
virtual void OnLayerAnimationAborted(
ui::LayerAnimationSequence* sequence) OVERRIDE {}

private:
ui::LayerAnimator* animator_;
base::TimeDelta duration_;

DISALLOW_COPY_AND_ASSIGN(MinimizeAnimationObserver);
};

TEST_F(WindowAnimationsTest, HideShowBrightnessGrayscaleAnimation) {
scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
window->Show();
Expand Down Expand Up @@ -133,5 +167,77 @@ TEST_F(WindowAnimationsTest, CrossFadeToBounds) {
Step(base::TimeTicks::Now() + base::TimeDelta::FromSeconds(1));
}

TEST_F(WindowAnimationsTest, LockAnimationDuration) {
ui::ScopedAnimationDurationScaleMode normal_duration_mode(
ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);

scoped_ptr<Window> window(CreateTestWindowInShellWithId(0));
Layer* layer = window->layer();
window->SetBounds(gfx::Rect(5, 10, 320, 240));
window->Show();

// Test that it is possible to override transition duration when it is not
// locked.
{
ui::ScopedLayerAnimationSettings settings1(layer->GetAnimator());
settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
{
ui::ScopedLayerAnimationSettings settings2(layer->GetAnimator());
// Duration is not locked so it gets overridden.
settings2.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
wm::GetWindowState(window.get())->Minimize();
EXPECT_TRUE(layer->GetAnimator()->is_animating());
// Expect duration from the inner scope
EXPECT_EQ(50,
layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
}
window->Show();
layer->GetAnimator()->StopAnimating();
}

// Test that it is possible to lock transition duration
{
ui::ScopedLayerAnimationSettings settings1(layer->GetAnimator());
settings1.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
// Duration is locked in outer scope.
settings1.LockTransitionDuration();
{
ui::ScopedLayerAnimationSettings settings2(layer->GetAnimator());
// Transition duration setting is ignored.
settings2.SetTransitionDuration(base::TimeDelta::FromMilliseconds(50));
wm::GetWindowState(window.get())->Minimize();
EXPECT_TRUE(layer->GetAnimator()->is_animating());
// Expect duration from the outer scope
EXPECT_EQ(1000,
layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
}
window->Show();
layer->GetAnimator()->StopAnimating();
}

// Test that duration respects default.
{
// Query default duration.
MinimizeAnimationObserver observer(layer->GetAnimator());
wm::GetWindowState(window.get())->Minimize();
EXPECT_TRUE(layer->GetAnimator()->is_animating());
base::TimeDelta default_duration(observer.duration());
window->Show();
layer->GetAnimator()->StopAnimating();

ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
settings.LockTransitionDuration();
// Setting transition duration is ignored since duration is locked
settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(1000));
wm::GetWindowState(window.get())->Minimize();
EXPECT_TRUE(layer->GetAnimator()->is_animating());
// Expect default duration (200ms for stock ash minimizing animation).
EXPECT_EQ(default_duration.InMilliseconds(),
layer->GetAnimator()->GetTransitionDuration().InMilliseconds());
window->Show();
layer->GetAnimator()->StopAnimating();
}
}

} // namespace internal
} // namespace ash
11 changes: 9 additions & 2 deletions ui/compositor/layer_animator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ gfx::AnimationContainer* GetAnimationContainer() {
LayerAnimator::LayerAnimator(base::TimeDelta transition_duration)
: delegate_(NULL),
preemption_strategy_(IMMEDIATELY_SET_NEW_TARGET),
is_transition_duration_locked_(false),
transition_duration_(transition_duration),
tween_type_(gfx::Tween::LINEAR),
is_started_(false),
Expand Down Expand Up @@ -118,6 +119,10 @@ ANIMATED_PROPERTY(float, BRIGHTNESS, Brightness, float, brightness);
ANIMATED_PROPERTY(float, GRAYSCALE, Grayscale, float, grayscale);
ANIMATED_PROPERTY(SkColor, COLOR, Color, SkColor, color);

base::TimeDelta LayerAnimator::GetTransitionDuration() const {
return transition_duration_;
}

void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) {
delegate_ = delegate;
}
Expand Down Expand Up @@ -810,8 +815,10 @@ void LayerAnimator::OnScheduled(LayerAnimationSequence* sequence) {
sequence->OnScheduled();
}

base::TimeDelta LayerAnimator::GetTransitionDuration() const {
return transition_duration_;
void LayerAnimator::SetTransitionDuration(base::TimeDelta duration) {
if (is_transition_duration_locked_)
return;
transition_duration_ = duration;
}

void LayerAnimator::ClearAnimationsInternal() {
Expand Down
13 changes: 10 additions & 3 deletions ui/compositor/layer_animator.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ class COMPOSITOR_EXPORT LayerAnimator
virtual void SetColor(SkColor color);
SkColor GetTargetColor() const;

// Returns the default length of animations, including adjustment for slow
// animation mode if set.
base::TimeDelta GetTransitionDuration() const;

// Sets the layer animation delegate the animator is associated with. The
// animator does not own the delegate. The layer animator expects a non-NULL
// delegate for most of its operations, so do not call any methods without
Expand Down Expand Up @@ -294,9 +298,8 @@ class COMPOSITOR_EXPORT LayerAnimator
// starting the animation or adding to the queue.
void OnScheduled(LayerAnimationSequence* sequence);

// Returns the default length of animations, including adjustment for slow
// animation mode if set.
base::TimeDelta GetTransitionDuration() const;
// Sets |transition_duration_| unless |is_transition_duration_locked_| is set.
void SetTransitionDuration(base::TimeDelta duration);

// Clears the animation queues and notifies any running animations that they
// have been aborted.
Expand All @@ -317,6 +320,10 @@ class COMPOSITOR_EXPORT LayerAnimator
// Determines how animations are replaced.
PreemptionStrategy preemption_strategy_;

// Whether the length of animations is locked. While it is locked
// SetTransitionDuration does not set |transition_duration_|.
bool is_transition_duration_locked_;

// The default length of animations.
base::TimeDelta transition_duration_;

Expand Down
16 changes: 12 additions & 4 deletions ui/compositor/scoped_layer_animation_settings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ class InvertingObserver : public ImplicitAnimationObserver {
ScopedLayerAnimationSettings::ScopedLayerAnimationSettings(
LayerAnimator* animator)
: animator_(animator),
old_transition_duration_(animator->transition_duration_),
old_is_transition_duration_locked_(
animator->is_transition_duration_locked_),
old_transition_duration_(animator->GetTransitionDuration()),
old_tween_type_(animator->tween_type()),
old_preemption_strategy_(animator->preemption_strategy()),
inverse_observer_(new InvertingObserver()) {
Expand All @@ -90,7 +92,9 @@ ScopedLayerAnimationSettings::ScopedLayerAnimationSettings(
}

ScopedLayerAnimationSettings::~ScopedLayerAnimationSettings() {
animator_->transition_duration_ = old_transition_duration_;
animator_->is_transition_duration_locked_ =
old_is_transition_duration_locked_;
animator_->SetTransitionDuration(old_transition_duration_);
animator_->set_tween_type(old_tween_type_);
animator_->set_preemption_strategy(old_preemption_strategy_);

Expand All @@ -113,11 +117,15 @@ void ScopedLayerAnimationSettings::AddObserver(

void ScopedLayerAnimationSettings::SetTransitionDuration(
base::TimeDelta duration) {
animator_->transition_duration_ = duration;
animator_->SetTransitionDuration(duration);
}

void ScopedLayerAnimationSettings::LockTransitionDuration() {
animator_->is_transition_duration_locked_ = true;
}

base::TimeDelta ScopedLayerAnimationSettings::GetTransitionDuration() const {
return animator_->transition_duration_;
return animator_->GetTransitionDuration();
}

void ScopedLayerAnimationSettings::SetTweenType(gfx::Tween::Type tween_type) {
Expand Down
7 changes: 7 additions & 0 deletions ui/compositor/scoped_layer_animation_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ class COMPOSITOR_EXPORT ScopedLayerAnimationSettings {
void SetTransitionDuration(base::TimeDelta duration);
base::TimeDelta GetTransitionDuration() const;

// Locks transition duration in |animator_|. When transition duration
// is locked any subsequent changes to it are ignored until the
// ScopedLayerAnimationSettings object that has locked the duration goes out
// of scope.
void LockTransitionDuration();

void SetTweenType(gfx::Tween::Type tween_type);
gfx::Tween::Type GetTweenType() const;

Expand All @@ -50,6 +56,7 @@ class COMPOSITOR_EXPORT ScopedLayerAnimationSettings {

private:
LayerAnimator* animator_;
bool old_is_transition_duration_locked_;
base::TimeDelta old_transition_duration_;
gfx::Tween::Type old_tween_type_;
LayerAnimator::PreemptionStrategy old_preemption_strategy_;
Expand Down

0 comments on commit fbc9448

Please sign in to comment.