blob: a0390bc7ce46a145f931250e1fba1fd03f4c23a6 [file] [log] [blame]
// 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/powerd/policy/internal_backlight_controller.h"
#include <sys/time.h>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include "power_manager/common/clock.h"
#include "power_manager/common/power_constants.h"
#include "power_manager/common/prefs.h"
#include "power_manager/powerd/policy/backlight_controller_observer.h"
#include "power_manager/powerd/system/display/display_power_setter.h"
#include "power_manager/proto_bindings/policy.pb.h"
namespace power_manager {
namespace policy {
namespace {
// Maximum valid value for percentages.
const double kMaxPercent = 100.0;
// When going into the idle-induced dim state, the backlight dims to this
// fraction (in the range [0.0, 1.0]) of its maximum brightness level. This is
// a fraction rather than a percent so it won't change if
// kDefaultLevelToPercentExponent is modified.
const double kDimmedBrightnessFraction = 0.1;
// Value for |level_to_percent_exponent_|, assuming that at least
// |kMinLevelsForNonLinearScale| brightness levels are available -- if not, we
// just use 1.0 to give us a linear scale.
const double kDefaultLevelToPercentExponent = 0.5;
// Minimum number of brightness levels needed before we use a non-linear mapping
// between levels and percents.
const double kMinLevelsForNonLinearMapping = 100;
// Returns the animation duration for |transition|.
base::TimeDelta TransitionStyleToTimeDelta(
BacklightController::TransitionStyle transition) {
switch (transition) {
case BacklightController::TRANSITION_INSTANT:
return base::TimeDelta();
case BacklightController::TRANSITION_FAST:
return base::TimeDelta::FromMilliseconds(kFastBacklightTransitionMs);
case BacklightController::TRANSITION_SLOW:
return base::TimeDelta::FromMilliseconds(kSlowBacklightTransitionMs);
}
NOTREACHED();
return base::TimeDelta();
}
// Clamps |percent| to fit between kMinVisiblePercent and 100.
double ClampPercentToVisibleRange(double percent) {
return std::min(kMaxPercent,
std::max(InternalBacklightController::kMinVisiblePercent, percent));
}
// Reads |pref_name| from |prefs| and returns the desired initial brightness
// percent corresponding to |backlight_nits|, the backlight's actual maximum
// luminance. Crashes on failure.
//
// The pref's value should consist of one or more lines, each containing either
// a single double brightness percentage or a space-separated "<double-percent>
// <int64_t-max-level>" pair. The percentage from the first line either using
// the single-value format or matching |backlight_nits| will be returned.
//
// For example,
//
// 60.0 300
// 50.0 400
// 40.0
//
// indicates that 60% should be used if the maximum luminance is 300, 50% should
// be used if it's 400, and 40% should be used otherwise.
//
// Note that this method will crash if no matching lines are found.
double GetInitialBrightnessPercent(PrefsInterface* prefs,
const std::string& pref_name,
int64_t backlight_nits) {
DCHECK(prefs);
std::string pref_value;
CHECK(prefs->GetString(pref_name, &pref_value))
<< "Unable to read pref " << pref_name;
std::vector<std::string> lines;
base::SplitString(pref_value, '\n', &lines);
for (size_t i = 0; i < lines.size(); ++i) {
std::vector<std::string> parts;
base::SplitStringAlongWhitespace(lines[i], &parts);
CHECK(parts.size() == 1U || parts.size() == 2U)
<< "Unable to parse \"" << lines[i] << "\" from pref " << pref_name;
double percent = 0.0;
CHECK(base::StringToDouble(parts[0], &percent) &&
percent >= 0.0 && percent <= 100.0)
<< "Unable to parse \"" << parts[0] << "\" from pref " << pref_name
<< " as double in [0.0, 100.0]";
if (parts.size() == 1U)
return percent;
int64_t nits = -1;
CHECK(base::StringToInt64(parts[1], &nits))
<< "Unable to parse \"" << parts[1] << "\" from pref " << pref_name;
if (nits == backlight_nits)
return percent;
}
LOG(FATAL) << "Unable to find initial brightness percentage in pref "
<< pref_name << " for " << backlight_nits << " nits";
return kMaxPercent;
}
} // namespace
const int64_t InternalBacklightController::kMaxBrightnessSteps = 16;
const double InternalBacklightController::kMinVisiblePercent =
kMaxPercent / kMaxBrightnessSteps;
const double InternalBacklightController::kDefaultMinVisibleBrightnessFraction =
0.0065;
const int InternalBacklightController::kAmbientLightSensorTimeoutSec = 10;
InternalBacklightController::InternalBacklightController()
: backlight_(NULL),
prefs_(NULL),
display_power_setter_(NULL),
clock_(new Clock),
power_source_(POWER_BATTERY),
display_mode_(DISPLAY_NORMAL),
dimmed_for_inactivity_(false),
off_for_inactivity_(false),
suspended_(false),
shutting_down_(false),
docked_(false),
got_ambient_light_brightness_percent_(false),
got_power_source_(false),
already_set_initial_state_(false),
als_adjustment_count_(0),
user_adjustment_count_(0),
ambient_light_brightness_percent_(kMaxPercent),
plugged_explicit_brightness_percent_(kMaxPercent),
unplugged_explicit_brightness_percent_(kMaxPercent),
using_policy_brightness_(false),
force_nonzero_brightness_for_user_activity_(true),
max_level_(0),
min_visible_level_(0),
instant_transitions_below_min_level_(false),
use_ambient_light_(true),
step_percent_(1.0),
dimmed_brightness_percent_(kDimmedBrightnessFraction * 100.0),
level_to_percent_exponent_(kDefaultLevelToPercentExponent),
current_level_(0),
display_power_state_(chromeos::DISPLAY_POWER_ALL_ON) {
}
InternalBacklightController::~InternalBacklightController() {}
void InternalBacklightController::Init(
system::BacklightInterface* backlight,
PrefsInterface* prefs,
system::AmbientLightSensorInterface* sensor,
system::DisplayPowerSetterInterface* display_power_setter) {
backlight_ = backlight;
prefs_ = prefs;
display_power_setter_ = display_power_setter;
max_level_ = backlight_->GetMaxBrightnessLevel();
current_level_ = backlight_->GetCurrentBrightnessLevel();
if (!prefs_->GetInt64(kMinVisibleBacklightLevelPref, &min_visible_level_)) {
min_visible_level_ = static_cast<int64_t>(
lround(kDefaultMinVisibleBrightnessFraction * max_level_));
}
min_visible_level_ = std::min(
std::max(min_visible_level_, static_cast<int64_t>(1)), max_level_);
const double initial_percent = LevelToPercent(current_level_);
ambient_light_brightness_percent_ = initial_percent;
int64_t max_nits = 0;
prefs_->GetInt64(kInternalBacklightMaxNitsPref, &max_nits);
plugged_explicit_brightness_percent_ = GetInitialBrightnessPercent(
prefs_, kInternalBacklightNoAlsAcBrightnessPref, max_nits);
unplugged_explicit_brightness_percent_ = GetInitialBrightnessPercent(
prefs_, kInternalBacklightNoAlsBatteryBrightnessPref, max_nits);
prefs_->GetBool(kInstantTransitionsBelowMinLevelPref,
&instant_transitions_below_min_level_);
if (sensor) {
ambient_light_handler_.reset(new AmbientLightHandler(sensor, this));
ambient_light_handler_->set_name("panel");
std::string pref_value;
CHECK(prefs_->GetString(kInternalBacklightAlsStepsPref, &pref_value))
<< "Failed to read pref " << kInternalBacklightAlsStepsPref;
ambient_light_handler_->Init(pref_value, initial_percent);
} else {
use_ambient_light_ = false;
}
int64_t turn_off_screen_timeout_ms = 0;
prefs_->GetInt64(kTurnOffScreenTimeoutMsPref, &turn_off_screen_timeout_ms);
turn_off_screen_timeout_ =
base::TimeDelta::FromMilliseconds(turn_off_screen_timeout_ms);
if (max_level_ == min_visible_level_ || kMaxBrightnessSteps == 1) {
step_percent_ = kMaxPercent;
} else {
// 1 is subtracted from kMaxBrightnessSteps to account for the step between
// |min_brightness_level_| and 0.
step_percent_ =
(kMaxPercent - kMinVisiblePercent) /
std::min(kMaxBrightnessSteps - 1, max_level_ - min_visible_level_);
}
CHECK_GT(step_percent_, 0.0);
level_to_percent_exponent_ =
max_level_ >= kMinLevelsForNonLinearMapping ?
kDefaultLevelToPercentExponent :
1.0;
dimmed_brightness_percent_ = ClampPercentToVisibleRange(
LevelToPercent(lround(kDimmedBrightnessFraction * max_level_)));
init_time_ = clock_->GetCurrentTime();
LOG(INFO) << "Backlight has range [0, " << max_level_ << "] with "
<< step_percent_ << "% step and minimum-visible level of "
<< min_visible_level_ << "; current level is " << current_level_
<< " (" << LevelToPercent(current_level_) << "%)";
}
double InternalBacklightController::LevelToPercent(int64_t raw_level) {
// If the passed-in level is below the minimum visible level, just map it
// linearly into [0, kMinVisiblePercent).
if (raw_level < min_visible_level_)
return kMinVisiblePercent * raw_level / min_visible_level_;
// Since we're at or above the minimum level, we know that we're at 100% if
// the min and max are equal.
if (min_visible_level_ == max_level_)
return 100.0;
double linear_fraction =
static_cast<double>(raw_level - min_visible_level_) /
(max_level_ - min_visible_level_);
return kMinVisiblePercent + (kMaxPercent - kMinVisiblePercent) *
pow(linear_fraction, level_to_percent_exponent_);
}
int64_t InternalBacklightController::PercentToLevel(double percent) {
if (percent < kMinVisiblePercent)
return lround(min_visible_level_ * percent / kMinVisiblePercent);
if (percent == kMaxPercent)
return max_level_;
double linear_fraction = (percent - kMinVisiblePercent) /
(kMaxPercent - kMinVisiblePercent);
return lround(min_visible_level_ + (max_level_ - min_visible_level_) *
pow(linear_fraction, 1.0 / level_to_percent_exponent_));
}
void InternalBacklightController::AddObserver(
BacklightControllerObserver* observer) {
DCHECK(observer);
observers_.AddObserver(observer);
}
void InternalBacklightController::RemoveObserver(
BacklightControllerObserver* observer) {
DCHECK(observer);
observers_.RemoveObserver(observer);
}
void InternalBacklightController::HandlePowerSourceChange(PowerSource source) {
if (got_power_source_ && power_source_ == source)
return;
VLOG(1) << "Power source changed to " << PowerSourceToString(source);
// Ensure that the screen isn't dimmed in response to a transition to AC
// or brightened in response to a transition to battery.
if (got_power_source_) {
bool plugged = source == POWER_AC;
bool unplugged_exceeds_plugged =
unplugged_explicit_brightness_percent_ >
plugged_explicit_brightness_percent_;
if (plugged && unplugged_exceeds_plugged) {
plugged_explicit_brightness_percent_ =
unplugged_explicit_brightness_percent_;
} else if (!plugged && unplugged_exceeds_plugged) {
unplugged_explicit_brightness_percent_ =
plugged_explicit_brightness_percent_;
}
}
power_source_ = source;
got_power_source_ = true;
UpdateState();
if (ambient_light_handler_)
ambient_light_handler_->HandlePowerSourceChange(source);
}
void InternalBacklightController::HandleDisplayModeChange(DisplayMode mode) {
if (display_mode_ == mode)
return;
display_mode_ = mode;
// If there's no external display now, make sure that the panel is on.
if (display_mode_ == DISPLAY_NORMAL)
EnsureUserBrightnessIsNonzero();
}
void InternalBacklightController::HandleSessionStateChange(SessionState state) {
EnsureUserBrightnessIsNonzero();
if (state == SESSION_STARTED) {
als_adjustment_count_ = 0;
user_adjustment_count_ = 0;
}
}
void InternalBacklightController::HandlePowerButtonPress() {
EnsureUserBrightnessIsNonzero();
}
void InternalBacklightController::HandleUserActivity(UserActivityType type) {
// Don't increase the brightness automatically when the user hits a
// brightness key: if they hit brightness-up, IncreaseUserBrightness()
// will be called soon anyway; if they hit brightness-down, the screen
// shouldn't get turned back on. Also ignore volume keys.
if (type != USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS &&
type != USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS &&
type != USER_ACTIVITY_VOLUME_UP_KEY_PRESS &&
type != USER_ACTIVITY_VOLUME_DOWN_KEY_PRESS &&
type != USER_ACTIVITY_VOLUME_MUTE_KEY_PRESS)
EnsureUserBrightnessIsNonzero();
}
void InternalBacklightController::HandlePolicyChange(
const PowerManagementPolicy& policy) {
if (policy.has_ac_brightness_percent()) {
LOG(INFO) << "Got policy-triggered request to set AC brightness to "
<< policy.ac_brightness_percent() << "%";
SetExplicitBrightnessPercent(policy.ac_brightness_percent(),
TRANSITION_FAST,
BRIGHTNESS_CHANGE_AUTOMATED,
POWER_AC);
}
if (policy.has_battery_brightness_percent()) {
LOG(INFO) << "Got policy-triggered request to set battery brightness to "
<< policy.battery_brightness_percent() << "%";
SetExplicitBrightnessPercent(policy.battery_brightness_percent(),
TRANSITION_FAST,
BRIGHTNESS_CHANGE_AUTOMATED,
POWER_BATTERY);
}
using_policy_brightness_ = policy.has_ac_brightness_percent() ||
policy.has_battery_brightness_percent();
force_nonzero_brightness_for_user_activity_ =
policy.has_force_nonzero_brightness_for_user_activity() ?
policy.force_nonzero_brightness_for_user_activity() : true;
}
void InternalBacklightController::HandleChromeStart() {
display_power_setter_->SetDisplayPower(
display_power_state_, base::TimeDelta());
}
void InternalBacklightController::SetDimmedForInactivity(bool dimmed) {
if (dimmed_for_inactivity_ == dimmed)
return;
VLOG(1) << (dimmed ? "Dimming" : "No longer dimming") << " for inactivity";
dimmed_for_inactivity_ = dimmed;
UpdateState();
}
void InternalBacklightController::SetOffForInactivity(bool off) {
if (off_for_inactivity_ == off)
return;
VLOG(1) << (off ? "Turning backlight off" : "No longer keeping backlight off")
<< " for inactivity";
off_for_inactivity_ = off;
UpdateState();
}
void InternalBacklightController::SetSuspended(bool suspended) {
if (suspended_ == suspended)
return;
VLOG(1) << (suspended ? "Suspending" : "Unsuspending") << " backlight";
suspended_ = suspended;
UpdateState();
}
void InternalBacklightController::SetShuttingDown(bool shutting_down) {
if (shutting_down_ == shutting_down)
return;
if (shutting_down)
VLOG(1) << "Preparing backlight for shutdown";
else
LOG(WARNING) << "Exiting shutting-down state";
shutting_down_ = shutting_down;
UpdateState();
}
void InternalBacklightController::SetDocked(bool docked) {
if (docked_ == docked)
return;
VLOG(1) << (docked ? "Entering" : "Leaving") << " docked mode";
docked_ = docked;
UpdateState();
}
bool InternalBacklightController::GetBrightnessPercent(double* percent) {
DCHECK(percent);
*percent = LevelToPercent(current_level_);
return true;
}
bool InternalBacklightController::SetUserBrightnessPercent(
double percent,
TransitionStyle style) {
LOG(INFO) << "Got user-triggered request to set brightness to "
<< percent << "%";
user_adjustment_count_++;
using_policy_brightness_ = false;
// When the user explicitly requests a specific brightness level, use it for
// both AC and battery power.
const PowerSource inactive_power_source =
power_source_ == POWER_AC ? POWER_BATTERY : POWER_AC;
SetExplicitBrightnessPercent(percent, style, BRIGHTNESS_CHANGE_USER_INITIATED,
inactive_power_source);
return SetExplicitBrightnessPercent(percent, style,
BRIGHTNESS_CHANGE_USER_INITIATED,
power_source_);
}
bool InternalBacklightController::IncreaseUserBrightness() {
double old_percent = GetUndimmedBrightnessPercent();
double new_percent =
(old_percent < kMinVisiblePercent - kEpsilon) ? kMinVisiblePercent :
ClampPercentToVisibleRange(
SnapBrightnessPercentToNearestStep(old_percent + step_percent_));
return SetUserBrightnessPercent(new_percent, TRANSITION_FAST);
}
bool InternalBacklightController::DecreaseUserBrightness(bool allow_off) {
// Lower the backlight to the next step, turning it off if it was already at
// the minimum visible level.
double old_percent = GetUndimmedBrightnessPercent();
double new_percent = old_percent <= kMinVisiblePercent + kEpsilon ? 0.0 :
ClampPercentToVisibleRange(
SnapBrightnessPercentToNearestStep(old_percent - step_percent_));
if (!allow_off && new_percent <= kEpsilon) {
user_adjustment_count_++;
return false;
}
return SetUserBrightnessPercent(new_percent, TRANSITION_FAST);
}
int InternalBacklightController::GetNumAmbientLightSensorAdjustments() const {
return als_adjustment_count_;
}
int InternalBacklightController::GetNumUserAdjustments() const {
return user_adjustment_count_;
}
void InternalBacklightController::SetBrightnessPercentForAmbientLight(
double brightness_percent,
AmbientLightHandler::BrightnessChangeCause cause) {
ambient_light_brightness_percent_ = brightness_percent;
got_ambient_light_brightness_percent_ = true;
if (use_ambient_light_) {
if (!already_set_initial_state_) {
// UpdateState() defers doing anything until the first ambient light
// reading has been received, so it may need to be called at this point.
UpdateState();
} else {
TransitionStyle transition =
cause == AmbientLightHandler::CAUSED_BY_AMBIENT_LIGHT ?
TRANSITION_SLOW : TRANSITION_FAST;
if (UpdateUndimmedBrightness(transition, BRIGHTNESS_CHANGE_AUTOMATED) &&
cause == AmbientLightHandler::CAUSED_BY_AMBIENT_LIGHT)
als_adjustment_count_++;
}
}
}
double InternalBacklightController::SnapBrightnessPercentToNearestStep(
double percent) const {
return round(percent / step_percent_) * step_percent_;
}
double InternalBacklightController::GetExplicitBrightnessPercent() const {
return power_source_ == POWER_AC ? plugged_explicit_brightness_percent_ :
unplugged_explicit_brightness_percent_;
}
double InternalBacklightController::GetUndimmedBrightnessPercent() const {
if (use_ambient_light_)
return ClampPercentToVisibleRange(ambient_light_brightness_percent_);
const double percent = GetExplicitBrightnessPercent();
return percent <= kEpsilon ? 0.0 : ClampPercentToVisibleRange(percent);
}
void InternalBacklightController::EnsureUserBrightnessIsNonzero() {
// Avoid turning the backlight back on if an external display is
// connected since doing so may result in the desktop being resized. Also
// don't turn it on if a policy has forced the brightness to zero.
if (force_nonzero_brightness_for_user_activity_ &&
display_mode_ == DISPLAY_NORMAL &&
GetExplicitBrightnessPercent() < kMinVisiblePercent &&
!using_policy_brightness_) {
SetExplicitBrightnessPercent(kMinVisiblePercent, TRANSITION_FAST,
BRIGHTNESS_CHANGE_AUTOMATED, power_source_);
}
}
bool InternalBacklightController::SetExplicitBrightnessPercent(
double percent,
TransitionStyle style,
BrightnessChangeCause cause,
PowerSource power_source) {
use_ambient_light_ = false;
const bool is_zero = percent <= kEpsilon;
percent = is_zero ? 0.0 : ClampPercentToVisibleRange(percent);
double* explicit_percent_ptr =
(power_source == POWER_AC) ? &plugged_explicit_brightness_percent_ :
&unplugged_explicit_brightness_percent_;
*explicit_percent_ptr = percent;
if (power_source != power_source_)
return false;
return UpdateUndimmedBrightness(style, cause);
}
void InternalBacklightController::UpdateState() {
// Give up on the ambient light sensor if it's not supplying readings.
if (use_ambient_light_ && !got_ambient_light_brightness_percent_ &&
clock_->GetCurrentTime() - init_time_ >=
base::TimeDelta::FromSeconds(kAmbientLightSensorTimeoutSec)) {
LOG(ERROR) << "Giving up on ambient light sensor after getting no reading "
<< "within " << kAmbientLightSensorTimeoutSec << " seconds";
use_ambient_light_ = false;
}
// Hold off on changing the brightness at startup until all the required
// state has been received.
if (!got_power_source_ ||
(use_ambient_light_ && !got_ambient_light_brightness_percent_))
return;
double brightness_percent = 100.0;
TransitionStyle brightness_transition = TRANSITION_INSTANT;
double resume_percent = -1.0;
chromeos::DisplayPowerState display_power = chromeos::DISPLAY_POWER_ALL_ON;
TransitionStyle display_transition = TRANSITION_INSTANT;
bool set_display_power = true;
if (shutting_down_) {
brightness_percent = 0.0;
display_power = chromeos::DISPLAY_POWER_ALL_OFF;
} else if (suspended_) {
brightness_percent = 0.0;
resume_percent = GetUndimmedBrightnessPercent();
// Chrome puts displays into the correct power state before suspend.
set_display_power = false;
} else if (off_for_inactivity_) {
brightness_percent = 0.0;
brightness_transition = TRANSITION_FAST;
display_power = chromeos::DISPLAY_POWER_ALL_OFF;
display_transition = TRANSITION_FAST;
} else if (docked_) {
brightness_percent = 0.0;
display_power = chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON;
} else {
brightness_percent = std::min(GetUndimmedBrightnessPercent(),
dimmed_for_inactivity_ ? dimmed_brightness_percent_ : 100.0);
const bool turning_on =
display_power_state_ != chromeos::DISPLAY_POWER_ALL_ON ||
current_level_ == 0;
brightness_transition = turning_on ? TRANSITION_INSTANT :
(already_set_initial_state_ ? TRANSITION_FAST : TRANSITION_SLOW);
// Keep the external display(s) on if the brightness was explicitly set to
// 0.
display_power = (brightness_percent <= kEpsilon) ?
chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON :
chromeos::DISPLAY_POWER_ALL_ON;
}
if (set_display_power) {
SetDisplayPower(display_power,
TransitionStyleToTimeDelta(display_transition));
}
// Apply the brightess after toggling the display power since the bl_power
// sysfs interface is an asynchronous request. If we do it the other way
// around, then the brightness we set here has a potential to get interleaved
// with the display power toggle operation in some drivers resulting in the
// brightness getting set to the last value we applied. See
// chrome-os-partner:31186 for more details.
ApplyBrightnessPercent(brightness_percent, brightness_transition,
BRIGHTNESS_CHANGE_AUTOMATED);
if (resume_percent >= 0.0)
ApplyResumeBrightnessPercent(resume_percent);
already_set_initial_state_ = true;
}
bool InternalBacklightController::UpdateUndimmedBrightness(
TransitionStyle style,
BrightnessChangeCause cause) {
const double percent = GetUndimmedBrightnessPercent();
if (suspended_)
ApplyResumeBrightnessPercent(percent);
// Don't apply the change if we're in a state that overrides the new level.
if (shutting_down_ || suspended_ || docked_ || off_for_inactivity_ ||
dimmed_for_inactivity_)
return false;
if (!ApplyBrightnessPercent(percent, style, cause))
return false;
if (percent <= kEpsilon) {
// Keep the external display(s) on if the brightness was explicitly set to
// 0.
SetDisplayPower(
chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
docked_ ? base::TimeDelta() :
TransitionStyleToTimeDelta(style) + turn_off_screen_timeout_);
} else {
SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON, base::TimeDelta());
}
return true;
}
bool InternalBacklightController::ApplyBrightnessPercent(
double percent,
TransitionStyle transition,
BrightnessChangeCause cause) {
int64_t level = PercentToLevel(percent);
if (level == current_level_)
return false;
// Force an instant transition if needed while moving within the
// not-visible range.
bool starting_below_min_visible_level = current_level_ < min_visible_level_;
bool ending_below_min_visible_level = level < min_visible_level_;
if (instant_transitions_below_min_level_ &&
starting_below_min_visible_level != ending_below_min_visible_level)
transition = TRANSITION_INSTANT;
base::TimeDelta interval = TransitionStyleToTimeDelta(transition);
LOG(INFO) << "Setting brightness to " << level << " (" << percent
<< "%) over " << interval.InMilliseconds() << " ms";
if (!backlight_->SetBrightnessLevel(level, interval)) {
LOG(WARNING) << "Could not set brightness";
return false;
}
current_level_ = level;
FOR_EACH_OBSERVER(BacklightControllerObserver, observers_,
OnBrightnessChanged(percent, cause, this));
return true;
}
bool InternalBacklightController::ApplyResumeBrightnessPercent(
double resume_percent) {
int64_t level = PercentToLevel(resume_percent);
LOG(INFO) << "Setting resume brightness to " << level << " ("
<< resume_percent << "%)";
return backlight_->SetResumeBrightnessLevel(level);
}
void InternalBacklightController::SetDisplayPower(
chromeos::DisplayPowerState state,
base::TimeDelta delay) {
if (state == display_power_state_)
return;
display_power_setter_->SetDisplayPower(state, delay);
display_power_state_ = state;
}
} // namespace policy
} // namespace power_manager