1 // Copyright 2020 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 "chromecast/ui/display_settings_manager_impl.h"
6
7 #include "base/logging.h"
8 #include "chromecast/graphics/cast_window_manager.h"
9 #include "chromecast/ui/display_settings/brightness_animation.h"
10 #include "chromecast/ui/display_settings/color_temperature_animation.h"
11 #include "ui/display/types/gamma_ramp_rgb_entry.h"
12
13 #if defined(USE_AURA)
14 #include "chromecast/browser/cast_browser_process.h"
15 #include "chromecast/browser/cast_display_configurator.h"
16 #include "chromecast/ui/display_settings/gamma_configurator.h"
17 #endif // defined(USE_AURA)
18
19 namespace chromecast {
20
21 namespace {
22
23 constexpr base::TimeDelta kAnimationDuration = base::TimeDelta::FromSeconds(2);
24 constexpr base::TimeDelta kScreenOnOffDuration =
25 base::TimeDelta::FromMilliseconds(200);
26
27 #if defined(USE_AURA)
28 // These delays are needed to ensure there are no visible artifacts due to the
29 // backlight turning on prior to the LCD fully initializing or vice-versa.
30 // TODO(b/161140301): Make this configurable for different products
31 // TODO(b/161268188): Remove these if the delays can be handled by the kernel
32 constexpr base::TimeDelta kDisplayPowerOnDelay =
33 base::TimeDelta::FromMilliseconds(35);
34 constexpr base::TimeDelta kDisplayPowerOffDelay =
35 base::TimeDelta::FromMilliseconds(85);
36 #endif // defined(USE_AURA)
37
38 const float kMinApiBrightness = 0.0f;
39 const float kMaxApiBrightness = 1.0f;
40 const float kDefaultApiBrightness = kMaxApiBrightness;
41
42 } // namespace
43
DisplaySettingsManagerImpl(CastWindowManager * window_manager,const DisplaySettingsManager::ColorTemperatureConfig & color_temperature_config)44 DisplaySettingsManagerImpl::DisplaySettingsManagerImpl(
45 CastWindowManager* window_manager,
46 const DisplaySettingsManager::ColorTemperatureConfig&
47 color_temperature_config)
48 : window_manager_(window_manager),
49 #if defined(USE_AURA)
50 display_configurator_(
51 shell::CastBrowserProcess::GetInstance()->display_configurator()),
52 gamma_configurator_(
53 std::make_unique<GammaConfigurator>(window_manager_,
54 display_configurator_)),
55 #else
56 display_configurator_(nullptr),
57 #endif // defined(USE_AURA)
58 brightness_(-1.0f),
59 screen_on_(true),
60 #if defined(USE_AURA)
61 screen_power_on_(true),
62 allow_screen_power_off_(false),
63 #endif // defined(USE_AURA)
64 color_temperature_animation_(std::make_unique<ColorTemperatureAnimation>(
65 window_manager_,
66 display_configurator_,
67 color_temperature_config)),
68 weak_factory_(this) {
69 DCHECK(window_manager_);
70 #if defined(USE_AURA)
71 DCHECK(display_configurator_);
72 #endif // defined(USE_AURA)
73 }
74
75 DisplaySettingsManagerImpl::~DisplaySettingsManagerImpl() = default;
76
SetDelegate(DisplaySettingsManager::Delegate * delegate)77 void DisplaySettingsManagerImpl::SetDelegate(
78 DisplaySettingsManager::Delegate* delegate) {
79 brightness_animation_ = std::make_unique<BrightnessAnimation>(delegate);
80 }
81
ResetDelegate()82 void DisplaySettingsManagerImpl::ResetDelegate() {
83 // Skip a brightess animation to its last step and stop
84 // This is important for the final brightness to be cached on reboot
85 brightness_animation_.reset();
86 }
87
SetGammaCalibration(const std::vector<display::GammaRampRGBEntry> & gamma)88 void DisplaySettingsManagerImpl::SetGammaCalibration(
89 const std::vector<display::GammaRampRGBEntry>& gamma) {
90 #if defined(USE_AURA)
91 gamma_configurator_->OnCalibratedGammaLoaded(gamma);
92 #endif // defined(USE_AURA)
93 }
94
NotifyBrightnessChanged(float new_brightness,float old_brightness)95 void DisplaySettingsManagerImpl::NotifyBrightnessChanged(float new_brightness,
96 float old_brightness) {
97 for (auto& observer : observers_)
98 observer->OnDisplayBrightnessChanged(new_brightness);
99 }
100
SetColorInversion(bool enable)101 void DisplaySettingsManagerImpl::SetColorInversion(bool enable) {
102 #if defined(USE_AURA)
103 gamma_configurator_->SetColorInversion(enable);
104 #endif // defined(USE_AURA)
105 window_manager_->NotifyColorInversionEnabled(enable);
106 }
107
AddReceiver(mojo::PendingReceiver<mojom::DisplaySettings> receiver)108 void DisplaySettingsManagerImpl::AddReceiver(
109 mojo::PendingReceiver<mojom::DisplaySettings> receiver) {
110 receivers_.Add(this, std::move(receiver));
111 }
112
SetColorTemperature(float temperature)113 void DisplaySettingsManagerImpl::SetColorTemperature(float temperature) {
114 DVLOG(4) << "Setting color temperature to " << temperature << " Kelvin.";
115 color_temperature_animation_->AnimateToNewValue(temperature,
116 kAnimationDuration);
117 }
118
SetColorTemperatureSmooth(float temperature,base::TimeDelta duration)119 void DisplaySettingsManagerImpl::SetColorTemperatureSmooth(
120 float temperature,
121 base::TimeDelta duration) {
122 DVLOG(4) << "Setting color temperature to " << temperature
123 << " Kelvin. Duration: " << duration;
124 color_temperature_animation_->AnimateToNewValue(temperature, duration);
125 }
126
ResetColorTemperature()127 void DisplaySettingsManagerImpl::ResetColorTemperature() {
128 color_temperature_animation_->AnimateToNeutral(kAnimationDuration);
129 }
130
SetBrightness(float brightness)131 void DisplaySettingsManagerImpl::SetBrightness(float brightness) {
132 SetBrightnessSmooth(brightness, base::TimeDelta::FromSeconds(0));
133 }
134
SetBrightnessSmooth(float brightness,base::TimeDelta duration)135 void DisplaySettingsManagerImpl::SetBrightnessSmooth(float brightness,
136 base::TimeDelta duration) {
137 if (brightness < kMinApiBrightness) {
138 LOG(ERROR) << "brightness " << brightness
139 << " is less than minimum brightness " << kMinApiBrightness
140 << ".";
141 return;
142 }
143
144 if (brightness > kMaxApiBrightness) {
145 LOG(ERROR) << "brightness " << brightness
146 << " is greater than maximum brightness " << kMaxApiBrightness
147 << ".";
148 return;
149 }
150
151 brightness_ = brightness;
152
153 // If the screen is off, keep the new brightness but don't apply it
154 if (!screen_on_) {
155 return;
156 }
157
158 UpdateBrightness(duration);
159 }
160
ResetBrightness()161 void DisplaySettingsManagerImpl::ResetBrightness() {
162 SetBrightness(kDefaultApiBrightness);
163 }
164
165 #if defined(USE_AURA)
OnDisplayOn(const base::flat_map<int64_t,bool> & statuses)166 void DisplaySettingsManagerImpl::OnDisplayOn(
167 const base::flat_map<int64_t, bool>& statuses) {
168 for (const auto& status : statuses) {
169 bool display_success = status.second;
170 if (!display_success) {
171 // Fatal since the user has no other way of turning the screen on if this
172 // failed.
173 LOG(FATAL) << "Failed to enable screen";
174 return;
175 }
176 }
177 screen_power_on_ = true;
178 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
179 FROM_HERE,
180 base::BindOnce(&DisplaySettingsManagerImpl::OnDisplayOnTimeoutCompleted,
181 weak_factory_.GetWeakPtr()),
182 kDisplayPowerOnDelay);
183 }
184
OnDisplayOnTimeoutCompleted()185 void DisplaySettingsManagerImpl::OnDisplayOnTimeoutCompleted() {
186 UpdateBrightness(kScreenOnOffDuration);
187 window_manager_->SetTouchInputDisabled(false /* since screen_on = true */);
188 }
189
OnDisplayOffTimeoutCompleted()190 void DisplaySettingsManagerImpl::OnDisplayOffTimeoutCompleted() {
191 display_configurator_->DisableDisplay(
192 base::BindOnce([](const base::flat_map<int64_t, bool>& statuses) {
193 for (const auto& status : statuses) {
194 bool display_success = status.second;
195 LOG_IF(FATAL, !display_success) << "Failed to disable display";
196 }
197 }));
198 screen_power_on_ = false;
199 }
200
SetScreenOn(bool screen_on)201 void DisplaySettingsManagerImpl::SetScreenOn(bool screen_on) {
202 // Allow this to run if screen_on == screen_on_ == false IF
203 // previously, the screen was turned off without powering off the screen
204 // and we want to power it off this time
205 if (screen_on == screen_on_ &&
206 !(!screen_on && allow_screen_power_off_ && screen_power_on_)) {
207 return;
208 }
209
210 LOG(INFO) << "Setting screen on to " << screen_on;
211 screen_on_ = screen_on;
212
213 // TODO(b/161268188): This can be simplified and the delays removed
214 // if backlight timing is handled by the kernel
215 if (screen_on && !screen_power_on_) {
216 display_configurator_->EnableDisplay(base::BindOnce(
217 &DisplaySettingsManagerImpl::OnDisplayOn, weak_factory_.GetWeakPtr()));
218 } else {
219 UpdateBrightness(kScreenOnOffDuration);
220 window_manager_->SetTouchInputDisabled(!screen_on_);
221 if (!screen_on && allow_screen_power_off_) {
222 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
223 FROM_HERE,
224 base::BindOnce(
225 &DisplaySettingsManagerImpl::OnDisplayOffTimeoutCompleted,
226 weak_factory_.GetWeakPtr()),
227 kDisplayPowerOffDelay + kScreenOnOffDuration);
228 }
229 }
230 }
231
SetAllowScreenPowerOff(bool allow_power_off)232 void DisplaySettingsManagerImpl::SetAllowScreenPowerOff(bool allow_power_off) {
233 allow_screen_power_off_ = allow_power_off;
234 }
235 #else
SetScreenOn(bool screen_on)236 void DisplaySettingsManagerImpl::SetScreenOn(bool screen_on) {
237 if (screen_on == screen_on_) {
238 return;
239 }
240
241 LOG(INFO) << "Setting screen on to " << screen_on;
242 screen_on_ = screen_on;
243
244 UpdateBrightness(kScreenOnOffDuration);
245 window_manager_->SetTouchInputDisabled(!screen_on_);
246 }
SetAllowScreenPowerOff(bool allow_power_off)247 void DisplaySettingsManagerImpl::SetAllowScreenPowerOff(bool allow_power_off) {}
248 #endif
249
AddDisplaySettingsObserver(mojo::PendingRemote<mojom::DisplaySettingsObserver> observer)250 void DisplaySettingsManagerImpl::AddDisplaySettingsObserver(
251 mojo::PendingRemote<mojom::DisplaySettingsObserver> observer) {
252 mojo::Remote<mojom::DisplaySettingsObserver> observer_remote(
253 std::move(observer));
254 observers_.Add(std::move(observer_remote));
255 }
256
UpdateBrightness(base::TimeDelta duration)257 void DisplaySettingsManagerImpl::UpdateBrightness(base::TimeDelta duration) {
258 float brightness = screen_on_ ? brightness_ : 0;
259
260 if (brightness_animation_)
261 brightness_animation_->AnimateToNewValue(brightness, duration);
262 }
263
264 } // namespace chromecast
265