blob: bd18d746ed2030ea5273eb5188352b1d54691a45 [file] [log] [blame]
bruthig37f9cad02015-03-12 22:28:501// Copyright 2015 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/rotator/screen_rotation_animator.h"
6
7#include <string>
dchengcbf0d9d2015-12-27 22:49:238#include <utility>
bruthig37f9cad02015-03-12 22:28:509#include <vector>
10
bruthig37f9cad02015-03-12 22:28:5011#include "ash/display/display_manager.h"
oshimae2818922015-07-28 01:18:5212#include "ash/display/window_tree_host_manager.h"
bruthig37f9cad02015-03-12 22:28:5013#include "ash/rotator/screen_rotation_animation.h"
14#include "ash/shell.h"
15#include "base/command_line.h"
16#include "base/time/time.h"
17#include "ui/aura/window.h"
18#include "ui/compositor/layer.h"
19#include "ui/compositor/layer_animation_observer.h"
20#include "ui/compositor/layer_animation_sequence.h"
21#include "ui/compositor/layer_animator.h"
22#include "ui/compositor/layer_owner.h"
23#include "ui/compositor/layer_tree_owner.h"
oshimaf84b0da722016-04-27 19:47:1924#include "ui/display/display.h"
rjkroege259c01882016-08-30 19:29:5025#include "ui/display/manager/managed_display_info.h"
bruthig37f9cad02015-03-12 22:28:5026#include "ui/gfx/animation/tween.h"
bruthig37f9cad02015-03-12 22:28:5027#include "ui/gfx/geometry/point.h"
28#include "ui/gfx/geometry/rect.h"
29#include "ui/gfx/geometry/rect_f.h"
30#include "ui/gfx/transform.h"
31#include "ui/gfx/transform_util.h"
32#include "ui/wm/core/window_util.h"
33
34namespace ash {
35
36namespace {
37
bruthigaff7d0f2015-09-01 17:46:5538// The number of degrees that the rotation animations animate through.
39const int kRotationDegrees = 20;
bruthig37f9cad02015-03-12 22:28:5040
bruthig2ce3f232015-04-02 15:21:3541// The time it takes for the rotation animations to run.
bruthig37f9cad02015-03-12 22:28:5042const int kRotationDurationInMs = 250;
43
bruthig37f9cad02015-03-12 22:28:5044// Gets the current display rotation for the display with the specified
45// |display_id|.
oshimaf84b0da722016-04-27 19:47:1946display::Display::Rotation GetCurrentRotation(int64_t display_id) {
bruthig37f9cad02015-03-12 22:28:5047 return Shell::GetInstance()
48 ->display_manager()
49 ->GetDisplayInfo(display_id)
jonrossd01de7f2015-04-23 19:52:0050 .GetActiveRotation();
bruthig37f9cad02015-03-12 22:28:5051}
52
53// Returns true if the rotation between |initial_rotation| and |new_rotation| is
54// 180 degrees.
oshimaf84b0da722016-04-27 19:47:1955bool Is180DegreeFlip(display::Display::Rotation initial_rotation,
56 display::Display::Rotation new_rotation) {
bruthig37f9cad02015-03-12 22:28:5057 return (initial_rotation + 2) % 4 == new_rotation;
58}
59
60// A LayerAnimationObserver that will destroy the contained LayerTreeOwner when
61// notified that a layer animation has ended or was aborted.
62class LayerCleanupObserver : public ui::LayerAnimationObserver {
63 public:
64 explicit LayerCleanupObserver(
dchenga94547472016-04-08 08:41:1165 std::unique_ptr<ui::LayerTreeOwner> layer_tree_owner);
bruthig37f9cad02015-03-12 22:28:5066 ~LayerCleanupObserver() override;
67
68 // Get the root layer of the owned layer tree.
69 ui::Layer* GetRootLayer();
70
71 // ui::LayerAnimationObserver:
72 void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
73 void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;
74 void OnLayerAnimationScheduled(
75 ui::LayerAnimationSequence* sequence) override {}
76
77 protected:
78 // ui::LayerAnimationObserver:
79 bool RequiresNotificationWhenAnimatorDestroyed() const override {
80 return true;
81 }
82 void OnAttachedToSequence(ui::LayerAnimationSequence* sequence) override;
83 void OnDetachedFromSequence(ui::LayerAnimationSequence* sequence) override;
84
85 private:
jonross7351feb2015-04-23 22:10:2686 // Aborts the active animations of the layer, and recurses upon its child
87 // layers.
88 void AbortAnimations(ui::Layer* layer);
89
bruthig37f9cad02015-03-12 22:28:5090 // The owned layer tree.
dchenga94547472016-04-08 08:41:1191 std::unique_ptr<ui::LayerTreeOwner> layer_tree_owner_;
bruthig37f9cad02015-03-12 22:28:5092
93 // The LayerAnimationSequence that |this| has been attached to. Defaults to
94 // nullptr.
95 ui::LayerAnimationSequence* sequence_;
96
97 DISALLOW_COPY_AND_ASSIGN(LayerCleanupObserver);
98};
99
100LayerCleanupObserver::LayerCleanupObserver(
dchenga94547472016-04-08 08:41:11101 std::unique_ptr<ui::LayerTreeOwner> layer_tree_owner)
dchengcbf0d9d2015-12-27 22:49:23102 : layer_tree_owner_(std::move(layer_tree_owner)), sequence_(nullptr) {}
bruthig37f9cad02015-03-12 22:28:50103
104LayerCleanupObserver::~LayerCleanupObserver() {
105 // We must eplicitly detach from |sequence_| because we return true from
106 // RequiresNotificationWhenAnimatorDestroyed.
107 if (sequence_)
108 sequence_->RemoveObserver(this);
jonross7351feb2015-04-23 22:10:26109 AbortAnimations(layer_tree_owner_->root());
bruthig37f9cad02015-03-12 22:28:50110}
111
112ui::Layer* LayerCleanupObserver::GetRootLayer() {
113 return layer_tree_owner_->root();
114}
115
116void LayerCleanupObserver::OnLayerAnimationEnded(
117 ui::LayerAnimationSequence* sequence) {
118 delete this;
119}
120
121void LayerCleanupObserver::OnLayerAnimationAborted(
122 ui::LayerAnimationSequence* sequence) {
123 delete this;
124}
125
126void LayerCleanupObserver::OnAttachedToSequence(
127 ui::LayerAnimationSequence* sequence) {
128 sequence_ = sequence;
129}
130
131void LayerCleanupObserver::OnDetachedFromSequence(
132 ui::LayerAnimationSequence* sequence) {
133 DCHECK_EQ(sequence, sequence_);
134 sequence_ = nullptr;
135}
136
jonross7351feb2015-04-23 22:10:26137void LayerCleanupObserver::AbortAnimations(ui::Layer* layer) {
138 for (ui::Layer* child_layer : layer->children())
139 AbortAnimations(child_layer);
140 layer->GetAnimator()->AbortAllAnimations();
141}
142
bruthigaff7d0f2015-09-01 17:46:55143// Set the screen orientation for the given |display_id| to |new_rotation| and
144// animate the change. The animation will rotate the initial orientation's
145// layer towards the new orientation through |rotation_degrees| while fading
146// out, and the new orientation's layer will be rotated in to the
147// |new_orientation| through |rotation_degrees| arc.
avidb567a8a2015-12-20 17:07:24148void RotateScreen(int64_t display_id,
oshimaf84b0da722016-04-27 19:47:19149 display::Display::Rotation new_rotation,
150 display::Display::RotationSource source) {
oshimae2818922015-07-28 01:18:52151 aura::Window* root_window = Shell::GetInstance()
152 ->window_tree_host_manager()
153 ->GetRootWindowForDisplayId(display_id);
bruthig37f9cad02015-03-12 22:28:50154
oshimaf84b0da722016-04-27 19:47:19155 const display::Display::Rotation initial_orientation =
bruthig37f9cad02015-03-12 22:28:50156 GetCurrentRotation(display_id);
157
danakj335602b2015-08-31 23:35:03158 const gfx::Rect original_screen_bounds = root_window->GetTargetBounds();
bruthig37f9cad02015-03-12 22:28:50159 // 180 degree rotations should animate clock-wise.
160 const int rotation_factor =
161 (initial_orientation + 3) % 4 == new_rotation ? 1 : -1;
162
bruthigaff7d0f2015-09-01 17:46:55163 const int old_layer_initial_rotation_degrees =
164 (Is180DegreeFlip(initial_orientation, new_rotation) ? 180 : 90);
165
166 const base::TimeDelta duration =
167 base::TimeDelta::FromMilliseconds(kRotationDurationInMs);
168
169 const gfx::Tween::Type tween_type = gfx::Tween::FAST_OUT_LINEAR_IN;
170
dchenga94547472016-04-08 08:41:11171 std::unique_ptr<ui::LayerTreeOwner> old_layer_tree =
oshimae1dbe8e02016-05-20 04:08:16172 ::wm::RecreateLayers(root_window, nullptr);
bruthig37f9cad02015-03-12 22:28:50173
174 // Add the cloned layer tree in to the root, so it will be rendered.
175 root_window->layer()->Add(old_layer_tree->root());
176 root_window->layer()->StackAtTop(old_layer_tree->root());
177
dchenga94547472016-04-08 08:41:11178 std::unique_ptr<LayerCleanupObserver> layer_cleanup_observer(
dchengcbf0d9d2015-12-27 22:49:23179 new LayerCleanupObserver(std::move(old_layer_tree)));
bruthig37f9cad02015-03-12 22:28:50180
jonrossd01de7f2015-04-23 19:52:00181 Shell::GetInstance()->display_manager()->SetDisplayRotation(
182 display_id, new_rotation, source);
bruthig37f9cad02015-03-12 22:28:50183
danakj335602b2015-08-31 23:35:03184 const gfx::Rect rotated_screen_bounds = root_window->GetTargetBounds();
bruthig37f9cad02015-03-12 22:28:50185 const gfx::Point pivot = gfx::Point(rotated_screen_bounds.width() / 2,
186 rotated_screen_bounds.height() / 2);
187
bruthig37f9cad02015-03-12 22:28:50188 // We must animate each non-cloned child layer individually because the cloned
189 // layer was added as a child to |root_window|'s layer so that it will be
190 // rendered.
191 // TODO(bruthig): Add a NOT_DRAWN layer in between the root_window's layer and
192 // its current children so that we only need to initiate two
193 // LayerAnimationSequences. One for the new layers and one for the old layer.
194 for (ui::Layer* child_layer : root_window->layer()->children()) {
195 // Skip the cloned layer because it has a different animation.
196 if (child_layer == layer_cleanup_observer->GetRootLayer())
197 continue;
198
dchenga94547472016-04-08 08:41:11199 std::unique_ptr<ScreenRotationAnimation> screen_rotation(
bruthig37f9cad02015-03-12 22:28:50200 new ScreenRotationAnimation(
bruthigaff7d0f2015-09-01 17:46:55201 child_layer, kRotationDegrees * rotation_factor,
bruthig37f9cad02015-03-12 22:28:50202 0 /* end_degrees */, child_layer->opacity(),
bruthigaff7d0f2015-09-01 17:46:55203 1.0f /* target_opacity */, pivot, duration, tween_type));
bruthig37f9cad02015-03-12 22:28:50204
205 ui::LayerAnimator* animator = child_layer->GetAnimator();
206 animator->set_preemption_strategy(
207 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
dchenga94547472016-04-08 08:41:11208 std::unique_ptr<ui::LayerAnimationSequence> animation_sequence(
bruthig37f9cad02015-03-12 22:28:50209 new ui::LayerAnimationSequence(screen_rotation.release()));
210 animator->StartAnimation(animation_sequence.release());
211 }
212
213 // The old layer will also be transformed into the new orientation. We will
214 // translate it so that the old layer's center point aligns with the new
215 // orientation's center point and use that center point as the pivot for the
216 // rotation animation.
217 gfx::Transform translate_transform;
218 translate_transform.Translate(
219 (rotated_screen_bounds.width() - original_screen_bounds.width()) / 2,
220 (rotated_screen_bounds.height() - original_screen_bounds.height()) / 2);
221 layer_cleanup_observer->GetRootLayer()->SetTransform(translate_transform);
222
dchenga94547472016-04-08 08:41:11223 std::unique_ptr<ScreenRotationAnimation> screen_rotation(
bruthig37f9cad02015-03-12 22:28:50224 new ScreenRotationAnimation(
225 layer_cleanup_observer->GetRootLayer(),
bruthigaff7d0f2015-09-01 17:46:55226 old_layer_initial_rotation_degrees * rotation_factor,
227 (old_layer_initial_rotation_degrees - kRotationDegrees) *
228 rotation_factor,
bruthig37f9cad02015-03-12 22:28:50229 layer_cleanup_observer->GetRootLayer()->opacity(),
bruthigaff7d0f2015-09-01 17:46:55230 0.0f /* target_opacity */, pivot, duration, tween_type));
bruthig37f9cad02015-03-12 22:28:50231
232 ui::LayerAnimator* animator =
233 layer_cleanup_observer->GetRootLayer()->GetAnimator();
234 animator->set_preemption_strategy(
235 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
dchenga94547472016-04-08 08:41:11236 std::unique_ptr<ui::LayerAnimationSequence> animation_sequence(
bruthig37f9cad02015-03-12 22:28:50237 new ui::LayerAnimationSequence(screen_rotation.release()));
238 // Add an observer so that the cloned layers can be cleaned up with the
239 // animation completes/aborts.
240 animation_sequence->AddObserver(layer_cleanup_observer.release());
241 animator->StartAnimation(animation_sequence.release());
242}
243
244} // namespace
245
avidb567a8a2015-12-20 17:07:24246ScreenRotationAnimator::ScreenRotationAnimator(int64_t display_id)
247 : display_id_(display_id) {}
bruthig37f9cad02015-03-12 22:28:50248
jamescookb8dcef522016-06-25 14:42:55249ScreenRotationAnimator::~ScreenRotationAnimator() {}
bruthig37f9cad02015-03-12 22:28:50250
bruthigf57a7bba2015-04-24 21:19:31251bool ScreenRotationAnimator::CanAnimate() const {
252 return Shell::GetInstance()
jonrossd30c42f2015-05-20 15:27:11253 ->display_manager()
254 ->GetDisplayForId(display_id_)
255 .is_valid();
bruthigf57a7bba2015-04-24 21:19:31256}
257
oshimaf84b0da722016-04-27 19:47:19258void ScreenRotationAnimator::Rotate(display::Display::Rotation new_rotation,
259 display::Display::RotationSource source) {
260 const display::Display::Rotation current_rotation =
bruthig37f9cad02015-03-12 22:28:50261 GetCurrentRotation(display_id_);
262
263 if (current_rotation == new_rotation)
264 return;
265
bruthigaff7d0f2015-09-01 17:46:55266 RotateScreen(display_id_, new_rotation, source);
bruthig37f9cad02015-03-12 22:28:50267}
268
269} // namespace ash