Index: ash/launcher/launcher_button.cc |
=================================================================== |
--- ash/launcher/launcher_button.cc (revision 152351) |
+++ ash/launcher/launcher_button.cc (working copy) |
@@ -5,6 +5,7 @@ |
#include "ash/launcher/launcher_button.h" |
#include <algorithm> |
+#include <vector> |
#include "ash/launcher/launcher_button_host.h" |
#include "grit/ui_resources.h" |
@@ -15,10 +16,14 @@ |
#include "ui/base/events.h" |
#include "ui/base/resource/resource_bundle.h" |
#include "ui/compositor/layer.h" |
+#include "ui/compositor/layer_animation_element.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/gfx/canvas.h" |
#include "ui/gfx/image/image.h" |
#include "ui/gfx/image/image_skia_operations.h" |
+#include "ui/gfx/transform_util.h" |
#include "ui/views/controls/image_view.h" |
namespace { |
@@ -95,6 +100,102 @@ |
}; |
//////////////////////////////////////////////////////////////////////////////// |
+// LauncherButton::IconPulseAnimation |
+ |
+// IconPulseAnimation plays a pulse animation in a loop for given |icon_view|. |
+// It iterates through all animations, wait for one duration then starts again. |
+class LauncherButton::IconPulseAnimation { |
+ public: |
+ explicit IconPulseAnimation(IconView* icon_view) |
+ : icon_view_(icon_view) { |
+ SchedulePulseAnimations(); |
+ } |
+ virtual ~IconPulseAnimation() { |
+ // Restore icon_view_ on destruction. |
+ ScheduleRestoreAnimation(); |
+ } |
+ |
+ private: |
+ // Animation duration in millisecond. |
+ static const int kAnimationDurationInMs; |
+ |
+ // Number of animations to run and animation parameters. |
+ static const float kAnimationOpacity[]; |
+ static const float kAnimationScale[]; |
+ |
+ // Schedules pulse animations. |
+ void SchedulePulseAnimations(); |
+ |
+ // Schedule an animation to restore the view to normal state. |
+ void ScheduleRestoreAnimation(); |
+ |
+ IconView* icon_view_; // Owned by views hierarchy of LauncherButton. |
+ |
+ DISALLOW_COPY_AND_ASSIGN(IconPulseAnimation); |
+}; |
+ |
+// static |
+const int LauncherButton::IconPulseAnimation::kAnimationDurationInMs = 600; |
+const float LauncherButton::IconPulseAnimation::kAnimationOpacity[] = |
+ { 0.4f, 0.8f }; |
+const float LauncherButton::IconPulseAnimation::kAnimationScale[] = |
+ { 0.8f, 1.0f }; |
+ |
+void LauncherButton::IconPulseAnimation::SchedulePulseAnimations() { |
+ // The two animation set should have the same size. |
+ DCHECK(arraysize(kAnimationOpacity) == arraysize(kAnimationScale)); |
+ |
+ scoped_ptr<ui::LayerAnimationSequence> opacity_sequence( |
+ new ui::LayerAnimationSequence()); |
+ scoped_ptr<ui::LayerAnimationSequence> transform_sequence( |
+ new ui::LayerAnimationSequence()); |
+ |
+ // The animations loop infinitely. |
+ opacity_sequence->set_is_cyclic(true); |
+ transform_sequence->set_is_cyclic(true); |
+ |
+ for (size_t i = 0; i < arraysize(kAnimationOpacity); ++i) { |
+ opacity_sequence->AddElement( |
+ ui::LayerAnimationElement::CreateOpacityElement( |
+ kAnimationOpacity[i], |
+ base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); |
+ transform_sequence->AddElement( |
+ ui::LayerAnimationElement::CreateTransformElement( |
+ ui::GetScaleTransform(icon_view_->GetLocalBounds().CenterPoint(), |
+ kAnimationScale[i]), |
+ base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); |
+ } |
+ |
+ ui::LayerAnimationElement::AnimatableProperties opacity_properties; |
+ opacity_properties.insert(ui::LayerAnimationElement::OPACITY); |
+ opacity_sequence->AddElement( |
+ ui::LayerAnimationElement::CreatePauseElement( |
+ opacity_properties, |
+ base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); |
+ |
+ ui::LayerAnimationElement::AnimatableProperties transform_properties; |
+ transform_properties.insert(ui::LayerAnimationElement::TRANSFORM); |
+ transform_sequence->AddElement( |
+ ui::LayerAnimationElement::CreatePauseElement( |
+ transform_properties, |
+ base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); |
+ |
+ std::vector<ui::LayerAnimationSequence*> animations; |
+ // LayerAnimator::ScheduleTogether takes ownership of the sequences. |
+ animations.push_back(opacity_sequence.release()); |
+ animations.push_back(transform_sequence.release()); |
+ icon_view_->layer()->GetAnimator()->ScheduleTogether(animations); |
+} |
+ |
+// Schedule an animation to restore the view to normal state. |
+void LauncherButton::IconPulseAnimation::ScheduleRestoreAnimation() { |
+ ui::Layer* layer = icon_view_->layer(); |
+ ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); |
+ layer->SetOpacity(1.0f); |
+ layer->SetTransform(ui::Transform()); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
// LauncherButton::IconView |
LauncherButton::IconView::IconView() : icon_size_(kIconSize) { |
@@ -192,6 +293,8 @@ |
} |
if (state & STATE_ATTENTION) |
bar_->ShowAttention(true); |
+ if (state & STATE_PENDING) |
+ icon_pulse_animation_.reset(new IconPulseAnimation(icon_view_)); |
} |
} |
@@ -211,6 +314,8 @@ |
} |
if (state & STATE_ATTENTION) |
bar_->ShowAttention(false); |
+ if (state & STATE_PENDING) |
+ icon_pulse_animation_.reset(); |
} |
} |
@@ -356,7 +461,7 @@ |
} |
void LauncherButton::UpdateState() { |
- if (state_ == STATE_NORMAL) { |
+ if (state_ == STATE_NORMAL || state_ & STATE_PENDING) { |
bar_->SetVisible(false); |
} else { |
int bar_id; |