Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: ui/views/animation/ink_drop_animation_controller_impl.cc

Issue 1286693004: Extracted InkDropAnimator class from InkDropAnimationController. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merge branch 'master' Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/animation/ink_drop_animation_controller_impl.h" 5 #include "ui/views/animation/ink_drop_animation_controller_impl.h"
6 6
7 #include "base/command_line.h" 7 #include "ui/views/animation/ink_drop_animation.h"
8 #include "ui/base/ui_base_switches.h"
9 #include "ui/compositor/layer.h"
10 #include "ui/compositor/layer_animation_observer.h"
11 #include "ui/compositor/layer_animation_sequence.h"
12 #include "ui/compositor/paint_recorder.h"
13 #include "ui/compositor/scoped_layer_animation_settings.h"
14 #include "ui/events/event.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/geometry/size.h"
17 #include "ui/views/animation/ink_drop_delegate.h"
18 #include "ui/views/animation/ink_drop_host.h" 8 #include "ui/views/animation/ink_drop_host.h"
19 #include "ui/views/view.h"
20
21 namespace {
22
23 // Animation constants
24 const float kMinimumScale = 0.1f;
25 const float kMinimumScaleCenteringOffset = 0.5f - kMinimumScale / 2.0f;
26
27 const int kHideAnimationDurationFastMs = 100;
28 const int kHideAnimationDurationSlowMs = 1000;
29
30 const int kShowInkDropAnimationDurationFastMs = 250;
31 const int kShowInkDropAnimationDurationSlowMs = 750;
32
33 const int kShowLongPressAnimationDurationFastMs = 250;
34 const int kShowLongPressAnimationDurationSlowMs = 2500;
35
36 const int kRoundedRectCorners = 5;
37 const int kCircleRadius = 30;
38
39 const SkColor kInkDropColor = SK_ColorLTGRAY;
40 const SkColor kLongPressColor = SkColorSetRGB(182, 182, 182);
41
42 // Checks CommandLine switches to determine if the visual feedback should be
43 // circular.
44 bool UseCircularFeedback() {
45 static bool circular =
46 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
47 (::switches::kMaterialDesignInkDrop)) !=
48 ::switches::kMaterialDesignInkDropSquare;
49 return circular;
50 }
51
52 // Checks CommandLine switches to determine if the visual feedback should have
53 // a fast animations speed.
54 bool UseFastAnimations() {
55 static bool fast =
56 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
57 (::switches::kMaterialDesignInkDropAnimationSpeed)) !=
58 ::switches::kMaterialDesignInkDropAnimationSpeedSlow;
59 return fast;
60 }
61
62 } // namespace
63 9
64 namespace views { 10 namespace views {
65 11
66 // An animation observer that should be set on animations of the provided
67 // ui::Layer. Can be used to either start a hide animation, or to trigger one
68 // upon completion of the current animation.
69 //
70 // Sequential animations with PreemptionStrategy::ENQUEUE_NEW_ANIMATION cannot
71 // be used as the observed animation can complete before user input is received
72 // which determines if the hide animation should run.
73 class AppearAnimationObserver : public ui::LayerAnimationObserver {
74 public:
75 // Will automatically start a hide animation of |layer| if |hide| is true.
76 // Otherwise StartHideAnimation() or HideNowIfDoneOrOnceCompleted() must be
77 // called.
78 AppearAnimationObserver(ui::Layer* layer, bool hide);
79 ~AppearAnimationObserver() override;
80
81 // Returns true during both the appearing animation, and the hiding animation.
82 bool IsAnimationActive();
83
84 // Starts a hide animation, preempting any current animations on |layer_|.
85 void StartHideAnimation();
86
87 // Starts a hide animation if |layer_| is no longer animating. Otherwise the
88 // hide animation will be started once the current animation is completed.
89 void HideNowIfDoneOrOnceCompleted();
90
91 // Hides |background_layer| (without animation) after the current animation
92 // completes.
93 void SetBackgroundToHide(ui::Layer* background_layer);
94
95 private:
96 // ui::ImplicitAnimationObserver:
97 void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
98 void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;
99 void OnLayerAnimationScheduled(
100 ui::LayerAnimationSequence* sequence) override {}
101
102 bool RequiresNotificationWhenAnimatorDestroyed() const override;
103
104 // The ui::Layer being observed, which hide animations will be set on.
105 ui::Layer* layer_;
106
107 // Optional ui::Layer which will be hidden upon the completion of animating
108 // |layer_|
109 ui::Layer* background_layer_;
110
111 // If true the hide animation will immediately be scheduled upon completion of
112 // the observed animation.
113 bool hide_;
114
115 DISALLOW_COPY_AND_ASSIGN(AppearAnimationObserver);
116 };
117
118 AppearAnimationObserver::AppearAnimationObserver(ui::Layer* layer, bool hide)
119 : layer_(layer), background_layer_(nullptr), hide_(hide) {}
120
121 AppearAnimationObserver::~AppearAnimationObserver() {
122 StopObserving();
123 }
124
125 bool AppearAnimationObserver::IsAnimationActive() {
126 // Initial animation ongoing
127 if (!attached_sequences().empty())
128 return true;
129 // Maintain the animation until told to hide.
130 if (!hide_)
131 return true;
132
133 // Check the state of the triggered hide animation
134 return layer_->GetAnimator()->IsAnimatingProperty(
135 ui::LayerAnimationElement::OPACITY) &&
136 layer_->GetTargetOpacity() == 0.0f &&
137 layer_->GetAnimator()->IsAnimatingProperty(
138 ui::LayerAnimationElement::VISIBILITY) &&
139 !layer_->GetTargetVisibility();
140 }
141
142 void AppearAnimationObserver::StartHideAnimation() {
143 if (background_layer_)
144 background_layer_->SetVisible(false);
145 if (!layer_->GetTargetVisibility())
146 return;
147
148 ui::ScopedLayerAnimationSettings animation(layer_->GetAnimator());
149 animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
150 UseFastAnimations() ? kHideAnimationDurationFastMs
151 : kHideAnimationDurationSlowMs));
152 animation.SetPreemptionStrategy(
153 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
154 layer_->SetOpacity(0.0f);
155 layer_->SetVisible(false);
156 }
157
158 void AppearAnimationObserver::HideNowIfDoneOrOnceCompleted() {
159 hide_ = true;
160 if (attached_sequences().empty())
161 StartHideAnimation();
162 }
163
164 void AppearAnimationObserver::SetBackgroundToHide(ui::Layer* background_layer) {
165 background_layer_ = background_layer;
166 }
167
168 void AppearAnimationObserver::OnLayerAnimationEnded(
169 ui::LayerAnimationSequence* sequence) {
170 if (hide_)
171 StartHideAnimation();
172 }
173
174 void AppearAnimationObserver::OnLayerAnimationAborted(
175 ui::LayerAnimationSequence* sequence) {
176 if (hide_)
177 StartHideAnimation();
178 }
179
180 bool AppearAnimationObserver::RequiresNotificationWhenAnimatorDestroyed()
181 const {
182 // Ensures that OnImplicitAnimationsCompleted is called even if the observed
183 // animation is deleted. Allows for setting the proper state on |layer_|.
184 return true;
185 }
186
187 InkDropAnimationControllerImpl::InkDropAnimationControllerImpl( 12 InkDropAnimationControllerImpl::InkDropAnimationControllerImpl(
188 InkDropHost* ink_drop_host) 13 InkDropHost* ink_drop_host)
189 : ink_drop_host_(ink_drop_host), 14 : ink_drop_host_(ink_drop_host),
190 root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), 15 ink_drop_animation_(new InkDropAnimation()) {
191 ink_drop_layer_(new ui::Layer()),
192 appear_animation_observer_(nullptr),
193 long_press_layer_(new ui::Layer()),
194 long_press_animation_observer_(nullptr),
195 ink_drop_bounds_(0, 0, 0, 0) {
196 ink_drop_delegate_.reset(new InkDropDelegate(ink_drop_layer_.get(),
197 kInkDropColor, kCircleRadius,
198 kRoundedRectCorners));
199 long_press_delegate_.reset(new InkDropDelegate(long_press_layer_.get(),
200 kLongPressColor, kCircleRadius,
201 kRoundedRectCorners));
202
203 SetupAnimationLayer(long_press_layer_.get(), long_press_delegate_.get());
204 SetupAnimationLayer(ink_drop_layer_.get(), ink_drop_delegate_.get());
205
206 root_layer_->Add(ink_drop_layer_.get());
207 root_layer_->Add(long_press_layer_.get());
208
209 // TODO(bruthig): Change this to only be called before the ink drop becomes 16 // TODO(bruthig): Change this to only be called before the ink drop becomes
210 // active. See www.crbug.com/522175. 17 // active. See www.crbug.com/522175.
211 ink_drop_host_->AddInkDropLayer(root_layer_.get()); 18 ink_drop_host_->AddInkDropLayer(ink_drop_animation_->root_layer());
212 } 19 }
213 20
214 InkDropAnimationControllerImpl::~InkDropAnimationControllerImpl() { 21 InkDropAnimationControllerImpl::~InkDropAnimationControllerImpl() {
215 // TODO(bruthig): Change this to be called when the ink drop becomes hidden. 22 // TODO(bruthig): Change this to be called when the ink drop becomes hidden.
216 // See www.crbug.com/522175. 23 // See www.crbug.com/522175.
217 ink_drop_host_->RemoveInkDropLayer(root_layer_.get()); 24 ink_drop_host_->RemoveInkDropLayer(ink_drop_animation_->root_layer());
218 } 25 }
219 26
220 void InkDropAnimationControllerImpl::AnimateToState(InkDropState state) { 27 void InkDropAnimationControllerImpl::AnimateToState(InkDropState state) {
221 // TODO(bruthig): Do not transition if we are already in |state| and restrict 28 ink_drop_animation_->AnimateToState(state);
222 // any state transition that don't make sense or wouldn't look visually
223 // appealing.
224 switch (state) {
225 case InkDropState::HIDDEN:
226 AnimateHide();
227 break;
228 case InkDropState::ACTION_PENDING:
229 AnimateTapDown();
230 break;
231 case InkDropState::QUICK_ACTION:
232 AnimateTapDown();
233 AnimateHide();
234 break;
235 case InkDropState::SLOW_ACTION:
236 AnimateLongPress();
237 break;
238 case InkDropState::ACTIVATED:
239 AnimateLongPress();
240 break;
241 }
242 } 29 }
243 30
244 void InkDropAnimationControllerImpl::SetInkDropSize(const gfx::Size& size) { 31 void InkDropAnimationControllerImpl::SetInkDropSize(const gfx::Size& size) {
245 SetInkDropBounds(gfx::Rect(ink_drop_bounds_.origin(), size)); 32 ink_drop_animation_->SetInkDropSize(size);
246 } 33 }
247 34
248 gfx::Rect InkDropAnimationControllerImpl::GetInkDropBounds() const { 35 gfx::Rect InkDropAnimationControllerImpl::GetInkDropBounds() const {
249 return ink_drop_bounds_; 36 return ink_drop_animation_->GetInkDropBounds();
250 } 37 }
251 38
252 void InkDropAnimationControllerImpl::SetInkDropBounds(const gfx::Rect& bounds) { 39 void InkDropAnimationControllerImpl::SetInkDropBounds(const gfx::Rect& bounds) {
253 ink_drop_bounds_ = bounds; 40 ink_drop_animation_->SetInkDropBounds(bounds);
254 SetLayerBounds(ink_drop_layer_.get());
255 SetLayerBounds(long_press_layer_.get());
256 }
257
258 void InkDropAnimationControllerImpl::AnimateTapDown() {
259 if ((appear_animation_observer_ &&
260 appear_animation_observer_->IsAnimationActive()) ||
261 (long_press_animation_observer_ &&
262 long_press_animation_observer_->IsAnimationActive())) {
263 // Only one animation at a time. Subsequent tap downs are ignored until the
264 // current animation completes.
265 return;
266 }
267 appear_animation_observer_.reset(
268 new AppearAnimationObserver(ink_drop_layer_.get(), false));
269 AnimateShow(ink_drop_layer_.get(), appear_animation_observer_.get(),
270 base::TimeDelta::FromMilliseconds(
271 (UseFastAnimations() ? kShowInkDropAnimationDurationFastMs
272 : kShowInkDropAnimationDurationSlowMs)));
273 }
274
275 void InkDropAnimationControllerImpl::AnimateHide() {
276 if (appear_animation_observer_ &&
277 appear_animation_observer_->IsAnimationActive()) {
278 appear_animation_observer_->HideNowIfDoneOrOnceCompleted();
279 } else if (long_press_animation_observer_) {
280 long_press_animation_observer_->HideNowIfDoneOrOnceCompleted();
281 }
282 }
283
284 void InkDropAnimationControllerImpl::AnimateLongPress() {
285 // Only one animation at a time. Subsequent long presses are ignored until the
286 // current animation completes.
287 if (long_press_animation_observer_ &&
288 long_press_animation_observer_->IsAnimationActive()) {
289 return;
290 }
291 appear_animation_observer_.reset();
292 long_press_animation_observer_.reset(
293 new AppearAnimationObserver(long_press_layer_.get(), false));
294 long_press_animation_observer_->SetBackgroundToHide(ink_drop_layer_.get());
295 AnimateShow(long_press_layer_.get(), long_press_animation_observer_.get(),
296 base::TimeDelta::FromMilliseconds(
297 UseFastAnimations() ? kShowLongPressAnimationDurationFastMs
298 : kShowLongPressAnimationDurationSlowMs));
299 }
300
301 void InkDropAnimationControllerImpl::AnimateShow(
302 ui::Layer* layer,
303 AppearAnimationObserver* observer,
304 base::TimeDelta duration) {
305 layer->SetVisible(true);
306 layer->SetOpacity(1.0f);
307
308 float start_x = ink_drop_bounds_.x() +
309 layer->bounds().width() * kMinimumScaleCenteringOffset;
310 float start_y = ink_drop_bounds_.y() +
311 layer->bounds().height() * kMinimumScaleCenteringOffset;
312
313 gfx::Transform initial_transform;
314 initial_transform.Translate(start_x, start_y);
315 initial_transform.Scale(kMinimumScale, kMinimumScale);
316 layer->SetTransform(initial_transform);
317
318 ui::LayerAnimator* animator = layer->GetAnimator();
319 ui::ScopedLayerAnimationSettings animation(animator);
320 animation.SetPreemptionStrategy(
321 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
322
323 gfx::Transform target_transform;
324 target_transform.Translate(ink_drop_bounds_.x(), ink_drop_bounds_.y());
325 ui::LayerAnimationElement* element =
326 ui::LayerAnimationElement::CreateTransformElement(target_transform,
327 duration);
328 ui::LayerAnimationSequence* sequence =
329 new ui::LayerAnimationSequence(element);
330 sequence->AddObserver(observer);
331 animator->StartAnimation(sequence);
332 }
333
334 void InkDropAnimationControllerImpl::SetLayerBounds(ui::Layer* layer) {
335 bool circle = UseCircularFeedback();
336 gfx::Size size = ink_drop_bounds_.size();
337 float circle_width = circle ? 2.0f * kCircleRadius : size.width();
338 float circle_height = circle ? 2.0f * kCircleRadius : size.height();
339 float circle_x = circle ? (size.width() - circle_width) * 0.5f : 0;
340 float circle_y = circle ? (size.height() - circle_height) * 0.5f : 0;
341 layer->SetBounds(gfx::Rect(circle_x, circle_y, circle_width, circle_height));
342 }
343
344 void InkDropAnimationControllerImpl::SetupAnimationLayer(
345 ui::Layer* layer,
346 InkDropDelegate* delegate) {
347 layer->SetFillsBoundsOpaquely(false);
348 layer->set_delegate(delegate);
349 layer->SetVisible(false);
350 layer->SetBounds(gfx::Rect());
351 delegate->set_should_render_circle(UseCircularFeedback());
352 } 41 }
353 42
354 } // namespace views 43 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/animation/ink_drop_animation_controller_impl.h ('k') | ui/views/animation/ink_drop_state.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698