blob: 102b8d0e7b3082f7ff25656d2f1243ecad206e22 [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
oshimae2818922015-07-28 01:18:5211#include "ash/display/window_tree_host_manager.h"
bruthig37f9cad02015-03-12 22:28:5012#include "ash/rotator/screen_rotation_animation.h"
wutao6ddafa32017-03-18 03:10:0813#include "ash/rotator/screen_rotation_animator_observer.h"
bruthig37f9cad02015-03-12 22:28:5014#include "ash/shell.h"
15#include "base/command_line.h"
ratsunnybd5087e2016-12-17 05:19:2516#include "base/memory/ptr_util.h"
wutao3f08f812017-03-25 03:06:3317#include "base/metrics/histogram_macros.h"
bruthig37f9cad02015-03-12 22:28:5018#include "base/time/time.h"
19#include "ui/aura/window.h"
20#include "ui/compositor/layer.h"
wutao3f08f812017-03-25 03:06:3321#include "ui/compositor/layer_animation_element.h"
bruthig37f9cad02015-03-12 22:28:5022#include "ui/compositor/layer_animation_observer.h"
23#include "ui/compositor/layer_animation_sequence.h"
24#include "ui/compositor/layer_animator.h"
25#include "ui/compositor/layer_owner.h"
26#include "ui/compositor/layer_tree_owner.h"
oshimaf84b0da722016-04-27 19:47:1927#include "ui/display/display.h"
rjkroege72f8154f2016-10-29 00:49:0228#include "ui/display/manager/display_manager.h"
rjkroege259c01882016-08-30 19:29:5029#include "ui/display/manager/managed_display_info.h"
bruthig37f9cad02015-03-12 22:28:5030#include "ui/gfx/animation/tween.h"
bruthig37f9cad02015-03-12 22:28:5031#include "ui/gfx/geometry/point.h"
32#include "ui/gfx/geometry/rect.h"
33#include "ui/gfx/geometry/rect_f.h"
34#include "ui/gfx/transform.h"
35#include "ui/gfx/transform_util.h"
36#include "ui/wm/core/window_util.h"
37
38namespace ash {
39
40namespace {
41
bruthigaff7d0f2015-09-01 17:46:5542// The number of degrees that the rotation animations animate through.
43const int kRotationDegrees = 20;
bruthig37f9cad02015-03-12 22:28:5044
bruthig2ce3f232015-04-02 15:21:3545// The time it takes for the rotation animations to run.
bruthig37f9cad02015-03-12 22:28:5046const int kRotationDurationInMs = 250;
47
wutao6ddafa32017-03-18 03:10:0848// The rotation factors.
49const int kCounterClockWiseRotationFactor = 1;
50const int kClockWiseRotationFactor = -1;
51
52// Aborts the active animations of the layer, and recurses upon its child
53// layers.
54void AbortAnimations(ui::Layer* layer) {
55 for (ui::Layer* child_layer : layer->children())
56 AbortAnimations(child_layer);
57 layer->GetAnimator()->AbortAllAnimations();
58}
59
60display::Display::Rotation GetCurrentScreenRotation(int64_t display_id) {
bruthig37f9cad02015-03-12 22:28:5061 return Shell::GetInstance()
62 ->display_manager()
63 ->GetDisplayInfo(display_id)
jonrossd01de7f2015-04-23 19:52:0064 .GetActiveRotation();
bruthig37f9cad02015-03-12 22:28:5065}
66
wutao6ddafa32017-03-18 03:10:0867bool IsDisplayIdValid(int64_t display_id) {
68 return Shell::GetInstance()->display_manager()->IsDisplayIdValid(display_id);
69}
70
71// 180 degree rotations should animate clock-wise.
72int GetRotationFactor(display::Display::Rotation initial_rotation,
73 display::Display::Rotation new_rotation) {
74 return (initial_rotation + 3) % 4 == new_rotation
75 ? kCounterClockWiseRotationFactor
76 : kClockWiseRotationFactor;
77}
78
79aura::Window* GetRootWindow(int64_t display_id) {
80 return Shell::GetInstance()
81 ->window_tree_host_manager()
82 ->GetRootWindowForDisplayId(display_id);
83}
84
bruthig37f9cad02015-03-12 22:28:5085// Returns true if the rotation between |initial_rotation| and |new_rotation| is
86// 180 degrees.
oshimaf84b0da722016-04-27 19:47:1987bool Is180DegreeFlip(display::Display::Rotation initial_rotation,
88 display::Display::Rotation new_rotation) {
bruthig37f9cad02015-03-12 22:28:5089 return (initial_rotation + 2) % 4 == new_rotation;
90}
91
wutao6ddafa32017-03-18 03:10:0892// Returns the initial degrees the old layer animation to begin with.
93int GetInitialDegrees(display::Display::Rotation initial_rotation,
94 display::Display::Rotation new_rotation) {
95 return (Is180DegreeFlip(initial_rotation, new_rotation) ? 180 : 90);
96}
97
98// A LayerAnimationObserver that will destroy the contained LayerTreeOwner
99// when notified that a layer animation has ended or was aborted.
bruthig37f9cad02015-03-12 22:28:50100class LayerCleanupObserver : public ui::LayerAnimationObserver {
101 public:
wutao6ddafa32017-03-18 03:10:08102 // Takes WeakPtr of ScreenRotationAnimator. |this| may outlive the |animator_|
103 // instance and the |animator_| isn't detaching itself as an observer when
104 // being destroyed. However, ideally, when |animator_| is destroying,
105 // deleting |old_layer_tree_owner_| will trigger OnLayerAnimationAborted and
106 // delete |this| before |animator_| deleted.
107 explicit LayerCleanupObserver(base::WeakPtr<ScreenRotationAnimator> animator);
bruthig37f9cad02015-03-12 22:28:50108 ~LayerCleanupObserver() override;
109
bruthig37f9cad02015-03-12 22:28:50110 // ui::LayerAnimationObserver:
111 void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override;
112 void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override;
113 void OnLayerAnimationScheduled(
114 ui::LayerAnimationSequence* sequence) override {}
115
116 protected:
117 // ui::LayerAnimationObserver:
118 bool RequiresNotificationWhenAnimatorDestroyed() const override {
119 return true;
120 }
121 void OnAttachedToSequence(ui::LayerAnimationSequence* sequence) override;
122 void OnDetachedFromSequence(ui::LayerAnimationSequence* sequence) override;
123
124 private:
wutao6ddafa32017-03-18 03:10:08125 base::WeakPtr<ScreenRotationAnimator> animator_;
bruthig37f9cad02015-03-12 22:28:50126
127 // The LayerAnimationSequence that |this| has been attached to. Defaults to
128 // nullptr.
129 ui::LayerAnimationSequence* sequence_;
130
131 DISALLOW_COPY_AND_ASSIGN(LayerCleanupObserver);
132};
133
134LayerCleanupObserver::LayerCleanupObserver(
wutao6ddafa32017-03-18 03:10:08135 base::WeakPtr<ScreenRotationAnimator> animator)
136 : animator_(animator), sequence_(nullptr) {}
bruthig37f9cad02015-03-12 22:28:50137
138LayerCleanupObserver::~LayerCleanupObserver() {
139 // We must eplicitly detach from |sequence_| because we return true from
140 // RequiresNotificationWhenAnimatorDestroyed.
141 if (sequence_)
142 sequence_->RemoveObserver(this);
bruthig37f9cad02015-03-12 22:28:50143}
144
145void LayerCleanupObserver::OnLayerAnimationEnded(
146 ui::LayerAnimationSequence* sequence) {
wutao6ddafa32017-03-18 03:10:08147 if (animator_)
wutao3f08f812017-03-25 03:06:33148 animator_->ProcessAnimationQueue();
wutao6ddafa32017-03-18 03:10:08149
bruthig37f9cad02015-03-12 22:28:50150 delete this;
151}
152
153void LayerCleanupObserver::OnLayerAnimationAborted(
154 ui::LayerAnimationSequence* sequence) {
wutao6ddafa32017-03-18 03:10:08155 if (animator_)
wutao3f08f812017-03-25 03:06:33156 animator_->ProcessAnimationQueue();
wutao6ddafa32017-03-18 03:10:08157
bruthig37f9cad02015-03-12 22:28:50158 delete this;
159}
160
161void LayerCleanupObserver::OnAttachedToSequence(
162 ui::LayerAnimationSequence* sequence) {
163 sequence_ = sequence;
164}
165
166void LayerCleanupObserver::OnDetachedFromSequence(
167 ui::LayerAnimationSequence* sequence) {
168 DCHECK_EQ(sequence, sequence_);
169 sequence_ = nullptr;
170}
171
wutao3f08f812017-03-25 03:06:33172class ScreenRotationAnimationMetricsReporter
173 : public ui::AnimationMetricsReporter {
174 public:
175 ScreenRotationAnimationMetricsReporter() {}
176 ~ScreenRotationAnimationMetricsReporter() override {}
177
178 void Report(int value) override {
179 UMA_HISTOGRAM_PERCENTAGE("Ash.Rotation.AnimationSmoothness", value);
180 }
181
182 private:
183 DISALLOW_COPY_AND_ASSIGN(ScreenRotationAnimationMetricsReporter);
184};
185
wutao6ddafa32017-03-18 03:10:08186} // namespace
jonross7351feb2015-04-23 22:10:26187
wutao6ddafa32017-03-18 03:10:08188struct ScreenRotationAnimator::ScreenRotationRequest {
189 ScreenRotationRequest(display::Display::Rotation to_rotation,
190 display::Display::RotationSource from_source)
191 : new_rotation(to_rotation), source(from_source) {}
192 display::Display::Rotation new_rotation;
193 display::Display::RotationSource source;
194};
bruthig37f9cad02015-03-12 22:28:50195
wutao6ddafa32017-03-18 03:10:08196ScreenRotationAnimator::ScreenRotationAnimator(int64_t display_id)
197 : display_id_(display_id),
198 is_rotating_(false),
wutao3f08f812017-03-25 03:06:33199 metrics_reporter_(
200 base::MakeUnique<ScreenRotationAnimationMetricsReporter>()),
wutao6ddafa32017-03-18 03:10:08201 disable_animation_timers_for_test_(false),
202 weak_factory_(this) {}
203
wutao3f08f812017-03-25 03:06:33204ScreenRotationAnimator::~ScreenRotationAnimator() {
205 // To prevent a call to |LayerCleanupObserver::OnLayerAnimationAborted()| from
206 // calling a method on the |animator_|.
207 weak_factory_.InvalidateWeakPtrs();
208
209 // Explicitly reset the |old_layer_tree_owner_| and |metrics_reporter_| in
210 // order to make sure |metrics_reporter_| outlives the attached animation
211 // sequence.
212 old_layer_tree_owner_.reset();
213 metrics_reporter_.reset();
214}
wutao6ddafa32017-03-18 03:10:08215
216void ScreenRotationAnimator::AnimateRotation(
217 std::unique_ptr<ScreenRotationRequest> rotation_request) {
218 aura::Window* root_window = GetRootWindow(display_id_);
bruthig37f9cad02015-03-12 22:28:50219
danakj335602b2015-08-31 23:35:03220 const gfx::Rect original_screen_bounds = root_window->GetTargetBounds();
bruthig37f9cad02015-03-12 22:28:50221
wutao6ddafa32017-03-18 03:10:08222 const int rotation_factor = GetRotationFactor(
223 GetCurrentScreenRotation(display_id_), rotation_request->new_rotation);
224
225 const int old_layer_initial_rotation_degrees = GetInitialDegrees(
226 GetCurrentScreenRotation(display_id_), rotation_request->new_rotation);
bruthigaff7d0f2015-09-01 17:46:55227
228 const base::TimeDelta duration =
229 base::TimeDelta::FromMilliseconds(kRotationDurationInMs);
230
231 const gfx::Tween::Type tween_type = gfx::Tween::FAST_OUT_LINEAR_IN;
232
dchenga94547472016-04-08 08:41:11233 std::unique_ptr<ui::LayerTreeOwner> old_layer_tree =
domlaskowski4b33bfe2016-10-27 00:34:22234 ::wm::RecreateLayers(root_window);
wutao6ddafa32017-03-18 03:10:08235 old_layer_tree->root()->set_name("ScreenRotationAnimator:old_layer_tree");
bruthig37f9cad02015-03-12 22:28:50236
237 // Add the cloned layer tree in to the root, so it will be rendered.
238 root_window->layer()->Add(old_layer_tree->root());
239 root_window->layer()->StackAtTop(old_layer_tree->root());
240
wutao6ddafa32017-03-18 03:10:08241 old_layer_tree_owner_ = std::move(old_layer_tree);
242 std::unique_ptr<LayerCleanupObserver> old_layer_cleanup_observer(
243 new LayerCleanupObserver(weak_factory_.GetWeakPtr()));
bruthig37f9cad02015-03-12 22:28:50244
jonrossd01de7f2015-04-23 19:52:00245 Shell::GetInstance()->display_manager()->SetDisplayRotation(
wutao6ddafa32017-03-18 03:10:08246 display_id_, rotation_request->new_rotation, rotation_request->source);
bruthig37f9cad02015-03-12 22:28:50247
danakj335602b2015-08-31 23:35:03248 const gfx::Rect rotated_screen_bounds = root_window->GetTargetBounds();
bruthig37f9cad02015-03-12 22:28:50249 const gfx::Point pivot = gfx::Point(rotated_screen_bounds.width() / 2,
250 rotated_screen_bounds.height() / 2);
251
wutao6ddafa32017-03-18 03:10:08252 ui::Layer* old_root_layer = old_layer_tree_owner_->root();
bruthig37f9cad02015-03-12 22:28:50253 // We must animate each non-cloned child layer individually because the cloned
254 // layer was added as a child to |root_window|'s layer so that it will be
255 // rendered.
256 // TODO(bruthig): Add a NOT_DRAWN layer in between the root_window's layer and
257 // its current children so that we only need to initiate two
258 // LayerAnimationSequences. One for the new layers and one for the old layer.
259 for (ui::Layer* child_layer : root_window->layer()->children()) {
260 // Skip the cloned layer because it has a different animation.
wutao6ddafa32017-03-18 03:10:08261 if (child_layer == old_root_layer)
bruthig37f9cad02015-03-12 22:28:50262 continue;
263
ratsunnybd5087e2016-12-17 05:19:25264 std::unique_ptr<ScreenRotationAnimation> screen_rotation =
265 base::MakeUnique<ScreenRotationAnimation>(
bruthigaff7d0f2015-09-01 17:46:55266 child_layer, kRotationDegrees * rotation_factor,
bruthig37f9cad02015-03-12 22:28:50267 0 /* end_degrees */, child_layer->opacity(),
ratsunnybd5087e2016-12-17 05:19:25268 1.0f /* target_opacity */, pivot, duration, tween_type);
bruthig37f9cad02015-03-12 22:28:50269
270 ui::LayerAnimator* animator = child_layer->GetAnimator();
271 animator->set_preemption_strategy(
272 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
ratsunnybd5087e2016-12-17 05:19:25273 std::unique_ptr<ui::LayerAnimationSequence> animation_sequence =
274 base::MakeUnique<ui::LayerAnimationSequence>(
275 std::move(screen_rotation));
bruthig37f9cad02015-03-12 22:28:50276 animator->StartAnimation(animation_sequence.release());
277 }
278
279 // The old layer will also be transformed into the new orientation. We will
280 // translate it so that the old layer's center point aligns with the new
281 // orientation's center point and use that center point as the pivot for the
282 // rotation animation.
283 gfx::Transform translate_transform;
284 translate_transform.Translate(
285 (rotated_screen_bounds.width() - original_screen_bounds.width()) / 2,
286 (rotated_screen_bounds.height() - original_screen_bounds.height()) / 2);
wutao6ddafa32017-03-18 03:10:08287 old_root_layer->SetTransform(translate_transform);
bruthig37f9cad02015-03-12 22:28:50288
ratsunnybd5087e2016-12-17 05:19:25289 std::unique_ptr<ScreenRotationAnimation> screen_rotation =
290 base::MakeUnique<ScreenRotationAnimation>(
wutao6ddafa32017-03-18 03:10:08291 old_root_layer, old_layer_initial_rotation_degrees * rotation_factor,
bruthigaff7d0f2015-09-01 17:46:55292 (old_layer_initial_rotation_degrees - kRotationDegrees) *
293 rotation_factor,
wutao6ddafa32017-03-18 03:10:08294 old_root_layer->opacity(), 0.0f /* target_opacity */, pivot, duration,
295 tween_type);
bruthig37f9cad02015-03-12 22:28:50296
wutao6ddafa32017-03-18 03:10:08297 ui::LayerAnimator* animator = old_root_layer->GetAnimator();
bruthig37f9cad02015-03-12 22:28:50298 animator->set_preemption_strategy(
299 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
ratsunnybd5087e2016-12-17 05:19:25300 std::unique_ptr<ui::LayerAnimationSequence> animation_sequence =
301 base::MakeUnique<ui::LayerAnimationSequence>(std::move(screen_rotation));
bruthig37f9cad02015-03-12 22:28:50302 // Add an observer so that the cloned layers can be cleaned up with the
303 // animation completes/aborts.
wutao6ddafa32017-03-18 03:10:08304 animation_sequence->AddObserver(old_layer_cleanup_observer.release());
305 // In unit test, we can use ash::test::ScreenRotationAnimatorTestApi to
306 // control the animation.
307 if (disable_animation_timers_for_test_)
308 animator->set_disable_timer_for_test(true);
wutao3f08f812017-03-25 03:06:33309 animation_sequence->SetAnimationMetricsReporter(metrics_reporter_.get());
bruthig37f9cad02015-03-12 22:28:50310 animator->StartAnimation(animation_sequence.release());
bruthig37f9cad02015-03-12 22:28:50311
wutao6ddafa32017-03-18 03:10:08312 rotation_request.reset();
bruthigf57a7bba2015-04-24 21:19:31313}
314
oshimaf84b0da722016-04-27 19:47:19315void ScreenRotationAnimator::Rotate(display::Display::Rotation new_rotation,
316 display::Display::RotationSource source) {
wutao6ddafa32017-03-18 03:10:08317 if (GetCurrentScreenRotation(display_id_) == new_rotation)
bruthig37f9cad02015-03-12 22:28:50318 return;
319
wutao6ddafa32017-03-18 03:10:08320 std::unique_ptr<ScreenRotationRequest> rotation_request =
321 base::MakeUnique<ScreenRotationRequest>(new_rotation, source);
322
323 if (is_rotating_) {
324 last_pending_request_ = std::move(rotation_request);
325 // The pending request will be processed when the
326 // OnLayerAnimation(Ended|Aborted) methods should be called after
327 // StopAnimating().
328 StopAnimating();
329 } else {
330 is_rotating_ = true;
331 AnimateRotation(std::move(rotation_request));
332 }
333}
334
335void ScreenRotationAnimator::AddScreenRotationAnimatorObserver(
336 ScreenRotationAnimatorObserver* observer) {
337 screen_rotation_animator_observers_.AddObserver(observer);
338}
339
340void ScreenRotationAnimator::RemoveScreenRotationAnimatorObserver(
341 ScreenRotationAnimatorObserver* observer) {
342 screen_rotation_animator_observers_.RemoveObserver(observer);
343}
344
wutao6ddafa32017-03-18 03:10:08345void ScreenRotationAnimator::ProcessAnimationQueue() {
346 is_rotating_ = false;
347 old_layer_tree_owner_.reset();
348 if (last_pending_request_ && IsDisplayIdValid(display_id_)) {
349 std::unique_ptr<ScreenRotationRequest> rotation_request =
350 std::move(last_pending_request_);
351 Rotate(rotation_request->new_rotation, rotation_request->source);
352 rotation_request.reset();
353 return;
354 }
355
356 for (auto& observer : screen_rotation_animator_observers_)
357 observer.OnScreenRotationAnimationFinished(this);
358}
359
360void ScreenRotationAnimator::set_disable_animation_timers_for_test(
361 bool disable_timers) {
362 disable_animation_timers_for_test_ = disable_timers;
363}
364
365void ScreenRotationAnimator::StopAnimating() {
366 aura::Window* root_window = GetRootWindow(display_id_);
367 for (ui::Layer* child_layer : root_window->layer()->children()) {
368 if (child_layer == old_layer_tree_owner_->root())
369 continue;
370
371 child_layer->GetAnimator()->StopAnimating();
372 }
373
374 old_layer_tree_owner_->root()->GetAnimator()->StopAnimating();
bruthig37f9cad02015-03-12 22:28:50375}
376
377} // namespace ash