blob: ccbc7ccc5a1c6db5b42e1df0736fdfafe4118881 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <memory>
#include "ash/ash_export.h"
#include "ash/display/display_configuration_controller.h"
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "ui/display/display.h"
namespace aura {
class Window;
} // namesapce aura
namespace viz {
class CopyOutputRequest;
class CopyOutputResult;
} // namespace cc
namespace ui {
class AnimationMetricsReporter;
class LayerTreeOwner;
class ScopedAnimationDurationScaleMode;
} // namespace ui
namespace ash {
class ScreenRotationAnimatorObserver;
// Utility to perform a screen rotation with an animation.
class ASH_EXPORT ScreenRotationAnimator {
static ScreenRotationAnimator* GetForRootWindow(aura::Window* root_window);
explicit ScreenRotationAnimator(aura::Window* root_window);
virtual ~ScreenRotationAnimator();
// Rotates the display::Display specified by |display_id| of the |root_window|
// to the |new_rotation| orientation, for the given |source|. The rotation
// will also become active. |screen_rotation_animator_observer_| will be
// notified when rotation is finished and there is no more pending rotation
// request. Otherwise, any ongoing animation will be stopped and progressed to
// the target position, followed by a new |Rotate()| call with the pending
// rotation request.
void Rotate(display::Display::Rotation new_rotation,
display::Display::RotationSource source,
DisplayConfigurationController::RotationAnimation mode);
void AddObserver(ScreenRotationAnimatorObserver* observer);
void RemoveObserver(ScreenRotationAnimatorObserver* observer);
// When screen rotation animation is ended or aborted, calls |Rotate()| with
// the pending rotation request if the request queue is not empty. Otherwise
// notifies |screen_rotation_animator_observer_|.
void ProcessAnimationQueue();
// True if the screen is in rotating state (not IDLE).
bool IsRotating() const;
// Returns the target (new) rotation. This will return the last requested
// orientation if |IsRotating()| is false.
display::Display::Rotation GetTargetRotation() const;
static void SetScreenRotationAnimatorForTest(
aura::Window* root_window,
std::unique_ptr<ScreenRotationAnimator> animator);
using CopyCallback =
base::OnceCallback<void(std::unique_ptr<viz::CopyOutputResult> result)>;
struct ScreenRotationRequest {
int64_t id,
int64_t display_id,
display::Display::Rotation to_rotation,
display::Display::RotationSource from_source,
DisplayConfigurationController::RotationAnimation mode)
: id(id),
mode(mode) {}
int64_t id;
int64_t display_id;
display::Display::Rotation old_rotation;
display::Display::Rotation new_rotation;
display::Display::RotationSource source;
DisplayConfigurationController::RotationAnimation mode;
// This function can be overridden in unit test to test removing external
// display.
virtual CopyCallback CreateAfterCopyCallbackBeforeRotation(
std::unique_ptr<ScreenRotationRequest> rotation_request);
// This function can be overridden in unit test to test removing external
// display.
virtual CopyCallback CreateAfterCopyCallbackAfterRotation(
std::unique_ptr<ScreenRotationRequest> rotation_request);
friend class ScreenRotationAnimatorTestApi;
void StartRotationAnimation(
std::unique_ptr<ScreenRotationRequest> rotation_request);
// The code path to start "slow animation". The difference between the "slow"
// and "smooth" animation, is that "slow animation" will recreate all the
// layers before rotation and use the recreated layers and rotated layers for
// cross-fading animation. This is slow by adding multiple layer animation
// elements. The "smooth animation" copies the layer output before and after
// rotation, and use them for cross-fading animation. The output copy layer
// flatten the layer hierarchy and makes the animation smooth.
void StartSlowAnimation(
std::unique_ptr<ScreenRotationRequest> rotation_request);
// A wrapper to call |display_manager| to set screen rotation and rotate the
// |old_layer_tree| to the |old_rotation|.
void SetRotation(int64_t display_id,
display::Display::Rotation old_rotation,
display::Display::Rotation new_rotation,
display::Display::RotationSource source);
// This is an asynchronous call to request copy output of root layer.
void RequestCopyScreenRotationContainerLayer(
std::unique_ptr<viz::CopyOutputRequest> copy_output_request);
// The callback in |RequestCopyScreenRotationContainerLayer()| before screen
// rotation.
void OnScreenRotationContainerLayerCopiedBeforeRotation(
std::unique_ptr<ScreenRotationRequest> rotation_request,
std::unique_ptr<viz::CopyOutputResult> result);
// The callback in |RequestCopyScreenRotationContainerLayer()| after screen
// rotation.
void OnScreenRotationContainerLayerCopiedAfterRotation(
std::unique_ptr<ScreenRotationRequest> rotation_request,
std::unique_ptr<viz::CopyOutputResult> result);
// Recreates all |root_window| layers and their layer tree owner.
void CreateOldLayerTreeForSlowAnimation();
// Creates a new layer and its layer tree owner from |CopyOutputResult|.
std::unique_ptr<ui::LayerTreeOwner> CopyLayerTree(
std::unique_ptr<viz::CopyOutputResult> result);
// Note: Only call this function when the |old_layer_tree_owner_| is set up
// properly.
// Sets the screen orientation to |new_rotation| and animate the change. The
// animation will rotate the initial orientation's layer towards the new
// orientation through |rotation_degrees| while fading out, and the new
// orientation's layer will be rotated in to the |new_orientation| through
// |rotation_degrees| arc.
void AnimateRotation(std::unique_ptr<ScreenRotationRequest> rotation_request);
void NotifyAnimationFinished(bool canceled);
void set_disable_animation_timers_for_test(bool disable_timers) {
disable_animation_timers_for_test_ = disable_timers;
void StopAnimating();
aura::Window* root_window_;
// For current slow rotation animation, there are two states |ROTATING| and
// |IDLE|. For the smooth rotation animation, we need to send copy request
// and get copy result before animating.
enum ScreenRotationState {
ScreenRotationState screen_rotation_state_;
// Rotation request id, used to ignore copy request callback if we decide to
// cancel the previous rotation request.
int64_t rotation_request_id_;
std::unique_ptr<ui::AnimationMetricsReporter> metrics_reporter_;
// Only set in unittest to disable animation timers.
bool disable_animation_timers_for_test_;
std::unique_ptr<ui::LayerTreeOwner> old_layer_tree_owner_;
std::unique_ptr<ui::LayerTreeOwner> new_layer_tree_owner_;
std::unique_ptr<ui::LayerTreeOwner> mask_layer_tree_owner_;
std::unique_ptr<ScreenRotationRequest> last_pending_request_;
base::Optional<ScreenRotationRequest> current_async_rotation_request_;
display::Display::Rotation target_rotation_ = display::Display::ROTATE_0;
std::unique_ptr<ui::ScopedAnimationDurationScaleMode> animation_scale_mode_;
base::WeakPtrFactory<ScreenRotationAnimator> weak_factory_;
} // namespace ash