1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/app_list/views/pulsing_block_view.h" 6 7 #include <vector> 8 9 #include "base/rand_util.h" 10 #include "third_party/skia/include/core/SkColor.h" 11 #include "ui/compositor/layer.h" 12 #include "ui/compositor/layer_animation_element.h" 13 #include "ui/compositor/layer_animation_sequence.h" 14 #include "ui/compositor/layer_animator.h" 15 #include "ui/gfx/canvas.h" 16 #include "ui/gfx/transform_util.h" 17 18 namespace { 19 20 const SkColor kBlockColor = SkColorSetRGB(225, 225, 225); 21 const int kBlockSize = 64; 22 23 const int kAnimationDurationInMs = 600; 24 const float kAnimationOpacity[] = { 0.4f, 0.8f, 0.4f }; 25 const float kAnimationScale[] = { 0.8f, 1.0f, 0.8f }; 26 27 void SchedulePulsingAnimation(ui::Layer* layer) { 28 DCHECK(layer); 29 DCHECK_EQ(arraysize(kAnimationOpacity), arraysize(kAnimationScale)); 30 31 scoped_ptr<ui::LayerAnimationSequence> opacity_sequence( 32 new ui::LayerAnimationSequence()); 33 scoped_ptr<ui::LayerAnimationSequence> transform_sequence( 34 new ui::LayerAnimationSequence()); 35 36 // The animations loop infinitely. 37 opacity_sequence->set_is_cyclic(true); 38 transform_sequence->set_is_cyclic(true); 39 40 const gfx::Rect local_bounds(layer->bounds().size()); 41 for (size_t i = 0; i < arraysize(kAnimationOpacity); ++i) { 42 opacity_sequence->AddElement( 43 ui::LayerAnimationElement::CreateOpacityElement( 44 kAnimationOpacity[i], 45 base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); 46 transform_sequence->AddElement( 47 ui::LayerAnimationElement::CreateTransformElement( 48 gfx::GetScaleTransform(local_bounds.CenterPoint(), 49 kAnimationScale[i]), 50 base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); 51 } 52 53 opacity_sequence->AddElement( 54 ui::LayerAnimationElement::CreatePauseElement( 55 ui::LayerAnimationElement::OPACITY, 56 base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); 57 58 transform_sequence->AddElement( 59 ui::LayerAnimationElement::CreatePauseElement( 60 ui::LayerAnimationElement::TRANSFORM, 61 base::TimeDelta::FromMilliseconds(kAnimationDurationInMs))); 62 63 std::vector<ui::LayerAnimationSequence*> animations; 64 animations.push_back(opacity_sequence.release()); 65 animations.push_back(transform_sequence.release()); 66 layer->GetAnimator()->ScheduleTogether(animations); 67 } 68 69 } // namespace 70 71 namespace app_list { 72 73 PulsingBlockView::PulsingBlockView(const gfx::Size& size, bool start_delay) { 74 SetPaintToLayer(true); 75 SetFillsBoundsOpaquely(false); 76 77 const int max_delay = kAnimationDurationInMs * arraysize(kAnimationOpacity); 78 const int delay = start_delay ? base::RandInt(0, max_delay) : 0; 79 start_delay_timer_.Start( 80 FROM_HERE, 81 base::TimeDelta::FromMilliseconds(delay), 82 this, &PulsingBlockView::OnStartDelayTimer); 83 } 84 85 PulsingBlockView::~PulsingBlockView() { 86 } 87 88 void PulsingBlockView::OnStartDelayTimer() { 89 SchedulePulsingAnimation(layer()); 90 } 91 92 void PulsingBlockView::OnPaint(gfx::Canvas* canvas) { 93 gfx::Rect rect(GetContentsBounds()); 94 rect.ClampToCenteredSize(gfx::Size(kBlockSize, kBlockSize)); 95 canvas->FillRect(rect, kBlockColor); 96 } 97 98 } // namespace app_list 99