blob: cd193d76cf1a65194e7544b23c6daf848b0fee10 [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
James Cookb0bf8e82017-04-09 17:01:447#include "ash/ash_switches.h"
wutao33576082017-04-14 18:51:108#include "ash/public/cpp/shell_window_ids.h"
bruthig37f9cad02015-03-12 22:28:509#include "ash/rotator/screen_rotation_animation.h"
wutao6ddafa32017-03-18 03:10:0810#include "ash/rotator/screen_rotation_animator_observer.h"
bruthig37f9cad02015-03-12 22:28:5011#include "ash/shell.h"
wutao6d394112017-04-20 02:17:3512#include "ash/utility/transformer_util.h"
bruthig37f9cad02015-03-12 22:28:5013#include "base/command_line.h"
ratsunnybd5087e2016-12-17 05:19:2514#include "base/memory/ptr_util.h"
wutao3f08f812017-03-25 03:06:3315#include "base/metrics/histogram_macros.h"
bruthig37f9cad02015-03-12 22:28:5016#include "base/time/time.h"
wutao2c0ca182017-04-06 22:40:5417#include "cc/output/copy_output_request.h"
18#include "cc/output/copy_output_result.h"
bruthig37f9cad02015-03-12 22:28:5019#include "ui/aura/window.h"
wutao6d394112017-04-20 02:17:3520#include "ui/compositor/callback_layer_animation_observer.h"
bruthig37f9cad02015-03-12 22:28:5021#include "ui/compositor/layer.h"
wutao3f08f812017-03-25 03:06:3322#include "ui/compositor/layer_animation_element.h"
bruthig37f9cad02015-03-12 22:28:5023#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"
wutaoc18f66c2017-06-02 18:11:0130#include "ui/display/screen.h"
bruthig37f9cad02015-03-12 22:28:5031#include "ui/gfx/animation/tween.h"
bruthig37f9cad02015-03-12 22:28:5032#include "ui/gfx/geometry/point.h"
33#include "ui/gfx/geometry/rect.h"
34#include "ui/gfx/geometry/rect_f.h"
35#include "ui/gfx/transform.h"
36#include "ui/gfx/transform_util.h"
37#include "ui/wm/core/window_util.h"
38
39namespace ash {
40
41namespace {
42
bruthigaff7d0f2015-09-01 17:46:5543// The number of degrees that the rotation animations animate through.
44const int kRotationDegrees = 20;
bruthig37f9cad02015-03-12 22:28:5045
bruthig2ce3f232015-04-02 15:21:3546// The time it takes for the rotation animations to run.
bruthig37f9cad02015-03-12 22:28:5047const int kRotationDurationInMs = 250;
48
wutao6ddafa32017-03-18 03:10:0849// The rotation factors.
50const int kCounterClockWiseRotationFactor = 1;
51const int kClockWiseRotationFactor = -1;
52
wutao6ddafa32017-03-18 03:10:0853display::Display::Rotation GetCurrentScreenRotation(int64_t display_id) {
skycb4be5b2017-04-06 17:52:4554 return Shell::Get()
bruthig37f9cad02015-03-12 22:28:5055 ->display_manager()
56 ->GetDisplayInfo(display_id)
jonrossd01de7f2015-04-23 19:52:0057 .GetActiveRotation();
bruthig37f9cad02015-03-12 22:28:5058}
59
wutao6ddafa32017-03-18 03:10:0860// 180 degree rotations should animate clock-wise.
61int GetRotationFactor(display::Display::Rotation initial_rotation,
62 display::Display::Rotation new_rotation) {
63 return (initial_rotation + 3) % 4 == new_rotation
64 ? kCounterClockWiseRotationFactor
65 : kClockWiseRotationFactor;
66}
67
wutao6d394112017-04-20 02:17:3568aura::Window* GetScreenRotationContainer(aura::Window* root_window) {
69 return root_window->GetChildById(kShellWindowId_ScreenRotationContainer);
70}
71
bruthig37f9cad02015-03-12 22:28:5072// Returns true if the rotation between |initial_rotation| and |new_rotation| is
73// 180 degrees.
oshimaf84b0da722016-04-27 19:47:1974bool Is180DegreeFlip(display::Display::Rotation initial_rotation,
75 display::Display::Rotation new_rotation) {
bruthig37f9cad02015-03-12 22:28:5076 return (initial_rotation + 2) % 4 == new_rotation;
77}
78
wutao6ddafa32017-03-18 03:10:0879// Returns the initial degrees the old layer animation to begin with.
80int GetInitialDegrees(display::Display::Rotation initial_rotation,
81 display::Display::Rotation new_rotation) {
82 return (Is180DegreeFlip(initial_rotation, new_rotation) ? 180 : 90);
83}
84
wutao6d394112017-04-20 02:17:3585void AddLayerAtTopOfWindowLayers(aura::Window* root_window, ui::Layer* layer) {
86 // Add the cloned/copied layer tree into the root, so it will be rendered.
87 root_window->layer()->Add(layer);
88 root_window->layer()->StackAtTop(layer);
bruthig37f9cad02015-03-12 22:28:5089}
90
wutao6d394112017-04-20 02:17:3591void AddLayerBelowWindowLayer(aura::Window* root_window,
92 ui::Layer* top_layer,
93 ui::Layer* layer) {
94 // Add the cloned/copied layer tree into the root, so it will be rendered.
95 root_window->layer()->Add(layer);
96 root_window->layer()->StackBelow(layer, top_layer);
bruthig37f9cad02015-03-12 22:28:5097}
98
wutao6d394112017-04-20 02:17:3599// The Callback will be invoked when all animation sequences have
100// finished. |observer| will be destroyed after invoking the Callback if it
101// returns true.
102bool AnimationEndedCallback(
103 base::WeakPtr<ScreenRotationAnimator> animator,
104 const ui::CallbackLayerAnimationObserver& observer) {
105 if (animator)
106 animator->ProcessAnimationQueue();
107 return true;
bruthig37f9cad02015-03-12 22:28:50108}
109
wutao6d394112017-04-20 02:17:35110// Creates a Transform for the old layer in screen rotation animation.
111gfx::Transform CreateScreenRotationOldLayerTransformForDisplay(
112 display::Display::Rotation old_rotation,
113 display::Display::Rotation new_rotation,
114 const display::Display& display) {
115 gfx::Transform inverse;
116 CHECK(CreateRotationTransform(old_rotation, new_rotation, display)
117 .GetInverse(&inverse));
118 return inverse;
bruthig37f9cad02015-03-12 22:28:50119}
120
wutao6d394112017-04-20 02:17:35121// The |request_id| changed since last copy request, which means a
122// new rotation stated, we need to ignore this copy result.
123bool IgnoreCopyResult(int64_t request_id, int64_t current_request_id) {
124 DCHECK(request_id <= current_request_id);
125 return request_id < current_request_id;
126}
127
wutaoc18f66c2017-06-02 18:11:01128bool RootWindowChangedForDisplayId(aura::Window* root_window,
129 int64_t display_id) {
Scott Violet596bb46342017-06-21 14:43:13130 return root_window != Shell::GetRootWindowForDisplayId(display_id);
wutaoc18f66c2017-06-02 18:11:01131}
132
133// Creates a mask layer and returns the |mask_layer_tree_owner|.
134std::unique_ptr<ui::LayerTreeOwner> CreateMaskLayerTreeOwner(
wutao6d394112017-04-20 02:17:35135 const gfx::Rect& rect) {
wutaoc18f66c2017-06-02 18:11:01136 std::unique_ptr<ui::Layer> mask_layer =
wutao6d394112017-04-20 02:17:35137 base::MakeUnique<ui::Layer>(ui::LAYER_SOLID_COLOR);
wutaoc18f66c2017-06-02 18:11:01138 mask_layer->SetBounds(rect);
139 mask_layer->SetColor(SK_ColorBLACK);
140 return base::MakeUnique<ui::LayerTreeOwner>(std::move(mask_layer));
bruthig37f9cad02015-03-12 22:28:50141}
142
wutao3f08f812017-03-25 03:06:33143class ScreenRotationAnimationMetricsReporter
144 : public ui::AnimationMetricsReporter {
145 public:
wutao883ea6f2017-05-16 19:40:51146 ScreenRotationAnimationMetricsReporter() = default;
147 ~ScreenRotationAnimationMetricsReporter() override = default;
wutao3f08f812017-03-25 03:06:33148
149 void Report(int value) override {
150 UMA_HISTOGRAM_PERCENTAGE("Ash.Rotation.AnimationSmoothness", value);
151 }
152
153 private:
154 DISALLOW_COPY_AND_ASSIGN(ScreenRotationAnimationMetricsReporter);
155};
156
wutao6ddafa32017-03-18 03:10:08157} // namespace
jonross7351feb2015-04-23 22:10:26158
wutaoc18f66c2017-06-02 18:11:01159ScreenRotationAnimator::ScreenRotationAnimator(aura::Window* root_window)
160 : root_window_(root_window),
wutao4a485532017-04-11 00:04:28161 screen_rotation_state_(IDLE),
wutao88733df2017-04-13 19:39:06162 rotation_request_id_(0),
wutao3f08f812017-03-25 03:06:33163 metrics_reporter_(
164 base::MakeUnique<ScreenRotationAnimationMetricsReporter>()),
wutao6ddafa32017-03-18 03:10:08165 disable_animation_timers_for_test_(false),
wutaob161bf22017-04-26 16:55:03166 has_switch_ash_disable_smooth_screen_rotation_(
wutao6d394112017-04-20 02:17:35167 base::CommandLine::ForCurrentProcess()->HasSwitch(
wutaob161bf22017-04-26 16:55:03168 switches::kAshDisableSmoothScreenRotation)),
wutao6ddafa32017-03-18 03:10:08169 weak_factory_(this) {}
170
wutao3f08f812017-03-25 03:06:33171ScreenRotationAnimator::~ScreenRotationAnimator() {
wutao6d394112017-04-20 02:17:35172 // To prevent a call to |AnimationEndedCallback()| from calling a method on
173 // the |animator_|.
wutao3f08f812017-03-25 03:06:33174 weak_factory_.InvalidateWeakPtrs();
175
176 // Explicitly reset the |old_layer_tree_owner_| and |metrics_reporter_| in
177 // order to make sure |metrics_reporter_| outlives the attached animation
178 // sequence.
179 old_layer_tree_owner_.reset();
180 metrics_reporter_.reset();
181}
wutao6ddafa32017-03-18 03:10:08182
wutao2c0ca182017-04-06 22:40:54183void ScreenRotationAnimator::StartRotationAnimation(
184 std::unique_ptr<ScreenRotationRequest> rotation_request) {
wutao6d394112017-04-20 02:17:35185 const display::Display::Rotation current_rotation =
wutaoc18f66c2017-06-02 18:11:01186 GetCurrentScreenRotation(rotation_request->display_id);
wutao6d394112017-04-20 02:17:35187 if (current_rotation == rotation_request->new_rotation) {
188 // We need to call |ProcessAnimationQueue()| to prepare for next rotation
189 // request.
wutao2c0ca182017-04-06 22:40:54190 ProcessAnimationQueue();
191 return;
192 }
193
wutao6d394112017-04-20 02:17:35194 rotation_request->old_rotation = current_rotation;
wutaob161bf22017-04-26 16:55:03195 if (has_switch_ash_disable_smooth_screen_rotation_) {
196 StartSlowAnimation(std::move(rotation_request));
197 } else {
wutao6d394112017-04-20 02:17:35198 std::unique_ptr<cc::CopyOutputRequest> copy_output_request =
199 cc::CopyOutputRequest::CreateRequest(
200 CreateAfterCopyCallbackBeforeRotation(std::move(rotation_request)));
201 RequestCopyScreenRotationContainerLayer(std::move(copy_output_request));
202 screen_rotation_state_ = COPY_REQUESTED;
wutao6d394112017-04-20 02:17:35203 }
204}
205
206void ScreenRotationAnimator::StartSlowAnimation(
207 std::unique_ptr<ScreenRotationRequest> rotation_request) {
208 CreateOldLayerTreeForSlowAnimation();
wutaoc18f66c2017-06-02 18:11:01209 SetRotation(rotation_request->display_id, rotation_request->old_rotation,
210 rotation_request->new_rotation, rotation_request->source);
wutao2c0ca182017-04-06 22:40:54211 AnimateRotation(std::move(rotation_request));
212}
213
wutao6d394112017-04-20 02:17:35214void ScreenRotationAnimator::SetRotation(
wutaoc18f66c2017-06-02 18:11:01215 int64_t display_id,
wutao6d394112017-04-20 02:17:35216 display::Display::Rotation old_rotation,
217 display::Display::Rotation new_rotation,
218 display::Display::RotationSource source) {
wutaoeb552052017-05-10 22:35:29219 // Allow compositor locks to extend timeout, so that screen rotation only
220 // takes output copy after contents are properlly resized, such as wallpaper
221 // and ARC apps.
222 ui::Compositor* compositor = root_window_->layer()->GetCompositor();
223 compositor->set_allow_locks_to_extend_timeout(true);
wutaoc18f66c2017-06-02 18:11:01224 Shell::Get()->display_manager()->SetDisplayRotation(display_id, new_rotation,
wutao6d394112017-04-20 02:17:35225 source);
wutaoeb552052017-05-10 22:35:29226 compositor->set_allow_locks_to_extend_timeout(false);
wutao6d394112017-04-20 02:17:35227 const display::Display display =
wutaoc18f66c2017-06-02 18:11:01228 Shell::Get()->display_manager()->GetDisplayForId(display_id);
wutao6d394112017-04-20 02:17:35229 old_layer_tree_owner_->root()->SetTransform(
230 CreateScreenRotationOldLayerTransformForDisplay(old_rotation,
231 new_rotation, display));
wutao2c0ca182017-04-06 22:40:54232}
233
wutao6d394112017-04-20 02:17:35234void ScreenRotationAnimator::RequestCopyScreenRotationContainerLayer(
235 std::unique_ptr<cc::CopyOutputRequest> copy_output_request) {
wutaoa0f3ea2a2017-06-20 03:26:31236 ui::Layer* screen_rotation_container_layer =
237 GetScreenRotationContainer(root_window_)->layer();
wutao6d394112017-04-20 02:17:35238 copy_output_request->set_area(
wutaoa0f3ea2a2017-06-20 03:26:31239 gfx::Rect(screen_rotation_container_layer->size()));
240 screen_rotation_container_layer->RequestCopyOfOutput(
wutao6d394112017-04-20 02:17:35241 std::move(copy_output_request));
242}
243
244ScreenRotationAnimator::CopyCallback
245ScreenRotationAnimator::CreateAfterCopyCallbackBeforeRotation(
246 std::unique_ptr<ScreenRotationRequest> rotation_request) {
247 return base::Bind(&ScreenRotationAnimator::
248 OnScreenRotationContainerLayerCopiedBeforeRotation,
249 weak_factory_.GetWeakPtr(),
250 base::Passed(&rotation_request));
251}
252
253ScreenRotationAnimator::CopyCallback
254ScreenRotationAnimator::CreateAfterCopyCallbackAfterRotation(
255 std::unique_ptr<ScreenRotationRequest> rotation_request) {
256 return base::Bind(&ScreenRotationAnimator::
257 OnScreenRotationContainerLayerCopiedAfterRotation,
258 weak_factory_.GetWeakPtr(),
259 base::Passed(&rotation_request));
260}
261
262void ScreenRotationAnimator::OnScreenRotationContainerLayerCopiedBeforeRotation(
263 std::unique_ptr<ScreenRotationRequest> rotation_request,
264 std::unique_ptr<cc::CopyOutputResult> result) {
265 if (IgnoreCopyResult(rotation_request->id, rotation_request_id_))
266 return;
wutaoc18f66c2017-06-02 18:11:01267 // Abort rotation and animation if the display was removed or the
268 // |root_window| was changed for |display_id|.
269 if (RootWindowChangedForDisplayId(root_window_,
270 rotation_request->display_id)) {
wutaob161bf22017-04-26 16:55:03271 ProcessAnimationQueue();
272 return;
273 }
274 // Abort animation and set the rotation to target rotation when the copy
275 // request has been canceled or failed. It would fail if, for examples: a) The
276 // layer is removed from the compositor and destroye before committing the
277 // request to the compositor. b) The compositor is shutdown.
278 if (result->IsEmpty()) {
279 Shell::Get()->display_manager()->SetDisplayRotation(
wutaoc18f66c2017-06-02 18:11:01280 rotation_request->display_id, rotation_request->new_rotation,
281 rotation_request->source);
wutao6d394112017-04-20 02:17:35282 ProcessAnimationQueue();
283 return;
284 }
285
286 old_layer_tree_owner_ = CopyLayerTree(std::move(result));
287 AddLayerAtTopOfWindowLayers(root_window_, old_layer_tree_owner_->root());
wutaoc18f66c2017-06-02 18:11:01288 SetRotation(rotation_request->display_id, rotation_request->old_rotation,
289 rotation_request->new_rotation, rotation_request->source);
wutao6d394112017-04-20 02:17:35290 std::unique_ptr<cc::CopyOutputRequest> copy_output_request =
291 cc::CopyOutputRequest::CreateRequest(
292 CreateAfterCopyCallbackAfterRotation(std::move(rotation_request)));
293 RequestCopyScreenRotationContainerLayer(std::move(copy_output_request));
294}
295
296void ScreenRotationAnimator::OnScreenRotationContainerLayerCopiedAfterRotation(
297 std::unique_ptr<ScreenRotationRequest> rotation_request,
298 std::unique_ptr<cc::CopyOutputResult> result) {
299 if (IgnoreCopyResult(rotation_request->id, rotation_request_id_))
300 return;
wutaob161bf22017-04-26 16:55:03301 // In the following cases, abort animation:
302 // 1) if the display was removed,
wutaoc18f66c2017-06-02 18:11:01303 // 2) if the |root_window| was changed for |display_id|,
304 // 3) the copy request has been canceled or failed. It would fail if,
wutaob161bf22017-04-26 16:55:03305 // for examples: a) The layer is removed from the compositor and destroye
306 // before committing the request to the compositor. b) The compositor is
307 // shutdown.
wutaoc18f66c2017-06-02 18:11:01308 if (RootWindowChangedForDisplayId(root_window_,
309 rotation_request->display_id) ||
310 result->IsEmpty()) {
wutao6d394112017-04-20 02:17:35311 ProcessAnimationQueue();
312 return;
313 }
314
315 new_layer_tree_owner_ = CopyLayerTree(std::move(result));
316 AddLayerBelowWindowLayer(root_window_, old_layer_tree_owner_->root(),
317 new_layer_tree_owner_->root());
318 AnimateRotation(std::move(rotation_request));
319}
320
321void ScreenRotationAnimator::CreateOldLayerTreeForSlowAnimation() {
322 old_layer_tree_owner_ = ::wm::RecreateLayers(root_window_);
wutao6d394112017-04-20 02:17:35323 AddLayerAtTopOfWindowLayers(root_window_, old_layer_tree_owner_->root());
324}
325
326std::unique_ptr<ui::LayerTreeOwner> ScreenRotationAnimator::CopyLayerTree(
wutao2c0ca182017-04-06 22:40:54327 std::unique_ptr<cc::CopyOutputResult> result) {
Fady Samuel2a725ce52017-07-11 22:30:00328 viz::TextureMailbox texture_mailbox;
wutao2c0ca182017-04-06 22:40:54329 std::unique_ptr<cc::SingleReleaseCallback> release_callback;
330 result->TakeTexture(&texture_mailbox, &release_callback);
331 DCHECK(texture_mailbox.IsTexture());
wutaoa0f3ea2a2017-06-20 03:26:31332 const gfx::Rect rect(
333 GetScreenRotationContainer(root_window_)->layer()->size());
wutao2c0ca182017-04-06 22:40:54334 std::unique_ptr<ui::Layer> copy_layer = base::MakeUnique<ui::Layer>();
335 copy_layer->SetBounds(rect);
336 copy_layer->SetTextureMailbox(texture_mailbox, std::move(release_callback),
337 rect.size());
wutao6d394112017-04-20 02:17:35338 return base::MakeUnique<ui::LayerTreeOwner>(std::move(copy_layer));
wutao2c0ca182017-04-06 22:40:54339}
340
wutao6ddafa32017-03-18 03:10:08341void ScreenRotationAnimator::AnimateRotation(
342 std::unique_ptr<ScreenRotationRequest> rotation_request) {
wutao4a485532017-04-11 00:04:28343 screen_rotation_state_ = ROTATING;
wutao6d394112017-04-20 02:17:35344 const int rotation_factor = GetRotationFactor(rotation_request->old_rotation,
345 rotation_request->new_rotation);
wutao6ddafa32017-03-18 03:10:08346 const int old_layer_initial_rotation_degrees = GetInitialDegrees(
wutao6d394112017-04-20 02:17:35347 rotation_request->old_rotation, rotation_request->new_rotation);
bruthigaff7d0f2015-09-01 17:46:55348 const base::TimeDelta duration =
349 base::TimeDelta::FromMilliseconds(kRotationDurationInMs);
bruthigaff7d0f2015-09-01 17:46:55350 const gfx::Tween::Type tween_type = gfx::Tween::FAST_OUT_LINEAR_IN;
wutao6d394112017-04-20 02:17:35351 const gfx::Rect rotated_screen_bounds = root_window_->GetTargetBounds();
bruthig37f9cad02015-03-12 22:28:50352 const gfx::Point pivot = gfx::Point(rotated_screen_bounds.width() / 2,
353 rotated_screen_bounds.height() / 2);
354
wutaoa0f3ea2a2017-06-20 03:26:31355 ui::Layer* screen_rotation_container_layer =
356 GetScreenRotationContainer(root_window_)->layer();
wutao6d394112017-04-20 02:17:35357 ui::Layer* new_root_layer;
wutaob161bf22017-04-26 16:55:03358 if (!new_layer_tree_owner_ ||
359 has_switch_ash_disable_smooth_screen_rotation_) {
wutaoa0f3ea2a2017-06-20 03:26:31360 new_root_layer = screen_rotation_container_layer;
wutaob161bf22017-04-26 16:55:03361 } else {
wutao6d394112017-04-20 02:17:35362 new_root_layer = new_layer_tree_owner_->root();
wutaoa0f3ea2a2017-06-20 03:26:31363 // Add a black mask layer on top of |screen_rotation_container_layer|.
wutaoc18f66c2017-06-02 18:11:01364 mask_layer_tree_owner_ = CreateMaskLayerTreeOwner(
wutaoa0f3ea2a2017-06-20 03:26:31365 gfx::Rect(screen_rotation_container_layer->size()));
wutao6d394112017-04-20 02:17:35366 AddLayerBelowWindowLayer(root_window_, new_root_layer,
wutaoc18f66c2017-06-02 18:11:01367 mask_layer_tree_owner_->root());
wutao6d394112017-04-20 02:17:35368 }
369
370 std::unique_ptr<ScreenRotationAnimation> new_layer_screen_rotation =
wutao33576082017-04-14 18:51:10371 base::MakeUnique<ScreenRotationAnimation>(
wutao6d394112017-04-20 02:17:35372 new_root_layer, kRotationDegrees * rotation_factor,
373 0 /* end_degrees */, new_root_layer->opacity(),
374 new_root_layer->opacity() /* target_opacity */, pivot, duration,
375 tween_type);
bruthig37f9cad02015-03-12 22:28:50376
wutao6d394112017-04-20 02:17:35377 ui::LayerAnimator* new_layer_animator = new_root_layer->GetAnimator();
378 new_layer_animator->set_preemption_strategy(
wutao33576082017-04-14 18:51:10379 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
wutao6d394112017-04-20 02:17:35380 std::unique_ptr<ui::LayerAnimationSequence> new_layer_animation_sequence =
wutao33576082017-04-14 18:51:10381 base::MakeUnique<ui::LayerAnimationSequence>(
wutao6d394112017-04-20 02:17:35382 std::move(new_layer_screen_rotation));
bruthig37f9cad02015-03-12 22:28:50383
wutao6d394112017-04-20 02:17:35384 ui::Layer* old_root_layer = old_layer_tree_owner_->root();
385 const gfx::Rect original_screen_bounds = old_root_layer->GetTargetBounds();
bruthig37f9cad02015-03-12 22:28:50386 // The old layer will also be transformed into the new orientation. We will
387 // translate it so that the old layer's center point aligns with the new
388 // orientation's center point and use that center point as the pivot for the
389 // rotation animation.
390 gfx::Transform translate_transform;
391 translate_transform.Translate(
392 (rotated_screen_bounds.width() - original_screen_bounds.width()) / 2,
393 (rotated_screen_bounds.height() - original_screen_bounds.height()) / 2);
wutao6ddafa32017-03-18 03:10:08394 old_root_layer->SetTransform(translate_transform);
bruthig37f9cad02015-03-12 22:28:50395
wutao33576082017-04-14 18:51:10396 std::unique_ptr<ScreenRotationAnimation> old_layer_screen_rotation =
ratsunnybd5087e2016-12-17 05:19:25397 base::MakeUnique<ScreenRotationAnimation>(
wutao6ddafa32017-03-18 03:10:08398 old_root_layer, old_layer_initial_rotation_degrees * rotation_factor,
bruthigaff7d0f2015-09-01 17:46:55399 (old_layer_initial_rotation_degrees - kRotationDegrees) *
400 rotation_factor,
wutao6ddafa32017-03-18 03:10:08401 old_root_layer->opacity(), 0.0f /* target_opacity */, pivot, duration,
402 tween_type);
bruthig37f9cad02015-03-12 22:28:50403
wutao33576082017-04-14 18:51:10404 ui::LayerAnimator* old_layer_animator = old_root_layer->GetAnimator();
405 old_layer_animator->set_preemption_strategy(
bruthig37f9cad02015-03-12 22:28:50406 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
wutao33576082017-04-14 18:51:10407 std::unique_ptr<ui::LayerAnimationSequence> old_layer_animation_sequence =
408 base::MakeUnique<ui::LayerAnimationSequence>(
409 std::move(old_layer_screen_rotation));
wutao6d394112017-04-20 02:17:35410
wutao6ddafa32017-03-18 03:10:08411 // In unit test, we can use ash::test::ScreenRotationAnimatorTestApi to
412 // control the animation.
wutao6d394112017-04-20 02:17:35413 if (disable_animation_timers_for_test_) {
414 if (new_layer_tree_owner_)
415 new_layer_animator->set_disable_timer_for_test(true);
wutao33576082017-04-14 18:51:10416 old_layer_animator->set_disable_timer_for_test(true);
wutao6d394112017-04-20 02:17:35417 }
wutao33576082017-04-14 18:51:10418 old_layer_animation_sequence->SetAnimationMetricsReporter(
419 metrics_reporter_.get());
wutao33576082017-04-14 18:51:10420
wutao6d394112017-04-20 02:17:35421 // Add an observer so that the cloned/copied layers can be cleaned up with the
422 // animation completes/aborts.
423 ui::CallbackLayerAnimationObserver* observer =
424 new ui::CallbackLayerAnimationObserver(
425 base::Bind(&AnimationEndedCallback, weak_factory_.GetWeakPtr()));
426 if (new_layer_tree_owner_)
427 new_layer_animator->AddObserver(observer);
428 new_layer_animator->StartAnimation(new_layer_animation_sequence.release());
429 old_layer_animator->AddObserver(observer);
430 old_layer_animator->StartAnimation(old_layer_animation_sequence.release());
431 observer->SetActive();
bruthigf57a7bba2015-04-24 21:19:31432}
433
oshimaf84b0da722016-04-27 19:47:19434void ScreenRotationAnimator::Rotate(display::Display::Rotation new_rotation,
435 display::Display::RotationSource source) {
wutao6d394112017-04-20 02:17:35436 // |rotation_request_id_| is used to skip stale requests. Before the layer
437 // CopyOutputResult callback called, there could have new rotation request.
438 // Increases |rotation_request_id_| for each new request and in the callback,
439 // we compare the |rotation_request.id| and |rotation_request_id_| to
440 // determine the stale status.
wutao88733df2017-04-13 19:39:06441 rotation_request_id_++;
wutaoc18f66c2017-06-02 18:11:01442 const int64_t display_id =
443 display::Screen::GetScreen()->GetDisplayNearestWindow(root_window_).id();
wutao6ddafa32017-03-18 03:10:08444 std::unique_ptr<ScreenRotationRequest> rotation_request =
wutaoc18f66c2017-06-02 18:11:01445 base::MakeUnique<ScreenRotationRequest>(rotation_request_id_, display_id,
wutao88733df2017-04-13 19:39:06446 new_rotation, source);
wutao4a485532017-04-11 00:04:28447 switch (screen_rotation_state_) {
448 case IDLE:
wutao88733df2017-04-13 19:39:06449 case COPY_REQUESTED:
wutao4a485532017-04-11 00:04:28450 StartRotationAnimation(std::move(rotation_request));
451 break;
452 case ROTATING:
453 last_pending_request_ = std::move(rotation_request);
454 // The pending request will be processed when the
wutao6d394112017-04-20 02:17:35455 // |AnimationEndedCallback()| should be called after |StopAnimating()|.
wutao4a485532017-04-11 00:04:28456 StopAnimating();
457 break;
wutao6ddafa32017-03-18 03:10:08458 }
459}
460
461void ScreenRotationAnimator::AddScreenRotationAnimatorObserver(
462 ScreenRotationAnimatorObserver* observer) {
463 screen_rotation_animator_observers_.AddObserver(observer);
464}
465
466void ScreenRotationAnimator::RemoveScreenRotationAnimatorObserver(
467 ScreenRotationAnimatorObserver* observer) {
468 screen_rotation_animator_observers_.RemoveObserver(observer);
469}
470
wutao6ddafa32017-03-18 03:10:08471void ScreenRotationAnimator::ProcessAnimationQueue() {
wutao4a485532017-04-11 00:04:28472 screen_rotation_state_ = IDLE;
wutao6ddafa32017-03-18 03:10:08473 old_layer_tree_owner_.reset();
wutao6d394112017-04-20 02:17:35474 new_layer_tree_owner_.reset();
wutaoc18f66c2017-06-02 18:11:01475 mask_layer_tree_owner_.reset();
476 if (last_pending_request_ &&
477 !RootWindowChangedForDisplayId(root_window_,
478 last_pending_request_->display_id)) {
wutao6d394112017-04-20 02:17:35479 StartRotationAnimation(std::move(last_pending_request_));
wutao6ddafa32017-03-18 03:10:08480 return;
481 }
482
wutao6d394112017-04-20 02:17:35483 // This is only used in test to notify animator observer.
wutao6ddafa32017-03-18 03:10:08484 for (auto& observer : screen_rotation_animator_observers_)
485 observer.OnScreenRotationAnimationFinished(this);
486}
487
wutao6ddafa32017-03-18 03:10:08488void ScreenRotationAnimator::StopAnimating() {
wutao6d394112017-04-20 02:17:35489 // |old_layer_tree_owner_| new_layer_tree_owner_| could be nullptr if another
490 // the rotation request comes before the copy request finished.
wutao33576082017-04-14 18:51:10491 if (old_layer_tree_owner_)
492 old_layer_tree_owner_->root()->GetAnimator()->StopAnimating();
wutao6d394112017-04-20 02:17:35493 if (new_layer_tree_owner_)
494 new_layer_tree_owner_->root()->GetAnimator()->StopAnimating();
wutaoc18f66c2017-06-02 18:11:01495 mask_layer_tree_owner_.reset();
bruthig37f9cad02015-03-12 22:28:50496}
497
498} // namespace ash