| // Copyright (c) 2012 The Chromium OS 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 "power_manager/external_backlight_controller.h" |
| |
| #include <dbus/dbus-glib-lowlevel.h> |
| |
| #include <algorithm> |
| #include <cmath> |
| |
| #include "chromeos/dbus/dbus.h" |
| #include "chromeos/dbus/service_constants.h" |
| #include "power_manager/backlight_interface.h" |
| #include "power_manager/monitor_reconfigure.h" |
| |
| namespace { |
| |
| // Amount that the brightness should be changed (across a [0.0, 100.0] range) |
| // when the brightness-increase or -decrease keys are pressed. |
| double kBrightnessAdjustmentPercent = 10.0; |
| |
| } // namespace |
| |
| namespace power_manager { |
| |
| ExternalBacklightController::ExternalBacklightController( |
| BacklightInterface* backlight) |
| : backlight_(backlight), |
| monitor_reconfigure_(NULL), |
| observer_(NULL), |
| power_state_(BACKLIGHT_UNINITIALIZED), |
| max_level_(0), |
| currently_dimming_(false), |
| currently_off_(false), |
| num_user_adjustments_(0), |
| disable_dbus_for_testing_(false) { |
| backlight_->set_observer(this); |
| } |
| |
| ExternalBacklightController::~ExternalBacklightController() { |
| backlight_->set_observer(NULL); |
| } |
| |
| bool ExternalBacklightController::Init() { |
| // If we get restarted while Chrome is running, make sure that it doesn't get |
| // wedged in a dimmed state. |
| if (!disable_dbus_for_testing_) { |
| SendSoftwareDimmingSignal(currently_dimming_ ? |
| kSoftwareScreenDimmingIdle : |
| kSoftwareScreenDimmingNone); |
| } |
| |
| if (!backlight_->GetMaxBrightnessLevel(&max_level_)) { |
| LOG(ERROR) << "Unable to query maximum brightness level"; |
| max_level_ = 0; |
| return false; |
| } |
| LOG(INFO) << "Initialized external backlight controller: " |
| << "max_level=" << max_level_; |
| return true; |
| } |
| |
| void ExternalBacklightController::SetAmbientLightSensor( |
| AmbientLightSensor* sensor) { |
| // Desktop systems aren't expected to have a light sensor. |
| NOTIMPLEMENTED(); |
| } |
| |
| void ExternalBacklightController::SetMonitorReconfigure( |
| MonitorReconfigure* monitor_reconfigure) { |
| monitor_reconfigure_ = monitor_reconfigure; |
| } |
| |
| void ExternalBacklightController::SetObserver( |
| BacklightControllerObserver* observer) { |
| observer_ = observer; |
| } |
| |
| double ExternalBacklightController::GetTargetBrightnessPercent() { |
| // Just query and return the current level. The external display could've |
| // been set to a different level without us hearing about it. |
| double current_percent = 0.0; |
| if (!GetCurrentBrightnessPercent(¤t_percent)) |
| return 100.0; |
| |
| return current_percent; |
| } |
| |
| bool ExternalBacklightController::GetCurrentBrightnessPercent(double* percent) { |
| int64 current_level = 0; |
| if (!backlight_->GetCurrentBrightnessLevel(¤t_level)) |
| return false; |
| |
| *percent = LevelToPercent(current_level); |
| return true; |
| } |
| |
| bool ExternalBacklightController::SetCurrentBrightnessPercent( |
| double percent, |
| BrightnessChangeCause cause, |
| TransitionStyle style) { |
| if (max_level_ <= 0) |
| return false; |
| // Always perform instant transitions; there's no guarantee about how quickly |
| // an external display will respond to our requests. |
| if (!backlight_->SetBrightnessLevel(PercentToLevel(percent))) |
| return false; |
| if (cause == BRIGHTNESS_CHANGE_USER_INITIATED) |
| num_user_adjustments_++; |
| if (observer_) |
| observer_->OnScreenBrightnessChanged(GetTargetBrightnessPercent(), cause); |
| return true; |
| } |
| |
| bool ExternalBacklightController::IncreaseBrightness( |
| BrightnessChangeCause cause) { |
| return AdjustBrightnessByOffset(kBrightnessAdjustmentPercent, cause); |
| } |
| |
| bool ExternalBacklightController::DecreaseBrightness( |
| bool allow_off, |
| BrightnessChangeCause cause) { |
| return AdjustBrightnessByOffset(-kBrightnessAdjustmentPercent, cause); |
| } |
| |
| bool ExternalBacklightController::SetPowerState(PowerState state) { |
| DCHECK(state != BACKLIGHT_UNINITIALIZED); |
| power_state_ = state; |
| |
| bool should_dim = state != BACKLIGHT_ACTIVE; |
| if (should_dim != currently_dimming_) { |
| if (!disable_dbus_for_testing_) { |
| SendSoftwareDimmingSignal(should_dim ? |
| kSoftwareScreenDimmingIdle : |
| kSoftwareScreenDimmingNone); |
| } |
| currently_dimming_ = should_dim; |
| } |
| |
| bool should_turn_off = |
| state == BACKLIGHT_IDLE_OFF || state == BACKLIGHT_SUSPENDED; |
| if (should_turn_off != currently_off_) { |
| if (monitor_reconfigure_) { |
| if (should_turn_off ) |
| monitor_reconfigure_->SetScreenOff(); |
| else |
| monitor_reconfigure_->SetScreenOn(); |
| } |
| currently_off_ = should_turn_off; |
| } |
| |
| return true; |
| } |
| |
| PowerState ExternalBacklightController::GetPowerState() const { |
| return power_state_; |
| } |
| |
| bool ExternalBacklightController::OnPlugEvent(bool is_plugged) { |
| return false; |
| } |
| |
| void ExternalBacklightController::SetAlsBrightnessOffsetPercent( |
| double percent) { |
| // Desktop systems aren't expected to have a light sensor. |
| NOTIMPLEMENTED(); |
| } |
| |
| bool ExternalBacklightController::IsBacklightActiveOff() { |
| return false; |
| } |
| |
| int ExternalBacklightController::GetNumAmbientLightSensorAdjustments() const { |
| return 0; |
| } |
| |
| int ExternalBacklightController::GetNumUserAdjustments() const { |
| return num_user_adjustments_; |
| } |
| |
| void ExternalBacklightController::OnBacklightDeviceChanged() { |
| Init(); |
| } |
| |
| double ExternalBacklightController::LevelToPercent(int64 level) { |
| if (max_level_ <= 0) |
| return 0.0; |
| |
| level = std::min(std::max(level, static_cast<int64>(0)), max_level_); |
| return 100.0 * level / max_level_; |
| } |
| |
| int64 ExternalBacklightController::PercentToLevel(double percent) { |
| if (max_level_ <= 0) |
| return 0; |
| |
| percent = std::min(std::max(percent, 0.0), 100.0); |
| return llround(percent / 100.0 * max_level_); |
| } |
| |
| bool ExternalBacklightController::AdjustBrightnessByOffset( |
| double percent_offset, |
| BrightnessChangeCause cause) { |
| double percent = 0.0; |
| if (!GetCurrentBrightnessPercent(&percent)) |
| return false; |
| |
| percent += percent_offset; |
| percent = std::min(std::max(percent, 0.0), 100.0); |
| return SetCurrentBrightnessPercent(percent, cause, TRANSITION_INSTANT); |
| } |
| |
| void ExternalBacklightController::SendSoftwareDimmingSignal(int state) { |
| chromeos::dbus::Proxy proxy(chromeos::dbus::GetSystemBusConnection(), |
| kPowerManagerServicePath, |
| kPowerManagerInterface); |
| DBusMessage* signal = dbus_message_new_signal( |
| kPowerManagerServicePath, |
| kPowerManagerInterface, |
| kSoftwareScreenDimmingRequestedSignal); |
| CHECK(signal); |
| |
| dbus_message_append_args(signal, |
| DBUS_TYPE_INT32, &state, |
| DBUS_TYPE_INVALID); |
| dbus_g_proxy_send(proxy.gproxy(), signal, NULL); |
| dbus_message_unref(signal); |
| } |
| |
| } // namespace power_manager |