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

Side by Side Diff: ash/wm/power_button_controller.cc

Issue 8976012: chromeos: Implement power button animations for Aura. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: update copyright year to 2012 Created 8 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « ash/wm/power_button_controller.h ('k') | ash/wm/power_button_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "ash/wm/power_button_controller.h"
6
7 #include "ash/shell.h"
8 #include "ash/shell_window_ids.h"
9 #include "base/logging.h"
10 #include "base/time.h"
11 #include "third_party/skia/include/core/SkColor.h"
12 #include "ui/aura/root_window.h"
13 #include "ui/aura/window.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/gfx/compositor/layer.h"
16 #include "ui/gfx/compositor/layer_animation_element.h"
17 #include "ui/gfx/compositor/layer_animation_sequence.h"
18 #include "ui/gfx/compositor/layer_animator.h"
19 #include "ui/gfx/rect.h"
20 #include "ui/gfx/size.h"
21 #include "ui/gfx/transform.h"
22
23 namespace ash {
24
25 namespace {
26
27 // Amount of time that the power button needs to be held before we lock the
28 // screen.
29 const int kLockTimeoutMs = 400;
30
31 // Amount of time that the power button needs to be held before we shut down.
32 const int kShutdownTimeoutMs = 400;
33
34 // Amount of time to wait for our lock requests to be honored before giving up.
35 const int kLockFailTimeoutMs = 4000;
36
37 // When the button has been held continuously from the unlocked state, amount of
38 // time that we wait after the screen locker window is shown before starting the
39 // pre-shutdown animation.
40 const int kLockToShutdownTimeoutMs = 150;
41
42 // Amount of time taken to scale the snapshot of the screen down to a
43 // slightly-smaller size once the user starts holding the power button. Used
44 // for both the pre-lock and pre-shutdown animations.
45 const int kSlowCloseAnimMs = 400;
46
47 // Amount of time taken to scale the snapshot of the screen back to its original
48 // size when the button is released.
49 const int kUndoSlowCloseAnimMs = 100;
50
51 // Amount of time taken to scale the snapshot down to a point in the center of
52 // the screen once the screen has been locked or we've been notified that the
53 // system is shutting down.
54 const int kFastCloseAnimMs = 150;
55
56 // Amount of time taken to make the lock window fade in when the screen is
57 // locked.
58 const int kLockFadeInAnimMs = 500;
59
60 // Slightly-smaller size that we scale the screen down to for the pre-lock and
61 // pre-shutdown states.
62 const float kSlowCloseSizeRatio = 0.95f;
63
64 // Containers holding screen locker windows.
65 const int kScreenLockerContainerIds[] = {
66 internal::kShellWindowId_LockScreenContainer,
67 internal::kShellWindowId_LockModalContainer,
68 };
69
70 // Containers holding additional windows that should be shown while the screen
71 // is locked.
72 const int kRelatedContainerIds[] = {
73 internal::kShellWindowId_StatusContainer,
74 internal::kShellWindowId_MenusAndTooltipsContainer,
75 };
76
77 // Is |window| a container that holds screen locker windows?
78 bool IsScreenLockerContainer(aura::Window* window) {
79 for (size_t i = 0; i < arraysize(kScreenLockerContainerIds); ++i)
80 if (window->id() == kScreenLockerContainerIds[i])
81 return true;
82 return false;
83 }
84
85 // Is |window| a container that holds other windows that should be shown while
86 // the screen is locked?
87 bool IsRelatedContainer(aura::Window* window) {
88 for (size_t i = 0; i < arraysize(kRelatedContainerIds); ++i)
89 if (window->id() == kRelatedContainerIds[i])
90 return true;
91 return false;
92 }
93
94 // Returns the transform that should be applied to containers for the slow-close
95 // animation.
96 ui::Transform GetSlowCloseTransform() {
97 gfx::Size root_size = aura::RootWindow::GetInstance()->bounds().size();
98 ui::Transform transform;
99 transform.SetScale(kSlowCloseSizeRatio, kSlowCloseSizeRatio);
100 transform.ConcatTranslate(
101 floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.width() + 0.5),
102 floor(0.5 * (1.0 - kSlowCloseSizeRatio) * root_size.height() + 0.5));
103 return transform;
104 }
105
106 // Returns the transform that should be applied to containers for the fast-close
107 // animation.
108 ui::Transform GetFastCloseTransform() {
109 gfx::Size root_size = aura::RootWindow::GetInstance()->bounds().size();
110 ui::Transform transform;
111 transform.SetScale(0.0, 0.0);
112 transform.ConcatTranslate(floor(0.5 * root_size.width() + 0.5),
113 floor(0.5 * root_size.height() + 0.5));
114 return transform;
115 }
116
117 // Slowly shrinks |window| to a slightly-smaller size.
118 void StartSlowCloseAnimationForWindow(aura::Window* window) {
119 ui::LayerAnimator* animator = window->layer()->GetAnimator();
120 animator->set_preemption_strategy(
121 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
122 animator->StartAnimation(
123 new ui::LayerAnimationSequence(
124 ui::LayerAnimationElement::CreateTransformElement(
125 GetSlowCloseTransform(),
126 base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs))));
127 }
128
129 // Quickly undoes the effects of the slow-close animation on |window|.
130 void StartUndoSlowCloseAnimationForWindow(aura::Window* window) {
131 ui::LayerAnimator* animator = window->layer()->GetAnimator();
132 animator->set_preemption_strategy(
133 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
134 animator->StartAnimation(
135 new ui::LayerAnimationSequence(
136 ui::LayerAnimationElement::CreateTransformElement(
137 ui::Transform(),
138 base::TimeDelta::FromMilliseconds(kUndoSlowCloseAnimMs))));
139 }
140
141 // Quickly shrinks |window| down to a point in the center of the screen and
142 // fades it out to 0 opacity.
143 void StartFastCloseAnimationForWindow(aura::Window* window) {
144 ui::LayerAnimator* animator = window->layer()->GetAnimator();
145 animator->set_preemption_strategy(
146 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
147 animator->StartAnimation(
148 new ui::LayerAnimationSequence(
149 ui::LayerAnimationElement::CreateTransformElement(
150 GetFastCloseTransform(),
151 base::TimeDelta::FromMilliseconds(kFastCloseAnimMs))));
152 animator->StartAnimation(
153 new ui::LayerAnimationSequence(
154 ui::LayerAnimationElement::CreateOpacityElement(
155 0.0, base::TimeDelta::FromMilliseconds(kFastCloseAnimMs))));
156 }
157
158 // Fades |window| in to full opacity.
159 void FadeInWindow(aura::Window* window) {
160 ui::LayerAnimator* animator = window->layer()->GetAnimator();
161 animator->set_preemption_strategy(
162 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
163 animator->StartAnimation(
164 new ui::LayerAnimationSequence(
165 ui::LayerAnimationElement::CreateOpacityElement(
166 1.0, base::TimeDelta::FromMilliseconds(kLockFadeInAnimMs))));
167 }
168
169 // Makes |window| fully transparent instantaneously.
170 void HideWindow(aura::Window* window) {
171 window->layer()->SetOpacity(0.0);
172 }
173
174 // Restores |window| to its original position and scale and full opacity
175 // instantaneously.
176 void RestoreWindow(aura::Window* window) {
177 window->layer()->SetTransform(ui::Transform());
178 window->layer()->SetOpacity(1.0);
179 }
180
181 // Fills |containers| with the containers described by |group|.
182 void GetContainers(PowerButtonController::ContainerGroup group,
183 aura::Window::Windows* containers) {
184 containers->clear();
185
186 aura::Window* root = aura::RootWindow::GetInstance();
187 for (aura::Window::Windows::const_iterator it = root->children().begin();
188 it != root->children().end(); ++it) {
189 aura::Window* window = *it;
190
191 bool matched = true;
192 if (group != PowerButtonController::ALL_CONTAINERS) {
193 bool is_screen_locker = IsScreenLockerContainer(window);
194 bool is_related = IsRelatedContainer(window);
195
196 switch (group) {
197 case PowerButtonController::SCREEN_LOCKER_CONTAINERS:
198 matched = is_screen_locker;
199 break;
200 case PowerButtonController::SCREEN_LOCKER_AND_RELATED_CONTAINERS:
201 matched = is_screen_locker || is_related;
202 break;
203 case PowerButtonController::
204 ALL_BUT_SCREEN_LOCKER_AND_RELATED_CONTAINERS:
205 matched = !is_screen_locker && !is_related;
206 break;
207 default:
208 NOTREACHED() << "Unhandled container group " << group;
209 }
210 }
211
212 if (matched)
213 containers->push_back(window);
214 }
215 }
216
217 // Apply animation |type| to all containers described by |group|.
218 void StartAnimation(PowerButtonController::ContainerGroup group,
219 PowerButtonController::AnimationType type) {
220 aura::Window::Windows containers;
221 GetContainers(group, &containers);
222
223 for (aura::Window::Windows::const_iterator it = containers.begin();
224 it != containers.end(); ++it) {
225 aura::Window* window = *it;
226 switch (type) {
227 case PowerButtonController::ANIMATION_SLOW_CLOSE:
228 StartSlowCloseAnimationForWindow(window);
229 break;
230 case PowerButtonController::ANIMATION_UNDO_SLOW_CLOSE:
231 StartUndoSlowCloseAnimationForWindow(window);
232 break;
233 case PowerButtonController::ANIMATION_FAST_CLOSE:
234 StartFastCloseAnimationForWindow(window);
235 break;
236 case PowerButtonController::ANIMATION_FADE_IN:
237 FadeInWindow(window);
238 break;
239 case PowerButtonController::ANIMATION_HIDE:
240 HideWindow(window);
241 break;
242 case PowerButtonController::ANIMATION_RESTORE:
243 RestoreWindow(window);
244 break;
245 default:
246 NOTREACHED() << "Unhandled animation type " << type;
247 }
248 }
249 }
250
251 } // namespace
252
253 bool PowerButtonController::TestApi::ContainerGroupIsAnimated(
254 ContainerGroup group, AnimationType type) const {
255 aura::Window::Windows containers;
256 GetContainers(group, &containers);
257 for (aura::Window::Windows::const_iterator it = containers.begin();
258 it != containers.end(); ++it) {
259 aura::Window* window = *it;
260 ui::Layer* layer = window->layer();
261
262 switch (type) {
263 case PowerButtonController::ANIMATION_SLOW_CLOSE:
264 if (layer->GetTargetTransform() != GetSlowCloseTransform())
265 return false;
266 break;
267 case PowerButtonController::ANIMATION_UNDO_SLOW_CLOSE:
268 if (layer->GetTargetTransform() != ui::Transform())
269 return false;
270 break;
271 case PowerButtonController::ANIMATION_FAST_CLOSE:
272 if (layer->GetTargetTransform() != GetFastCloseTransform() ||
273 layer->GetTargetOpacity() > 0.0001)
274 return false;
275 break;
276 case PowerButtonController::ANIMATION_FADE_IN:
277 if (layer->GetTargetOpacity() < 0.9999)
278 return false;
279 break;
280 case PowerButtonController::ANIMATION_HIDE:
281 if (layer->GetTargetOpacity() > 0.0001)
282 return false;
283 break;
284 case PowerButtonController::ANIMATION_RESTORE:
285 if (layer->opacity() < 0.9999 || layer->transform() != ui::Transform())
286 return false;
287 break;
288 default:
289 NOTREACHED() << "Unhandled animation type " << type;
290 return false;
291 }
292 }
293 return true;
294 }
295
296 bool PowerButtonController::TestApi::BackgroundLayerIsVisible() const {
297 return controller_->background_layer_.get() &&
298 controller_->background_layer_->visible();
299 }
300
301 // Simple class that fills |background_layer_| with black.
302 class PowerButtonController::BackgroundLayerDelegate
303 : public ui::LayerDelegate {
304 public:
305 BackgroundLayerDelegate() {}
306 virtual ~BackgroundLayerDelegate() {}
307
308 // ui::LayerDelegate implementation:
309 virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
310 canvas->FillRect(SK_ColorBLACK, aura::RootWindow::GetInstance()->bounds());
311 }
312
313 private:
314 DISALLOW_COPY_AND_ASSIGN(BackgroundLayerDelegate);
315 };
316
317 PowerButtonController::PowerButtonController()
318 : logged_in_as_non_guest_(false),
319 locked_(false),
320 power_button_down_(false),
321 lock_button_down_(false),
322 shutting_down_(false) {
323 }
324
325 PowerButtonController::~PowerButtonController() {
326 }
327
328 void PowerButtonController::OnLoginStateChange(bool logged_in, bool is_guest) {
329 logged_in_as_non_guest_ = logged_in && !is_guest;
330 }
331
332 void PowerButtonController::OnLockStateChange(bool locked) {
333 if (shutting_down_ || locked_ == locked)
334 return;
335
336 locked_ = locked;
337 if (locked) {
338 StartAnimation(SCREEN_LOCKER_CONTAINERS, ANIMATION_FADE_IN);
339 lock_timer_.Stop();
340 lock_fail_timer_.Stop();
341
342 if (power_button_down_) {
343 lock_to_shutdown_timer_.Stop();
344 lock_to_shutdown_timer_.Start(
345 FROM_HERE,
346 base::TimeDelta::FromMilliseconds(kLockToShutdownTimeoutMs),
347 this, &PowerButtonController::OnLockToShutdownTimeout);
348 }
349 } else {
350 StartAnimation(ALL_BUT_SCREEN_LOCKER_AND_RELATED_CONTAINERS,
351 ANIMATION_RESTORE);
352 HideBackgroundLayer();
353 }
354 }
355
356 void PowerButtonController::OnStartingLock() {
357 if (shutting_down_ || locked_)
358 return;
359
360 StartAnimation(ALL_BUT_SCREEN_LOCKER_AND_RELATED_CONTAINERS,
361 ANIMATION_FAST_CLOSE);
362
363 // Hide the screen locker containers so we can make them fade in later.
364 StartAnimation(SCREEN_LOCKER_CONTAINERS, ANIMATION_HIDE);
365 }
366
367 void PowerButtonController::OnPowerButtonEvent(
368 bool down, const base::TimeTicks& timestamp) {
369 power_button_down_ = down;
370
371 if (shutting_down_)
372 return;
373
374 if (down) {
375 // If we already have a pending request to lock the screen, wait.
376 if (lock_fail_timer_.IsRunning())
377 return;
378
379 if (logged_in_as_non_guest_ && !locked_) {
380 ShowBackgroundLayer();
381 StartAnimation(ALL_BUT_SCREEN_LOCKER_AND_RELATED_CONTAINERS,
382 ANIMATION_SLOW_CLOSE);
383 lock_timer_.Stop();
384 lock_timer_.Start(FROM_HERE,
385 base::TimeDelta::FromMilliseconds(kSlowCloseAnimMs),
386 this, &PowerButtonController::OnLockTimeout);
387 } else {
388 StartShutdownTimer();
389 }
390 } else { // Button is up.
391 if (lock_timer_.IsRunning() || shutdown_timer_.IsRunning())
392 StartAnimation(
393 locked_ ? SCREEN_LOCKER_AND_RELATED_CONTAINERS : ALL_CONTAINERS,
394 ANIMATION_UNDO_SLOW_CLOSE);
395
396 // Drop the background layer after the undo animation finishes.
397 if (lock_timer_.IsRunning() ||
398 (shutdown_timer_.IsRunning() && !logged_in_as_non_guest_)) {
399 hide_background_layer_timer_.Stop();
400 hide_background_layer_timer_.Start(
401 FROM_HERE,
402 base::TimeDelta::FromMilliseconds(kUndoSlowCloseAnimMs),
403 this, &PowerButtonController::HideBackgroundLayer);
404 }
405
406 lock_timer_.Stop();
407 shutdown_timer_.Stop();
408 lock_to_shutdown_timer_.Stop();
409 }
410 }
411
412 void PowerButtonController::OnLockButtonEvent(
413 bool down, const base::TimeTicks& timestamp) {
414 lock_button_down_ = down;
415
416 if (shutting_down_)
417 return;
418
419 NOTIMPLEMENTED();
420 }
421
422 void PowerButtonController::OnRootWindowResized(const gfx::Size& new_size) {
423 if (background_layer_.get())
424 background_layer_->SetBounds(gfx::Rect(new_size));
425 }
426
427 void PowerButtonController::OnLockTimeout() {
428 delegate_->RequestLockScreen();
429 lock_fail_timer_.Start(
430 FROM_HERE,
431 base::TimeDelta::FromMilliseconds(kLockFailTimeoutMs),
432 this, &PowerButtonController::OnLockFailTimeout);
433 }
434
435 void PowerButtonController::OnLockFailTimeout() {
436 DCHECK(!locked_);
437 LOG(ERROR) << "Screen lock request timed out";
438 StartAnimation(ALL_BUT_SCREEN_LOCKER_AND_RELATED_CONTAINERS,
439 ANIMATION_RESTORE);
440 HideBackgroundLayer();
441 }
442
443 void PowerButtonController::OnLockToShutdownTimeout() {
444 DCHECK(locked_);
445 StartShutdownTimer();
446 }
447
448 void PowerButtonController::OnShutdownTimeout() {
449 DCHECK(!shutting_down_);
450 shutting_down_ = true;
451 aura::RootWindow::GetInstance()->ShowCursor(false);
452 StartAnimation(ALL_CONTAINERS, ANIMATION_FAST_CLOSE);
453 real_shutdown_timer_.Start(
454 FROM_HERE,
455 base::TimeDelta::FromMilliseconds(kFastCloseAnimMs),
456 this, &PowerButtonController::OnRealShutdownTimeout);
457 }
458
459 void PowerButtonController::OnRealShutdownTimeout() {
460 DCHECK(shutting_down_);
461 delegate_->RequestShutdown();
462 }
463
464 void PowerButtonController::StartShutdownTimer() {
465 ShowBackgroundLayer();
466 StartAnimation(ALL_CONTAINERS, ANIMATION_SLOW_CLOSE);
467 shutdown_timer_.Stop();
468 shutdown_timer_.Start(
469 FROM_HERE,
470 base::TimeDelta::FromMilliseconds(kShutdownTimeoutMs),
471 this, &PowerButtonController::OnShutdownTimeout);
472 }
473
474 void PowerButtonController::ShowBackgroundLayer() {
475 if (hide_background_layer_timer_.IsRunning())
476 hide_background_layer_timer_.Stop();
477
478 if (!background_layer_.get()) {
479 background_layer_delegate_.reset(new BackgroundLayerDelegate);
480 background_layer_.reset(new ui::Layer(ui::Layer::LAYER_HAS_TEXTURE));
481 background_layer_->set_delegate(background_layer_delegate_.get());
482
483 ui::Layer* root_layer = aura::RootWindow::GetInstance()->layer();
484 background_layer_->SetBounds(root_layer->bounds());
485 root_layer->Add(background_layer_.get());
486 root_layer->StackAtBottom(background_layer_.get());
487 }
488 background_layer_->SetVisible(true);
489 }
490
491 void PowerButtonController::HideBackgroundLayer() {
492 background_layer_.reset();
493 }
494
495 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/power_button_controller.h ('k') | ash/wm/power_button_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698