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.
5 #include "ash/wm/workspace/workspace_cycler_animator.h"
10 #include "ash/launcher/launcher.h"
11 #include "ash/root_window_controller.h"
12 #include "ash/screen_ash.h"
13 #include "ash/shelf/shelf_layout_manager.h"
14 #include "ash/shelf/shelf_widget.h"
15 #include "ash/shell_window_ids.h"
16 #include "ash/wm/property_util.h"
17 #include "ash/wm/window_properties.h"
18 #include "ash/wm/workspace/colored_window_controller.h"
19 #include "ash/wm/workspace/workspace.h"
20 #include "ash/wm/workspace/workspace_cycler_configuration.h"
21 #include "base/values.h"
22 #include "ui/aura/root_window.h"
23 #include "ui/aura/window.h"
24 #include "ui/base/events/event_utils.h"
25 #include "ui/compositor/layer_animator.h"
26 #include "ui/compositor/scoped_layer_animation_settings.h"
27 #include "ui/gfx/transform_util.h"
28 #include "ui/views/widget/widget.h"
30 typedef ash::WorkspaceCyclerConfiguration Config
;
35 // Class which computes the transform, brightness, and visbility of workspaces
36 // on behalf of the animator.
37 class StyleCalculator
{
39 StyleCalculator(const gfx::Rect
& screen_bounds
,
40 const gfx::Rect
& maximized_bounds
,
41 size_t num_workspaces
);
44 // Returns the transform, brightness, and visibility that the workspace at
45 // |workspace_index| should be animated to when the user has stopped cycling
46 // through workspaces given |selected_workspace_index|.
47 // Unlike GetTargetProperties(), the method does not have a |scroll_delta|
48 // argument as stopping the workspace cycler always results in complately
49 // selecting a workspace.
50 void GetStoppedTargetProperties(size_t selected_workspace_index
,
51 size_t workspace_index
,
52 gfx::Transform
* transform
,
56 // Returns the transform, brightness, and visibility that the workspace at
57 // |workspace_index| should be animated to when the user is cycling through
58 // workspaces given |selected_workspace_index| and |scroll_delta|.
59 // |scroll_delta| is the amount of pixels that the user has scrolled
60 // vertically since completely selecting the workspace at
61 // |selected_workspace_index|.
62 void GetTargetProperties(size_t selected_workspace_index
,
63 size_t workspace_index
,
65 gfx::Transform
* transform
,
70 // Returns the target animation transform of the workspace which is at
71 // |offset_from_selected| from the selected workspace when the user is not
72 // cycling through workspaces.
73 // This method assumes |scroll_delta| == 0.
74 gfx::Transform
GetStoppedTargetTransformForOffset(
75 int offset_from_selected
) const;
77 // Returns the target animation transform of the workspace which is at
78 // |offset_from_selected| from the selected workspace.
79 // This method like all the methods below assumes |scroll_delta| == 0 for the
80 // sake of simplicity. The transform for |scroll_delta| != 0 can be obtained
82 gfx::DecomposedTransform
GetTargetTransformForOffset(
83 int offset_from_selected
) const;
85 // Returns the target animation brightness of the workspace which is at
86 // |offset_from_selected| from the selected workspace.
87 // This method assumes |scroll_delta| == 0.
88 float GetTargetBrightnessForOffset(int offset_from_selected
) const;
90 // Returns the target animation visibility of the workspace with the given
92 // This method assumes |scroll_delta| == 0.
93 bool GetTargetVisibilityForOffset(int offset_from_selected
,
94 size_t workspace_index
) const;
96 // Returns the minimum offset from the selected workspace at which a
97 // workspace can be visible. The offset is used to limit the amount of
98 // workspaces which are simultaneously visible.
99 int GetMinVisibleOffsetFromSelected() const;
101 // Returns the maximum offset from the selected workspace at which a
102 // workspace can be visible. The offset is used to limit the amount of
103 // workspaces which are simultaneously visible.
104 int GetMaxVisibleOffsetFromSelected() const;
106 // The bounds of the display containing the workspaces in workspace
107 // coordinates, including the shelf if any.
108 const gfx::Rect screen_bounds_
;
110 // The bounds of a maximized window. This excludes the shelf if any.
111 const gfx::Rect maximized_bounds_
;
113 // The combined number of visible and hidden workspaces.
114 size_t num_workspaces_
;
116 DISALLOW_COPY_AND_ASSIGN(StyleCalculator
);
119 StyleCalculator::StyleCalculator(const gfx::Rect
& screen_bounds
,
120 const gfx::Rect
& maximized_bounds
,
121 size_t num_workspaces
)
122 : screen_bounds_(screen_bounds
),
123 maximized_bounds_(maximized_bounds
),
124 num_workspaces_(num_workspaces
) {
127 StyleCalculator::~StyleCalculator() {
130 void StyleCalculator::GetStoppedTargetProperties(
131 size_t selected_workspace_index
,
132 size_t workspace_index
,
133 gfx::Transform
* transform
,
135 bool* visible
) const {
136 DCHECK_LT(selected_workspace_index
, num_workspaces_
);
137 DCHECK_LT(workspace_index
, num_workspaces_
);
138 int offset_from_selected
= static_cast<int>(
139 workspace_index
- selected_workspace_index
);
141 *transform
= GetStoppedTargetTransformForOffset(offset_from_selected
);
144 *brightness
= GetTargetBrightnessForOffset(offset_from_selected
);
146 // All the workspaces other than the selected workspace are either occluded by
147 // the selected workspace or off screen.
149 *visible
= (selected_workspace_index
== workspace_index
);
152 void StyleCalculator::GetTargetProperties(
153 size_t selected_workspace_index
,
154 size_t workspace_index
,
156 gfx::Transform
* transform
,
158 bool* visible
) const {
159 DCHECK_LT(selected_workspace_index
, num_workspaces_
);
160 DCHECK_LT(workspace_index
, num_workspaces_
);
162 int offset_from_selected
= static_cast<int>(
163 workspace_index
- selected_workspace_index
);
165 int first_offset_from_selected
= offset_from_selected
;
166 int second_offset_from_selected
= offset_from_selected
;
167 if (scroll_delta
< 0) {
168 // The user is part of the way to selecting the workspace at
169 // |selected_workspace_index| - 1 -> |offset_from_selected| + 1.
170 second_offset_from_selected
= offset_from_selected
+ 1;
171 } else if (scroll_delta
> 0) {
172 // The user is part of the way to selecting the workspace at
173 // |selected_workspace_index| + 1 -> |offset_from_selected| - 1.
174 second_offset_from_selected
= offset_from_selected
- 1;
177 double scroll_distance_to_cycle_to_next_workspace
= Config::GetDouble(
178 Config::SCROLL_DISTANCE_TO_CYCLE_TO_NEXT_WORKSPACE
);
179 double progress
= fabs(
180 scroll_delta
/ scroll_distance_to_cycle_to_next_workspace
);
181 DCHECK_GT(1.0, progress
);
184 gfx::DecomposedTransform first_transform
= GetTargetTransformForOffset(
185 first_offset_from_selected
);
187 gfx::DecomposedTransform interpolated_transform
;
188 if (first_offset_from_selected
== second_offset_from_selected
) {
189 interpolated_transform
= first_transform
;
191 gfx::DecomposedTransform second_transform
= GetTargetTransformForOffset(
192 second_offset_from_selected
);
193 gfx::BlendDecomposedTransforms(&interpolated_transform
,
198 *transform
= gfx::ComposeTransform(interpolated_transform
);
202 float first_brightness
= GetTargetBrightnessForOffset(
203 first_offset_from_selected
);
204 float second_brightness
= GetTargetBrightnessForOffset(
205 second_offset_from_selected
);
206 *brightness
= first_brightness
+ progress
*
207 (second_brightness
- first_brightness
);
211 bool first_visible
= GetTargetVisibilityForOffset(
212 first_offset_from_selected
, workspace_index
);
213 bool second_visible
= GetTargetVisibilityForOffset(
214 second_offset_from_selected
, workspace_index
);
215 *visible
= (first_visible
|| second_visible
);
219 gfx::Transform
StyleCalculator::GetStoppedTargetTransformForOffset(
220 int offset_from_selected
) const {
221 if (offset_from_selected
<= 0) {
222 // The selected workspace takes up the entire screen. The workspaces deeper
223 // than the selected workspace are stacked exactly under the selected
224 // workspace and are completely occluded by it.
225 return gfx::Transform();
228 // The workspaces shallower than the selected workspace are stacked exactly
229 // on top of each other offscreen.
230 double max_scale
= Config::GetDouble(Config::MAX_SCALE
);
232 gfx::Transform transform
;
233 transform
.Translate(0, screen_bounds_
.height());
234 transform
.Scale(max_scale
, max_scale
);
238 gfx::DecomposedTransform
StyleCalculator::GetTargetTransformForOffset(
239 int offset_from_selected
) const {
240 // When cycling, the workspaces are spread out from the positions computed by
241 // GetStoppedTargetTransformForOffset(). The transforms are computed so that
242 // on screen the workspaces look like this:
243 // ____________________________________________
244 // | ________________________ |
245 // | | deepest workpace |_________|_
246 // | _|________________________|_ | |
248 // | _|____________________________|_ | |_ top stack.
249 // | | selected / shallowest workspace| | |
254 // | _|________________________________|_ |
255 // | | deepest workspace |___|_
256 // | _|____________________________________|_ | |_ bottom stack.
257 // | | shallowest workspace |_|_|
258 // |_|________________________________________|_|
259 // The selected workspace is the most visible workspace. It is the workspace
260 // which will be activated if the user does not do any more cycling.
261 bool in_top_stack
= (offset_from_selected
<= 0);
263 int min_visible_offset_from_selected
= GetMinVisibleOffsetFromSelected();
264 int max_visible_offset_from_selected
= GetMaxVisibleOffsetFromSelected();
266 // Give workspaces at hidden offsets the transform of the workspace at the
267 // nearest visible offset. This is needed to produce a valid result when
268 // interpolating between the values of GetTargetTransformForOffset() for a
269 // visible and hidden offset.
270 if (offset_from_selected
< min_visible_offset_from_selected
)
271 offset_from_selected
= min_visible_offset_from_selected
;
272 else if (offset_from_selected
> max_visible_offset_from_selected
)
273 offset_from_selected
= max_visible_offset_from_selected
;
275 double selected_scale
= Config::GetDouble(Config::SELECTED_SCALE
);
277 double scale
= selected_scale
;
279 double min_scale
= Config::GetDouble(Config::MIN_SCALE
);
280 scale
-= static_cast<double>(offset_from_selected
) /
281 min_visible_offset_from_selected
* (selected_scale
- min_scale
);
283 double max_scale
= Config::GetDouble(Config::MAX_SCALE
);
284 scale
+= static_cast<double>(offset_from_selected
) /
285 max_visible_offset_from_selected
* (max_scale
- selected_scale
);
288 // Compute the workspace's y offset.
290 if (offset_from_selected
== 0) {
291 y_offset
= Config::GetDouble(Config::SELECTED_Y_OFFSET
);
293 Config::Property y_offsets_property
;
295 y_offsets_property
= Config::DEEPER_THAN_SELECTED_Y_OFFSETS
;
297 y_offsets_property
= Config::SHALLOWER_THAN_SELECTED_Y_OFFSETS
;
298 y_offset
= maximized_bounds_
.height();
300 const base::ListValue
& y_offsets
= Config::GetListValue(y_offsets_property
);
301 size_t y_offset_index
= static_cast<size_t>(
302 std::abs(offset_from_selected
) - 1);
303 DCHECK_GT(y_offsets
.GetSize(), y_offset_index
);
304 double y_offset_config_value
= 0;
305 y_offsets
.GetDouble(y_offset_index
, &y_offset_config_value
);
306 y_offset
+= y_offset_config_value
;
309 // Center the workspace horizontally.
310 double x_offset
= maximized_bounds_
.width() * (1 - scale
) / 2;
312 gfx::DecomposedTransform transform
;
313 transform
.translate
[0] = x_offset
;
314 transform
.translate
[1] = y_offset
;
315 transform
.scale
[0] = scale
;
316 transform
.scale
[1] = scale
;
320 float StyleCalculator::GetTargetBrightnessForOffset(
321 int offset_from_selected
) const {
322 int max_visible_distance_from_selected
= std::max(
323 std::abs(GetMinVisibleOffsetFromSelected()),
324 GetMaxVisibleOffsetFromSelected());
325 return Config::GetDouble(Config::MIN_BRIGHTNESS
) * std::min(
327 static_cast<double>(std::abs(offset_from_selected
)) /
328 max_visible_distance_from_selected
);
331 bool StyleCalculator::GetTargetVisibilityForOffset(
332 int offset_from_selected
,
333 size_t workspace_index
) const {
334 // The workspace at the highest possible index is the shallowest workspace
335 // out of both stacks and is always visible.
336 // The workspace at |GetMaxVisibleOffsetFromSelected()| is hidden because it
337 // has the same transform as the shallowest workspace and is completely
339 if (workspace_index
== num_workspaces_
- 1)
342 return offset_from_selected
>= GetMinVisibleOffsetFromSelected() &&
343 offset_from_selected
< GetMaxVisibleOffsetFromSelected();
346 int StyleCalculator::GetMinVisibleOffsetFromSelected() const {
347 const base::ListValue
& y_offsets
= Config::GetListValue(
348 Config::DEEPER_THAN_SELECTED_Y_OFFSETS
);
349 // Hide workspaces for which there is no y offset specified.
350 return -1 * static_cast<int>(y_offsets
.GetSize());
353 int StyleCalculator::GetMaxVisibleOffsetFromSelected() const {
354 const base::ListValue
& y_offsets
= Config::GetListValue(
355 Config::SHALLOWER_THAN_SELECTED_Y_OFFSETS
);
356 // Hide workspaces for which there is no y offset specified.
357 return y_offsets
.GetSize();
360 WorkspaceCyclerAnimator::WorkspaceCyclerAnimator(Delegate
* delegate
)
361 : delegate_(delegate
),
362 initial_active_workspace_index_(0),
363 selected_workspace_index_(0),
365 animation_type_(NONE
),
366 launcher_background_controller_(NULL
),
367 style_calculator_(NULL
) {
370 WorkspaceCyclerAnimator::~WorkspaceCyclerAnimator() {
371 StopObservingImplicitAnimations();
372 animation_type_
= NONE
;
375 void WorkspaceCyclerAnimator::Init(const std::vector
<Workspace
*>& workspaces
,
376 Workspace
* initial_active_workspace
) {
377 workspaces_
= workspaces
;
379 std::vector
<Workspace
*>::iterator it
= std::find(workspaces_
.begin(),
380 workspaces_
.end(), initial_active_workspace
);
381 DCHECK(it
!= workspaces_
.end());
382 initial_active_workspace_index_
= it
- workspaces_
.begin();
383 selected_workspace_index_
= initial_active_workspace_index_
;
385 screen_bounds_
= ScreenAsh::GetDisplayBoundsInParent(
386 workspaces_
[0]->window());
387 maximized_bounds_
= ScreenAsh::GetMaximizedWindowBoundsInParent(
388 workspaces_
[0]->window());
389 style_calculator_
.reset(new StyleCalculator(
390 screen_bounds_
, maximized_bounds_
, workspaces_
.size()));
393 void WorkspaceCyclerAnimator::AnimateStartingCycler() {
394 // Set kCyclingThroughWorkspaces so that the window frame is painted with the
396 workspaces_
[0]->window()->GetRootWindow()->SetProperty(
397 ash::internal::kCyclingThroughWorkspacesKey
, true);
399 // Ensure that the workspaces are stacked with respect to their order
401 aura::Window
* parent
= workspaces_
[0]->window()->parent();
403 for (size_t i
= 0; i
< workspaces_
.size() - 1; ++i
) {
404 parent
->StackChildAbove(workspaces_
[i
+ 1]->window(),
405 workspaces_
[i
]->window());
408 // Set the initial transform and brightness of the workspaces such that they
409 // animate correctly when AnimateToUpdatedState() is called after the loop.
410 // Start at index 1 as the desktop workspace is not animated.
411 for (size_t i
= 1; i
< workspaces_
.size(); ++i
) {
412 aura::Window
* window
= workspaces_
[i
]->window();
413 ui::Layer
* layer
= window
->layer();
415 gfx::Transform transform
;
416 float brightness
= 0.0f
;
417 style_calculator_
->GetStoppedTargetProperties(selected_workspace_index_
, i
,
418 &transform
, &brightness
, NULL
);
419 layer
->SetTransform(transform
);
420 layer
->SetLayerBrightness(brightness
);
423 int start_cycler_animation_duration
= static_cast<int>(Config::GetDouble(
424 Config::START_CYCLER_ANIMATION_DURATION
));
427 animation_type_
= CYCLER_START
;
428 AnimateToUpdatedState(start_cycler_animation_duration
);
430 // Dim the desktop workspace and the desktop background.
431 AnimateTo(0, false, start_cycler_animation_duration
, gfx::Transform(),
432 Config::GetDouble(Config::DESKTOP_WORKSPACE_BRIGHTNESS
), true);
434 aura::Window
* background
= GetDesktopBackground();
436 ui::Layer
* layer
= background
->layer();
438 if (!background
->IsVisible()) {
440 layer
->SetOpacity(0.0f
);
444 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
445 settings
.SetPreemptionStrategy(
446 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
447 settings
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
448 start_cycler_animation_duration
));
450 layer
->SetOpacity(Config::GetDouble(Config::BACKGROUND_OPACITY
));
454 // Create a window to simulate a fully opaque launcher. This prevents
455 // workspaces from showing from behind the launcher.
456 CreateLauncherBackground();
459 void WorkspaceCyclerAnimator::AnimateStoppingCycler() {
460 if (scroll_delta_
!= 0) {
461 // Completely select the workspace at |selected_workspace_index_|.
462 int animation_duration
= GetAnimationDurationForChangeInScrollDelta(
465 animation_type_
= CYCLER_COMPLETELY_SELECT
;
466 AnimateToUpdatedState(animation_duration
);
470 int stop_cycler_animation_duration
= static_cast<int>(Config::GetDouble(
471 Config::STOP_CYCLER_ANIMATION_DURATION
));
473 animation_type_
= CYCLER_END
;
474 AnimateToUpdatedState(stop_cycler_animation_duration
);
476 AnimateTo(0, false, stop_cycler_animation_duration
, gfx::Transform(),
479 aura::Window
* background
= GetDesktopBackground();
481 ui::Layer
* layer
= background
->layer();
482 ui::ScopedLayerAnimationSettings
settings(layer
->GetAnimator());
483 settings
.SetPreemptionStrategy(
484 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
485 settings
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
486 stop_cycler_animation_duration
));
488 layer
->SetOpacity((selected_workspace_index_
== 0) ? 1.0f
: 0.0f
);
492 void WorkspaceCyclerAnimator::AbortAnimations() {
493 StopObservingImplicitAnimations();
494 animation_type_
= NONE
;
495 CyclerStopped(initial_active_workspace_index_
);
498 void WorkspaceCyclerAnimator::AnimateCyclingByScrollDelta(double scroll_delta
) {
499 if (scroll_delta
== 0)
502 // Drop any updates received while an animation is running.
503 // TODO(pkotwicz): Do something better.
504 if (animation_type_
!= NONE
)
507 if (ui::IsNaturalScrollEnabled())
510 double old_scroll_delta
= scroll_delta_
;
511 scroll_delta_
+= scroll_delta
;
513 double scroll_distance_to_cycle_to_next_workspace
= Config::GetDouble(
514 Config::SCROLL_DISTANCE_TO_CYCLE_TO_NEXT_WORKSPACE
);
516 double min_scroll_delta
= -1 *
517 static_cast<double>(selected_workspace_index_
) *
518 scroll_distance_to_cycle_to_next_workspace
;
519 double max_scroll_delta
= static_cast<double>(
520 workspaces_
.size() - 1 - selected_workspace_index_
) *
521 scroll_distance_to_cycle_to_next_workspace
;
523 if (scroll_delta_
< min_scroll_delta
)
524 scroll_delta_
= min_scroll_delta
;
525 else if (scroll_delta_
> max_scroll_delta
)
526 scroll_delta_
= max_scroll_delta
;
528 if (scroll_delta_
== old_scroll_delta
)
531 // Set the selected workspace to the workspace that the user is closest to
532 // selecting completely. A workspace is completely selected when the user
533 // has scrolled the exact amount to select the workspace with no undershoot /
535 int workspace_change
= floor(scroll_delta_
/
536 scroll_distance_to_cycle_to_next_workspace
+ .5);
537 selected_workspace_index_
+= workspace_change
;
539 // Set |scroll_delta_| to the amount of undershoot / overshoot.
540 scroll_delta_
-= workspace_change
*
541 scroll_distance_to_cycle_to_next_workspace
;
543 int animation_duration
= GetAnimationDurationForChangeInScrollDelta(
544 scroll_delta_
- old_scroll_delta
);
546 animation_type_
= CYCLER_UPDATE
;
547 AnimateToUpdatedState(animation_duration
);
550 void WorkspaceCyclerAnimator::AnimateToUpdatedState(int animation_duration
) {
551 DCHECK_NE(NONE
, animation_type_
);
553 bool animator_to_wait_for_selected
= false;
555 // Start at index 1, as the animator does not animate the desktop workspace.
556 for (size_t i
= 1; i
< workspaces_
.size(); ++i
) {
557 gfx::Transform transform
;
558 float brightness
= 0.0f
;
559 bool visible
= false;
560 if (animation_type_
== CYCLER_END
) {
561 DCHECK_EQ(0, scroll_delta_
);
562 style_calculator_
->GetStoppedTargetProperties(selected_workspace_index_
,
563 i
, &transform
, &brightness
, &visible
);
565 style_calculator_
->GetTargetProperties(selected_workspace_index_
, i
,
566 scroll_delta_
, &transform
, &brightness
, &visible
);
569 aura::Window
* window
= workspaces_
[i
]->window();
570 int workspace_animation_duration
= animation_duration
;
571 if (!window
->IsVisible()) {
573 // The workspace's previous state is unknown, set the state immediately.
574 workspace_animation_duration
= 0;
576 // Don't bother animating workspaces which aren't visible.
580 // Hide the workspace after |animation_duration| in the case of
581 // |visible| == false as the workspace to be hidden may not be completely
582 // occluded till the animation has completed.
584 bool wait_for_animator
= false;
585 if (!animator_to_wait_for_selected
&& workspace_animation_duration
!= 0) {
586 // The completion of the animations for this workspace will be used to
587 // indicate that the animations for all workspaces have completed.
588 wait_for_animator
= true;
589 animator_to_wait_for_selected
= true;
592 AnimateTo(i
, wait_for_animator
, workspace_animation_duration
,
593 transform
, brightness
, visible
);
596 // All of the animations started by this method were of zero duration.
597 // Call the animation callback.
598 if (!animator_to_wait_for_selected
)
599 OnImplicitAnimationsCompleted();
602 void WorkspaceCyclerAnimator::CyclerStopped(size_t visible_workspace_index
) {
603 aura::Window
* root_window
= workspaces_
[0]->window()->GetRootWindow();
604 root_window
->SetProperty(ash::internal::kCyclingThroughWorkspacesKey
,
607 for(size_t i
= 0; i
< workspaces_
.size(); ++i
) {
608 aura::Window
* window
= workspaces_
[i
]->window();
609 ui::Layer
* layer
= window
->layer();
610 layer
->SetLayerBrightness(0.0f
);
611 layer
->SetTransform(gfx::Transform());
613 if (i
== visible_workspace_index
)
619 aura::Window
* background
= GetDesktopBackground();
621 background
->layer()->SetOpacity(1.0);
622 if (visible_workspace_index
!= 0u)
626 launcher_background_controller_
.reset();
629 void WorkspaceCyclerAnimator::AnimateTo(size_t workspace_index
,
630 bool wait_for_animation_to_complete
,
631 int animation_duration
,
632 const gfx::Transform
& target_transform
,
633 float target_brightness
,
634 bool target_visibility
) {
635 aura::Window
* window
= workspaces_
[workspace_index
]->window();
636 ui::Layer
* layer
= window
->layer();
637 ui::LayerAnimator
* animator
= layer
->GetAnimator();
638 ui::ScopedLayerAnimationSettings
settings(animator
);
640 if (wait_for_animation_to_complete
) {
641 StopObservingImplicitAnimations();
642 DCHECK_NE(animation_type_
, NONE
);
643 settings
.AddObserver(this);
646 settings
.SetPreemptionStrategy(
647 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
648 settings
.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
649 animation_duration
));
651 if (target_visibility
) {
654 // Set the opacity in case the layer has some weird initial state.
655 layer
->SetOpacity(1.0f
);
660 layer
->SetTransform(target_transform
);
661 layer
->SetLayerBrightness(target_brightness
);
664 int WorkspaceCyclerAnimator::GetAnimationDurationForChangeInScrollDelta(
665 double change
) const {
666 double ratio
= Config::GetDouble(
667 Config::CYCLER_STEP_ANIMATION_DURATION_RATIO
);
668 return static_cast<int>(fabs(change
) * ratio
);
671 void WorkspaceCyclerAnimator::CreateLauncherBackground() {
672 if (screen_bounds_
== maximized_bounds_
)
675 // TODO(pkotwicz): Figure out what to do when the launcher visible state is
677 ShelfLayoutManager
* shelf_layout_manager
=
678 ShelfLayoutManager::ForLauncher(workspaces_
[0]->window());
679 if (!shelf_layout_manager
->IsVisible())
682 aura::Window
* launcher_window
= shelf_layout_manager
->shelf_widget()->
685 gfx::Rect shelf_bounds
= shelf_layout_manager
->GetIdealBounds();
687 launcher_background_controller_
.reset(new ColoredWindowController(
688 launcher_window
->parent(), "LauncherBackground"));
689 launcher_background_controller_
->SetColor(SK_ColorBLACK
);
690 aura::Window
* tint_window
=
691 launcher_background_controller_
->GetWidget()->GetNativeWindow();
692 tint_window
->SetBounds(shelf_bounds
);
693 launcher_window
->parent()->StackChildBelow(tint_window
, launcher_window
);
697 aura::Window
* WorkspaceCyclerAnimator::GetDesktopBackground() const {
698 RootWindowController
* root_controller
= GetRootWindowController(
699 workspaces_
[0]->window()->GetRootWindow());
700 if (!root_controller
)
703 return root_controller
->GetContainer(
704 kShellWindowId_DesktopBackgroundContainer
);
707 void WorkspaceCyclerAnimator::NotifyDelegate(
708 AnimationType completed_animation
) {
709 if (completed_animation
== CYCLER_START
)
710 delegate_
->StartWorkspaceCyclerAnimationFinished();
711 else if (completed_animation
== CYCLER_END
)
712 delegate_
->StopWorkspaceCyclerAnimationFinished();
715 void WorkspaceCyclerAnimator::OnImplicitAnimationsCompleted() {
716 AnimationType completed_animation
= animation_type_
;
717 animation_type_
= NONE
;
719 if (completed_animation
== CYCLER_COMPLETELY_SELECT
)
720 AnimateStoppingCycler();
721 else if (completed_animation
== CYCLER_END
)
722 CyclerStopped(selected_workspace_index_
);
724 if (completed_animation
== CYCLER_START
||
725 completed_animation
== CYCLER_END
) {
726 // Post a task to notify the delegate of the animation completion because
727 // the delegate may delete |this| as a result of getting notified.
728 base::MessageLoopForUI::current()->PostTask(
730 base::Bind(&WorkspaceCyclerAnimator::NotifyDelegate
,
732 completed_animation
));
736 } // namespace internal