blob: ec6f43ea89ec036646a3e064fdc381326ddf7873 [file] [log] [blame]
// Copyright 2016 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 "ash/display/display_configuration_controller.h"
#include "ash/display/display_animator.h"
#include "ash/display/display_util.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/root_window_controller.h"
#include "ash/rotator/screen_rotation_animator.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/bind.h"
#include "base/time/time.h"
#include "chromeos/system/devicemode.h"
#include "ui/base/class_property.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/display/display_layout.h"
#include "ui/display/manager/display_manager.h"
DEFINE_UI_CLASS_PROPERTY_TYPE(ash::ScreenRotationAnimator*);
namespace ash {
namespace {
// Specifies how long the display change should have been disabled
// after each display change operations.
// |kCycleDisplayThrottleTimeoutMs| is set to be longer to avoid
// changing the settings while the system is still configurating
// displays. It will be overriden by |kAfterDisplayChangeThrottleTimeoutMs|
// when the display change happens, so the actual timeout is much shorter.
const int64_t kAfterDisplayChangeThrottleTimeoutMs = 500;
const int64_t kCycleDisplayThrottleTimeoutMs = 4000;
const int64_t kSetPrimaryDisplayThrottleTimeoutMs = 500;
// A property key to store the ScreenRotationAnimator of the window; Used for
// screen rotation.
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ash::ScreenRotationAnimator,
kScreenRotationAnimatorKey,
nullptr);
bool g_disable_animator_for_test = false;
display::DisplayPositionInUnifiedMatrix GetUnifiedModeShelfCellPosition() {
const ShelfAlignment alignment =
Shell::GetPrimaryRootWindowController()->shelf()->alignment();
switch (alignment) {
case SHELF_ALIGNMENT_BOTTOM:
case SHELF_ALIGNMENT_BOTTOM_LOCKED:
return display::DisplayPositionInUnifiedMatrix::kBottomLeft;
case SHELF_ALIGNMENT_LEFT:
return display::DisplayPositionInUnifiedMatrix::kTopLeft;
case SHELF_ALIGNMENT_RIGHT:
return display::DisplayPositionInUnifiedMatrix::kTopRight;
}
NOTREACHED();
return display::DisplayPositionInUnifiedMatrix::kBottomLeft;
}
} // namespace
class DisplayConfigurationController::DisplayChangeLimiter {
public:
DisplayChangeLimiter() : throttle_timeout_(base::Time::Now()) {}
void SetThrottleTimeout(int64_t throttle_ms) {
throttle_timeout_ =
base::Time::Now() + base::TimeDelta::FromMilliseconds(throttle_ms);
}
bool IsThrottled() const { return base::Time::Now() < throttle_timeout_; }
private:
base::Time throttle_timeout_;
DISALLOW_COPY_AND_ASSIGN(DisplayChangeLimiter);
};
// static
void DisplayConfigurationController::DisableAnimatorForTest() {
g_disable_animator_for_test = true;
}
DisplayConfigurationController::DisplayConfigurationController(
display::DisplayManager* display_manager,
WindowTreeHostManager* window_tree_host_manager)
: display_manager_(display_manager),
window_tree_host_manager_(window_tree_host_manager),
weak_ptr_factory_(this) {
window_tree_host_manager_->AddObserver(this);
if (chromeos::IsRunningAsSystemCompositor())
limiter_.reset(new DisplayChangeLimiter);
if (!g_disable_animator_for_test)
display_animator_.reset(new DisplayAnimator());
}
DisplayConfigurationController::~DisplayConfigurationController() {
window_tree_host_manager_->RemoveObserver(this);
}
void DisplayConfigurationController::SetDisplayLayout(
std::unique_ptr<display::DisplayLayout> layout) {
if (display_animator_) {
display_animator_->StartFadeOutAnimation(
base::Bind(&DisplayConfigurationController::SetDisplayLayoutImpl,
weak_ptr_factory_.GetWeakPtr(), base::Passed(&layout)));
} else {
SetDisplayLayoutImpl(std::move(layout));
}
}
void DisplayConfigurationController::SetUnifiedDesktopLayoutMatrix(
const display::UnifiedDesktopLayoutMatrix& matrix) {
DCHECK(display_manager_->IsInUnifiedMode());
if (display_animator_) {
display_animator_->StartFadeOutAnimation(base::Bind(
&DisplayConfigurationController::SetUnifiedDesktopLayoutMatrixImpl,
weak_ptr_factory_.GetWeakPtr(), matrix));
} else {
SetUnifiedDesktopLayoutMatrixImpl(matrix);
}
}
void DisplayConfigurationController::SetMirrorMode(bool mirror, bool throttle) {
if (display_manager_->num_connected_displays() <= 1 ||
display_manager_->IsInMirrorMode() == mirror ||
(throttle && IsLimited())) {
return;
}
SetThrottleTimeout(kCycleDisplayThrottleTimeoutMs);
if (display_animator_) {
display_animator_->StartFadeOutAnimation(
base::Bind(&DisplayConfigurationController::SetMirrorModeImpl,
weak_ptr_factory_.GetWeakPtr(), mirror));
} else {
SetMirrorModeImpl(mirror);
}
}
void DisplayConfigurationController::SetDisplayRotation(
int64_t display_id,
display::Display::Rotation rotation,
display::Display::RotationSource source,
DisplayConfigurationController::RotationAnimation mode) {
if (display_manager_->IsDisplayIdValid(display_id)) {
if (GetTargetRotation(display_id) == rotation)
return;
if (display_animator_) {
ScreenRotationAnimator* screen_rotation_animator =
GetScreenRotationAnimatorForDisplay(display_id);
screen_rotation_animator->Rotate(rotation, source, mode);
return;
}
}
// Invalid |display_id| or animator is disabled; call
// DisplayManager::SetDisplayRotation directly.
display_manager_->SetDisplayRotation(display_id, rotation, source);
}
display::Display::Rotation DisplayConfigurationController::GetTargetRotation(
int64_t display_id) {
if (!display_manager_->IsDisplayIdValid(display_id))
return display::Display::ROTATE_0;
ScreenRotationAnimator* animator =
GetScreenRotationAnimatorForDisplay(display_id);
if (animator->IsRotating())
return animator->GetTargetRotation();
return display_manager_->GetDisplayInfo(display_id).GetActiveRotation();
}
void DisplayConfigurationController::SetPrimaryDisplayId(int64_t display_id,
bool throttle) {
if (display_manager_->GetNumDisplays() <= 1 || (IsLimited() && throttle))
return;
SetThrottleTimeout(kSetPrimaryDisplayThrottleTimeoutMs);
if (display_animator_) {
display_animator_->StartFadeOutAnimation(
base::Bind(&DisplayConfigurationController::SetPrimaryDisplayIdImpl,
weak_ptr_factory_.GetWeakPtr(), display_id));
} else {
SetPrimaryDisplayIdImpl(display_id);
}
}
display::Display
DisplayConfigurationController::GetPrimaryMirroringDisplayForUnifiedDesktop()
const {
DCHECK(display_manager_->IsInUnifiedMode());
return display_manager_->GetMirroringDisplayForUnifiedDesktop(
GetUnifiedModeShelfCellPosition());
}
void DisplayConfigurationController::OnDisplayConfigurationChanged() {
// TODO(oshima): Stop all animations.
SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
}
// Protected
void DisplayConfigurationController::SetAnimatorForTest(bool enable) {
if (display_animator_ && !enable)
display_animator_.reset();
else if (!display_animator_ && enable)
display_animator_.reset(new DisplayAnimator());
}
void DisplayConfigurationController::SetScreenRotationAnimatorForTest(
int64_t display_id,
std::unique_ptr<ScreenRotationAnimator> animator) {
aura::Window* root_window = Shell::GetRootWindowForDisplayId(display_id);
root_window->SetProperty(kScreenRotationAnimatorKey, animator.release());
}
// Private
void DisplayConfigurationController::SetThrottleTimeout(int64_t throttle_ms) {
if (limiter_)
limiter_->SetThrottleTimeout(throttle_ms);
}
bool DisplayConfigurationController::IsLimited() {
return limiter_ && limiter_->IsThrottled();
}
void DisplayConfigurationController::SetDisplayLayoutImpl(
std::unique_ptr<display::DisplayLayout> layout) {
display_manager_->SetLayoutForCurrentDisplays(std::move(layout));
if (display_animator_)
display_animator_->StartFadeInAnimation();
}
void DisplayConfigurationController::SetMirrorModeImpl(bool mirror) {
display_manager_->SetMirrorMode(
mirror ? display::MirrorMode::kNormal : display::MirrorMode::kOff,
base::nullopt);
if (display_animator_)
display_animator_->StartFadeInAnimation();
}
void DisplayConfigurationController::SetPrimaryDisplayIdImpl(
int64_t display_id) {
window_tree_host_manager_->SetPrimaryDisplayId(display_id);
if (display_animator_)
display_animator_->StartFadeInAnimation();
}
void DisplayConfigurationController::SetUnifiedDesktopLayoutMatrixImpl(
const display::UnifiedDesktopLayoutMatrix& matrix) {
display_manager_->SetUnifiedDesktopMatrix(matrix);
if (display_animator_)
display_animator_->StartFadeInAnimation();
}
ScreenRotationAnimator*
DisplayConfigurationController::GetScreenRotationAnimatorForDisplay(
int64_t display_id) {
aura::Window* root_window = Shell::GetRootWindowForDisplayId(display_id);
ScreenRotationAnimator* animator =
root_window->GetProperty(kScreenRotationAnimatorKey);
if (!animator) {
animator = new ScreenRotationAnimator(root_window);
root_window->SetProperty(kScreenRotationAnimatorKey, animator);
}
return animator;
}
} // namespace ash