| // 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), |
| ac_explicit_brightness_percent_(kMaxPercent), |
| battery_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); |
| ac_explicit_brightness_percent_ = GetInitialBrightnessPercent( |
| prefs_, kInternalBacklightNoAlsAcBrightnessPref, max_nits); |
| battery_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_) { |
| const bool on_ac = source == POWER_AC; |
| const bool battery_exceeds_ac = |
| battery_explicit_brightness_percent_ > ac_explicit_brightness_percent_; |
| if (on_ac && battery_exceeds_ac) |
| ac_explicit_brightness_percent_ = battery_explicit_brightness_percent_; |
| else if (!on_ac && battery_exceeds_ac) |
| battery_explicit_brightness_percent_ = ac_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) { |
| bool got_policy_brightness = false; |
| |
| double ac_brightness = ac_explicit_brightness_percent_; |
| if (policy.has_ac_brightness_percent()) { |
| LOG(INFO) << "Got policy-triggered request to set AC brightness to " |
| << policy.ac_brightness_percent() << "%"; |
| ac_brightness = policy.ac_brightness_percent(); |
| got_policy_brightness = true; |
| } |
| double battery_brightness = battery_explicit_brightness_percent_; |
| if (policy.has_battery_brightness_percent()) { |
| LOG(INFO) << "Got policy-triggered request to set battery brightness to " |
| << policy.battery_brightness_percent() << "%"; |
| battery_brightness = policy.battery_brightness_percent(); |
| got_policy_brightness = true; |
| } |
| |
| using_policy_brightness_ = got_policy_brightness; |
| if (got_policy_brightness) { |
| SetExplicitBrightnessPercent(ac_brightness, battery_brightness, |
| TRANSITION_FAST, BRIGHTNESS_CHANGE_AUTOMATED); |
| } |
| 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. |
| return SetExplicitBrightnessPercent(percent, percent, style, |
| BRIGHTNESS_CHANGE_USER_INITIATED); |
| } |
| |
| 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 ? ac_explicit_brightness_percent_ : |
| battery_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_ && |
| !use_ambient_light_) { |
| SetExplicitBrightnessPercent(kMinVisiblePercent, kMinVisiblePercent, |
| TRANSITION_FAST, BRIGHTNESS_CHANGE_AUTOMATED); |
| } |
| } |
| |
| bool InternalBacklightController::SetExplicitBrightnessPercent( |
| double ac_percent, |
| double battery_percent, |
| TransitionStyle style, |
| BrightnessChangeCause cause) { |
| use_ambient_light_ = false; |
| ac_explicit_brightness_percent_ = ac_percent <= kEpsilon ? 0.0 : |
| ClampPercentToVisibleRange(ac_percent); |
| battery_explicit_brightness_percent_ = battery_percent <= kEpsilon ? 0.0 : |
| ClampPercentToVisibleRange(battery_percent); |
| 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) { |
| // For instant transitions, this call blocks until Chrome confirms that it |
| // has made the change. |
| SetDisplayPower(display_power, |
| TransitionStyleToTimeDelta(display_transition)); |
| } |
| |
| // Apply the brightness after toggling the display power. If we do it the |
| // other way around, then the brightness set here has a potential to get |
| // interleaved with the display power toggle operation in some drivers |
| // resulting in this request being dropped and the brightness being set to its |
| // previous value instead. See chrome-os-partner:31186 and :35662 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_ && !backlight_->TransitionInProgress()) |
| 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 |